使用stm32cubeide stm32f103 freeRTOS 实现Modbus RTU协议寄存器读写过程详解

1前言

项目需要使用MCU实现Modbus RTU协议与PLC通信,STM32作为从机需要将一些传感器信息上报给PLC,有时也需要STM32作为主机采用Modbus RTU协议获取伺服器或者其他设备的一些状态信息。这些信息不需要很多,很多场景下可能就几个地址的寄存器信息。文末给出使用工程的下载地址。

如下图所示,本文主要主要设计使用stm32cubeide stm32f103 freeRTOS 实现Modbus RTU协议对从机寄存器的读写。

2详细设计

采用STM32CubeIDE 1.19.0,其他版本类似,基本上一样,针对硬件配置如下

2.1时钟配置

采用8Mhz外部时钟经过倍频后放大

2.2调试串口1配置

如下图所示

该串口波特率设置为115200,用于调试信息打印,这里在main.c中添加如下代码,实现printf数据打印

cpp 复制代码
#ifdef __GNUC__
#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
#else
#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#endif

PUTCHAR_PROTOTYPE
{
	while((USART1->SR&0x40)==0){};
	USART1->DR = ch;
    return ch;
}

2.3485串口的配置

采用uart2作为485串口,波特率选择9600,打开NVIC Settings,是能接受中断。

打开该中断后会在stm32f4xx_it.c有如下中断处理函数

cpp 复制代码
/**
  * @brief This function handles USART2 global interrupt.
  */
void USART2_IRQHandler(void)

2.4freeRTOS的配置

使用freeRTOS可以简化编程,实现多任务编程。首先配置调试接口,可以根据需要配置,这里配置SW接口,这里需要配置Timebase Source为TIM1,避免和HAL库共用了SysTick时钟源。

添加485串口接受数据处理任务,以及对应的接受数据队列,这里也对默认任务的堆栈做了放大处理。

在Advanced settings中USE_NEWLIB_REENTRANT 需要Enabled,不然会又警告提示,项目实际上芯片资源充分,这里选择了使能。这里是否需要使能 USE_NEWLIB_REENTRANT 取决于应用需求。如果需要线程安全且可以接受额外的内存开销,建议启用此选项。如果不需要线程安全或内存资源有限,可以选择不启用,但需避免使用可能引发线程安全问题的函数。

3关键代码

3.1Modbus RTU 06功能码处理

针对06功能码,主要主机写入寄存器,将寄存器的值保存到本地。

cpp 复制代码
  // Modbus RTU 6号功能码函数
// Modbus RTU 主机写入寄存器值
void Modbus_RTU_Func6(u8 *src, u16 len)
{
	u16 Regadd;
	u16 val,j;

	Regadd = src[2] * 256 + src[3];  //得到要修改的地址
	val = src[4] * 256 + src[5];     //修改后的值

	setVal2Regadd(Regadd, val);

	// 开始返回Modbus RTU数据
	Modbus_RTU_485_TX_Mode;
	vTaskDelay(5);
	for(j=0;j<len;j++)
	{
		Modbus_RTU_Send_Byte(src[j]);
	}
	vTaskDelay(5);
	Modbus_RTU_485_RX_Mode;

}

3.2Modbus RTU 03功能码处理

03功能码主要实现主机读取寄存器数据的回复。将本地的数据返回给主机。

cpp 复制代码
// Modbus RTU 3号功能码函数
// Modbus RTU 主机读取寄存器值
void Modbus_RTU_Func3(u8 *src, u16 len)
{
	u16 Regadd,Reglen,crc,tmp,buf[8];
	u8 i,j;
	//要读取寄存器的首地址
	Regadd = src[2] * 256 + src[3];
	//要读取寄存器的数据长度
	Reglen = src[4] * 256 + src[5];
	//发送回应数据包
	i = 0;
	sendbuf[i++] = MY_MODBUS RTU_ADDR;      //发送本设备地址
	sendbuf[i++] = 0x03;              //发送功能码
	//Modbus_RTU.sendbuf[i++] = ((Reglen*2)/256);   //返回字节个数
	sendbuf[i++] = ((Reglen*2)%256);   //返回字节个数
	tmp = getValFromRegadd(Regadd, Reglen, buf);
	if(tmp == 0)
	{
		printf("getValFromRegadd tmp = %d,error\r\n", tmp);
		return;
	}

	for(j = 0;j < tmp; j++)                    //返回数据
	{
		sendbuf[i++] = buf[j]/256;//Reg[Regadd+j]/256;
		sendbuf[i++] = buf[j]%256;//Reg[Regadd+j]%256;
	}
	crc = Modbus_RTU_CRC16(sendbuf,i);    //计算要返回数据的CRC
	sendbuf[i++] = crc%256;
	sendbuf[i++] = crc/256;
	// 开始返回Modbus_RTU数据
	Modbus_RTU_485_TX_Mode;
	vTaskDelay(5);
	for(j=0;j<i;j++)
	{
		Modbus_RTU_Send_Byte(sendbuf[j]);
	}
	vTaskDelay(5);
	Modbus_RTU_485_RX_Mode;

}

3.3Modbus RTU crc校验函数

针对Modbus RTU crc校验的函数如下,Modbus RTU可以选择的校验很多这里采用CRC16,有时候可能对不上对方校验码,这时可能要考虑更换校验算法。

cpp 复制代码
u16  Modbus_RTU_CRC16(u8 *data, u16 length)//简化CRC校验提升通信速度
{
	u16 j;
	u16 reg_crc = 0xffff;
	while(length--)
	{
		reg_crc ^= *data++;
		for(j = 0; j < 8; j++)
		{
			if(reg_crc & 0x0001)
				reg_crc = (reg_crc>>1) ^ 0xa001;
			else
				reg_crc = reg_crc>>1;
		}
	}
	return reg_crc;
}

4测试记录

使用电脑模拟485主机进程测试,电脑端运行,sscom5.13.1,打开对485进行电压转换,这里需要借助一根线,连接到电脑。比如USB转485。

这里还需要补充实测记录

这里举例说明,发送指令

01 03 00 01 00 08 15 CC

其中

01 //从机地址

03 //功能码

00 01 //读取地址01

00 08 //读取长度08

15 CC //校验

关于CRC计算可以使用如下网址的在线计算,也可以使用其他软件:

CRC在线计算

返回指令

01 03 10 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 E4 59

01 //地址

03 //功能码

10 //数据长度

00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 //数据字节

E4 59//校验

实际测试返回数据截图如下

5本文工程下载地址:

使用stm32cubeidestm32f103freeRTOS实现ModbusRTU协议寄存器读写过程详解,含说明文档、工程代码,测试记录,加速项目开发资源-CSDN下载

相关推荐
蓑衣客VS索尼克4 小时前
第二篇:按键交互入门:STM32 GPIO输入与消抖处理
stm32·单片机·嵌入式硬件
蓬荜生灰4 小时前
第5章—STM32工程创建
stm32·单片机·嵌入式硬件
hazy1k4 小时前
51单片机基础-定时器中断
stm32·单片机·嵌入式硬件·51单片机
可爱的鸡仔7 小时前
STM32--------DMA
stm32·单片机·嵌入式硬件
D.....l8 小时前
STM32学习(MCU控制)(GPIO)
stm32·嵌入式硬件·学习
GilgameshJSS17 小时前
STM32H743-ARM例程24-USB_MSC
c语言·arm开发·stm32·单片机·嵌入式硬件
showmethetime18 小时前
STM32实现LED舞台灯具控制
stm32·单片机·嵌入式硬件
python百炼成钢18 小时前
3.Linux 网络相关
linux·运维·网络·stm32·单片机
XiangrongZ19 小时前
江协科技STM32课程笔记(五)— ADC模数转换器
笔记·科技·stm32