一、任务
stm32f103通过串口二向485总线轮询发送问答帧
访问所有modbus温湿度传感器模块,并且把得到的应答帧
进行解析,得到对应的温湿度的值,再通过串口一发送至PC端。
二、代码
1.通过CubeMX配置stm32
配置RCC
配置时钟
配置串口二波特率4800
配置串口二DMA
配置串口一
配置中断
2.主要代码
重定向输出串口一
usart.c
#include <stdio.h>
int fputc(int ch,FILE *f)
{
HAL_UART_Transmit(&huart1,(uint8_t *)&ch,1,0xFFFF);
//等待发送结束
while(__HAL_UART_GET_FLAG(&huart1,UART_FLAG_TC)!=SET){
}
return ch;
}
添加中断处理
stm32f1xx_it.c的串口2中断处理函数
void USART2_IRQHandler(void)
{
/* USER CODE BEGIN USART2_IRQn 0 */
uint32_t tmp = 0;
tmp =__HAL_UART_GET_FLAG(&huart2,UART_FLAG_IDLE); //获取IDLE标志位
if((tmp != RESET))//idle标志被置位
{
//清除标志位
//__HAL_UART_CLEAR_IDLEFLAG(&huart2);
//清除状态寄存器SR,读取SR寄存器可以实现清除SR寄存器的功能
huart2.Instance->SR;
//读取数据寄存器中的数据
huart2.Instance->DR;
HAL_UART_DMAStop(&huart2); //
// 获取DMA中未传输的数据个数
dataLength=hdma_usart2_rx.Instance->CNDTR;
// 接受完成
isDataEnd = 1;
//清除标志位
__HAL_UART_CLEAR_IDLEFLAG(&huart2);
}
/* USER CODE END USART2_IRQn 0 */
HAL_UART_IRQHandler(&huart2);
/* USER CODE BEGIN USART2_IRQn 1 */
/* USER CODE END USART2_IRQn 1 */
}
main.c
添加变量
extern DMA_HandleTypeDef hdma_usart2_rx;
//modbus问询帧
uint8_t commands[3][8]={
{0x01,0x03,0x00,0x00,0x00,0x02,0xC4,0x38},
{0x02,0x03,0x00,0x00,0x00,0x02,0xC4,0x38},
{0x03,0x03,0x00,0x00,0x00,0x02,0xC5,0xE9},
};
//modbus应答帧
uint8_t dataBuff[20];
//中断完成标志
uint8_t isDataEnd=0;
//应答帧长度
uint8_t dataLength;
//温度
uint16_t temperature;
//湿度
uint16_t humidity;
main函数
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_USART1_UART_Init();
MX_DMA_Init();
MX_USART2_UART_Init();
/* USER CODE BEGIN 2 */
//使能idle中断
__HAL_UART_ENABLE_IT(&huart2, UART_IT_IDLE);
//打开串口DMA接收
HAL_UART_Receive_DMA(&huart2,dataBuff,sizeof(dataBuff));
//传感器地址
uint8_t i=0;
while (1)
{
//中断完成,解析应答帧
if(isDataEnd){
//提取湿度
humidity=(dataBuff[3] << 8) + (dataBuff[4]);
//提取温度
temperature=(dataBuff[5] << 8) + (dataBuff[6]);
//串口一发送解析结果
printf("温度: %.1f\t 湿度: %.1f\r\n",temperature/10.0,humidity/10.0);
memset(dataBuff,0,sizeof(dataBuff));//清空接收数组
isDataEnd=0;//清除接收结束标志位
}
//发送第 i 个传感器的 modbus 问询帧
HAL_UART_Transmit(&huart2,commands[i],sizeof(commands),0xFFFF);
//轮询读取三个传感器
i=(i+1)%3;
//打开串口DMA接收
HAL_UART_Receive_DMA(&huart2,dataBuff,sizeof(dataBuff));
//程序运行标志,闪灯
HAL_Delay(1000);
HAL_GPIO_TogglePin(GPIOC,GPIO_PIN_13);
}
三、效果
四、总结
这里只是简单的采用了静态指令进行访问数据,没有使用CRC校验。当采用动态指令的时候需要对编号进行自增以及对数据进行CRC校验,并且还需要对各种错误进行解析以及判断。
五、源代码
https://github.com/TangtangSix/Modbus_RTU
https://gitee.com/tangtangsix/Modbus_RTU