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