stm32,modbus

文章详细描述了如何在通用从机上实现MODBUS协议的两个功能码(3和4)处理,包括读取HOLD和输入IN_HOLD寄存器,以及使用中断方式接收数据,并涉及CRC校验。内容强调了代码的可移植性和中断机制的应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

通用从机MODBUS,可移植

// 功能码3处理
 void  MODBUS_RD_HOLD(volatile MODBUS_Define *mv,u16 Adrr,u16 RegNum,u8 ADDRESS )
 {
	u8	i = 0,LenCNT=0;	
	s32 data = 0;
	u16  TEMPCRC = 0;
	 
	 
	 switch(ADDRESS)//串口号
	{
		 case 1:
			 mv->txBuf[LenCNT++] = MODBUS__ADDRESS;//0x02
			 break;
		 case 2:
			 mv->txBuf[LenCNT++] = MODBUS__ADDRESS2;//0x03
			 break;
		 case 3:
			 mv->txBuf[LenCNT++] = MODBUS__ADDRESS3;//0x04
			 break;
		 default :
			 break;
	}
	mv->txBuf[LenCNT++]=MODBUS_RD_HOLD_REG;//0x03
	mv->txBuf[LenCNT++]=0;//数据长度
	switch(ADDRESS)
	{
		case 1:
			for(i=Adrr;i<((Adrr+RegNum));i++)
			{
				data = * HoldReg_4xxxx[i];
				mv->txBuf[LenCNT++] = data>>8;
				mv->txBuf[LenCNT++] = data&0xFF;
			}
			break;
		case 2:
			for(i=Adrr;i<((Adrr+RegNum));i++)
			{
				data = * HoldReg_4xxxx[i];
				mv->txBuf[LenCNT++] = data>>8;
				mv->txBuf[LenCNT++] = data&0xFF;
			}
			break;
		case 3:
			for(i=Adrr;i<((Adrr+RegNum));i++)
			{
				data = * HoldReg_4xxxx[i];
				mv->txBuf[LenCNT++] = data>>8;
				mv->txBuf[LenCNT++] = data&0xFF;
			}
			break;
		default :
			break;
		
	
	}
	mv->txBuf[2] = LenCNT - 3;
	TEMPCRC = ModbusCRC(mv->txBuf,LenCNT);
	mv->txBuf[LenCNT++] =  LBYTE(TEMPCRC); 							
	mv->txBuf[LenCNT++] =  HBYTE(TEMPCRC);							
	mv->txLen = LenCNT;
 }  
  
// 功能码4处理
 void MODBUS_IN_HOLD(volatile MODBUS_Define *mv,u16 Adrr,u16 RegNum,u8 ADDRESS)    
{
	u8	i = 0,LenCNT=0;	
	s32 data = 0;
	u16  TEMPCRC = 0;
	switch(ADDRESS)//串口号
	{
		 case 1:
			 mv->txBuf[LenCNT++] = MODBUS__ADDRESS;//0x01
			 break;
		 case 2:
			 mv->txBuf[LenCNT++] = MODBUS__ADDRESS2;//
			 break;
		 case 3:
			 mv->txBuf[LenCNT++] = MODBUS__ADDRESS3;//0x04
			 break;
		  case 4:
			 mv->txBuf[LenCNT++] = MODBUS__ADDRESS4;//0x05
			 break;
		 default :
			 break;
	}
	mv->txBuf[LenCNT++]=MODBUS_RD_IN_REG;//0x04
	mv->txBuf[LenCNT++]=0;//数据长度
	switch(ADDRESS)//串口号
	{
		case 1:
			for(i=Adrr;i<((Adrr+RegNum));i++)
			{
				data = *InputReg_3xxxx[i];
				mv->txBuf[LenCNT++] = data>>8;
				mv->txBuf[LenCNT++] = data&0xFF;
			}
			break;
		case 2:
			if((Adrr<=0x01DA)&&(Adrr>0))
			{
				for(i=Adrr;i<((Adrr+RegNum));i++)
				{
					data = *InputReg_3xxxx[i];
					mv->txBuf[LenCNT++] = data>>8;
					mv->txBuf[LenCNT++] = data&0xFF;
				}
			}else if((Adrr>0x01DA)&&(Adrr<=0x031E)&&(Adrr>0))//SOC
			{
				for(i=(Adrr-0x01DB);i<((Adrr+RegNum)-0x01DB);i++)
				{
					mv->txBuf[LenCNT++] = li_battery_.Cell_SOC[i]>>8;
					mv->txBuf[LenCNT++] = li_battery_.Cell_SOC[i]&0xFF;
				}
			}
			else if((Adrr<=0x462)&&(Adrr>0x031E)&&(Adrr>0))//SOH
			{
				for(i=(Adrr -0x031F);i<((Adrr+RegNum)-0X031F);i++)
				{
					mv->txBuf[LenCNT++] = li_battery_.Cell_SOH[i]>>8;
					mv->txBuf[LenCNT++] = li_battery_.Cell_SOH[i]&0xFF;
				}
			}
			
			break;
		case 3:
			for(i=Adrr;i<((Adrr+RegNum));i++)
			{
				data = *InputReg_3xxxx[i];
				mv->txBuf[LenCNT++] = data>>8;
				mv->txBuf[LenCNT++] = data&0xFF;
			}
			break;
		case 4:
			if(Adrr<0x01C5)
			{
				for(i=Adrr;i<((Adrr+RegNum));i++)
				{
					data = *InputReg_3xxxx[i];
					mv->txBuf[LenCNT++] = data>>8;
					mv->txBuf[LenCNT++] = data&0xFF;
				}
			}
			else if((Adrr>=0x01C5)&&(Adrr<0x02E5))//SOC
			{
				for(i=(Adrr-0x01C5);i<((Adrr+RegNum)-0x01C5);i++)
				{
					mv->txBuf[LenCNT++] = li_battery_.Cell_SOC[i]>>8;
					mv->txBuf[LenCNT++] = li_battery_.Cell_SOC[i]&0xFF;
				}
			}
			else if((Adrr<0x405)&&(Adrr>=0x02E5))//SOH
			{
				for(i=(Adrr -0x02DD);i<((Adrr+RegNum)-0X02DD);i++)
				{
					mv->txBuf[LenCNT++] = li_battery_.Cell_SOH[i]>>8;
					mv->txBuf[LenCNT++] = li_battery_.Cell_SOH[i]&0xFF;
				}
			}
			break;
		default :
			break ;		
	}
	mv->txBuf[2] = LenCNT - 3;
	TEMPCRC = ModbusCRC(mv->txBuf,LenCNT);
	mv->txBuf[LenCNT++] =  LBYTE(TEMPCRC); 							
	mv->txBuf[LenCNT++] =  HBYTE(TEMPCRC);
	mv->txLen = LenCNT;	
}

好用可移植,接收数据采用中断方式

### STM32 Modbus 配置编程示例 #### 一、Modbus RTU 协议简介 Modbus 是一种串行通讯协议,由 Modicon 公司于1979年发明。该协议支持典型的主/从模式通信,在工业自动化领域广泛应用。Modbus RTU 特别适合用于 RS-485 或者 RS-232 的物理层传输[^1]。 #### 二、STM32作为Modbus主设备的配置过程 为了使 STM32 成功工作在 Modbus 主站角色下,需完成如下几个方面的设置: - **硬件准备** - 使用RS485模块来构建半双工或全双工通信链路。 - 进行必要的电气连接,确保电源供应稳定以及信号线正确对接。 - **软件初始化** - 初始化 UART 接口参数(波特率、停止位等),使之匹配目标从机的要求。 - 设置定时器或其他机制处理字符间超时检测功能。 - 实现 CRC 校验算法以保障数据完整性验证。 #### 三、编写程序向从设备发送请求命令 当一切准备工作完成后,就可以通过调用特定函数库中的 API 来发起读取或写入操作了。下面给出一段简单的 C 语言代码片段展示如何利用 HAL 库执行批量写入动作: ```c #include "stm32f1xx_hal.h" // 假设已经定义好了相应的句柄 huart1 和其他必要变量... void WriteMultipleCoils(uint16_t startAddr, uint16_t quantityOfOutputs, uint8_t *outputValue){ MODBUS_TxRxStatusTypeDef status; uint8_t pdu[MODBUS_PDU_MAX_LENGTH]; /* 构造 PDU */ pdu[0] = (uint8_t)(startAddr >> 8); // 起始地址高位字节 pdu[1] = (uint8_t)startAddr; // 起始地址低位字节 pdu[2] = (uint8_t)(quantityOfOutputs >> 8); // 输出数量高位字节 pdu[3] = (uint8_t)quantityOfOutputs; // 输出数量低位字节 pdu[4] = ((quantityOfOutputs + 7)/8); // 字节数 memcpy(&pdu[5], outputValue, pdu[4]); // 复制实际的数据值 /* 执行事务 */ status = ModbusMaster_WriteMultipleCoils(huart1, SLAVE_ADDRESS, pdu); } ``` 上述例子展示了怎样封装一个用来修改远程 IO 设备状态的方法 `WriteMultipleCoils` ,它接受三个参数:起始寄存器地址、要改变的状态数目还有具体的数值列表[^2]。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值