STM32F407+Cubemx学习&应用[4]——DMA收发ModbusRS485数据——RS485温度传感器

STM32F407+Cubemx学习&应用[4]——DMA收发ModbusRS485数据——RS485温度传感器

  • 硬件
  • 串口参数
  • Cubemx配置工程
  • Keil中代码
  • 测试

本《STM32F407+Cubemx学习&应用系列》是自己在做工程时学习和琢磨的总结,还有诸多不足希望能够指出。本系列主要针对串口通信的一些应用,和TCP、CAN通信的一些简单应用。

本例程的目的:用RS485通过modus协议读取西星科技非接触式RS485红外线温度传感器测的温度,并用串口打印出来。

本例程的基础例程:https://blog.csdn.net/LW_12345/article/details/121453986《STM32F407+Cubemx学习&应用[2]——时间中断中处理任务(相当于多了个线程,能够处理多任务)》

参考:硬石例程《YSF4_HAL_Modbus_004. 基于Modbus主从机的温湿度数据获取》

硬件

硬石开发板:YS-F4Pro(用于工业控制~~~师兄选的哈)
西星科技非接触式RS485红外线温度传感器一个

串口参数

波特率:9600
数据位:8
校 验:noparity
停止位:1

Cubemx配置工程

时钟配置
STLink下载配置
USART1配置及串口打印
TIM6时间中断配置
USART3配置
STM32F407+Cubemx学习&应用[4]——DMA收发ModbusRS485数据——RS485温度传感器_第1张图片
STM32F407+Cubemx学习&应用[4]——DMA收发ModbusRS485数据——RS485温度传感器_第2张图片
STM32F407+Cubemx学习&应用[4]——DMA收发ModbusRS485数据——RS485温度传感器_第3张图片
STM32F407+Cubemx学习&应用[4]——DMA收发ModbusRS485数据——RS485温度传感器_第4张图片
注意:我这个版本的PB10和PB11的GPIO Pull-up/Pull-down选项不可选再代码中应该改为GPIO_NOPULL。
GPIO配置
STM32F407+Cubemx学习&应用[4]——DMA收发ModbusRS485数据——RS485温度传感器_第5张图片
用于RS485的收发数据控制。

其他配置默认

Keil中代码

增加了bsp_MB_host.h,bsp_MB_host.c两个文件,是关于modbus协议的相关文件。

main.c中添加

/* USER CODE BEGIN Includes */
#include "bsp_MB_host.h"
/* USER CODE END Includes */
/* USER CODE BEGIN 0 */
float humidity,temperature;
typedef struct
{
	uint16_t DATA_01H;
	uint16_t DATA_02H;
 	uint16_t DATA_03H;

	uint16_t DATA_04H;
	uint16_t DATA_05H;
	uint16_t DATA_06H;
	uint8_t DATA_10H[64];
}REG_DATA;

#define MSG_ERR_FLAG  0xFFFF    // 接收错误 字符间超时
#define MSG_IDLE      0x0000    // 空闲状态
#define MSG_RXING     0x0001    // 正在接收数据
#define MSG_COM       0x0002    // 接收完成
#define MSG_INC       0x8000    // 数据帧不完整(两字符间的空闲间隔大于1.5个字符时间)
#define TIME_OVERRUN  100       // 定义超时时间 ms
/* 私有变量 ------------------------------------------------------------------*/
__IO uint16_t Rx_MSG = MSG_IDLE;   // 接收报文状态
__IO uint8_t rx_flag=0;
__IO uint8_t data_length=0;
#define RX_BUFFSIZE                                  256
REG_DATA reg_value;
__IO uint8_t tmp_Rx_Buf;             // 临时接收缓存
__IO uint16_t RxCount = 0;      // 接收字符计数
#define MB_SLAVEADDR        0x0010 //从机地址 0x0001
#define HoldingReg          0x0000 //保持寄存器 0x0010
int test_count;
/* USER CODE END 0 */
  /* USER CODE BEGIN 2 */
	__HAL_UART_ENABLE_IT(&huart3,UART_IT_IDLE);
  HAL_UART_Receive_DMA(&huart3,(uint8_t *)Rx_Buf,RX_BUFFSIZE);
	
  Rx_MSG = MSG_IDLE;
	reg_value.DATA_03H=0x02;      //2个保持寄存器 0x02
  /* USER CODE END 2 */
   /* USER CODE BEGIN 3 */
	test_count++;
    if(test_count==6500000)
    {
	  test_count=0;
      Rx_MSG = MSG_IDLE;
      /* 读取线圈状态 */
      MB_ReadHoldingReg_03H(MB_SLAVEADDR, HoldingReg, reg_value.DATA_03H);
			rx_flag=1;
      /* 等待从机响应 */ 
    }
    /* 接收到一帧的数据,对缓存提取数据 */
    if(Rx_MSG == MSG_COM)
    {  			
      /* 收到非期望的从站反馈的数据 */
      if(Rx_Buf[0] != MB_SLAVEADDR)
      {
        Rx_MSG = MSG_IDLE;
        continue;
      }
			if(rx_flag==1)
			{
				humidity=(Rx_Buf[3]<<8|Rx_Buf[4]);
		 		printf("环境温度:%.1f %RH\n",humidity/100);
				temperature=(Rx_Buf[5]<<8|Rx_Buf[6]);
				printf("物体温度:%.1f ℃\n",temperature/100);
			}
      static uint16_t crc_check = 0;
      crc_check = ( (Rx_Buf[RxCount-1]<<8) | Rx_Buf[RxCount-2] );
      /* CRC 校验正确 */
      if(crc_check == MB_CRC16((uint8_t*)&Rx_Buf,RxCount-2)) 
      {
        /* 通信错误 */
        if(Rx_Buf[1]&0x80)
        {
			printf("通信错误\n");
        }
      }
      else
      printf("校验错误\n");
      Rx_MSG = MSG_IDLE;
    }
  }
  /* USER CODE END 3 */
/* USER CODE BEGIN 4 */
void USER_UART_IDLECallback(UART_HandleTypeDef *huart)
{
	if(huart->Instance ==USART3)
	{
		if(__HAL_UART_GET_FLAG(huart, UART_FLAG_IDLE) !=RESET)   
		{	 // 清除空闲中断标志(否则会一直不断进入中断)
			 __HAL_UART_CLEAR_IDLEFLAG(huart);                    
						// 调用中断处理函数
			if(Rx_MSG ==MSG_IDLE)
			{
				// 停止本次DMA传输
				HAL_UART_DMAStop(huart);                                                         
				// 计算接收到的数据长度
				data_length  = RX_BUFFSIZE - __HAL_DMA_GET_COUNTER(&hdma_usart3_rx);
				// 清零接收缓冲区 
				Rx_MSG =MSG_COM;		
				// 重启开始DMA传输 每次255字节数据            
			}
			HAL_UART_Receive_DMA(huart, (uint8_t *)Rx_Buf, RX_BUFFSIZE); 
		}
	}
}
void USER_DMATransmitCplt(DMA_HandleTypeDef *hdma)
{
	if(hdma->Instance ==DMA1_Stream3)
  {
	if(__HAL_DMA_GET_FLAG(hdma, DMA_FLAG_TCIF3_7) !=RESET)   
    {	 // 清除空闲中断标志(否则会一直不断进入中断)
        __HAL_DMA_CLEAR_FLAG(hdma,DMA_FLAG_TCIF3_7);   
		RS485_RX_MODE();
    }
  }
}
/* USER CODE END 4 */

stm32f4xx_it.c添加

/* USER CODE BEGIN EV */
void USER_UART_IDLECallback(UART_HandleTypeDef *huart);
void USER_DMATransmitCplt(DMA_HandleTypeDef *hdma);
/* USER CODE END EV */
  /* USER CODE BEGIN DMA1_Stream3_IRQn 0 */
	USER_DMATransmitCplt(&hdma_usart3_tx);
  /* USER CODE END DMA1_Stream3_IRQn 0 */
  /* USER CODE BEGIN USART3_IRQn 1 */
	USER_UART_IDLECallback(&huart3);  
  /* USER CODE END USART3_IRQn 1 */

usart.c中添加

/* USER CODE BEGIN 0 */
#include "gpio.h"
/* USER CODE END 0 */

注意对PB10,PB11的GPIO_InitStruct.Pull配置变换为:

    GPIO_InitStruct.Pull = GPIO_NOPULL;
void UART_Tx(uint8_t *Tx_Buf,uint16_t TxCount)
{
	RS485_TX_MODE();
	HAL_UART_Transmit_DMA(&huart3, Tx_Buf, TxCount);
}
/* USER CODE END 1 */

测试

STM32F407+Cubemx学习&应用[4]——DMA收发ModbusRS485数据——RS485温度传感器_第6张图片
RS485总线可以挂多个设备,如果波特率需要切换的请参考:https://blog.csdn.net/LW_12345/article/details/120638654?spm=1001.2014.3001.5502

源码下载:
https://gitee.com/Luweizhiyuan2020/stm32-f407_-cubemx.git
(cubemx_485_1.0)

你可能感兴趣的:(STM32,485,嵌入式,stm32,modbus,传感器)