?? modbus.c
字號:
#include "main.h"
//unsigned int GwRxCount; // GwSciRxBuffer[]數(shù)組的下標
//unsigned int GwTxCount; // GwSciTxBuffer[]數(shù)組的下標
//unsigned char GwRxFlag; // 接收標志 1: 準備接收; 0: 接收結(jié)束
//unsigned char GwTxFlag; // 發(fā)送標志 1: 準備發(fā)送; 0: 發(fā)送結(jié)束
unsigned char GwSciTxBuffer[32],GwSciRxBuffer[32];
unsigned int GwSciTxBytes; // 每幀信息中發(fā)送字節(jié)總數(shù)
unsigned int GwSciRxBytes; // 每幀信息中接收字節(jié)總數(shù)
int GwSciRxFlag = 0; //SCI接收中斷標志,'1'表示接收中斷發(fā)生
static unsigned char CRCHi[] = {
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81,
0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01,
0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81,
0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01,
0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81,
0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01,
0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81,
0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01,
0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81,
0x40
};
static unsigned char CRCLo[] = {
0x00, 0xC0, 0xC1, 0x01, 0xC3, 0x03, 0x02, 0xC2, 0xC6, 0x06, 0x07, 0xC7, 0x05, 0xC5, 0xC4,
0x04, 0xCC, 0x0C, 0x0D, 0xCD, 0x0F, 0xCF, 0xCE, 0x0E, 0x0A, 0xCA, 0xCB, 0x0B, 0xC9, 0x09,
0x08, 0xC8, 0xD8, 0x18, 0x19, 0xD9, 0x1B, 0xDB, 0xDA, 0x1A, 0x1E, 0xDE, 0xDF, 0x1F, 0xDD,
0x1D, 0x1C, 0xDC, 0x14, 0xD4, 0xD5, 0x15, 0xD7, 0x17, 0x16, 0xD6, 0xD2, 0x12, 0x13, 0xD3,
0x11, 0xD1, 0xD0, 0x10, 0xF0, 0x30, 0x31, 0xF1, 0x33, 0xF3, 0xF2, 0x32, 0x36, 0xF6, 0xF7,
0x37, 0xF5, 0x35, 0x34, 0xF4, 0x3C, 0xFC, 0xFD, 0x3D, 0xFF, 0x3F, 0x3E, 0xFE, 0xFA, 0x3A,
0x3B, 0xFB, 0x39, 0xF9, 0xF8, 0x38, 0x28, 0xE8, 0xE9, 0x29, 0xEB, 0x2B, 0x2A, 0xEA, 0xEE,
0x2E, 0x2F, 0xEF, 0x2D, 0xED, 0xEC, 0x2C, 0xE4, 0x24, 0x25, 0xE5, 0x27, 0xE7, 0xE6, 0x26,
0x22, 0xE2, 0xE3, 0x23, 0xE1, 0x21, 0x20, 0xE0, 0xA0, 0x60, 0x61, 0xA1, 0x63, 0xA3, 0xA2,
0x62, 0x66, 0xA6, 0xA7, 0x67, 0xA5, 0x65, 0x64, 0xA4, 0x6C, 0xAC, 0xAD, 0x6D, 0xAF, 0x6F,
0x6E, 0xAE, 0xAA, 0x6A, 0x6B, 0xAB, 0x69, 0xA9, 0xA8, 0x68, 0x78, 0xB8, 0xB9, 0x79, 0xBB,
0x7B, 0x7A, 0xBA, 0xBE, 0x7E, 0x7F, 0xBF, 0x7D, 0xBD, 0xBC, 0x7C, 0xB4, 0x74, 0x75, 0xB5,
0x77, 0xB7, 0xB6, 0x76, 0x72, 0xB2, 0xB3, 0x73, 0xB1, 0x71, 0x70, 0xB0, 0x50, 0x90, 0x91,
0x51, 0x93, 0x53, 0x52, 0x92, 0x96, 0x56, 0x57, 0x97, 0x55, 0x95, 0x94, 0x54, 0x9C, 0x5C,
0x5D, 0x9D, 0x5F, 0x9F, 0x9E, 0x5E, 0x5A, 0x9A, 0x9B, 0x5B, 0x99, 0x59, 0x58, 0x98, 0x88,
0x48, 0x49, 0x89, 0x4B, 0x8B, 0x8A, 0x4A, 0x4E, 0x8E, 0x8F, 0x4F, 0x8D, 0x4D, 0x4C, 0x8C,
0x44, 0x84, 0x85, 0x45, 0x87, 0x47, 0x46, 0x86, 0x82, 0x42, 0x43, 0x83, 0x41, 0x81, 0x80,
0x40
};
// 功能 :對SCI模塊進行初始化,與油氣分離單元進行通信以串口為硬件接口,采用MODBUS協(xié)議
// 返回 :無
// 形參 : 無
void SciInit(void)
{
MCRA=MCRA|0x0003; // IOPA0(SCITXD), IOPA1(SCIRXD)為串口
SCICCR=0x67; // 1位停止位,使能偶校驗功能,數(shù)據(jù)字為8位長度
SCICTL1=0x03; // 不使能接收錯誤中斷,軟件復(fù)位,使能發(fā)送和接收,SLEEP位為0
// TXWAKE=0,沒有選定的發(fā)送特征
//todo:暫不采用中斷方式接收
//SCICTL2=0x02; //接收中斷使能,不使能發(fā)送中斷,發(fā)送采用置軟件標志位方法
SCIPRI=0x00; //高優(yōu)先級中斷,使用INT1,INT1(高優(yōu)先級中斷)還是INT5(低優(yōu)先級中斷)
SCIHBAUD=0x01; //波特率設(shè)置為19200bit/s
SCILBAUD=0x03;
SCICTL1=0x23; //SW位置1,串口初始化完成
}
// 功能 :生成MODBUA協(xié)議中的CRC校驗碼(16位)
// 返回 :CRC校驗碼(16位)
// 形參 : 指向待發(fā)送或已接收到的數(shù)組的指針,數(shù)組長度
unsigned int CRC16( const unsigned char *buf, int len)
{
unsigned char Hi=0xFF;
unsigned char Lo=0xFF;
unsigned short index;
if (buf == 0 || len <= 0)
return(0);
while (len--)
{
index = Hi ^ (unsigned char)*buf++;
Hi = Lo ^ CRCHi[index];
Lo = CRCLo[index] ;
}
index=(Hi<<8)|Lo;
return(index);
}
// 功能 :對接收的數(shù)據(jù)進行CRC校驗,與發(fā)送來的CRC校驗值(在所接收的數(shù)據(jù)中)進行比較
// 返回 :如果CRC校驗值與接收到的CRC校驗值相等,則返回1,否則返回0
// 形參 :
unsigned char CheckCRC(unsigned char *crctmp,unsigned int length)
{
unsigned int crc_result, crc_tmp;
//取接收到數(shù)據(jù)中的CRC值
crc_tmp = *(crctmp + length-2); // CRC高字節(jié)
crc_tmp = crc_tmp << 8 + *( crctmp+length-1); // CRC高字節(jié)左移8位+CRC低字節(jié) = CRC 值
//crc_tmp = crc_tmp * 256 + *( crctmp+length-1); // CRC高字節(jié)左移8位+CRC低字節(jié) = CRC 值
crc_result = CRC16(crctmp, length-2); // 根據(jù)接收到的數(shù)據(jù)計算CRC 值
if ( crc_tmp != crc_result ) // 比較CRC值
return(0);
else
return(1);
}
// 功能 :把按MODBUS協(xié)議規(guī)定的數(shù)據(jù)形式組織好的數(shù)據(jù)發(fā)給油氣分離單元
// 返回 :無
// 形參 : 無
void SciSend(void)
{
//開始發(fā)送,后續(xù)數(shù)據(jù)在中斷中繼續(xù)發(fā)送
//GwTxFlag = 1; //準備發(fā)送,發(fā)送完成后清零
unsigned int wTempSciRxBuf = 0;
unsigned int wTxCount = 0; //發(fā)送計數(shù)器初始化
// 在開始發(fā)送之前先清接收緩沖區(qū)(實際是清SCIRXST的RXRDY位),以保證SCIRXBUF中沒有新數(shù)據(jù)(即未讀過的數(shù)據(jù))
wTempSciRxBuf = SCIRXBUF; // 通過讀SCIRXBUF可以清SCIRXST的RXRDY位
// 開始發(fā)送數(shù)據(jù)
while (wTxCount < GwSciTxBytes)
{
SCITXBUF = GwSciTxBuffer[wTxCount]; //發(fā)送數(shù)據(jù),寫SCITXBUF會清除TXRDY位,即表示此時SCITXBUF滿
while((SCICTL2 & 0x80) == 0); //等待TXRDY位變"1",即SCITXBUF為空,可以接收下一個數(shù)據(jù)
wTxCount ++;
}
}
// 功能 :接收響應(yīng)
// 返回 :無
// 形參 : 無
void SciReceive(void)
{
//GwRxFlag = 1; //準備接收,接收完成后清零
//GwRxCount = 0; //接收指針清零,保證數(shù)據(jù)從緩沖區(qū)的首地址處開始存放
unsigned int wDelayCount = 0; //等待接收的延時
unsigned int wRxCount = 0; //接收計數(shù)器初始化
while (wRxCount < GwSciRxBytes) //等待接收完成,數(shù)據(jù)在中斷服務(wù)程序中接收,GwRxCount在中斷服務(wù)程序中累加
{
if (GwForceInitFlag == 1) //如果強制命令發(fā)生
{
wRxCount = GwSciRxBytes;
}
//等待SCIRXST的RXRDY位置'1',RXRDY位為'0'時wDelayCount++,以便超時退出
while ((SCIRXST & BIT6) == 0) //如果SCIRXBUF中沒有新數(shù)據(jù)(SCIRXST的RXRDY位為'0',代表沒有新數(shù)據(jù))
{
wDelayCount ++;
//todo:延時多少次為宜,等待接收的延時
if (wDelayCount > 50000)
{
wRxCount = GwSciRxBytes;
break; //跳出while ((SCIRXST & BIT6) == 0)循環(huán)
}
}
wDelayCount = 0; //就馬上對計數(shù)清零
GwSciRxBuffer[wRxCount] = SCIRXBUF; //讀緩沖區(qū)內(nèi)的數(shù)據(jù)(如果是由于超時退出的,則這里讀到是上一次的數(shù)據(jù))
wRxCount ++; //字節(jié)數(shù)計數(shù)加'1'
}
}
// 功能 :構(gòu)建RTU模式幀,RTU模式的ADU
// 返回 :無
// 形參 :
void ConstructRtuFrame (unsigned char *dst_buf,unsigned char *src_buf,unsigned char lenth)
{
unsigned int crc_tmp;
crc_tmp = CRC16(src_buf, lenth); //對二進制串,計算getCRC16校驗
*(src_buf+lenth) = crc_tmp >> 8; //CRC 高字節(jié)在前
*(src_buf+lenth+1) = crc_tmp & 0xff; //CRC 低字節(jié)在后
lenth++;
lenth++;
while ( lenth--) //形成Modbus通信的RTU串
{
*dst_buf = *src_buf;
dst_buf++;
src_buf++;
}
}
char ProcessMasterRTU( unsigned int *dest, unsigned char *src,unsigned int start_address, unsigned int fr_lenth)
{
unsigned int crc_result, crc_tmp;
unsigned char i, j, shift;
crc_tmp = *(src + fr_lenth-2); // crc 第一字節(jié)
crc_tmp = crc_tmp * 256 + *( src+fr_lenth-1); // CRC 值
crc_result = CRC16(src, fr_lenth-2); // 計算CRC 值
if ( crc_tmp != crc_result )
{
return CRC_ERR; // CRC 校驗錯誤
}
switch ( *(src+1) ) // 功能碼
{
case READ_COIL: //讀取繼電器狀態(tài) 01
{
for ( i=0; i<*( src+2); i++)
{
shift = 1;
for ( j=0; j<8; j++)
{
*(dest+start_address+i*8+j) = shift & *( src+3+i);
*( src+3+i) >>= 1;
}
}
break;
}
case READ_DI: //讀取開關(guān)量輸入 02
{
for ( i=0; i<*( src+2); i++)
{
shift = 1;
for (j=0; j<8; j ++)
{
*(dest+start_address+i*8+j) = shift & *( src+3+i);
*( src+3+i)>>=1;
}
}
break;
}
case READ_HLD_REGs: //讀取多個保持寄存器 03
{
for ( i=0; i<*( src+2); i+=2)
{
//todo: 這個式子是否正確
*(dest + start_address+ i/2)= *(src+i+3)*256 + *(src+i+4) ;
}
break ;
}
case READ_AI: //讀取模擬量輸入 04
{
for ( i=0; i<*( src+2); i+=2)
{
*(dest + start_address+ i/2) = *( src+i+3)*256 + *( src+i+4) ;
}
break;
}
case SET_COIL: //05強制單個線圈進行
{
break;
}
case SET_HLD_REG: //06寫單個寄存器
{
break;
}
case SET_COILs: //15強制多個線圈進行
{
break;
}
case SET_HLD_REGs: //16寫多個寄存器
{
break;
}
case READ_SET_HLD_REGs: //23讀寫多個寄存器
{
break;
}
default: //功能碼錯誤
return(CMD_ERR);
break;
}
return(1);
}
// 功能 :讀取繼電器狀態(tài):CMD == 1
// 返回 :成功返回1,否則返回0
// 請求命令:[設(shè)備地址] [命令號01] [起始寄存器地址高8位] [低8位] [讀取的線圈數(shù)高8位] [低8位] [CRC校驗的高8位] [CRC校驗的低8位]
// 設(shè)備響應(yīng):[設(shè)備地址] [命令號01] [返回的字節(jié)個數(shù)][數(shù)據(jù)1][數(shù)據(jù)2]...[數(shù)據(jù)n][CRC校驗的高8位] [CRC校驗的低8位]
// tmmp存放讀回寄存器的狀態(tài)
char ReadCoilStatus(unsigned int *pwCoilState, unsigned char DeviceID,unsigned int start_address,unsigned int lenth)
{
unsigned char tmp[64],tmp_lenth;
tmp[0] = DeviceID; //從設(shè)備地址
tmp[1] = 0x01; //命令
tmp[2] = start_address>>8; //起始地址 高字節(jié)
tmp[3] = start_address & 0xFF; //起始地址 低字節(jié)
tmp[4] = lenth>>8; //讀取數(shù)據(jù)量 高字節(jié)
tmp[5] = lenth & 0xFF; //讀取數(shù)據(jù)量 低字節(jié)
tmp_lenth = 6; //二進制包長度
ConstructRtuFrame(GwSciTxBuffer,tmp,tmp_lenth);
GwSciTxBytes = tmp_lenth+2;
if(lenth % 8==0) //如果余數(shù)為零
{
GwSciRxBytes=(lenth/8)+3+2; // lenth/8線圈狀態(tài)的字節(jié)數(shù),3為地址碼,功能碼,字節(jié)數(shù),2為兩個CRC字節(jié)
}
else
{
GwSciRxBytes=(lenth/8+1)+3+2;
}
SciSend(); //發(fā)送請求
SciReceive(); //接收設(shè)備響應(yīng)
if(GwSciRxBuffer[1] == 0x01) //通信正常,數(shù)據(jù)處理
{
ProcessMasterRTU(pwCoilState,GwSciRxBuffer,0,GwSciRxBytes);
}
else //通信異常0x83,查詢異常碼,可重新發(fā)送請求或作其他處理
{
return(CMD_ERR);
}
}
// 功能 :讀取開關(guān)量輸入:CMD == 2
// 返回 :成功返回1,否則返回0
// 備注 :全局變量Modbus_mode,GwSciTxBuffer[],GwSciTxBytes,GwSciRxBuffer[],GwSciRxBytes
// 請求命令:[設(shè)備地址] [命令號02] [起始寄存器地址高8位] [低8位] [讀取的寄存器數(shù)高8位] [低8位] [CRC校驗的高8位] [CRC校驗的低8位]
// 設(shè)備響應(yīng):[設(shè)備地址] [命令號02] [返回的字節(jié)個數(shù)][數(shù)據(jù)1][數(shù)據(jù)2]...[數(shù)據(jù)n][CRC校驗的高8位] [CRC校驗的低8位]
char ReadInStatus(unsigned int *pwInState, unsigned char DeviceID, unsigned int start_address, unsigned int lenth)
{
unsigned char tmp[64], tmp_lenth;
// int tmmp[256];
tmp[0] = DeviceID; //從設(shè)備地址
tmp[1] = 0x02; //命令
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -