当前位置: 首页 > news >正文

工业互联项目总结:UART

3.3 UART编程

UART有三种编程方式:

(1)查询方式:也是最基础的一种方式,通过TDR和RDR寄存器来发送和接收数据;

static void CH1_UART2_TxTaskFunction( void *pvParameters )	
{uint8_t c = 0;//每隔500ms发送while (1){HAL_UART_Transmit(&huart2, &c, 1, 100);vTaskDelay(500);c++;}
}
static void CH2_UART4_RxTaskFunction( void *pvParameters )	
{uint8_t c = 0;int cnt = 0;char buf[100];HAL_StatusTypeDef err;while (1){//每次接收一个字节并打印(此函数不常用)err = HAL_UART_Receive(&huart4, &c, 1, 100);if (!err){sprintf(buf, "Recv Data : 0x%02x, Cnt : %d", c, cnt++);Draw_String(0, 0, buf, 0x0000ff00, 0);}}
}

(2)中断方式:

uart.cpp文件//发送和接收完成标志
static volatile int g_uart2_tx_complete = 0;
static volatile int g_uart4_rx_complete = 0;//发送完成回调函数
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
{if (huart == &huart2){g_uart2_tx_complete = 1;}
}//等待发送完成
int Wait_UART2_Tx_Complete(int timeout)
{while (g_uart2_tx_complete == 0 && timeout){vTaskDelay(1);timeout--;}if (timeout == 0)return -1;else{//清空发送完成标志,用于下次发送g_uart2_tx_complete = 0;return 0;}
}//接收完成回调函数
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{if (huart == &huart4){g_uart4_rx_complete = 1;}	
}//等待接收完成
int Wait_UART4_Rx_Complete(int timeout)
{while (g_uart4_rx_complete == 0 && timeout){vTaskDelay(1);timeout--;}if (timeout == 0)return -1;else{//清空接收完成标志,用于下次接收g_uart4_rx_complete = 0;return 0;}
}
//app_freertos.c 文件static void CH1_UART2_TxTaskFunction( void *pvParameters )	
{uint8_t c = 0;while (1){//启动发送中断HAL_UART_Transmit_IT(&huart2, &c, 1);Wait_UART2_Tx_Complete(100);vTaskDelay(500);c++;}
}static void CH2_UART4_RxTaskFunction( void *pvParameters )	
{uint8_t c = 0;int cnt = 0;char buf[100];HAL_StatusTypeDef err;while (1){//启动接收中断err = HAL_UART_Receive_IT(&huart4, &c, 1);if (Wait_UART4_Rx_Complete(10) == 0)		{sprintf(buf, "Recv Data : 0x%02x, Cnt : %d", c, cnt++);Draw_String(0, 0, buf, 0x0000ff00, 0);}else{HAL_UART_AbortReceive_IT(&huart4);}}
}

(3)DMA方式(和中断方式的回调函数相同)

static void CH1_UART2_TxTaskFunction( void *pvParameters )	
{uint8_t c = 0;while (1){//改为DMA后缀HAL_UART_Transmit_DMA(&huart2, &c, 1);Wait_UART2_Tx_Complete(100);vTaskDelay(500);c++;}
}static void CH2_UART4_RxTaskFunction( void *pvParameters )	
{uint8_t c = 0;int cnt = 0;char buf[100];HAL_StatusTypeDef err;while (1){//改为DMA后缀err = HAL_UART_Receive_DMA(&huart4, &c, 1);if (Wait_UART4_Rx_Complete(10) == 0)		{sprintf(buf, "Recv Data : 0x%02x, Cnt : %d", c, cnt++);Draw_String(0, 0, buf, 0x0000ff00, 0);}else{//改动HAL_UART_DMAStop(&huart4);}}
}

3.8 在RTOS中使用DMA

//在接收指定字节数完成时触发
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{if (huart == &huart4){g_uart4_rx_complete = 1;/* write queue : g_uart4_rx_buf 100 bytes ==> queue */for (int i = 0; i < 100; i++){xQueueSendFromISR(g_xUART4_RX_Queue, (const void *)&g_uart4_rx_buf[i], NULL);}/* re-start DMA+IDLE rx */HAL_UARTEx_ReceiveToIdle_DMA(&huart4, g_uart4_rx_buf, 100);}	
}//在接收事件发生时触发(如 DMA 完成或空闲状态),接收不固定长度的数据
void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size)
{if (huart == &huart4){g_uart4_rx_complete = 1;/* write queue : g_uart4_rx_buf Size bytes ==> queue */for (int i = 0; i < Size; i++){xQueueSendFromISR(g_xUART4_RX_Queue, (const void *)&g_uart4_rx_buf[i], NULL);}/* re-start DMA+IDLE rx */HAL_UARTEx_ReceiveToIdle_DMA(&huart4, g_uart4_rx_buf, 100);}	
}void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart)
{if (huart == &huart4){/* re-start DMA+IDLE rx */HAL_UARTEx_ReceiveToIdle_DMA(&huart4, g_uart4_rx_buf, 100);}
}int UART4_GetData(uint8_t *pData)
{xQueueReceive(g_xUART4_RX_Queue, pData, portMAX_DELAY);return 0;
}void UART4_Rx_Start(void)
{g_xUART4_RX_Queue = xQueueCreate(200, 1);HAL_UARTEx_ReceiveToIdle_DMA(&huart4, g_uart4_rx_buf, 100);
}
static void CH1_UART2_TxTaskFunction( void *pvParameters )	
{uint8_t c = 0;while (1){/* send data */HAL_UART_Transmit_DMA(&huart2, &c, 1);Wait_UART2_Tx_Complete(100);vTaskDelay(500);c++;}
}static void CH2_UART4_RxTaskFunction( void *pvParameters )	
{uint8_t c = 0;int cnt = 0;char buf[100];HAL_StatusTypeDef err;UART4_Rx_Start();while (1){err = UART4_GetData(&c);if (err == 0)		{sprintf(buf, "Recv Data : 0x%02x, Cnt : %d", c, cnt++);Draw_String(0, 0, buf, 0x0000ff00, 0);}else{HAL_UART_DMAStop(&huart4);}}
}

3.9 面向对象封装UART

static SemaphoreHandle_t g_UART2_TX_Semaphore;
static uint8_t g_uart2_rx_buf[100];
static QueueHandle_t g_xUART2_RX_Queue;static SemaphoreHandle_t g_UART4_TX_Semaphore;
static uint8_t g_uart4_rx_buf[100];
static QueueHandle_t g_xUART4_RX_Queue;void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
{if (huart == &huart2){//使用信号量替换发送完成标志xSemaphoreGiveFromISR(g_UART2_TX_Semaphore, NULL);}if (huart == &huart4){xSemaphoreGiveFromISR(g_UART4_TX_Semaphore, NULL);}
}void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{if (huart == &huart2){/* write queue : g_uart4_rx_buf 100 bytes ==> queue */for (int i = 0; i < 100; i++){xQueueSendFromISR(g_xUART2_RX_Queue, (const void *)&g_uart2_rx_buf[i], NULL);}/* re-start DMA+IDLE rx */HAL_UARTEx_ReceiveToIdle_DMA(&huart2, g_uart2_rx_buf, 100);}	if (huart == &huart4){/* write queue : g_uart4_rx_buf 100 bytes ==> queue */for (int i = 0; i < 100; i++){xQueueSendFromISR(g_xUART4_RX_Queue, (const void *)&g_uart4_rx_buf[i], NULL);}/* re-start DMA+IDLE rx */HAL_UARTEx_ReceiveToIdle_DMA(&huart4, g_uart4_rx_buf, 100);}	
}void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size)
{if (huart == &huart2){/* write queue : g_uart4_rx_buf Size bytes ==> queue *///将实际接收到的字节数据放入队列,而不是100字节for (int i = 0; i < Size; i++){xQueueSendFromISR(g_xUART2_RX_Queue, (const void *)&g_uart2_rx_buf[i], NULL);}/* re-start DMA+IDLE rx */HAL_UARTEx_ReceiveToIdle_DMA(&huart2, g_uart2_rx_buf, 100);}if (huart == &huart4){/* write queue : g_uart4_rx_buf Size bytes ==> queue */for (int i = 0; i < Size; i++){xQueueSendFromISR(g_xUART4_RX_Queue, (const void *)&g_uart4_rx_buf[i], NULL);}/* re-start DMA+IDLE rx */HAL_UARTEx_ReceiveToIdle_DMA(&huart4, g_uart4_rx_buf, 100);}	
}void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart)
{if (huart == &huart2){/* re-start DMA+IDLE rx */HAL_UARTEx_ReceiveToIdle_DMA(&huart2, g_uart2_rx_buf, 100);}	if (huart == &huart4){/* re-start DMA+IDLE rx */HAL_UARTEx_ReceiveToIdle_DMA(&huart4, g_uart4_rx_buf, 100);}
}/* uart2 */
//从队列取数据
int UART2_GetData(struct UART_Device *pdev, uint8_t *pData, int timeout)
{//从队列获取一个字节的数据if (pdPASS == xQueueReceive(g_xUART2_RX_Queue, pData, timeout))return 0;elsereturn -1;
}int UART2_Rx_Start(struct UART_Device *pDev, int baud, char parity, int data_bit, int stop_bit)
{if (!g_xUART2_RX_Queue){g_xUART2_RX_Queue = xQueueCreate(200, 1); // 200个元素,每个元素为一个字节大小g_UART2_TX_Semaphore = xSemaphoreCreateBinary( ); //创建二值信号量/*deepseek:在使用HAL_UARTEx_ReceiveToIdle_DMA时,当发生空闲中断时,会调用HAL_UARTEx_RxEventCallback,而如果接收满100字节,会先调用HAL_UART_RxCpltCallback,然后调用HAL_UARTEx_RxEventCallback(Size=100)。因此,这里存在重复处理的风险:当收到100字节时,两个回调都会被调用,导致数据被重复放入队列两次(一次100字节,一次又100字节)。这显然是不正确的。*/HAL_UARTEx_ReceiveToIdle_DMA(&huart2, g_uart2_rx_buf, 100);  //启动DMA+空闲中断接收,每次最多接收100个字节}return 0;
}int UART2_Send(struct UART_Device *pDev, uint8_t *datas, uint32_t len, int timeout)
{HAL_UART_Transmit_DMA(&huart2, datas, len);  /* 等待发生完成信号量(为何不用mutex? 因为在中断里Give mutex会出锿) */if (pdTRUE == xSemaphoreTake(g_UART2_TX_Semaphore, timeout))return 0;elsereturn -1;
}/**/int UART4_GetData(struct UART_Device *pDev, uint8_t *pData, int timeout)
{if (pdPASS == xQueueReceive(g_xUART4_RX_Queue, pData, timeout))return 0;elsereturn -1;
}int UART4_Rx_Start(struct UART_Device *pDev, int baud, char parity, int data_bit, int stop_bit)
{if (!g_xUART4_RX_Queue){g_xUART4_RX_Queue = xQueueCreate(200, 1);g_UART4_TX_Semaphore = xSemaphoreCreateBinary();HAL_UARTEx_ReceiveToIdle_DMA(&huart4, g_uart4_rx_buf, 100);}return 0;
}int UART4_Send(struct UART_Device *pDev, uint8_t *datas, uint32_t len, int timeout)
{HAL_UART_Transmit_DMA(&huart4, datas, len);/* 等待丿个信号量(为何不用mutex? 因为在中断里Give mutex会出锿) */if (pdTRUE == xSemaphoreTake(g_UART4_TX_Semaphore, timeout))return 0;elsereturn -1;
}struct UART_Device g_uart2_dev = {"uart2", UART2_Rx_Start, UART2_Send, UART2_GetData};
struct UART_Device g_uart4_dev = {"uart4", UART4_Rx_Start, UART4_Send, UART4_GetData};
//uart_device.h文件#include <stdio.h>
#include <string.h>
#include "uart_device.h"extern struct UART_Device g_uart2_dev;
extern struct UART_Device g_uart4_dev;static struct UART_Device *g_uart_devices[] = {&g_uart2_dev, &g_uart4_dev};struct UART_Device *GetUARTDevice(char *name)
{int i = 0;for (i = 0; i < sizeof(g_uart_devices)/sizeof(g_uart_devices[0]); i++){if (!strcmp(name, g_uart_devices[i]->name))return g_uart_devices[i];}return NULL;
}
struct UART_Device {char *name;int (*Init)( struct UART_Device *pDev, int baud, char parity, int data_bit, int stop_bit);int (*Send)( struct UART_Device *pDev, uint8_t *datas, uint32_t len, int timeout);int (*RecvByte)( struct UART_Device *pDev, uint8_t *data, int timeout);
};struct UART_Device *GetUARTDevice(char *name);
static void CH1_UART2_TxTaskFunction( void *pvParameters )	
{uint8_t c = 0;struct UART_Device *pdev = GetUARTDevice("uart2");pdev->Init(pdev, 115200, 'N', 8, 1);while (1){/* send data */pdev->Send(pdev, &c, 1, 100);vTaskDelay(500);c++;}
}static void CH2_UART4_RxTaskFunction( void *pvParameters )	
{uint8_t c = 0;int cnt = 0;char buf[100];int err;struct UART_Device *pdev = GetUARTDevice("uart4");pdev->Init(pdev, 115200, 'N', 8, 1);while (1){/* 接收数据 */err = pdev->RecvByte(pdev, &c, 200);if (err == 0)		{sprintf(buf, "Recv Data : 0x%02x, Cnt : %d", c, cnt++);Draw_String(0, 0, buf, 0x0000ff00, 0);}else{//HAL_UART_DMAStop(&huart4);}}
}

http://www.dtcms.com/a/360438.html

相关文章:

  • Backroom:信息代币化 AI 时代数据冗杂的解决方案
  • 漏洞基础与文件包含漏洞原理级分析
  • 使用 Python mlxtend库进行购物篮分析、关联规则
  • 软考中级习题与解答——第一章_数据结构与算法基础(3)
  • 进程状态 —— Linux内核(Kernel)
  • Linux 文件夹权限也会导致基本命令权限缺失问题
  • 【学Python自动化】 5. Python 数据结构学习笔记
  • postman带Token测试接口
  • 打工人日报#20250831
  • LangChain核心抽象:Runnable接口深度解析
  • * 和**有时展开,有时收集。*在对可迭代对象展开 **对字典展开。一般只看收集就够了,在函数定义的时候传入参数用
  • 第二十七天-ADC模数转换实验
  • linux系统学习(12.linux服务)
  • 【星闪】Hi2821 | SPI串行外设接口 + OLED显示屏驱动例程
  • 语音芯片3W输出唯创知音WTN6040FP、WT588F02BP-14S、WT588F04AP-14S
  • [回溯+堆优化]37. 解数独
  • Q1 Top IF 18.7 | 基于泛基因组揭示植物NLR进化
  • 高校心理教育辅导系统的设计与实现|基于SpringBoot高校心理教育辅导系统的设计与实现
  • 网格图--Day02--网格图DFS--面试题 16.19. 水域大小,LCS 03. 主题空间,463. 岛屿的周长
  • 技术总体方案设计思路
  • SAP报工与收货的区别(来自deepseek)
  • c++ 二维码、条形码开发实例
  • FFMPEG学习任务
  • 为什么计算机使用补码存储整数:补码的本质
  • 自定义AXI_PWM_v1.0——ZYNQ学习笔记15
  • Ultra Low Power Transceiver for Wireless Body Area Networks中文版
  • Makefile语句解析:头文件目录自动发现与包含标志生成
  • Day 01(01): Hadoop与大数据基石
  • RPC个人笔记(包含动态代理)
  • Qwen2.5-VL代码初步解读