平常是懒得去写点东西,但是今天,决定写点调试心得,主要是因为这个问题正真用了一周时间才得以解决,记得这几年在我调程序的过程里,因为一个问题,最长的解决周期也就是四天,但是今天这个问题却是打破了自己的记录。
内存泄露在程序设计中是较难的一个问题,如果在平常的应用程序设计中(PC机),内存泄露相对来说容易点,至少是可以通过一些工具去查找问题,解决问题。但是,在相对低端的嵌入式系统里,可是无法查找,虽说是有硬件仿真工具,可是面对,大量的数据和一些复杂的系统也是很难去仿真的,那么只有一点一点去分析代码,一点点去理解,假设最终找出问题,解决问题。
在嵌入式内存泄露的问题里,我个人以为,又有一些区别,一种是:因为一次内存泄露导致程序无法运行,这类问题是相对容易解决的;另一种是:一次内存泄露,不太影响整个程序,甚至可以得出正确数据,两次也可以,三次、、、、、,但是达到一定程序时,问题就会出现,那么要解决,必须把每个问题都解决了才能从根本上解决问题,所以首先必须要找到每个问题。对于这个问题也是最难的,因为或许从最开始就不知道是什么引起的问题。很蛋疼的是,第二种情况就是我遇到的。
下面将详细介绍整个过程,整个系统如下:
硬件系统(第一次做板见笑了)
软件系统
1、能和上位机链接,可以执行上位机给下位机的命令,在读写时钟过程中很正常(20个字节左右)
int16_t AddCmd(char* rev,int len) { int16_t i; // int16_t j; if(rev[0]==0&&rev[1]==0xff&&rev[2]==0&&rev[3]==0xff) { for(i=0;i<CMD_QUE;i++) { if(CmdQue[0][i].used == 0) { break; } else if(i==CMD_QUE-1) { return -1; } } CmdQue[0][i].used = 1; CmdQue[0][i].state = 1; CmdQue[0][i].pid = rev[4]; CmdQue[0][i].nCode = rev[7]; CmdQue[0][i].nFunction = rev[8]; memcpy(CmdQue[0][i].data,rev+7,len-7); // for(j=0;j<64;j++) // { // printf("CCAA%2X \n",CmdQue[0][i].data[j]); // 测试使用 // } return 0; } else { return -1; } } int16_t FindACmd(int8_t* num, int8_t state) { int i; for(i=0;i<CMD_QUE;i++) { if(CmdQue[0][i].state == state) { *num = i; return state; } } return 0; }
所以看底层的代码, 突然发现定义了这样一个sbuf[ ],起初在没有联机时,以为接收的数据是不定长的,所以没给具体的值,现在至少可以确定其最大值,因此将sbuf[ ]改为sbuf[256 ],同样的其他几个也改正。(C语言仍需加强) 下载程序,一看,很神奇的问题终于没了 ,呜呼,终于解决了!真的很激动!
最后,附小诗一首,以表在整个程序调试过程中的心境!
路
2014.1.10夜,梦醒,偶感,
同时赠与一朋友
远望一边天,近观两重山;
只是云深处,崎狞自有路。
不足之处仍有许多,希望大家多多指正!
附MODBUS协议:
1 #include "modbus.h" 2 #include "usart.h" 3 #include "delay.h" 4 5 //********************************************************************************/ 6 //modbus协议支持485总线 7 //修改日期:2013/12/9 8 //版本:V1.0 9 //Copyright(C) 象牙塔 All rights reserved 10 //Email:cronus_skl@163.com QQ:374199080 11 //********************************************************************************/ 12 u8 MODBUS_SEND_SBUF[64]; 13 u8 MODBUS_RECEIVE_SBUF[256]; 14 15 u8 Defaultspec=0; 16 u8 baseAddress=0; 17 18 19 20 21 //字地址 0 - 255 (只取低8位) 22 //位地址 0 - 255 (只取低8位) 23 24 /* CRC 高位字节值表 */ 25 const u8 auchCRCHi[] = { 26 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0/**/, 27 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 28 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 29 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 30 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 31 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 32 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 33 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 34 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 35 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 36 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 37 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 38 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 39 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 40 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 41 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 42 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 43 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 44 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 45 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 46 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 47 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 48 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 49 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 50 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 51 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40 52 }; 53 /* CRC低位字节值表*/ 54 const u8 auchCRCLo[] = { 55 0x00, 0xC0, 0xC1, 0x01, 0xC3, 0x03, 0x02, 0xC2, 0xC6, 0x06/**/, 56 0x07, 0xC7, 0x05, 0xC5, 0xC4, 0x04, 0xCC, 0x0C, 0x0D, 0xCD, 57 0x0F, 0xCF, 0xCE, 0x0E, 0x0A, 0xCA, 0xCB, 0x0B, 0xC9, 0x09, 58 0x08, 0xC8, 0xD8, 0x18, 0x19, 0xD9, 0x1B, 0xDB, 0xDA, 0x1A, 59 0x1E, 0xDE, 0xDF, 0x1F, 0xDD, 0x1D, 0x1C, 0xDC, 0x14, 0xD4, 60 0xD5, 0x15, 0xD7, 0x17, 0x16, 0xD6, 0xD2, 0x12, 0x13, 0xD3, 61 0x11, 0xD1, 0xD0, 0x10, 0xF0, 0x30, 0x31, 0xF1, 0x33, 0xF3, 62 0xF2, 0x32, 0x36, 0xF6, 0xF7, 0x37, 0xF5, 0x35, 0x34, 0xF4, 63 0x3C, 0xFC, 0xFD, 0x3D, 0xFF, 0x3F, 0x3E, 0xFE, 0xFA, 0x3A, 64 0x3B, 0xFB, 0x39, 0xF9, 0xF8, 0x38, 0x28, 0xE8, 0xE9, 0x29, 65 0xEB, 0x2B, 0x2A, 0xEA, 0xEE, 0x2E, 0x2F, 0xEF, 0x2D, 0xED, 66 0xEC, 0x2C, 0xE4, 0x24, 0x25, 0xE5, 0x27, 0xE7, 0xE6, 0x26, 67 0x22, 0xE2, 0xE3, 0x23, 0xE1, 0x21, 0x20, 0xE0, 0xA0, 0x60, 68 0x61, 0xA1, 0x63, 0xA3, 0xA2, 0x62, 0x66, 0xA6, 0xA7, 0x67, 69 0xA5, 0x65, 0x64, 0xA4, 0x6C, 0xAC, 0xAD, 0x6D, 0xAF, 0x6F, 70 0x6E, 0xAE, 0xAA, 0x6A, 0x6B, 0xAB, 0x69, 0xA9, 0xA8, 0x68, 71 0x78, 0xB8, 0xB9, 0x79, 0xBB, 0x7B, 0x7A, 0xBA, 0xBE, 0x7E, 72 0x7F, 0xBF, 0x7D, 0xBD, 0xBC, 0x7C, 0xB4, 0x74, 0x75, 0xB5, 73 0x77, 0xB7, 0xB6, 0x76, 0x72, 0xB2, 0xB3, 0x73, 0xB1, 0x71, 74 0x70, 0xB0, 0x50, 0x90, 0x91, 0x51, 0x93, 0x53, 0x52, 0x92, 75 0x96, 0x56, 0x57, 0x97, 0x55, 0x95, 0x94, 0x54, 0x9C, 0x5C, 76 0x5D, 0x9D, 0x5F, 0x9F, 0x9E, 0x5E, 0x5A, 0x9A, 0x9B, 0x5B, 77 0x99, 0x59, 0x58, 0x98, 0x88, 0x48, 0x49, 0x89, 0x4B, 0x8B, 78 0x8A, 0x4A, 0x4E, 0x8E, 0x8F, 0x4F, 0x8D, 0x4D, 0x4C, 0x8C, 79 0x44, 0x84, 0x85, 0x45, 0x87, 0x47, 0x46, 0x86, 0x82, 0x42, 80 0x43, 0x83, 0x41, 0x81, 0x80, 0x40 81 }; 82 83 /***************************CRC校验码生成函数 ******************************** 84 *函数功能:生成CRC校验码 85 *本代码中使用查表法,以提高运算速度 86 ****************************************************************************/ 87 u16 crc16(u8 *puchMsg, u16 usDataLen) 88 { 89 u8 uchCRCHi = 0xFF ; /* 高CRC字节初始化 */ 90 u8 uchCRCLo = 0xFF ; /* 低CRC 字节初始化 */ 91 u16 uIndex ; /* CRC循环中的索引 */ 92 while (usDataLen--) /* 传输消息缓冲区 */ 93 { 94 uIndex = uchCRCHi ^ *puchMsg++ ; /* 计算CRC */ 95 uchCRCHi = uchCRCLo ^ auchCRCHi[uIndex] ; 96 uchCRCLo = auchCRCLo[uIndex] ; 97 } 98 return (uchCRCLo << 8 | uchCRCHi) ; 99 } 100 101 /********************************读写线圈*********************************/ 102 /***************主要功能码:读线圈,写单个线圈,写多个线圈****************/ 103 /************************************************************************* 104 *SendReadCoilCommand();读线圈(0X01):最多读256个线圈 105 *SD:地址(1)+功能码(1)+起始地址(2)+线圈数量(2)+CRC 发送读线圈命令 106 *RD:地址(1)+功能码(1)+字节数N(1)+状态(N)+CRC 接受读线圈数据 107 *输入:StartingAddress:起始地址;CoilNumber:线圈数量 108 *输出:无 109 **************************************************************************/ 110 111 //发送命令 112 //最多可读256个线圈 113 void SendReadCoilCommand(u8 StartingAddress,u8 CoilNumber) 114 { 115 u16 crcData; 116 MODBUS_SEND_SBUF[0] = baseAddress;//地址 117 MODBUS_SEND_SBUF[1] = 0X01;//功能码 118 MODBUS_SEND_SBUF[2] = 0X00;//读地址只有48个0X2C,远小于0XFF个 119 MODBUS_SEND_SBUF[3] = StartingAddress; 120 MODBUS_SEND_SBUF[4] = 0X00; 121 MODBUS_SEND_SBUF[5] = CoilNumber; 122 crcData = crc16(MODBUS_SEND_SBUF,6); 123 MODBUS_SEND_SBUF[6] = crcData & 0xff; // CRC代码低位在前 124 MODBUS_SEND_SBUF[7] = crcData >> 8; //高位在后 125 RS485_Send_Data(MODBUS_SEND_SBUF,8); 126 // MODBUS_SEND_SBUF[]=0; 需不需要清零 127 } 128 //返回数据 129 u8 ReceiveReadCoilData(void) 130 { 131 u8 result=0; 132 u16 crcData; 133 RS485_Receive_Data(MODBUS_RECEIVE_SBUF,&RS485_RX_CNT); 134 crcData = crc16(MODBUS_RECEIVE_SBUF,RS485_RX_CNT-1); 135 if(MODBUS_RECEIVE_SBUF[RS485_RX_CNT-1] == ( crcData&0xff ) || MODBUS_RECEIVE_SBUF[RS485_RX_CNT] == ( crcData >> 8 )) 136 { 137 RS485_RX_CNT=0; //长度清零 138 return result=0; 139 } 140 else 141 { 142 RS485_RX_CNT=0; //长度清零 143 printf("读线圈出错!"); 144 result=0X01; 145 return result; 146 147 } 148 149 } 150 151 152 /*************************************************************************** 153 *写单个线圈(0X05): 可写线圈地址0~31 154 *SD: 地址(1)+功能码(1)+输出地址(2)+输出值(2)+CRC 155 *RD: 地址(1)+功能码(1)+输出地址(2)+输出值(2)+CRC 156 *输入:ExportAddress:输出地址;ExportData:输出值 157 * 158 ***************************************************************************/ 159 //发送命令 160 //ExportData 只能是0XFF 或 0X00 161 //地址范围0-31个 162 void SendWriteSingleCommand(u8 ExportAddress,u8 ExportData) 163 { 164 u16 crcData; 165 u8 i; 166 MODBUS_SEND_SBUF[0] = baseAddress;//地址 167 MODBUS_SEND_SBUF[1] = 0X05;//功能码 168 MODBUS_SEND_SBUF[2] = 0X00;//读地址只有48个0X2C,远小于0XFF个 169 MODBUS_SEND_SBUF[3] = ExportAddress; 170 MODBUS_SEND_SBUF[4] = ExportData; 171 MODBUS_SEND_SBUF[5] = 0X00; 172 173 crcData = crc16(MODBUS_SEND_SBUF,6); 174 MODBUS_SEND_SBUF[6] = crcData & 0xff; // CRC代码低位在前 175 MODBUS_SEND_SBUF[7] = crcData >> 8 ; //高位在后 176 RS485_Send_Data(MODBUS_SEND_SBUF,8); 177 for(i=0;i<8;i++) 178 { 179 printf("\n%2X\n\r",MODBUS_SEND_SBUF[i]); 180 } 181 182 // MODBUS_SEND_SBUF[]=0; 需不需要清零 183 } 184 //返回数据 185 u8 ReceiveWriteSingleData(void) 186 { 187 u8 result=0; 188 u16 crcData; 189 RS485_Receive_Data(MODBUS_RECEIVE_SBUF,&RS485_RX_CNT); 190 crcData = crc16(MODBUS_RECEIVE_SBUF,RS485_RX_CNT-1); 191 if(MODBUS_RECEIVE_SBUF[RS485_RX_CNT-1] == ( crcData&0xff ) || MODBUS_RECEIVE_SBUF[RS485_RX_CNT] == ( crcData >> 8 )) 192 { 193 RS485_RX_CNT=0; //长度清零 194 return result=0; 195 } 196 else 197 { 198 RS485_RX_CNT=0; //长度清零 199 printf("写单个线圈出错!"); 200 result=0X05; 201 return result; 202 } 203 204 } 205 /*************************************************************************** 206 *写多个线圈(0X0F): 可写线圈地址0~31 207 *SD:地址(1)+功能码(1)+起始地址(2)+输出数量(2)+字节数量N(1)+输出值(N字节)+CRC 208 *RD: 地址(1)+功能码(1)+起始地址(2)+输出数量(2)+CRC 209 *查询——0X11 0X0F 0X00 0X13 0X00 0X0A 0X02 0XCD 0X01 0XBF 0X0B 210 *从机地址-功能码-寄存器地址高字节-寄存器地址低字节-寄存器数量高字节-寄存器数量 211 *低字节-字节数-数据1-数据2-CRC校验高字节-CRC校验低字节 212 * 001AH 0019H 0018H 0017H 0016H 0015H 0014H 0013H 213 * 1 1 0 0 1 1 0 1 214 * 0022H 0021H 0020H 001FH 001EH 001DH 001CH 001BH 215 * 0 0 0 0 0 0 0 1 216 *传输的第一个字节CDH对应线圈为0013H到001AH,LSB(最低位)对应0013H 217 *输入:StartAddress:起始地址 ExportNumber:输出数量 ByteNumber:字节数量 218 * ExportData:输出值(本代码里,最多4个字节) 219 ***************************************************************************/ 220 //发送命令 221 //地址范围0-31个,即最多32个地址,因此字节数是4Bit 222 void SendWriteMulCoilCommand(u8 StartAddress,u8 ExportNumber,u8 ByteNumber,u32 ExportData) 223 { 224 u16 crcData; 225 u8 i; 226 MODBUS_SEND_SBUF[0] = baseAddress;//地址 227 MODBUS_SEND_SBUF[1] = 0X0F;//功能码 228 MODBUS_SEND_SBUF[2] = 0X00;//起始地址高,写地址只有32个0X2C,远小于0XFF个 229 MODBUS_SEND_SBUF[3] = StartAddress;//起始地址低位 230 MODBUS_SEND_SBUF[4] = 0X00; //输出数量高位 231 MODBUS_SEND_SBUF[5] = ExportNumber;//输出数量低位 232 MODBUS_SEND_SBUF[6] = ByteNumber;//字节数 233 // if((ByteNumber>=0)&&(ByteNumber<8)){i=1;} 234 // else if((8<=ByteNumber)&&(ByteNumber<16)){i=2;} 235 // else if((16<=ByteNumber)&&(ByteNumber<24)){i=3;} 236 // else if((24<=ByteNumber)&&(ByteNumber<32)){i=4;} 237 // else{i=5;} 238 switch(ByteNumber) 239 { 240 case 1: 241 MODBUS_SEND_SBUF[7]=ExportData&0XFF; 242 crcData = crc16(MODBUS_SEND_SBUF,8); 243 MODBUS_SEND_SBUF[8] = crcData & 0xff; // CRC代码低位在前 244 MODBUS_SEND_SBUF[9] = crcData >> 8 ; //高位在后 245 RS485_Send_Data(MODBUS_SEND_SBUF,10); 246 for(i=0;i<10;i++) 247 { 248 printf("\n%2X\n\r",MODBUS_SEND_SBUF[i]); 249 } 250 break; 251 case 2: 252 MODBUS_SEND_SBUF[7]=ExportData&0XFF; 253 MODBUS_SEND_SBUF[8]=(ExportData&0XFFFF)>>8; 254 crcData = crc16(MODBUS_SEND_SBUF,9); 255 MODBUS_SEND_SBUF[9] = crcData & 0xff; // CRC代码低位在前 256 MODBUS_SEND_SBUF[10] = crcData >> 8 ; //高位在后 257 RS485_Send_Data(MODBUS_SEND_SBUF,11); 258 for(i=0;i<11;i++) 259 { 260 printf("\n%2X\n\r",MODBUS_SEND_SBUF[i]); 261 } 262 break; 263 case 3: 264 MODBUS_SEND_SBUF[7]=ExportData&0XFF; 265 MODBUS_SEND_SBUF[8]=(ExportData&0XFFFF)>>8; 266 MODBUS_SEND_SBUF[9]=(ExportData&0XFFFFFF)>>16; 267 crcData = crc16(MODBUS_SEND_SBUF,10); 268 MODBUS_SEND_SBUF[10] = crcData & 0xff; // CRC代码低位在前 269 MODBUS_SEND_SBUF[11] = crcData >> 8 ; //高位在后 270 RS485_Send_Data(MODBUS_SEND_SBUF,12); 271 for(i=0;i<12;i++) 272 { 273 printf("\n%2X\n\r",MODBUS_SEND_SBUF[i]); 274 } 275 break; 276 case 4: 277 MODBUS_SEND_SBUF[7]=ExportData&0XFF; 278 MODBUS_SEND_SBUF[8]=(ExportData&0XFFFF)>>8; 279 MODBUS_SEND_SBUF[9]=(ExportData&0XFFFFFF)>>16; 280 MODBUS_SEND_SBUF[10]=ExportData>>24; 281 crcData = crc16(MODBUS_SEND_SBUF,11); 282 MODBUS_SEND_SBUF[11] = crcData & 0xff; // CRC代码低位在前 283 MODBUS_SEND_SBUF[12] = crcData >> 8 ; //高位在后 284 RS485_Send_Data(MODBUS_SEND_SBUF,13); 285 for(i=0;i<13;i++) 286 { 287 printf("\n%2X\n\r",MODBUS_SEND_SBUF[i]); 288 } 289 break; 290 case 5: 291 /***********************/ 292 break; 293 } 294 // MODBUS_SEND_SBUF[]=0; 需不需要清零 295 } 296 //返回数据 297 u8 ReceiveWriteMulCoilData(void) 298 { 299 u8 result=0; 300 u16 crcData; 301 RS485_Receive_Data(MODBUS_RECEIVE_SBUF,&RS485_RX_CNT); 302 crcData = crc16(MODBUS_RECEIVE_SBUF,RS485_RX_CNT-1); 303 if(MODBUS_RECEIVE_SBUF[RS485_RX_CNT-1] == ( crcData&0xff ) || MODBUS_RECEIVE_SBUF[RS485_RX_CNT] == ( crcData >> 8 )) 304 { 305 RS485_RX_CNT=0; //长度清零 306 return result=0; 307 } 308 else 309 { 310 RS485_RX_CNT=0; //长度清零 311 printf("写多线圈出错!"); 312 result=0X0F; 313 return result; 314 } 315 316 } 317 /*****************************读写保持寄存器*********************************/ 318 /*********主要功能码:读保持寄存器,写单个寄存器,写多个寄存器***************/ 319 /**************************************************************************** 320 *256套规范,每套规范预留256个寄存器,现有128个参数,每个参数2个字节。 321 *保持寄存器偏移量=规范号*256+参数号。 322 *规范号:0~255 参数号:0~127 323 *0<=保持寄存器偏移量<=255*256+127=65407=0XFF7F 324 *0XFF7F=65535 325 *get_MN(),动态定义规范 326 *****************************************************************************/ 327 //取值范围是0~255 328 u8 get_MN() 329 { 330 /***********测试使用************/ 331 // printf("\n%2X\n\r",Defaultspec); 332 return Defaultspec; 333 334 } 335 /***************************************************************************** 336 *读保持寄存器(0X03): 每次最多读取125个 337 *SD:地址(1)+功能码(1)+起始地址(2)+寄存器数量(2)+CRC 338 *RD:地址(1)+功能码(1)+字节数N(1)+寄存器值(N*2)+CRC 339 *输入:ParameterNum 参数号 RegNumber 寄存器数量 340 *****************************************************************************/ 341 void SendReadRegCommand(u8 ParameterNum,u8 RegNumber) 342 { 343 u16 crcData,StartAddress; 344 u8 i; 345 StartAddress=256*mn+ParameterNum; 346 MODBUS_SEND_SBUF[0] = baseAddress;//地址 347 MODBUS_SEND_SBUF[1] = 0X03;//功能码 348 MODBUS_SEND_SBUF[2] = StartAddress>>8; 349 MODBUS_SEND_SBUF[3] = StartAddress&0XFF; 350 MODBUS_SEND_SBUF[4] = 0X00; 351 MODBUS_SEND_SBUF[5] = RegNumber;//不超过 7D(125) 352 crcData = crc16(MODBUS_SEND_SBUF,6); 353 MODBUS_SEND_SBUF[6] = crcData & 0xff; // CRC代码低位在前 354 MODBUS_SEND_SBUF[7] = crcData >> 8; //高位在后 355 RS485_Send_Data(MODBUS_SEND_SBUF,8); 356 // MODBUS_SEND_SBUF[]=0; // 需不需要清零 357 // for(i=0;i<8;i++) 358 // { 359 // printf("\n%2X\n\r",MODBUS_SEND_SBUF[i]); 360 // } 361 } 362 u8 ReceiveReadRegData(void) 363 { 364 u8 result=0; 365 u16 crcData; 366 RS485_Receive_Data(MODBUS_RECEIVE_SBUF,&RS485_RX_CNT); 367 crcData = crc16(MODBUS_RECEIVE_SBUF,RS485_RX_CNT-1); 368 if(MODBUS_RECEIVE_SBUF[RS485_RX_CNT-1] == ( crcData&0xff ) || MODBUS_RECEIVE_SBUF[RS485_RX_CNT] == ( crcData >> 8 )) 369 { 370 RS485_RX_CNT=0; //长度清零 371 return result=0; 372 } 373 else 374 { 375 RS485_RX_CNT=0; //长度清零 376 printf("读寄存器出错!"); 377 result=0X03; 378 return result; 379 } 380 381 } 382 383 /************************************************************************* 384 *SendWriteRegisterCommand();写单个寄存器(0X06): 385 *SD:地址(1)+功能码(1)+寄存器地址(2)+寄存器值(2)+CRC 386 *RD:地址(1)+功能码(1)+寄存器地址(2)+寄存器值(2)+CRC 387 *输入:ParameterNum:寄存器地址;SinRegswitch:ON或OFF 388 *输出:无 389 **************************************************************************/ 390 391 //发送命令 392 void SendWriteSinRegCommand(u8 ParameterNum,u8 SinRegswitch) 393 { 394 u16 crcData,RegisterAddress; 395 u8 i; 396 RegisterAddress=256*mn+ParameterNum; 397 MODBUS_SEND_SBUF[0] = baseAddress;//地址 398 MODBUS_SEND_SBUF[1] = 0X06;//功能码 399 MODBUS_SEND_SBUF[2] = RegisterAddress>>8; 400 MODBUS_SEND_SBUF[3] = RegisterAddress&0XFF; 401 MODBUS_SEND_SBUF[4] = 0X00; 402 MODBUS_SEND_SBUF[5] = SinRegswitch; 403 crcData = crc16(MODBUS_SEND_SBUF,6); 404 MODBUS_SEND_SBUF[6] = crcData & 0xff; // CRC代码低位在前 405 MODBUS_SEND_SBUF[7] = crcData >> 8; //高位在后 406 RS485_Send_Data(MODBUS_SEND_SBUF,8); 407 // MODBUS_SEND_SBUF[]=0; 需不需要清零 408 for(i=0;i<8;i++) 409 { 410 printf("\n%2X\n\r",MODBUS_SEND_SBUF[i]); 411 } 412 } 413 u8 ReceiveWriteSinRegData(void) 414 { 415 u8 result=0; 416 u16 crcData; 417 RS485_Receive_Data(MODBUS_RECEIVE_SBUF,&RS485_RX_CNT); 418 crcData = crc16(MODBUS_RECEIVE_SBUF,RS485_RX_CNT-1); 419 if(MODBUS_RECEIVE_SBUF[RS485_RX_CNT-1] == ( crcData&0xff ) || MODBUS_RECEIVE_SBUF[RS485_RX_CNT] == ( crcData >> 8 )) 420 { 421 RS485_RX_CNT=0; //长度清零 422 return result=0; 423 } 424 else 425 { 426 RS485_RX_CNT=0; //长度清零 427 printf("写单个寄存器出错!"); 428 result=0X06; 429 return result; 430 } 431 432 } 433 /************************************************************************* 434 *写多个寄存器(0X10): 每次最多写123个 435 *SD:地址(1)+功能码(1)+起始地址(2)+寄存器数量(2)+字节数N(1)+寄存器值(2*N)+CRC 436 *RD:地址(1)+功能码(1)+起始地址(2)+寄存器数量(2)+CRC 437 *输入:StartAddress:寄存器地址;SinRegswitch:ON或OFF 438 *输出:无 439 **************************************************************************/ 440 // void SendWriteMulRegCommand( u8 ParameterNum, ) 441 // { 442 // u16 crcData,StartAddress; 443 // u8 i; 444 // StartAddress=256*mn+ParameterNum; 445 // MODBUS_SEND_SBUF[0] = baseAddress;//地址 446 // MODBUS_SEND_SBUF[1] = 0X10;//功能码 447 // MODBUS_SEND_SBUF[2] = StartAddress>>8; 448 // MODBUS_SEND_SBUF[3] = StartAddress&0XFF; 449 // } 450 /************************************************************************* 451 *读输入寄存器(0X04):读内存 452 *SD:地址(2)+命令(2)+起始地(2)址+寄存器数量(2) 453 *RD:地址(2)+命令(2)+字节数N(2)+数据内容(N*2) 454 *输入:StartAddress:起始地址0X0000~0XFFFF 455 *输入:RegisterNum:0X0001~0X007D(125) 456 *输出:无 457 **************************************************************************/ 458 void SendReadEnterRegCommand( u16 StartAddress,u8 RegisterNum ) 459 { 460 u16 crcData; 461 MODBUS_SEND_SBUF[0] = baseAddress;//地址 462 MODBUS_SEND_SBUF[1] = 0X04;//功能码 463 MODBUS_SEND_SBUF[2] = StartAddress>>8; 464 MODBUS_SEND_SBUF[3] = StartAddress&0XFF; 465 MODBUS_SEND_SBUF[4] = 0X00; 466 MODBUS_SEND_SBUF[5] = RegisterNum; 467 crcData = crc16(MODBUS_SEND_SBUF,6); 468 MODBUS_SEND_SBUF[6] = crcData & 0xff; // CRC代码低位在前 469 MODBUS_SEND_SBUF[7] = crcData >> 8; //高位在后 470 RS485_Send_Data(MODBUS_SEND_SBUF,8); 471 } 472 u8 ReceiveReadEnterRegData(void) 473 { 474 u8 result=0; 475 u16 crcData; 476 RS485_Receive_Data(MODBUS_RECEIVE_SBUF,&RS485_RX_CNT); 477 crcData = crc16(MODBUS_RECEIVE_SBUF,RS485_RX_CNT-1); 478 if(MODBUS_RECEIVE_SBUF[RS485_RX_CNT-1] == ( crcData&0xff ) || MODBUS_RECEIVE_SBUF[RS485_RX_CNT] == ( crcData >> 8 )) 479 { 480 RS485_RX_CNT=0; //长度清零 481 return result=0; 482 } 483 else 484 { 485 RS485_RX_CNT=0; //长度清零 486 printf("读输入寄存器出错!"); 487 result=0X04; 488 return result; 489 } 490 } 491 /************************************************************************* 492 *读焊接历史记录(功能码:0X41) 493 *焊接记录,最多960条记录;记录读取方式只有0和1,1代表读记录( 从最早的记录 494 *开始读),0代表重读记录。每次最多读取3条记录。每个记录体包含64个字节(低 495 *字节在先)。 496 *SD: 地址(1)+功能码(1)+读取方式(1)+CRC 497 *RD: 地址(1)+功能码(1)+读取方式(1)+回复的记录个数(1)+记录体(64)+CRC 498 **************************************************************************/ 499 void SendReadWeldingHistoryCommand( u8 ReadMode ) 500 { 501 u16 crcData; 502 // u8 i; 503 MODBUS_SEND_SBUF[0] = baseAddress;//地址 504 MODBUS_SEND_SBUF[1] = 0X41;//功能码 505 MODBUS_SEND_SBUF[2] = ReadMode; 506 crcData = crc16(MODBUS_SEND_SBUF,3); 507 MODBUS_SEND_SBUF[3] = crcData & 0xff; // CRC代码低位在前 508 MODBUS_SEND_SBUF[4] = crcData >> 8; //高位在后 509 RS485_Send_Data(MODBUS_SEND_SBUF,5); 510 // for(i=0;i<5;i++) 511 // { 512 // printf("\n%d\r",MODBUS_SEND_SBUF[i]); 513 // } 514 } 515 516 u8 ReceiveWeldingHistoryData(void) 517 { 518 u8 result=0; 519 u16 crcData; 520 RS485_Receive_Data(MODBUS_RECEIVE_SBUF,&RS485_RX_CNT); 521 crcData = crc16(MODBUS_RECEIVE_SBUF,RS485_RX_CNT-1); 522 if(MODBUS_RECEIVE_SBUF[RS485_RX_CNT-1] == ( crcData&0xff ) || MODBUS_RECEIVE_SBUF[RS485_RX_CNT] == ( crcData >> 8 )) 523 { 524 RS485_RX_CNT=0; //长度清零 525 return result=0; 526 } 527 else 528 { 529 RS485_RX_CNT=0; //长度清零 530 printf("读焊接历史记录错误!"); 531 result=0X41; 532 return result; 533 } 534 } 535 536 537 void SendReadWriteTimeCommand(u8 TimeCommand , u8 TimeNumber[7] ) 538 { 539 540 u16 crcData; 541 u8 i; 542 MODBUS_SEND_SBUF[0] = baseAddress;//地址 543 MODBUS_SEND_SBUF[1] = 0X44;//功能码 544 MODBUS_SEND_SBUF[2] = TimeCommand; 545 if(TimeCommand==0) 546 { 547 crcData = crc16(MODBUS_SEND_SBUF,3); 548 MODBUS_SEND_SBUF[3] = crcData & 0xff; // CRC代码低位在前 549 MODBUS_SEND_SBUF[4] = crcData >> 8; //高位在后 550 RS485_Send_Data(MODBUS_SEND_SBUF,5); 551 } 552 else 553 { 554 555 delay_ms(5); 556 for(i=0;i<7;i++) 557 { 558 MODBUS_SEND_SBUF[3+i] = TimeNumber[i]; 559 // printf("\n\r%d\n\r",TimeNumber[i]); 560 } 561 crcData = crc16(MODBUS_SEND_SBUF,10); 562 MODBUS_SEND_SBUF[10] = crcData & 0xff; // CRC代码低位在前 563 MODBUS_SEND_SBUF[11] = crcData >> 8; //高位在后 564 RS485_Send_Data(MODBUS_SEND_SBUF,12); 565 566 } 567 // MODBUS_SEND_SBUF[3] = RecordPointer&0XFF; 568 // MODBUS_SEND_SBUF[4] = RecordNumber; 569 // 570 } 571 572 u8 ReceiveReadWriteTimeData( void ) 573 { 574 u8 result=0; 575 u16 crcData; 576 RS485_Receive_Data(MODBUS_RECEIVE_SBUF,&RS485_RX_CNT); 577 crcData = crc16(MODBUS_RECEIVE_SBUF,RS485_RX_CNT-1); 578 if(MODBUS_RECEIVE_SBUF[RS485_RX_CNT-1] == ( crcData&0xff ) || MODBUS_RECEIVE_SBUF[RS485_RX_CNT] == ( crcData >> 8 )) 579 { 580 RS485_RX_CNT=0; //长度清零 581 return result=0; 582 } 583 else 584 { 585 RS485_RX_CNT=0; //长度清零 586 printf("读写时钟错误!"); 587 result=0X44; 588 return result; 589 } 590 } 591 /************************************************************************* 592 * 读设备标识(0X2B) 593 * 表:10:设备标识 594 * 对象ID 对象名称 类型 595 * 0X00 厂商名称 ASCII字符串 只读 596 * 0X01 产品代码 ASCII字符串 只读 597 * 0X02 主次版本号 ASCII字符串 只读 598 * SD:地址(1)+功能码(1)+MEI类型(1)+读设备ID码(1)+对象ID(1) 599 SD: **+2B+0E+01+00+CRC 600 * RD:地址(1)+功能码(1)+MEI类型(1)+设备ID码(1)+一致性等级[conformity 601 * level](1)+00(1)+下一个设备ID码(1)+对象数量n (1)+对象1 ID(1)+对象1 602 * 长度N(1)+对象内容(N)+… … +对象n ID(1)+对象n长度M(1)+对象内容(M)+CRC 603 *************************************************************************/ 604 void SendReadDeviceIdentifineCommand( void ) 605 { 606 607 u16 crcData; 608 MODBUS_SEND_SBUF[0] = baseAddress;//地址 609 MODBUS_SEND_SBUF[1] = 0X2B;//功能码 610 MODBUS_SEND_SBUF[2] = 0X0E; 611 MODBUS_SEND_SBUF[3] = 0X01; 612 MODBUS_SEND_SBUF[4] = 0X00; 613 crcData = crc16(MODBUS_SEND_SBUF,5); 614 MODBUS_SEND_SBUF[5] = crcData & 0xff; // CRC代码低位在前 615 MODBUS_SEND_SBUF[6] = crcData >> 8; //高位在后 616 RS485_Send_Data(MODBUS_SEND_SBUF,7); 617 } 618 619 u8 ReceiveDeviceIdentifineData( void ) 620 { 621 u8 result=0; 622 u16 crcData; 623 RS485_Receive_Data(MODBUS_RECEIVE_SBUF,&RS485_RX_CNT); 624 crcData = crc16(MODBUS_RECEIVE_SBUF,RS485_RX_CNT-1); 625 if(MODBUS_RECEIVE_SBUF[RS485_RX_CNT-1] == ( crcData&0xff ) || MODBUS_RECEIVE_SBUF[RS485_RX_CNT] == ( crcData >> 8 )) 626 { 627 RS485_RX_CNT=0; //长度清零 628 return result=0; 629 } 630 else 631 { 632 RS485_RX_CNT=0; //长度清零 633 printf("读设备标识错误!"); 634 result=0X2B; 635 return result; 636 } 637 }