RT-Thread 应用笔记 - 不正确使用LOG也会引发hard fault
RT-Thread 应用笔记 - RTC Alarm 组件的使用
RT-Thread 应用笔记 - freemodbus RTU RS485 从机
RT-Thread 应用笔记 - freemodbus RTU RS485 主机
RT-Thread 应用笔记 - libmodbus RTU RS485 从机
RT-Thread 应用笔记 - libmodbus RTU RS485 主机
RT-Thread 应用笔记 - STM32 CAN 通信双机
背景
- modbus协议,简单,实用,一些小数据通信控制场合,用的比较多。
- 部分用户使用起来,并不是想象中那么的顺利。
- freemodbus,官方提供从机的程序,代码比较易懂,易于学习协议的实现。
- 基于rt-thread,已经有freemodbus的主从机软件包。
前言
- 嵌入式软件工程师,需要了解原理图,获取到引脚定义,如串口、RS485控制引脚、等等。
- 我的板子,MCU 为STM32F103C8T6, Flash与SRAM都相对不大。
- UART1用于rt-thread MSH串口。
- UART3用于RS485,用于modbus rtu串口。
原理图
- 估计有些工程师,原理图不用看的,直接调代码。
- 后来发现,原来用的是RS485,不是RS232,
- 用的是串口3不是串口2
- 原来RS485的方向控制引脚,低电平是输入,高电平是输出,平时默认输入
- RS485是半双工串行通讯。
- 这里,我使用UART3, PB10 PB11,方向控制引脚PA8,rt-thread引脚编号为8。
代码移植
测试的demo如下,目前实现裸机freemodbus与基于rt-thread freemodbus rtu 从机功能。
https://gitee.com/zhangsz0516/rtt_stm32_freemodbus
- 可以先移植RT-Thread到STM32F103C8T6上,使用源码包里的类似STM32F1系列的BSP,修改过来。
- 实现RT-Thead最小系统,串口使用uart1。
- UART3 引脚配置(不要以为rt-thread已经适配好了,板级驱动,没有的,不用问,自己实现就好)
修改 stm32f1xx_hal_msp.c 文件,修改HAL_UART_MspInit。
void HAL_UART_MspInit(UART_HandleTypeDef* huart) { GPIO_InitTypeDef GPIO_InitStruct = {0}; if(huart->Instance==USART1) { /* USER CODE BEGIN USART1_MspInit 0 */ /* USER CODE END USART1_MspInit 0 */ /* Peripheral clock enable */ __HAL_RCC_USART1_CLK_ENABLE(); __HAL_RCC_GPIOA_CLK_ENABLE(); /**USART1 GPIO Configuration PA9 ------> USART1_TX PA10 ------> USART1_RX */ GPIO_InitStruct.Pin = GPIO_PIN_9; GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); GPIO_InitStruct.Pin = GPIO_PIN_10; GPIO_InitStruct.Mode = GPIO_MODE_INPUT; GPIO_InitStruct.Pull = GPIO_NOPULL; HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); /* USER CODE BEGIN USART1_MspInit 1 */ /* USER CODE END USART1_MspInit 1 */ } else if (huart->Instance==USART3) { __HAL_RCC_USART3_CLK_ENABLE(); __HAL_RCC_GPIOB_CLK_ENABLE(); /**USART3 GPIO Configuration PB10 ------> USART3_TX PB11 ------> USART3_RX */ GPIO_InitStruct.Pin = GPIO_PIN_10; GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); GPIO_InitStruct.Pin = GPIO_PIN_11; GPIO_InitStruct.Mode = GPIO_MODE_INPUT; GPIO_InitStruct.Pull = GPIO_NOPULL; HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); } } void HAL_UART_MspDeInit(UART_HandleTypeDef* huart) { if(huart->Instance==USART1) { __HAL_RCC_USART1_CLK_DISABLE(); HAL_GPIO_DeInit(GPIOA, GPIO_PIN_9|GPIO_PIN_10); } else if(huart->Instance==USART3) { __HAL_RCC_USART3_CLK_DISABLE(); HAL_GPIO_DeInit(GPIOB, GPIO_PIN_10|GPIO_PIN_11); } }
修改board下的Kconfig,增加uart3
menuconfig BSP_USING_UART bool "Enable UART" default y select RT_USING_SERIAL if BSP_USING_UART config BSP_USING_UART1 bool "Enable UART1" default y config BSP_UART1_RX_USING_DMA bool "Enable UART1 RX DMA" depends on BSP_USING_UART1 && RT_SERIAL_USING_DMA default n config BSP_USING_UART2 bool "Enable UART2" default n config BSP_USING_UART3 /* 使能UART3 */ bool "Enable UART3" default y endif
- 获取freemodbus软件包,通过ENV : menuconfig
- 使用 rt-thread ENV工具:pkgs --update,下载freemodbus软件包。
$ pkgs --update
Cloning into 'E:\Gitee\other\rtt_stm32_freemodbus\master_rtu\packages\freemodbus-latest'...
remote: Enumerating objects: 9, done.
remote: Counting objects: 100% (9/9), done.
remote: Compressing objects: 100% (6/6), done.
remote: Total 83 (delta 3), reused 8 (delta 3), pack-reused 74
Receiving objects: 100% (83/83), 191.63 KiB | 191.00 KiB/s, done.
Resolving deltas: 100% (23/23), done.
==============================> FREEMODBUS latest is downloaded successfully.
==============================> freemodbus update done
Operation completed successfully.
- 代码编译运行,打开串口中端,输入 mb_slave_samlpe 命令,开启从机功能
- RS485主从机接线,【A+】-> 【A+】, 【B-】 -> 【B-】,主机与从机要共地【GND】。
- modbus调试工具,可以使用 Modbus Poll。
总结
- 如果RS485不通,连接失败,首先确认串口引脚配置与RS485引脚的配置。
- 从机地址的设置,默认是1,可以改。
- 通信波特率设置,可以改,115200或更高速率。
- 寄存器,根据实际情况添加,注意个数,在读写测试时,不要超出范围。
- 我遇到通信后,马上hardfault的问题!!最终确认是SRAM剩余空间太小引起,因此关闭了一些无用的占用内存较大的组件。
- 如果RT-Thread上跑不通,建议裸机跑下。
- 如果要熟练掌握modbus协议,还是要多应用。