zlgARM:您好!<br /> 我按您的要求写了个单纯的调试例程,去掉了定时器中断、串口0接收中断、外部中断等等,目前只保留了串口1接收中断和I2C操作,但是现象跟原来基本一样,只是有一点不同,就是现在I2C操作错误的几率变小了,原来是1秒至2分钟左右,现在是1秒至10分钟左右。下面是我的代码,请您帮忙分析一下,如果能提供您的邮箱,我可以把整个工程发给您,谢谢!<br /><br />//用户主程序<br />int main(void)<br />{ <br /> IO_PortConf(); //IO端口配置程序;<br /> WP_SET1(); //24C64写保护<br /> I2C_Query_Init(100000); //I2C总线初始化(100k的速率) <br /> UART1_Initial(57600, 8,1,2); // 初始化串口1<br /> UART1_Open(); // 打开串口开始接收数据 <br /> //主循环部分<br /> while(1)<br /> { <br /> if(Rx_flag==1) // 判断接收缓冲区中是否有数据需要处理<br /> { <br /> UART1_Close();<br /> MCNP_V20_dataParse();<br /> Rx_flag=0;<br /> UART1_Open(); <br /> UART1_SendByteStream(Tx_start,0x00);<br /> } <br /> Read_SysDateTime(); // 读系统日期时间 <br /> Set_SysDateTime(); <br /> }<br /> return(0); <br />}<br /><br />//对通讯接收缓冲区中接收到的数据包进行解析,并进行相应的处理 <br />void MCNP_V20_dataParse(void)<br />{ uint16 i;<br /> uint8 anao; <br /> Tx_num=0; <br /> switch((Rx_buffer[3]<<8) | Rx_buffer[4]) // 取出命令号 <br /> {<br /> //读取系统时间 (格式:年|月|日|时|分|秒|星期) <br /> case 0x0003:<br /> {<br /> Tx_buffer[0]=0; // 装入本机地址<br /> Tx_buffer[1]=Rx_buffer[3]+48; // 装入返回的命令号1 <br /> Tx_buffer[2]=Rx_buffer[4]; // 装入返回的命令号2<br /> Tx_buffer[3]=0; // 装入返回数据的"字节数1"<br /> Tx_buffer[4]=7; // 装入返回数据的"字节数2"<br /> Tx_buffer[5]=WDataZone.var.SystemDate.year; // 年<br /> Tx_buffer[6]=WDataZone.var.SystemDate.month; // 月<br /> Tx_buffer[7]=WDataZone.var.SystemDate.day_of_month;// 日<br /> Tx_buffer[8]=WDataZone.var.SystemTime.hour; // 时<br /> Tx_buffer[9]=WDataZone.var.SystemTime.minute; // 分<br /> Tx_buffer[10]=WDataZone.var.SystemTime.second; // 秒<br /> Tx_buffer[11]=WDataZone.var.SystemDate.day_of_week;// 星期<br /> //------------------------<br /> //计算发送包的校验字节 <br /> anao=0;<br /> for(i=0;i<12;i++)<br /> {<br /> anao=anao+Tx_buffer;<br /> }<br /> anao=~anao+1; <br /> Tx_buffer[12]=anao; // 装入返回数据的校验字节 <br /> //------------------------<br /> Tx_num=13; // 返包数据中从源地址到校验数的字节总数<br /> }<br /> break; <br /><br /> //设定系统时间(格式:年|月|日|时|分|秒|星期) <br /> case 0x3000:<br /> {<br /> WDataZone.var.SystemDateTimeSetData.year=Rx_buffer[7]; // 年<br /> WDataZone.var.SystemDateTimeSetData.month=Rx_buffer[8];// 月<br /> WDataZone.var.SystemDateTimeSetData.day_of_month=Rx_buffer[9];// 日<br /> WDataZone.var.SystemDateTimeSetData.hour=Rx_buffer[10]; // 时<br /> WDataZone.var.SystemDateTimeSetData.minute=Rx_buffer[11]; // 分<br /> WDataZone.var.SystemDateTimeSetData.second=Rx_buffer[12]; // 秒<br /> WDataZone.var.SystemDateTimeSetData.day_of_week=Rx_buffer[13];// 星期<br /> WDataZone.var.SystemDateTimeSetData.DateTimeSetFlag=1;//为1表示需要设定系统时间<br /> Set_SysDateTime(); // 设定PCF8563的时间 <br /> }<br /> break; <br /> <br /> default :break; <br /> } <br /> return;<br />}<br /><br /><br />//设置系统日期和时间<br />void Set_SysDateTime(void)<br />{ <br /> if(WDataZone.var.SystemDateTimeSetData.DateTimeSetFlag==1)<br /> { <br /> WDataZone.var.SystemDateTimeSetData.DateTimeSetFlag=0;<br /> I2cmtd[0]=0; //控制字1<br /> I2cmtd[1]=0; //控制字2<br /> I2cmtd[2]=WDataZone.var.SystemDateTimeSetData.second;//秒 <br /> I2cmtd[3]=WDataZone.var.SystemDateTimeSetData.minute;//分钟 <br /> I2cmtd[4]=WDataZone.var.SystemDateTimeSetData.hour;//小时<br /> I2cmtd[5]=WDataZone.var.SystemDateTimeSetData.day_of_month;//日 <br /> I2cmtd[6]=WDataZone.var.SystemDateTimeSetData.day_of_week;//星期<br /> I2cmtd[7]=WDataZone.var.SystemDateTimeSetData.month;//月<br /> I2cmtd[8]=WDataZone.var.SystemDateTimeSetData.year;//年 <br /> I2C_Query_DeviceSendStr(PCF8563, 1, 0x00, I2cmtd, 9); <br /> }<br /> return;<br />}<br /><br /><br />//读系统日期和时间<br />void Read_SysDateTime(void)<br />{<br /> uint16 I2c_ok; // I2c_ok=1表示I2C读数据操作成功 <br /> I2c_ok=I2C_Query_DeviceRcvStr(PCF8563, 1, 0x02, I2cmrd, 7); <br /> if(I2c_ok==0) return; // 如果I2C总线读数据操作失败,则放弃该次操作,需读的参数保持原来的值 <br /> WDataZone.var.SystemTime.second=I2cmrd[0] & 0x7F; //秒 <br /> WDataZone.var.SystemTime.minute=I2cmrd[1] & 0x7F; //分钟 <br /> WDataZone.var.SystemTime.hour=I2cmrd[2] & 0x3F; //小时<br /> WDataZone.var.SystemDate.day_of_month=I2cmrd[3] & 0x3F; //日 <br /> WDataZone.var.SystemDate.day_of_week=I2cmrd[4] & 0x07;//星期<br /> WDataZone.var.SystemDate.month=I2cmrd[5] & 0x1F; //月<br /> WDataZone.var.SystemDate.year=I2cmrd[6]; //年 <br /> return; <br />}<br /><br /><br />//-----------------向有子地址器件发送多字节数据函数--------------------------------------------- <br />//原 形: uint8 I2C_Query_DeviceSendStr(uint8 sla, uint8 subatype, uint16 suba, uint8 *str, uint16 no)<br />//描 述: 从启动总线到发送地址,子地址,读数据,结束总线的全过程<br />//输入参数: sla 从器件地址,<br />// subatype 子地址类型, 子地址结构 1-单字节地址 2-双字节地址<br />// suba 子地址,<br />// str 要写入的内容放入str指向的存储区 <br />// no 读no个字节。 该参数超过缓存器的最大字节数无效 (注意!!!) <br />//输出参数: 函数返回1表示操作成功,否则操作有误。<br />//头 文 件: "I2C_chip.h"<br />//库 文 件: 无<br />//注意事项: 需注意当给定的起始地址与欲写的N字节数据超过本页最后一个存储单元后,将转入本页的第一个单元<br />// 进行"滚动循环".即读取的I2C器件中数据是在本页进行的页内部循环(注意!!!!!!!)<br />// 24C64中的RAM缓存器为32个字节,即一页为32个字节<br />//---------------------------------------------------------------------------------------------- <br />uint8 I2C_Query_DeviceSendStr(uint8 sla, uint8 subatype, uint16 suba, uint8 *str, uint16 no)<br />{<br /> uint16 i;<br /> uint8 var;<br /> uint8 *string;<br /> string=str;<br /> //INT_Close(); //关闭所有使用到的中断,防止I2C操作的时候,中断发生,导致I2C出错<br /> <br /> GetBus(); //启动总线//<br /> I2CONCLR=(1<<5); //清零STA位//<br /> I2CBusSendByte(sla); //发送从器件写操作地址sla//<br /><br /> if(I2STAT!=0x18)<br /> {<br /> I2CONSET = (1 << 4); // 置位STO,结束总线 //<br /> I2CONCLR = 0x28; // 清零SI, STA位,结束总线 //<br /> //INT_Open(); //打开所有使用到的中断,恢复原样<br /> return(0);<br /> }<br /> <br /> if(subatype==1) //器件地址为1个字节的地址<br /> {<br /> var = suba & 0xFF;<br /> I2CBusSendByte(var); //发送器件子地址//在此之后,将进入读寄存器模式<br /> <br /> if((I2STAT!=0x28))//&&(I2STAT!=0x30)<br /> {<br /> I2CONSET = (1 << 4); // 置位STO,结束总线 //<br /> I2CONCLR = 0x28; // 清零SI, STA位,结束总线 //<br /> //INT_Open(); //打开所有使用到的中断,恢复原样<br /> return(0);<br /> }<br /> }<br /> <br /> else if(subatype==2) //器件地址为2个字节的地址<br /> {<br /> var = suba>>8; //先发高8位地址<br /> I2CBusSendByte(var); //发送器件子地址高8位<br /> <br /> if((I2STAT!=0x28))//&&(I2STAT!=0x30)<br /> {<br /> I2CONSET = (1 << 4); // 置位STO,结束总线 //<br /> I2CONCLR = 0x28; // 清零SI, STA位,结束总线 //<br /> //INT_Open(); //打开所有使用到的中断,恢复原样<br /> return(0);<br /> }<br /> <br /> var=suba & 0xFF; //再发低8位地址<br /> I2CBusSendByte(var); //发送器件子地址低8位//在此之后,将进入读寄存器模式<br /> <br /> if((I2STAT!=0x28))//&&(I2STAT!=0x30)<br /> {<br /> I2CONSET = (1 << 4); // 置位STO,结束总线 //<br /> I2CONCLR = 0x28; // 清零SI, STA位,结束总线 //<br /> //INT_Open(); //打开所有使用到的中断,恢复原样<br /> return(0);<br /> }<br /> }<br /> <br /> for(i=0;i<no;i++)<br /> { <br /> I2CBusSendByte(*string); //发送数据//<br /> if((I2STAT!=0x28))//&&(I2STAT!=0x30)<br /> {<br /> I2CONSET = (1 << 4); // 置位STO,结束总线 //<br /> I2CONCLR = 0x28; // 清零SI, STA位,结束总线 //<br /> //INT_Open(); //打开所有使用到的中断,恢复原样<br /> return(0);<br /> }<br /> string++;<br /> } <br /> I2CONSET = (1 << 4); // 置位STO,结束总线 //<br /> I2CONCLR = 0x28; // 清零SI, STA位,结束总线 //<br /> Write24Cxx_delayNms(10); // 延时10ms(不论写1字节还是写32字节,延时都必须大于等于10ms)<br /> //INT_Open(); //打开所有使用到的中断,恢复原样<br /> return(1);<br />}<br /><br />//-----------------向有子地址器件读取多字节数据函数--------------------------------------------- <br />//原 形: I2C_Query_DeviceRcvStr(uint8 sla, uint8 subatype, uint16 suba, uint8 *str, uint16 no)<br />//描 述: 从启动总线到发送地址,子地址,读数据,结束总线的全过程<br />//输入参数: 从器件地址sla,<br />// 子地址类型subatype, 子地址结构 1-单字节地址 2-双字节地址<br />// 子地址suba,<br />// 读出的内容放入str指向的存储区 <br />// 需要读的字节个数在no中<br />//输出参数: 函数返回1表示操作成功,否则操作有误。<br />//头 文 件: "I2C_chip.h"<br />//库 文 件: 无<br />//注意事项: 需注意当给定的起始地址与欲读的N字节数据超过最后一页最后一个存储单元后,将转入第一页的第一个单元<br />// 即读取的I2C器件中数据是所有页进行的全循环<br />//---------------------------------------------------------------------------------------------- <br />uint16 I2C_Query_DeviceRcvStr(uint8 sla, uint8 subatype, uint16 suba, uint8 *str, uint16 no)<br />{<br /> uint16 i,j;<br /> uint8 var;<br /> uint8 *string;<br /> string=str;<br /> //INT_Close(); //关闭所有中断,防止I2C操作的时候,中断发生,导致I2C出错<br /> <br /> GetBus(); //启动总线//<br /> I2CONCLR=(1<<5); //清零STA位//<br /> I2CBusSendByte(sla); //发送从器件写操作地址sla//<br /> if(I2STAT!=0x18)<br /> {<br /> I2CONSET = (1 << 4); // 置位STO,结束总线 //<br /> I2CONCLR = 0x28; // 清零SI, STA位,结束总线 //<br /> //INT_Open(); //打开所有使用到的中断,恢复原样<br /> return(0);<br /> }<br /> <br /> if(subatype==1) //器件地址为1个字节的地址<br /> {<br /> var = suba & 0xFF;<br /> <br /> I2CBusSendByte(var); //发送器件子地址//在此之后,将进入读寄存器模式<br /> <br /> if((I2STAT!=0x28))//&&(I2STAT!=0x30)<br /> {<br /> I2CONSET = (1 << 4); // 置位STO,结束总线 //<br /> I2CONCLR = 0x28; // 清零SI, STA位,结束总线 //<br /> //INT_Open(); //打开所有使用到的中断,恢复原样<br /> return(0);<br /> }<br /> }<br /> <br /> else if(subatype==2) //器件地址为2个字节的地址<br /> {<br /> var = suba>>8; //先发高8位地址<br /> <br /> I2CBusSendByte(var); //发送器件子地址高8位<br /> <br /> if((I2STAT!=0x28))//&&(I2STAT!=0x30)<br /> {<br /> I2CONSET = (1 << 4); // 置位STO,结束总线 //<br /> I2CONCLR = 0x28; // 清零SI, STA位,结束总线 //<br /> //INT_Open(); //打开所有使用到的中断,恢复原样<br /> return(0);<br /> }<br /> <br /> var=suba & 0xFF; //再发低8位地址<br /> I2CBusSendByte(var); //发送器件子地址低8位//在此之后,将进入读寄存器模式<br /> <br /> if((I2STAT!=0x28))//&&(I2STAT!=0x30)<br /> {<br /> I2CONSET = (1 << 4); // 置位STO,结束总线 //<br /> I2CONCLR = 0x28; // 清零SI, STA位,结束总线 //<br /> //INT_Open(); //打开所有使用到的中断,恢复原样<br /> return(0);<br /> }<br /> }<br /> <br /> <br /> //I2CONSET = (1 << 4); // 置位STO,结束总线 //<br /> //I2CONCLR = 0x28; // 清零SI, STA位,结束总线 //<br /> I2CONCLR = (1 << 3); // 清零SI<br /> I2CONSET = (1 << 5); //置位STA, 重新启动总线//<br /> <br /> <br /> for(j=0;j<20000;j++)<br /> {<br /> if((I2CONSET & 0x08)!=0) break;<br /> } <br /> <br /> I2CONCLR = (1 << 5); // 清零STA<br /> I2CBusSendByte(sla+1);<br /> <br /> if(I2STAT!=0x40)<br /> {<br /> I2CONSET = (1 << 4); // 置位STO,结束总线 //<br /> I2CONCLR = 0x28; // 清零SI, STA位,结束总线 //<br /> //INT_Open(); //打开所有使用到的中断,恢复原样<br /> return(0);<br /> } <br /> <br /> for(i=0;i<no-1;i++)<br /> { <br /> I2CONSET = (1 << 2); //接收一字节数据并发送应答位//<br /> I2CONCLR = (1 << 3); //清零SI<br /> <br /> for(j=0;j<20000;j++)<br /> {<br /> if((I2CONSET & 0x08)!=0) break; //等待接收数据//<br /> }<br /> <br /> if(I2STAT!=0x50)<br /> {<br /> I2CONSET = (1 << 4); // 置位STO,结束总线 //<br /> I2CONCLR = 0x28; // 清零SI, STA位,结束总线 //<br /> //INT_Open(); //打开所有使用到的中断,恢复原样<br /> return(0);<br /> }<br /> <br /> *string=I2DAT; //读取数据// <br /> string++;<br /> } <br /> I2CONCLR = (1<<2); //接收最后一字节数据并发送非应答位//<br /> I2CONCLR = (1 << 3); //清零SI<br /> <br /> for(j=0;j<20000;j++)<br /> {<br /> if((I2CONSET & 0x08)!=0) break;<br /> }<br /><br /> *string=I2DAT;<br /> I2CONSET = (1 << 4); // 置位STO,结束总线 //<br /> I2CONCLR = 0x28; // 清零SI, STA位,结束总线 //<br /> //INT_Open(); //打开所有使用到的中断,恢复原样<br /> return(1);<br />}<br /><br /><br />
|