STM32F103C8基于Modbus协议读取温湿度

一、任务

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

版权声明:本文为CSDN博主「醉意丶千层梦」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_47281915/article/details/122328414

生成海报
点赞 0

醉意丶千层梦

我还没有学会写个人说明!

暂无评论

发表评论

相关推荐