?? modbus.c
字號:
//****************************************************************************
// 文件名: MODBUS.C
// 功 能: 實現從機MODBUS功能,負責接收主機命令,校驗,應答
// 規 范: 使用RTU 模式CRC校驗
// 串 口: 1位起始位,8位數據位,無校驗位,1位停止位19200 波特率
// 作 者: 李龍勝
// 版 本: V1.0
// 日 期: 2008.09.05
// 修 訂: 2008.12.17
// 說 明 : 移植到雙芯片主機中由串口0改為串口1
//****************************************************************************
//****************************************************************************
// @Project Includes
//****************************************************************************
#include "MAIN.H"
//****************************************************************************
// @全局變量
//****************************************************************************
bit Asc1_receive_ok;
bit Asc1_transfer_ok;
bit Asc1_lastFrame_indeal;
ubyte Asc1_Rx_BUF[Asc1_Rx_lengh_max] =
{
0, 0,
};
ubyte Asc1_Tx_BUF[Asc1_Tx_lengh_max] =
{
0, 0,
};
ubyte *Asc1_Rx_BUF_point = Asc1_Rx_BUF;
ubyte *Asc1_Tx_BUF_point = Asc1_Tx_BUF;
ubyte Asc1_Rx_lengh = 0;
ubyte Asc1_Tx_lengh = 0;
const unsigned int crc_ta[256] =
{
0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301, 0x03C0, 0x0280, 0xC241, 0xC601, 0x06C0, 0x0780, 0xC741, 0x0500, 0xC5C1, 0xC481, 0x0440, 0xCC01, 0x0CC0, 0x0D80, 0xCD41, 0x0F00, 0xCFC1, 0xCE81, 0x0E40, 0x0A00, 0xCAC1, 0xCB81, 0x0B40, 0xC901, 0x09C0, 0x0880, 0xC841, 0xD801, 0x18C0,
0x1980, 0xD941, 0x1B00, 0xDBC1, 0xDA81, 0x1A40, 0x1E00, 0xDEC1, 0xDF81, 0x1F40, 0xDD01, 0x1DC0, 0x1C80, 0xDC41, 0x1400, 0xD4C1, 0xD581, 0x1540, 0xD701, 0x17C0, 0x1680, 0xD641, 0xD201, 0x12C0, 0x1380, 0xD341, 0x1100, 0xD1C1, 0xD081, 0x1040, 0xF001, 0x30C0, 0x3180, 0xF141,
0x3300, 0xF3C1, 0xF281, 0x3240, 0x3600, 0xF6C1, 0xF781, 0x3740, 0xF501, 0x35C0, 0x3480, 0xF441, 0x3C00, 0xFCC1, 0xFD81, 0x3D40, 0xFF01, 0x3FC0, 0x3E80, 0xFE41, 0xFA01, 0x3AC0, 0x3B80, 0xFB41, 0x3900, 0xF9C1, 0xF881, 0x3840, 0x2800, 0xE8C1, 0xE981, 0x2940, 0xEB01, 0x2BC0,
0x2A80, 0xEA41, 0xEE01, 0x2EC0, 0x2F80, 0xEF41, 0x2D00, 0xEDC1, 0xEC81, 0x2C40, 0xE401, 0x24C0, 0x2580, 0xE541, 0x2700, 0xE7C1, 0xE681, 0x2640, 0x2200, 0xE2C1, 0xE381, 0x2340, 0xE101, 0x21C0, 0x2080, 0xE041, 0xA001, 0x60C0, 0x6180, 0xA141, 0x6300, 0xA3C1, 0xA281, 0x6240,
0x6600, 0xA6C1, 0xA781, 0x6740, 0xA501, 0x65C0, 0x6480, 0xA441, 0x6C00, 0xACC1, 0xAD81, 0x6D40, 0xAF01, 0x6FC0, 0x6E80, 0xAE41, 0xAA01, 0x6AC0, 0x6B80, 0xAB41, 0x6900, 0xA9C1, 0xA881, 0x6840, 0x7800, 0xB8C1, 0xB981, 0x7940, 0xBB01, 0x7BC0, 0x7A80, 0xBA41, 0xBE01, 0x7EC0,
0x7F80, 0xBF41, 0x7D00, 0xBDC1, 0xBC81, 0x7C40, 0xB401, 0x74C0, 0x7580, 0xB541, 0x7700, 0xB7C1, 0xB681, 0x7640, 0x7200, 0xB2C1, 0xB381, 0x7340, 0xB101, 0x71C0, 0x7080, 0xB041, 0x5000, 0x90C1, 0x9181, 0x5140, 0x9301, 0x53C0, 0x5280, 0x9241, 0x9601, 0x56C0, 0x5780, 0x9741,
0x5500, 0x95C1, 0x9481, 0x5440, 0x9C01, 0x5CC0, 0x5D80, 0x9D41, 0x5F00, 0x9FC1, 0x9E81, 0x5E40, 0x5A00, 0x9AC1, 0x9B81, 0x5B40, 0x9901, 0x59C0, 0x5880, 0x9841, 0x8801, 0x48C0, 0x4980, 0x8941, 0x4B00, 0x8BC1, 0x8A81, 0x4A40, 0x4E00, 0x8EC1, 0x8F81, 0x4F40, 0x8D01, 0x4DC0,
0x4C80, 0x8C41, 0x4400, 0x84C1, 0x8581, 0x4540, 0x8701, 0x47C0, 0x4680, 0x8641, 0x8201, 0x42C0, 0x4380, 0x8341, 0x4100, 0x81C1, 0x8081, 0x4040
};
//****************************************************************************
// @Function void Modbus_deal()
// @Description 在main()中循環執行
//****************************************************************************
void Modbus_deal()
{
//檢查是否有收到幀信息
//ASC1_vSendData(0x55);
if (Asc1_receive_ok)
{
Asc1_receive_ok = 0;
//標記處于幀處理中
//Asc1_lastFrame_indeal = 1;
//是否開辟限時處理功能,防止超時未應答,
//免得一直不退出上一幀處理
//比如定時器T3之???ms延時
//判定是否為本地址幀
if (Asc1_Rx_BUF[0] == Modbus_Node)
{
//判定地址符合情況下才進入幀處理
Frame_deal();
}
//不是本機地址直接退出
else
{
#if(MODBUS_DebugMode)
#if(Asc1_Send_while == 1)
ASC1_vSendData_While( 0xAA );
#endif
#endif
// do nothing
}
//完成幀處理
Asc1_lastFrame_indeal = 0;
//長度清零,指針指向數組第一個空間
Asc1_Rx_lengh = 0;
Asc1_Rx_BUF_point = Asc1_Rx_BUF;
}
}
//****************************************************************************
// @Function void crc_cal( ubyte* ptr, ubyte len )
// @Description 計算待發送的數據之CRC 值 并插入發送緩沖
// @Parameters * ptr : 待發送的數組的首地址
// len : 待發送的數組之字節數,不包括CRC碼
//****************************************************************************
__inline void crc_cal(ubyte *ptr, ubyte len)
{
uword crc1 = 0xffff; // 初始化
ubyte temp = 0;
while (len > 0)
{
crc1 = ( crc1 >> 8 ) ^ crc_ta[( crc1 ^ *ptr ) & 0xff];
len--;
ptr++;
}
//往發送緩沖區寫CRC之低字節
*ptr = ( ubyte ) ( crc1 % 256 );
//往發送緩沖區寫CRC之高字節
ptr++;
*ptr = ( ubyte ) ( crc1 / 256 );
}
//****************************************************************************
// @Function uword crc_check( ubyte* ptr, ubyte len )
// @Description 計算待接收的數據之CRC 值 ,正確則返回0
// @Rerurn 正確的編碼返回 0x00
// @Parameters * ptr : 待接收的數組的首地址
// len : 待接收的數組之字節數,包括CRC碼
//****************************************************************************
__inline uword crc_check(ubyte *ptr, ubyte len)
{
uword crc1 = 0xffff; // 初始化
#if(CRC_NeedSend)
uword temp = 0;
#endif
while (len > 0)
{
crc1 = ( crc1 >> 8 ) ^ crc_ta[( crc1 ^ *ptr ) & 0xff];
len--;
ptr++;
//調試幀數據時需要發送
#if(CRC_NeedSend)
temp = crc1 / 256;
#if(Asc1_Send_while == 1)
ASC1_vSendData_While( temp );
#endif
temp = crc1 % 256;
#if(Asc1_Send_while == 1)
ASC1_vSendData_While( temp );
#endif
#endif
}
return crc1;
}
//****************************************************************************
// @Function void Frame_deal()
// @Description 處理接收到的數據幀,在main中查詢執行
// 在地址也符合的情況下才進入幀處理
// @Rerurn
// @Parameters
//****************************************************************************
__inline void Frame_deal()
{
uword temp1 = 0;
//進行CRC 校驗,正確的校驗返回為0
temp1 = crc_check( Asc1_Rx_BUF, Asc1_Rx_lengh );
if (temp1 == 0)
{
#if(MODBUS_DebugMode == 1)
//{ 調試時
#if(Asc1_Send_while == 1)
ASC1_vSendData_While( 0x88 );
#endif
Frame_Data_Analyse();
//}
#else
//{ 正常處理
Frame_Data_Analyse();
//}
#endif
}
//校驗未通過處理
else
{
#if(MODBUS_DebugMode)
//{ 調試時
#if(Asc1_Send_while == 1)
ASC1_vSendData_While( 0x99 );
#endif
//}
#else
//{ 正常處理
#if(MODBUS_CRCerr_needDeal)
//{ CRC 校驗出錯 需處理
#if(Asc1_Send_while == 1)
ASC1_vSendData_While( 0x09 );
#endif
//}
#endif
//}
#endif
}
}
//****************************************************************************
// @Function void Frame_Data_Analyse()
// @Description 在正確的CRC 校驗之后進行對數據分析處理
// @Rerurn
// @Parameters
//****************************************************************************
__inline void Frame_Data_Analyse()
{
//-----------功能碼----------
//#define READ_Coils_State 01
//#define READ_Inputs_State 02
//#define READ_Hold_Registers 03
//#define READ_Input_Registers 04
//#define WRITE_One_Coil 05
//#define WRITE_One_Register 06
//#define WRITE_Some_Coil 15
//#define WRITE_Some_Register 16
//對應答作初步準備
Asc1_Tx_BUF[0] = Modbus_Node;
Asc1_Tx_lengh = 1;
//----根據功能碼分類-----
switch (Asc1_Rx_BUF[1])
{
case READ_Coils_State:
//01
Deal_READ_Coils_State();
break;
case READ_Inputs_State:
//02
break;
case READ_Hold_Registers:
//03
Deal_READ_Hold_Registers();
break;
case READ_Input_Registers:
//04
break;
case WRITE_One_Coil:
//05
Deal_WRITE_One_Coilr();
break;
case WRITE_One_Register:
//06
Deal_WRITE_One_Register();
break;
case WRITE_Some_Coil:
//15
Deal_WRITE_Some_Coil();
break;
case WRITE_Some_Register:
//16
Deal_WRITE_Some_Register();
break;
default:
break;
}
}
//****************************************************************************
// @Function void Send_Asc0_Tx_buf()
// @Description 處理發送緩沖區
//****************************************************************************
__inline void Send_Asc0_Tx_buf()
{
ubyte temp1;
for (temp1 = 0; temp1 < Asc1_Tx_lengh; temp1++)
{
#if(Asc1_Send_while == 1)
ASC1_vSendData_While( Asc1_Tx_BUF[temp1] );
#endif
}
}
//****************************************************************************
// @Function void Send_Asc0_Rx_buf_Back()
// @Description 正確處理完寫,直接回復接收緩沖區
//****************************************************************************
__inline void Send_Asc0_Rx_buf_Back()
{
ubyte temp1;
for (temp1 = 0; temp1 < Asc1_Rx_lengh; temp1++)
{
#if(Asc1_Send_while == 1)
ASC1_vSendData_While( Asc1_Rx_BUF[temp1] );
#endif
}
}
//****************************************************************************
// @Function void Deal_READ_Coils_State()
// @Description 讀一組邏輯線圈當前狀態
//****************************************************************************
__inline void Deal_READ_Coils_State()
{
bit Deal_all_OK = 0;
ubyte temp1, temp2, temp5, temp6, temp7, temp8, temp9;
uword temp3, temp4;
//清零發送緩沖區
for (temp1 = 0; temp1 < Asc1_Tx_lengh_max; temp1++)
{
Asc1_Tx_BUF[temp1] = 0;
}
//判定功能碼是否合法(01,但是幀長超出)
if (Asc1_Rx_lengh != 8)
{
Asc1_Tx_BUF[1] = 0x81;
Asc1_Tx_BUF[2] = 0x01;
Asc1_Tx_lengh = 3;
}
else
{
//判定輸出數量是否合法(這里僅開辟80個位)
temp3 = ( uword ) Asc1_Rx_BUF[4] * 256 + Asc1_Rx_BUF[5];
if (temp3 > ModBus_PLC_Bit_max) // 這里最多支持 80 bit
{
Asc1_Tx_BUF[1] = 0x81;
Asc1_Tx_BUF[2] = 0x03;
Asc1_Tx_lengh = 3;
}
else
{
//判定首地址、末地址是否合法
temp4 = ( uword ) Asc1_Rx_BUF[2] * 256 + Asc1_Rx_BUF[3]; //首地址
temp3 += temp4; //末地址
//判斷首地址、末地址均合法否
if (temp3 >= ModBus_PLC_Bit_max || temp4 >= ModBus_PLC_Bit_max)
{
Asc1_Tx_BUF[1] = 0x81;
Asc1_Tx_BUF[2] = 0x02;
Asc1_Tx_lengh = 3;
}
else
{
//處理讀請求
//開始地址: 第幾個字節,第幾位
temp1 = Asc1_Rx_BUF[3] / 8; //第幾字節
temp2 = ( ubyte ) ( Asc1_Rx_BUF[3] % 8 ); //該字節第幾位
//共發送幾個字節+ 幾位
temp5 = ( ubyte ) ( Asc1_Rx_BUF[5] / 8 + 1 ); //幾個字節
//ASC1_vSendData(temp5);
temp6 = ( ubyte ) ( Asc1_Rx_BUF[5] % 8 ); //加幾位
Asc1_Tx_BUF[0] = Modbus_Node;
Asc1_Tx_BUF[1] = 0x01;
Asc1_Tx_BUF[2] = temp5;
for (temp7 = 0; temp7 < temp5; temp7++)
{
temp9 = PLC_Bit_Buffer_all.PLC_Bit_Buffer[temp1 + 1];
temp3 = temp7 * 256 + PLC_Bit_Buffer_all.PLC_Bit_Buffer[temp1];
temp3 >>= temp2;
temp1++;
temp8 = temp7 + 3;
Asc1_Tx_BUF[temp8] = ( ubyte ) ( temp3 & 0x00FF );
}
temp2 = Asc1_Tx_BUF[temp8];
//對最后一個字節的無效高位清0
temp1 = 0;
for (temp7 = 0; temp7 < temp6; temp7++)
{
temp1 <<= 1;
temp1 |= 0x01;
}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -