【STM32F407VGT6】HAL库Rs485通信
实现了1.RS485发送定长数据,2.接收定长数据并回传,3.使用空闲中断+DMA发送不定长数据,4.发送语句控制小灯亮灭
·
一.RS485信号传输方式
采用两根差分信号线:通常称为A 线(非倒相端) 和B 线(倒相端),信号通过两线之间的电压差传递。
当 B 线电压 - A 线电压 > +200mV 时,定义为逻辑 1;
当 B 线电压 - A 线电压 < -200mV 时,定义为逻辑 0;
差分传输可以使通信更稳定。
电压差在 ±200mV 之间时,信号无效(判断电平是否有误)。
半双工通信,收发不能同时进行。有方向控制端(RE/DE)控制芯片工作模式。


二.CUBEMX



三.代码
(1)发送“hello”
(这里拼写错误hellow,不过不影响)
uint8_t t[50]= {"hello"};
/* USER CODE BEGIN 3 */
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_7, GPIO_PIN_SET);
HAL_UART_Transmit(&huart2, t,strlen((char*)t), 1000);
HAL_Delay(500);
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_7, GPIO_PIN_RESET);
HAL_Delay(1000);
}
/* USER CODE END 3 */

结果
示波器解码(A&B)




问题:示波器在有数据传输,但是串口调试助手没有显示传输数据。检查差分电压也在标准范围内。
解决:
换一个485线。

(2)中断回调函数返回接收数据
1.每1000ms定时发送0x11并且翻转小灯PE13
2.窗口发送数字,进入中断回调函数并翻转小灯PE14
3.若发送的数字为0x22则返回0x01,否则返回该发送值

/* USER CODE BEGIN PV */
uint8_t R;
uint8_t T;
/* USER CODE END PV */
/* USER CODE BEGIN 2 */
HAL_UART_Receive_IT(&huart2, (uint8_t *)&R, 1);
/* USER CODE END 2 */
/* USER CODE BEGIN 3 */
HAL_GPIO_TogglePin(GPIOE, GPIO_PIN_13);
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_7, GPIO_PIN_SET);
T = 0x11;
HAL_UART_Transmit(&huart2, (uint8_t *)&T, 1, 0xFF);
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_7, GPIO_PIN_RESET);
HAL_Delay(1000);
}
/* USER CODE END 3 */
/* USER CODE BEGIN 4 */
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
HAL_GPIO_TogglePin(GPIOE, GPIO_PIN_14);
if (0x22 == R)
{
T = 0x1;
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_7, GPIO_PIN_SET);
HAL_UART_Transmit(&huart2, (uint8_t *)&T, 1, 0xFF);
}
else
{
T = R;
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_7, GPIO_PIN_SET);
HAL_UART_Transmit(&huart2, (uint8_t *)&T, 1, 0xFF);
}
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_7, GPIO_PIN_RESET);
HAL_UART_Receive_IT(&huart2, (uint8_t *)&R, 1);
}
/* USER CODE END 4 */
结果

(3)传输不定长数据(DMA+空闲中断)
/* USER CODE BEGIN Includes */
#include "string.h"
/* USER CODE END Includes */
宏定义Rs485方向控制引脚(PD7)
RS485_TX_MODE:发送模式
RS485_RX_MODE:接收模式
/* USER CODE BEGIN PD */
#define RS485_DIR_PORT GPIOD
#define RS485_DIR_PIN GPIO_PIN_7
#define RS485_TX_MODE HAL_GPIO_WritePin(RS485_DIR_PORT, RS485_DIR_PIN, GPIO_PIN_SET)
#define RS485_RX_MODE HAL_GPIO_WritePin(RS485_DIR_PORT, RS485_DIR_PIN, GPIO_PIN_RESET)
/* USER CODE END PD */
/* USER CODE BEGIN PV */
uint8_t rxbuff[100];
uint16_t rx_len = 0; // 定义接收长度变量
/* USER CODE END PV */
/* USER CODE BEGIN 2 */
RS485_RX_MODE; // 初始化为接收模式
__HAL_UART_ENABLE_IT(&huart2, UART_IT_IDLE); //使能空闲中断
HAL_UARTEx_ReceiveToIdle_DMA(&huart2, rxbuff, 100);//启动DMA空闲接收
/* USER CODE END 2 */
/* USER CODE BEGIN 4 */
void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size)
{
if(huart->Instance == USART2)
{
rx_len = Size; // 获取接收长度
HAL_GPIO_TogglePin(GPIOE, GPIO_PIN_13); //翻转小灯观察是否进入中断
RS485_TX_MODE; //切换发送模式
HAL_UART_Transmit(&huart2, rxbuff, rx_len, 100);//回传数据
while(HAL_UART_GetState(&huart2) == HAL_UART_STATE_BUSY_TX);//等待发送完成
RS485_RX_MODE; //切换接收模式
memset(rxbuff, 0, rx_len); //清空缓冲区
HAL_UARTEx_ReceiveToIdle_DMA(&huart2, rxbuff, 100);//重新启动DMA空闲接收
}
}
/* USER CODE END 4 */
结果

(4)语句控制小灯+回传不定长数据
发送“LED ON”小灯PE13打开并发送“ok!”,发送“LED OFF”小灯PE14关闭并发送“ok!”。发送其他则按照原样回传。

只改动了中断回调函数部分。
/* USER CODE BEGIN 4 */
uint8_t a[3]={"ok!"};
void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size)
{
if(huart->Instance == USART2)
{
rx_len = Size; // 获取接收长度
if(strstr((const char*)rxbuff,"LED ON")!=NULL)
{
HAL_GPIO_WritePin(GPIOE,GPIO_PIN_13,GPIO_PIN_RESET);
RS485_TX_MODE;
HAL_UART_Transmit(&huart2, a, 3, 100);
}
else
{
if(strstr((const char*)rxbuff,"LED OFF")!=NULL)
{
HAL_GPIO_WritePin(GPIOE,GPIO_PIN_13,GPIO_PIN_SET);
RS485_TX_MODE;
HAL_UART_Transmit(&huart2, a, 3, 100);
}
else
{
RS485_TX_MODE;
HAL_UART_Transmit(&huart2, rxbuff, rx_len, 100);
}
}
RS485_RX_MODE;
memset(rxbuff, 0, rx_len);
HAL_UARTEx_ReceiveToIdle_DMA(&huart2, rxbuff, 100);
}
}
/* USER CODE END 4 */
结果

更多推荐



所有评论(0)