📄 modbusa.h
字号:
//*********************************************************************
//*********** modbusA.h ****************
#include "DEFMOD.h"
UCHAR convert_ascii_to_rtu(UCHAR* puc_buf,UCHAR uc_bytes,UCHAR uc_is_crc);
UCHAR convert_rtu_to_ascii(UCHAR* puc_buf,UCHAR uc_bytes);
//*****************************************************************************
//**Purpose:
// RTU读位,返回若干位组成的字节,输入位的首地址、位的数量(1-8)
// 从最低位添入,未读的位为0
//**Entry:
//** UINT ui_start_address: 指向开始地址。
//** UCHAR uc_bits : 要读的位数。
//**return:
//** 返回位的值。
#ifdef RTU_READ_BITS_EN
UCHAR rtu_read_bits(UINT ui_start_address,UCHAR uc_bits)
{
UCHAR uc_ret=0;
UCHAR uc_i;
for(uc_i=0;uc_i<uc_bits;uc_i++)
{
if(uc_RTU_get_bit(ui_start_address + uc_i)){uc_ret|=BIT(uc_i);}
}
return(uc_ret);
}
#endif //**end(#ifdef RTU_READ_BITS_EN)
#ifdef RTU_WRITE_BITS_EN
//***************************************************************************
//**Purpose:
//** 以下是自己发出了读PLC内部位的命令01,PLC返回了数据,填写入自己的内存
void write_bit_by_plc(uint ui_bit_address,uchar uc_bit_len,uchar *dat)
{
uchar uc_i;
for(uc_i = 0; uc_i<uc_bit_len; uc_i++)
{
uc_RTU_write_bit(ui_bit_address+uc_i,*(dat+uc_i/8) & BIT(uc_i%8));
}
}
#endif //**(#ifdef RTU_WRITE_BITS_EN )
//****************************************************************************
//**Purpose:
//** 当modbus为从时,RTU分析及返回,先效验 返回为发送串长(下标),返回0为不发送
UCHAR rtu_reqframe_anlys_slaver(UCHAR *puc_rec_buf,UCHAR uc_rec_len,UCHAR *puc_send_buf)
{
UCHAR ucp_rec_count,ucp_send_count,uc_count,uc_h,uc_l,uc_mid,uc_len_limit;
UCHAR uc_is_excep = 0,uc_excep_code=0,uc_bytes = 0;
UINT u16,ui_address,ui_mid;
if(is_modbus_asc) //modbus为ascii时的lrc校验
{
uc_mid = MAKE_HEX_TO_DEC(*(puc_rec_buf+uc_rec_len-2),*(puc_rec_buf+uc_rec_len-1));
uc_rec_len = convert_ascii_to_rtu(puc_rec_buf,uc_rec_len-2,0); //不包含lrc校验
if(uc_mid != lrc(puc_rec_buf,uc_rec_len))
{
return 0 ;
}
}
else //modbus为rtu时的crc校验
{
u16 = CRC16(puc_rec_buf,uc_rec_len -2);
uc_h = *(puc_rec_buf + uc_rec_len - 1);
uc_l = *(puc_rec_buf + uc_rec_len - 2);
if((HI_UINT(u16) != uc_h) || (LO_UINT(u16) != uc_l))//right first crcl,then crch
{
return(0);
}
}
ucp_rec_count = 0;
ucp_send_count = 0;
*(puc_send_buf + ucp_send_count++) = *(puc_rec_buf + ucp_rec_count++);//地址
*(puc_send_buf + ucp_send_count++) = *(puc_rec_buf + ucp_rec_count++);//功能码
uc_h = *(puc_rec_buf + ucp_rec_count++);//开始地址
uc_l = *(puc_rec_buf + ucp_rec_count++);
ui_address = (uc_h<<8) | uc_l;
switch(puc_rec_buf[1])
{
#ifdef MB_SLV_BIT_READ_EN //**读位开关
case ModbusC_ReadCoil: //ModbusC_ReadDiscrete 01
case ModbusC_ReadDiscrete: //read discrete 02
{
uc_h = *(puc_rec_buf + ucp_rec_count++);//获得读位的数量
uc_l = *(puc_rec_buf + ucp_rec_count++);
ui_mid = MAKE_UINT(uc_h,uc_l);
uc_len_limit = is_modbus_asc ?SEND_BIT_NUM_MAX_ASC:SEND_BIT_NUM_MAX_RTU;
//异常处理。
if((ui_mid < 0x0001) || (ui_mid > uc_len_limit)||(ui_mid > 0x07D0) ) //读位的数量不正确只能在(0x0001 - 0x07d0).只返回错误码。
{
uc_is_excep = 1;
uc_excep_code = 3;
break;
}
ui_mid -= 1;
uc_h = ui_mid / 8;
uc_l = ui_mid % 8;
*(pch_send_Buf + ucp_send_count++) = uc_h + 1;
for(uc_mid = 0;uc_mid < uc_h;uc_mid++)
{
*(pch_send_Buf + ucp_send_count++) = rtu_read_bits(ui_address + uc_mid*8,8);
}
*(puc_send_buf +ucp_send_count++) = rtu_read_bits(ui_address + uc_mid*8,uc_l+1);
}
break;
#endif //**(#ifdef MB_SLV_BIT_READ_EN )
#ifdef MB_SLV_BIT_WRITE_EN //**写位开关
case ModbusC_WriteSingleCoil: // 05
{
uc_mid = *(puc_rec_buf + ucp_rec_count++);//得到位值的高位
uc_count = *(puc_rec_buf + ucp_rec_count++);//得到位值的低位
ui_mid = (uc_mid << 8 | uc_count);
//异常检查
if((ui_mid != 0x0000) && (ui_mid != 0xFF00)) //如果要写的位数据不为0x0000或0xff00,生成异常串
{
uc_is_excep = 1;
uc_excep_code = 3;
break;
}
*(puc_send_buf + ucp_send_count++) = uc_h;//要写bit位地址的高位。
*(puc_send_buf + ucp_send_count++) = uc_l;//要写bit位地址的低位
*(puc_send_buf + ucp_send_count++) = uc_mid;//bit位值的高位。0xff or 0x00.
*(puc_send_buf + ucp_send_count++) = uc_count; //bit位值的低位.
uc_RTU_write_bit(ui_address,uc_mid); //不需要uc_l,总是为0,uc_h=0xff/00
}
break;
case ModbusC_WriteMultiCoil: //写多个线圈。
{
uc_mid = *(puc_rec_buf + ucp_rec_count++); //获得要写的bit位的数量的高位。
uc_count = *(puc_rec_buf + ucp_rec_count++); //获得要写的bit位的数量的低位
uc_bytes = *(puc_rec_buf + ucp_rec_count++); //获取位值的字节数。
ui_mid = (uc_mid << 8 | uc_count);
//异常检查,如果要写位的数量< 0x0001 或 要写位的数量 > 0x07D0 或 由位数量计算的字节数!= 接收帧中字节数,则产生异常。
if((ui_mid < 0x0001) || (ui_mid > 0x07D0) ||(((ui_mid % 8)?(ui_mid/8 +1):(ui_mid/8)) != uc_bytes)) //写位的数量不正确只能在(0x0001 - 0x07d0).只返回错误码。
{
uc_is_excep = 1;
uc_excep_code = 3;
break;
}
*(puc_send_buf + ucp_send_count++) = uc_h; //bit位开始地址的高位(写回应串)
*(puc_send_buf + ucp_send_count++) = uc_l; //bit位开始地址的低位。(写回应串)
*(puc_send_buf + ucp_send_count++) = uc_mid; // 要写的bit位。
*(puc_send_buf + ucp_send_count++) = uc_count;//回应到此为止
u16 = (uc_mid<<8) | uc_count;//位的个数,1-0x7B0
for(ui_mid=0;ui_mid<u16;ui_mid++)
{
uc_RTU_write_bit(ui_address+ui_mid,*(puc_rec_buf + ucp_rec_count+ui_mid/8) & BIT(ui_mid%8));
}
}
break;
#endif //** end(MB_SLV_BIT_WRITE_EN )
#ifdef MB_SLV_REG_READ_EN //**读字开关
case MB_READ_HOLD_REG: //read hold single register 03
case MB_READ_INPUT_REG: // 04 读保持寄存器。
{
uc_h = *(puc_rec_buf + ucp_rec_count++);//获得要读的字数量的高8位
uc_l = *(puc_rec_buf + ucp_rec_count++); //获得要读的字数量的低8位
ui_mid = (uc_h << 8 | uc_l);
uc_len_limit = is_modbus_asc ?SEND_WORD_NUM_MAX_ASC:SEND_WORD_NUM_MAX_RTU;
//uc_len_limit = 255;
//异常处理
if((ui_mid < 0x0001) || (ui_mid > 0x007D) ||(ui_mid >uc_len_limit)) //读字的数量不正确只能在(0x0001 - 0x007d).只返回错误码。
{
uc_is_excep = 1;
uc_excep_code = 3;
break;
}
*(puc_send_buf + ucp_send_count++) = uc_l<<1; //获取要读的字节数。字的数量*2
//uc_count字数
for(uc_mid=0;uc_mid<uc_l;uc_mid++)//字数!!!
{
u16 = ui_RTU_ret_Word(ui_address + uc_mid);
*(puc_send_buf + ucp_send_count++) = (HI_UINT(u16));
*(puc_send_buf + ucp_send_count++) = (LO_UINT(u16));
}
}
break;
#endif //** end( #ifdef MB_SLV_REG_WRITE_EN )
#ifdef MB_SLV_REG_WRITE_EN //**写字开关
case MB_WRITE_SINGLE_REG:// 06 写单个保持寄存器。
{
*(puc_send_buf + ucp_send_count++) = uc_h;//address
*(puc_send_buf + ucp_send_count++) = uc_l;
uc_h = *(puc_rec_buf + ucp_rec_count++);//data
uc_l = *(puc_rec_buf + ucp_rec_count++);
*(puc_send_buf + ucp_send_count++) = uc_h;
*(puc_send_buf + ucp_send_count++) = uc_l;
Rtu_write_singleReg(ui_address,MAKE_UINT(uc_h,uc_l));
}
break;
case MB_WRITE_MULTI_REG: //0x10 写多个寄存器
{
uc_mid = *(puc_rec_buf + ucp_rec_count++); //获得要写的字寄存器的数量的高位。
uc_count = *(puc_rec_buf + ucp_rec_count++); //获得要写的字寄存器的数量的的低位
uc_bytes = *(puc_rec_buf + ucp_rec_count++); //获取要写的值的字节数。
ui_mid = (uc_mid << 8 | uc_count);
//异常检查,如果要写位的数量< 0x0001 或 要写位的数量 > 0x007B 或 由要写的字数量计算的字节数!= 接收帧中要写的字节数,则产生异常。
if((ui_mid < 0x0001) || (ui_mid > 0x007B)||(ui_mid > SEND_WORD_NUM_MAX_RTU)||(ui_mid * 2 != uc_bytes)) //写位的数量不正确只能在(0x0001 - 0x07d0).只返回错误码。
{
uc_is_excep = 1;
uc_excep_code = 3;
break;
}//异常处理结束
*(puc_send_buf + ucp_send_count++) = uc_h; // 开始地址的高位.
*(puc_send_buf + ucp_send_count++) = uc_l; //开始地址的低位.
*(puc_send_buf + ucp_send_count++) = uc_mid; //写的字数量的高位。
*(puc_send_buf + ucp_send_count++) = uc_count;//返回到此为止
for(uc_mid=0;uc_mid<uc_count;uc_mid++) //uc_count:要写的字的数量。
{
uc_h = *(puc_rec_buf + ucp_rec_count++);//从接收串获得字
uc_l = *(puc_rec_buf + ucp_rec_count++);
Rtu_write_singleReg(ui_address+uc_mid,(uc_h<<8) | uc_l);
}
}
break;
#endif //**end( #ifdef MB_SLV_REG_WRITE_EN )
#ifdef MB_SLV_REG_RW_EN
case MB_READ_WRITE_REG://0x17 write and read multiple reg,first write and second read
{
ucp_rec_count++;//高位为0
uc_count = *(puc_rec_buf + ucp_rec_count++);//要读的数量
uc_h = *(puc_rec_buf + ucp_rec_count++);
uc_l = *(puc_rec_buf + ucp_rec_count++);
u16 = (uc_h << 8 | uc_l);//要写的开始地址
ucp_rec_count++;
uc_mid = *(puc_rec_buf + ucp_rec_count++);//要写的数量
uc_bytes = *(puc_rec_buf + ucp_rec_count++);//要写的字节数.
uc_len_limit = is_modbus_asc ?SEND_WORD_NUM_MAX_ASC:SEND_WORD_NUM_MAX_RTU;
//异常检查
if(uc_count > 0x7D || uc_mid > 0x79||(uc_count > uc_len_limit) || (uc_bytes != uc_mid<<1))
{
uc_is_excep = 1;
uc_excep_code = 3;
break;
}
//写操作
for(uc_bytes=0;uc_bytes<uc_mid;uc_bytes++) //uc_count:要写的字的数量。
{
uc_h = *(puc_rec_buf + ucp_rec_count++);//从接收串获得字
uc_l = *(puc_rec_buf + ucp_rec_count++);
Rtu_write_singleReg(u16 + uc_bytes,((uc_h<<8)|uc_l));
}
*(puc_send_buf + ucp_send_count++) = uc_count<<1;
//读操作
for(uc_bytes=0;uc_bytes< uc_count;uc_bytes++)//字数
{
u16 = ui_RTU_ret_Word(ui_address + uc_bytes);
*(puc_send_buf + ucp_send_count++) = (HI_UINT(u16));
*(puc_send_buf + ucp_send_count++) = (LO_UINT(u16));
}
}
break;
#endif //**end ( MB_SLV_REG_RW_EN )
default: //出现不支持的功能码,出现异常(01)
uc_is_excep = 1;
uc_excep_code = 1;
break;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -