⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 modbusa.h

📁 西门子PPI协议源码
💻 H
📖 第 1 页 / 共 2 页
字号:
//*********************************************************************
//*********** 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 + -