求教高手:PIC16F887的单片机-PC-485通信(有程序))
背景描述:小弟用PIC16F887单片机与电脑通信,因为是485的协议,所以使用了两片芯片SN75176,一片作为接收,一片作为发送。通信协议是,电脑先发送5个字节给单片机,单片机接收并判断正确了,则会置发送标志位,然后向电脑发送数据。问题描述:现在目前的情况是,在线调试时,发现单片机总是出现接收溢出错误,然后就再也接收不了数据(我们使用中断接收)。如果直接置发送标志位,则可以向电脑发送数据。所以,目前排除了硬件上的问题,认为是软件的问题,但是却找不出来。
请高手指点下,十分感谢!
下面是具体的程序,用在其他单片机PIC16F77,可以成功的通信。
#define RECV_INIT 0
#define RECV_ID 1
#define RECV_STATE 2
#define RECV_Sum 3
#define RECV_END 4
#define RECV_TIMEOUT 50
/********初始化**************/
void Init_UART(void)
{
ADCON1=0X07;
TRISC6=0; // output
TRISC7=1; // input
SPBRG=25; //9600
TXSTA=0b00100100;
RCSTA=0b10010000;
GIE = 1;
RCIE=1;
}
/********如果接收电脑发送的数据,若正确,则置标志位**************/
if(RCIF) // 放在中断程序里
{
ch=RCREG;
Receive_timeout=RECV_TIMEOUT;
switch(Receive_state)
{
case RECV_INIT:
if(ch==0x68)
{
Receive_state=RECV_ID;
Receive_timeout=RECV_TIMEOUT;
}
elseReceive_timeout=1;
break;
case RECV_ID:
Receive_state=RECV_STATE;
Receive_buf=ch; //uP ionizer ID
Data_Checksum=ch;
break;
case RECV_Sum:
Receive_state=RECV_END;
Receive_buf=ch; // the received checksum
break;
case RECV_END:
if(ch==0x68)
{
if(Receive_buf==Device_Address)
{
if(Receive_buf==Data_Checksum)
{
Receive_Flag=1; //receive ok
// Run_state=Receive_buf;
}
}
}
default:
Receive_timeout=0;
Receive_state=RECV_INIT;
break;
}
/********如果接收成功,则开始向电脑发送数据**************/
if(Receive_Flag==1) //放在main程序里
{
//增加通讯指示
WriteLCDCommand(PageAddress+3,2);
WriteLCDCommand(50,2);
for(ch=0;ch<8;ch++)WriteLCDData(0xFF,2);
//通讯开始,上传状态字 20060314
Receive_Flag=0;
RA2=1; //start to send
ch=Device_Address;
TXREG=ch; //TXREG:USART Transmit Data Register 20050313
Data_Checksum=ch;
while(!TRMT); //send the id
ch=temp1&0xff;
TXREG=ch;
Data_Checksum+=ch;
while(!TRMT); //send the VB3 data low byte
ch=(temp1>>8)&0xff;
ch |=0x80;
TXREG=ch;
Data_Checksum+=ch;
while(!TRMT); //send the VB3 data high byte
ch=temp2&0xff;
TXREG=ch;
Data_Checksum+=ch;
while(!TRMT); //send the VB2 data low byte
ch=(temp2>>8)&0xff;
ch |=0x80;
TXREG=ch;
Data_Checksum+=ch;
while(!TRMT); //send the VB2 data low byte
ch=temp3&0xff;
TXREG=ch;
Data_Checksum+=ch;
while(!TRMT); //send the VB1 data low byte
ch=(temp3>>8)&0xff;
ch |=0x80;
TXREG=ch;
Data_Checksum+=ch;
while(!TRMT); //send the VB1 data high byte
TXREG=Data_Checksum;
while(!TRMT); //send checksum
RA2=0; //switch off sending
} 在网上找到一篇**,解释为什么了出现溢出错误,但是没有指出如何处理。
PIC单片机的串口 OERR错误
根据883的规格书的介绍,FIFO接收缓冲只有2个字节的存储空间,因此,如果接受时的接收中断执行时间过长,而上位机的数据发送一次超过2个字节,超过FIFO的存储空间,就会造成单片机的FIFO溢出。如果没有对RCREG进行定期在主程序中读取,则错误标志无法清零,单片机的串口通信就会锁死,出现无**常通信的情况。
下图是883在上位机一次连续发送4个字节,在中断中读取RCREG,由于中断执行一次时间超过了发送3个字节的总时间,FIFO的接收缓冲器不能实时被RCREG转取走,造成FIFO溢出。单片机进入接收中断,取走第一次接收到的0x55,但是取走后中断要执行其他程序,不能马上退出中断再进入接收中断,因此后面的3个字节需要存储在FIFO中,造成FIFO的溢出。
C1:上位机发送0x55 4个字节的数据,接单片机RX引脚
C2:单片机执行中断程序,相应接收后的执行返回接收到得上位机数据,由于中断有一个长时间的延时,使单片机在退出第一个接收字节的中断时,已经错过了上位机发送的后3个字节。但是当时仍有2个字节存储在FIFO接收缓冲器中,由于还有3个字节要存储,而FIFO只有2个,造成第二个字节丢失,单片机OERR置位。接收中断响应了后2个存储成功的数据,执行完成后推出接收中断响应,FERR不会自动清零,单片机以后将无法执行接收中断,好比单片机已经进入通信锁死状态。
C3:单片机执行进入中断和退出中断的标志位,为了来查看中断的运行与单片机通信时序的关系。 本帖最后由 KF_3C 于 2010-5-14 08:19 编辑
上面的图显示不出来,怎么没有高手肯发表下? 这两点在思考,会不会是时钟频率不对呢? 试试检查在主程序或中断中是否发生Oerr,如果有清楚它 不大明白,这个OERR是通信溢出错误,现在我们是有这个问题,但如何查在主程序里也有这个错误呢? 后来终于把它解决了,还是漏了一个小细节,少检测一个数据位。 很有参考价值!谢谢! 很有参考价值!谢谢! :):handshak:handshake KF_3C 发表于 2010-8-19 16:59
后来终于把它解决了,还是漏了一个小细节,少检测一个数据位。
能把代码贴出来,学习下么
页:
[1]