请教PIC单片机写I2C和SPI时,卡住在 while(!SSPIF);

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了请教PIC单片机写I2C和SPI时,卡住在 while(!SSPIF);相关的知识,希望对你有一定的参考价值。

本人想实践一下PIC单片机的I2C,SPI总线,于是找了基于IIC的E2PROM和基于SPI的E2PROM,并写写了程序。但是问题出来了。写的程序不能实现向E2PROM写数据的功能。于是我在MPLAB中分步执行,结果程序卡在SSPIF这里不动。请问是什么原因?

基于SPI的E2PROM我选用的是25C040,写数据前要发送0X06,代表写使能的意思。我调用写使能函数,停留在 while(!SSPIF); 不动了。
void WriteEnable()

CS=0;
SSPBUF=0x06;
while(!SSPIF); //程序卡在这句话不动了。
SSPIF=0;
CS=1;


基于I2C的E2PROM我选用的是24C02,写应答程序的时候也是卡在这句话不动了。

void checksend()

while(SSPIF==0) //程序也是卡在这里不动了。
;
SSPIF=0;

请问是什么原因???????????

看看人家的程序吧,就搞定了
要点就是:1,要正确初始化ssp,2、SSPIF需要手动清除的
/***************************************************************************
****************************************************************************/
#include<pic.h>
#define uchar unsigned char
#define uint unsigned int
#define add 0xaa
__CONFIG(0x1832);
const uchar ee_data[]=1,2,3,4,5,6;
uchar read_data[6];
const uchar table[]=0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,
0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71;
void delay(uint x);
void init();
void didi(uchar num);
void disp(uchar num1,uchar num2,uchar num3,uchar num4,uchar num5,uchar num6);
void write();
void read();
void main()

init();
write();
delay(100);
read();

while(1)

disp(read_data[0],read_data[1],read_data[2],read_data[3],read_data[4],read_data[5]);


void delay(uint x)

uint a,b;
for(a=x;a>0;a--)
for(b=110;b>0;b--);

void init()

TRISD=0;
TRISA=0;
//TRISC=0;
TRISE0=1;
// ADCON1=0x07;
RE0=1;
PORTD=0;
PORTA=0;
TRISC=0xfe;
PORTC = 0x01; //74HC138控制端口
SSPSTAT=0x80;
SSPCON=0x38;
SSPCON2=0;
SSPADD=0x09;
PORTE=1;

void write()

uchar i;
SSPIF=0;
SEN=1;
while(!SSPIF);
SSPIF=0;
SSPBUF=0xA0;
while(!SSPIF);
SSPIF=0;
SSPBUF=add;
while(!SSPIF);
SSPIF=0;
for(i=0;i<6;i++)

SSPBUF=ee_data[i];
while(!SSPIF);
SSPIF=0;

PEN=1;
while(!SSPIF);
SSPIF=0;

void read()

uchar i;
SSPIF=0;
SEN=1;
while(!SSPIF);
SSPIF=0;
SSPBUF=0xA0;
while(!SSPIF);
SSPIF=0;
SSPBUF=add;
while(!SSPIF);
SSPIF=0;
SSPIF=0;
RSEN=1;
while(!SSPIF);
SSPIF=0;
SSPBUF=0xA1;
while(!SSPIF);
SSPIF=0;
for(i=0;i<6;i++)

RCEN=1;
while(!SSPIF);
read_data[i]=SSPBUF;
while(!SSPIF);
SSPIF=0;
if(i>=5)

ACKDT=1;

else

ACKDT=0;

ACKEN=1;
while(!SSPIF);
SSPIF=0;

PEN=1;
while(!SSPIF);
SSPIF=0;

void didi(uchar num)

uchar di_num;
for(di_num=num;di_num>0;di_num--)

RE0=1;
delay(50);
RE0=0;
delay(20);



void disp(uchar num1,uchar num2,uchar num3,uchar num4,uchar num5,uchar num6)

PORTD=table[num1];//显示第一个数码管
PORTA=0x01;//0010 0000
delay(2);
PORTD=table[num2];//显示第二个数码管
PORTA=0x02;//0001 0000
delay(2);
PORTD=table[num3];//显示第三个数码管
PORTA=0x04;//0000 1000
delay(2);
PORTD=table[num4];//显示第四个数码管
PORTA=0x06;//0000 0100
delay(2);
PORTD=table[num5];//显示第五个数码管
PORTA=0x08;//0000 0010
delay(2);
PORTD=table[num6];//显示第六个数码管
PORTA=0x0A;//0000 0001
delay(2);
参考技术A 我也遇到过这个问题,是没有对TRISC进行端口初始化造成的,在init()里面初始化RC的方向寄存器就可以了。就可以检测到数据发送完毕的信号了追问

我初始化了的啊,就是不行。

追答

我看了下25C040的write byte时序图,操作码,地址码,之后紧接着是8位数据,你没写地址码和数据怎么传的过去啊。

参考技术B void iic_init()

TRISC=0;
TRISB=0;
PORTC=0xff;
PORTB=0xff;
SSPSTAT=0x80;
SSPCON=0x38;
SSPCON2=0;
SSPADD=0x09;

void icc_delay(uint z)

uint x,y;
for(x=z;x>0;x--)
for(y=110;y>0;y--);

void iic_write_byte(uchar add,uchar dat)

uchar i;
SSPIF=0;
SEN=1; //开始位
while(!SSPIF);
SSPIF=0;
SSPBUF=0xa0; //器件地址
while(!SSPIF); //等待数据发完
SSPIF=0;
SSPBUF=add; //数据所存地址
while(!SSPIF);
SSPIF=0;
SSPBUF=dat;
while(!SSPIF);
SSPIF=0;
PEN=1; //停止信号
while(!SSPIF);
SSPIF=0;


iic_read_byte(uchar add)

uchar i,a;
SSPIF=0;
SEN=1; //开始信号
while(!SSPIF);
SSPIF=0;
SSPBUF=0XA0; //器件地址
while(!SSPIF);
SSPIF=0;
SSPBUF=add; //数据地址
while(!SSPIF);
SSPIF=0;
RSEN=1; //方向变化
while(!SSPIF);
SSPIF=0;
SSPBUF=0xA1;
while(!SSPIF);
SSPIF=0;
RCEN=1; //接收始能
while(!SSPIF);
a=SSPBUF;
SSPIF=0;
ACKDT=0;
ACKEN=1;
while(!SSPIF);
SSPIF=0;
PEN=1;
while(!SSPIF);
SSPIF=0;
return a;

PIC SPI配置问题

我有一些与SPI的SPIxCON寄存器有关的问题。我用的是PIC18F26K83。 1)有一个SPIxTCNTH:SPI传输计数器MSB寄存器。我可以在其上设置前3位,用于计数要传输的位。根据数据表,它是可写的。根据数据表,它计算将被传输的位然后为什么它是可写的?我是否需要根据我要发送的位来编写它?或者是否通知用户。

2)有SPIxTWIDTH:SPI TRANSFER WIDTH REGISTER。在BMODE = 1的情况下,传输计数器计数的每次传输的大小(以位为单位)I将向DAC发送诸如1.1或2.3的值。在这种情况下,我应该将它设置为什么?这个寄存器有标准价值吗?

3)根据我们无法用软件控制的数据表,我无法得到FIFO寄存器的内容。它不像缓冲区吗?因此,如果我写入发送寄存器的速度比传输速度快,则发送数据将被放入FIFO。他们将一个接一个地传播。我对么?我不需要任何东西而不是写入发送缓冲区。

4)我读了但无法理解SPIxCON1中的极性位。如果我不触摸控制寄存器中的这些位,可以吗?我不想搞砸。

5)我如何选择奴隶? SPIxCON2寄存器中有一个SSET(从器件选择使能位)。我可以把它做成1,但那我怎么能选择奴隶呢?

谢谢您的回答。我是新手。对不起,简单而且可能没有意义的问题。或者我可以简单地显示我的配置代码,但我相信它会更难分析。

答案

1)传输计数器(在使用时)被写入以发送或接收的字节数或部分字节数(取决于模式)。因此,如果您将它(BMODE = 0或TXR = 0)用于您希望发送或接收的字节数,则可以设置它。

2)您需要查看这些数字的二进制表示,以查看在每种情况下您要发送的位数。标准值是一个完整的字节。

3)FIFO是隐藏元素,写入SPIxTXB或从SPIxRXB寄存器读取访问相应的FIFO。 FIFO只有两个字节的深度,所以你仍然需要检查溢出,如果你发送快速TXWE位(iirc),但如果你有很多数据要快速传输我建议使用DMA进行传输然后你' d只需进行设置并让它去,并可以做其他事情,直到它完成。

4)我认为极性位只是将空闲状态下的线路电平设置为高电平或低电平。它应该为每个人(主人和奴隶)设置相同。

5)如果您只有一个从站,则可以将该线路连接到从站启用线路。如果你有多个从设备,你需要为每个设置一个gpio线路(对于每个设备)或者将信号设置在一起并将OR输出连接到从设备(如果它是低电平有效,通常是这样) 。确保一次只有一个从站处于活动状态。也可以做一个菊花链奴隶。我没有使用过这种设置。

以上是关于请教PIC单片机写I2C和SPI时,卡住在 while(!SSPIF);的主要内容,如果未能解决你的问题,请参考以下文章

请教一个i2s的问题,我在使用STM32,型号为STM32F103VCT6,该型号单片机为大容量单片机。

BMP280 driver对接单片机I2C或者SPI总线接口

51单片机——SPI

EFM8单片机与I2C外设通信

I2C总线出错

关于IO模拟时序(SPI)的注意事项