日常是懶得去寫點東西,可是今天,決定寫點調試心得,主要是由於這個問題正真用了一週時間才得以解決,記得這幾年在我調程序的過程裏,由於一個問題,最長的解決週期也就是四天,可是今天這個問題倒是打破了本身的記錄。
內存泄露在程序設計中是較難的一個問題,若是在日常的應用程序設計中(PC機),內存泄露相對來講容易點,至少是能夠經過一些工具去查找問題,解決問題。可是,在相對低端的嵌入式系統裏,但是沒法查找,雖然說是有硬件仿真工具,但是面對,大量的數據和一些複雜的系統也是很難去仿真的,那麼只有一點一點去分析代碼,一點點去理解,假設最終找出問題,解決問題。
在嵌入式內存泄露的問題裏,我我的覺得,又有一些區別,一種是:由於一次內存泄露致使程序沒法運行,這類問題是相對容易解決的;另外一種是:一次內存泄露,不太影響整個程序,甚至能夠得出正確數據,兩次也能夠,三次、、、、、,可是達到必定程序時,問題就會出現,那麼要解決,必須把每一個問題都解決了才能從根本上解決問題,因此首先必需要找到每一個問題。對於這個問題也是最難的,由於或許從最開始就不知道是什麼引發的問題。很蛋疼的是,第二種狀況就是我遇到的。
下面將詳細介紹整個過程,整個系統以下:函數
硬件系統(第一次作板見笑了)工具
軟件系統學習
一、能和上位機連接,能夠執行上位機給下位機的命令,在讀寫時鐘過程當中很正常(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語言仍需增強) 下載程序,一看,很神奇的問題終於沒了 ,嗚呼,終於解決了!真的很激動!spa
不足之處仍有許多,但願你們多多指正!設計
附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 }