UART基本定义、三种编程方式、freertos内怎么用、怎么封装

UART基本定义、三种编程方式、freertos内怎么用、怎么封装

码农世界 2024-06-18 后端 87 次浏览 0个评论

文章目录

    • 串口基本概念
    • 串口的三种编程方式
      • uart编程
        • 查询方式不常用、其他两个方式用的多
        • 中断方式:
          • 代码
          • 原理
          • DMA方式:
            • 配置DMA
            • 原理
            • 代码
            • 效率最高的UART编程方式:
              • 是什么?
              • 操作
              • 在freertos里面调用uart
                  • 应该怎么做?
                  • 代码
                  • 面向对象封装UART
                    • 串口的DMA设置:
                    • 编写代码:
                      • 信号量:启动DAM、等待信号量、释放信号量(在回调函数)
                      • 怎么封装函数
                      • 编写遇到的问题
                      • 寄存器
                        • 串口通讯不许连续发送,串口为什么一次只发一个字节?
                        • 波特率、比特率
                        • 通讯协议
                        • FIFO

                          串口基本概念

                          全双工

                          低位先行

                          TXD发、RXD接

                          起始位 | 数据位 | 校验位 | 停止位

                          0 8-9位 奇/偶校验 1

                          通讯前的约定(协议)用串口时双方要协定好没传输一个数据需要多少秒(约定好波特率)

                          奇偶校验位

                          数据位+校验位个数位奇数个,则正确

                          波特率bps,每一秒传输数据的位数

                          串口的三种编程方式

                          注意:中断方式和DMA方式

                          第一个Transmit都是使能中断,然后在中断中完成传输,在中断的最后有一个回调函数callback,callback为_weak函数,用户可以自己去写具体要求

                          1、查询方式

                          收/发数据时需要不停查看相应寄存器是否为空

                          2、中断方式

                          Transmit_IT使能中断

                          callback会给反馈,但也是会经常打断cpu

                          image.png

                          3、DMA

                          使用中断方式时,在传输、接收数据时,会发生中断,还需要 CPU 执行中断处理函数。有另外一种方法: DMA(Direct Memory Access),它可以直接在 2 个设备之间传递数据,无需 CPU 参与

                          DMA就是跑腿的

                          image.png

                          uart编程

                          查询方式不常用、其他两个方式用的多

                          三种方式,只实现串口2发送、串口4接收;

                          串口2接收、4发送省去;

                          中断方式:

                          收到一个字符就会产生一个中断,就会去中断cpu;DMA是接收完所有字符才产生一次中断

                          具体实现:

                          首先要使能中断

                          image.png

                          代码
                          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;//数据发送完后就会置成1,wait看到1则置为0表示完成、如果一直是0直到超时则返回-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;//数据发送完后就会置成1,wait看到1则置为0表示完成、如果一直是0直到超时则返回-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;
                          	}
                          }
                          
                          extern UART_HandleTypeDef huart4;
                          extern UART_HandleTypeDef huart2;
                          //发送
                          int Wait_UART2_Tx_Complete(int timeout);
                          //接收
                          int Wait_UART4_Rx_Complete(int timeout);
                          /* USER CODE END Variables */
                          /* Definitions for defaultTask */
                          osThreadId_t defaultTaskHandle;
                          const osThreadAttr_t defaultTask_attributes = {
                            .name = "defaultTask",
                            .priority = (osPriority_t) osPriorityNormal,
                            .stack_size = 128 * 4
                          };
                          /* Private function prototypes -----------------------------------------------*/
                          /* USER CODE BEGIN FunctionPrototypes */
                          //任务函数
                          static void SPILCDTaskFunction( void *pvParameters )
                          {
                          	char bur[100];
                          	int cnt = 0;
                          	
                          	while(1)
                          	{
                          		sprintf(bur, "lcd task test:%d" ,cnt++);
                          		//Draw_String(0, 0 , bur, 0x0000ff00, 0);
                          		vTaskDelay(1000);
                          	}
                          	
                          }
                          static void CH1_URAT2_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_URAT4_RxTaskFunction( void *pvParameters )
                          {
                          	
                          	uint8_t c = 0;
                          	char bur[100];
                          	int cnt = 0;
                          	HAL_StatusTypeDef err;
                          	while(1)
                          	{
                          		//接收数据
                          		err = HAL_UART_Receive_IT(&huart4, &c, 1);//串口、内容地坿、长度㿁超旿
                          		
                          		if(Wait_UART4_Rx_Complete(10) == 0)//=0表示接收完成
                          		{
                          			sprintf(bur,"receive dataset : 0x:%02x, numember:%d",c, cnt++);
                          			Draw_String(0, 0, bur, 0x0000ff00, 0);
                          		}
                          		else
                          		{
                          			HAL_UART_AbortReceive_IT(&huart4);//超时或者出错则调用终止中断接收的函数
                          		}
                          		
                          	}
                          		
                          }
                          
                          原理

                          image.png

                          image.png

                          DMA方式:

                          在dma传输过程中不产生中断,传输完指定数量的数据后产生中断;

                          dma只会去中断cpu一次;

                          优点:DMA优势就在于可以接收很多数据;

                          image.png

                          源 | 目的 | 长度

                          发送:内存的源地址++、TDR

                          接收:RDR 、目的地址++

                          image.png

                          配置DMA

                          image.png

                          原理

                          image.png

                          image.png

                          代码

                          就只是把中断的代码的这些换了

                          image.png

                          效率最高的UART编程方式:
                          是什么?

                          正常的三种编程方式1启动2等待完成,一般是等到如下图设置的1000个字节都收到后停止,但是其他比如完整的数据收到了没到1000字节,以及长时间未响应、产生error就要用到IDLE中断;

                          等待完成如果已经收到完整的数据但是没有达到如下如1000个字节,那么就要靠IDLE中断来告知收到完整数据了。

                          UART基本定义、三种编程方式、freertos内怎么用、怎么封装

                          问题:中断和DMA每次都要手工使能中断/启动DMA,如果代码里面有其他长时间的任务没结束,第二次就要等这个任务结束后才启动下一次;

                          方法:一开始就启动DMA

                          使用DAM+IDLE中断:

                          其他方式都可以用IDLE但是DMA是最好的,中断方式没有必要用这个,因为他要及时的获取数字每读到一个字节、就产生一次中断,去中断一次cpu

                          image.png

                          空闲而停止mcu检测到长的停止时间,就会产生IDLE中断

                          image.png

                          操作

                          1、一开始就使能IDLE的这个函数

                          image.png

                          2、实现回调函数

                          image.png

                          回调函数创建队列都是在中断函数中实现的,回调函数就是在中断函数中调用的

                          中断里面写队列要有一个后缀FromISR

                          在freertos里面调用uart

                          image.png

                          多了freertos队列

                          应该怎么做?

                          image.png

                          代码
                          static volatile int g_uart2_tx_complete = 0;//用来判断是否完成
                          static volatile int g_uart4_rx_complete = 0;
                          static uint8_t g_uart4_rx_buf[100];//定义一个buff来存接收到的数据
                          static QueueHandle_t g_xUART4_RX_Queue;//创建队列
                          void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
                          {
                          	//数据返鿁完毕,中断函数会调用这个回调函敿
                          	if(huart == &huart2)
                          	{
                          		g_uart2_tx_complete = 1;//数据发鿁完后就会置房1,wait看到1则置丿0表示完成、如果一直是0直到超时则返囿-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;//数据发鿁完后就会置房1,wait看到1则置丿0表示完成、如果一直是0直到超时则返囿-1表示失败
                          		
                          		//收到数据后把收到的数据存入buff,写队列
                          		for(int i = 0 ; i < 100; i++)
                          		{
                          			xQueueSendFromISR(g_xUART4_RX_Queue,&g_uart4_rx_buf[i], NULL);
                          		}
                          		
                          		//重新启动DMA+IDLE
                          		HAL_UARTEx_ReceiveToIdle_DMA(&huart4, g_uart4_rx_buf, 100);
                          	}
                          }
                          //void event,接收空闲,表示数据已经接收完成,但是还没到DMA接收设置的值
                          void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size)
                          {
                          	if(huart == &huart4)
                          	{
                          		g_uart4_rx_complete = 1;
                          		//写队列
                          		for(int i = 0 ; i < Size; i++)
                          		{
                          			xQueueSendFromISR(g_xUART4_RX_Queue,&g_uart4_rx_buf[i], NULL);
                          		}
                          		
                          		//重新启动DMA+IDLE
                          		HAL_UARTEx_ReceiveToIdle_DMA(&huart4, g_uart4_rx_buf, 100);
                          		
                          	}
                          		
                          }
                          //void error:重新启动DMA+IDLE
                          void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart)
                          {
                          	//重启DMA+IDLE
                          	HAL_UARTEx_ReceiveToIdle_DMA(&huart4, g_uart4_rx_buf, 100);
                          }
                          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从队列中读数据不从串口读数据了
                          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);
                          		//收到的数据保存在哪里,要定义一个buff;收到后回调函数就会被调用
                          }
                          
                          extern UART_HandleTypeDef huart4;
                          extern UART_HandleTypeDef huart2;
                          void UART4_RX_Start(void);
                          int UART4_GetData(uint8_t *pData);
                          //发鿿
                          int Wait_UART2_Tx_Complete(int timeout);
                          //接收
                          int Wait_UART4_Rx_Complete(int timeout);
                          /* USER CODE END Variables */
                          /* Definitions for defaultTask */
                          osThreadId_t defaultTaskHandle;
                          const osThreadAttr_t defaultTask_attributes = {
                            .name = "defaultTask",
                            .priority = (osPriority_t) osPriorityNormal,
                            .stack_size = 128 * 4
                          };
                          /* Private function prototypes -----------------------------------------------*/
                          /* USER CODE BEGIN FunctionPrototypes */
                          //任务函数
                          static void SPILCDTaskFunction( void *pvParameters )
                          {
                          	char bur[100];
                          	int cnt = 0;
                          	
                          	while(1)
                          	{
                          		sprintf(bur, "lcd task test:%d" ,cnt++);
                          		//Draw_String(0, 0 , bur, 0x0000ff00, 0);
                          		vTaskDelay(1000);
                          	}
                          	
                          }
                          static void CH1_URAT2_TxTaskFunction( void *pvParameters )
                          {
                          	uint8_t c = 0;
                          	while(1)
                          	{
                          		//发数捿
                          		HAL_UART_Transmit_DMA(&huart2, &c, 1);
                          		Wait_UART2_Tx_Complete(100);//等待发鿁完房
                          		vTaskDelay(500);
                          		c++;
                          	}
                          }
                          	
                          static void CH2_URAT4_RxTaskFunction( void *pvParameters )
                          {
                          	
                          	uint8_t c = 0;
                          	char bur[100];
                          	int cnt = 0;
                          	HAL_StatusTypeDef err;
                          	while(1)
                          	{
                          		//一开头就调用这个函数来调用到IDLE
                          		UART4_RX_Start();
                          		
                          		err = UART4_GetData(&c);//读到的数据保存在c
                          		if(err == 0)//=0表示接收完成
                          		{
                          			sprintf(bur,"receive dataset : 0x:%02x, numember:%d",c, cnt++);
                          			Draw_String(0, 0, bur, 0x0000ff00, 0);
                          		}
                          		else
                          		{
                          			HAL_UART_DMAStop(&huart4);//超时或迅出错则调用终止中断接收的函敿
                          		}
                          		
                          	}
                          		
                          }
                          

                          200个数据,每个数据一个字节

                          image.png

                          面向对象封装UART

                          构造处结构体,包含uart里面的初始话函数、构造函数等等;

                          串口的DMA设置:

                          前面只设置了uart2发送和uart4接收;

                          现在设置uart4接收和uart2发送;

                          源地址叠加和目的地址是否叠加在前面写了;

                          发送一定是内存到外设,接收则相反

                          image.pngimage.png

                          编写代码:

                          uart接收复制uart4接收,等待、获取数据、启动函数(等待接收函数不需要了删除即可,直接等待队列完成);

                          callback直接在callback里面复制;

                          getData设置超时时间;

                          等待函数去掉,等待队列就行了,换成freertos的信号量:

                          中断里面不能give互斥量mutex,啥是互斥量?信号量和互斥量

                          优先级的恢复工作不太好做

                          信号量:启动DAM、等待信号量、释放信号量(在回调函数)

                          image.png

                          过程原理

                          二进制信号量先定义出来->调用创建信号量函数

                          send函数发送出去,然后等待中断里面的callback回调函数give,计数值变成1

                          send函数take拿走这个1;

                          image.png

                          怎么封装的?

                          声明和定义结构体

                          image.png

                          把uart里面的这些函数封装起来

                          image.png

                          怎么封装函数

                          把这几个函数放入结构体中

                          image.png

                          这个结构体的成员函数如下,这样就能直接定义出这个结构体,用->来初始化、发数据、收数据

                          image.png

                          image.png

                          代码

                          #include "uart_device.h"
                          #include 
                          #include 
                          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 * GetUARDevice(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;
                          }
                          
                          #ifndef __UART_DEVICE_H
                          #define __UART_DEVICE_H
                          #include 
                          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 *GetUARDevice(char *name);
                          #endif /* __UART_DEVICE_H */
                          
                          //任务函数
                          static void SPILCDTaskFunction( void *pvParameters )
                          {
                          	char bur[100];
                          	int cnt = 0;
                          	
                          	while(1)
                          	{
                          		sprintf(bur, "lcd task test:%d" ,cnt++);
                          		//Draw_String(0, 0 , bur, 0x0000ff00, 0);
                          		vTaskDelay(1000);
                          	}
                          	
                          }
                          static void CH1_URAT2_TxTaskFunction( void *pvParameters )
                          { 
                          	uint8_t c = 0;
                          	
                          	
                          	struct UART_Device *pdev = GetUARDevice("uart2");
                          	pdev->Init(pdev , 115200, 'N', 8, 1);
                          	
                          	
                          	
                          	while(1)
                          	{
                          		pdev->Send(pdev, &c, 1, 100);
                          		vTaskDelay(500);
                          		c++;
                          	}
                          }
                          	
                          static void CH2_URAT4_RxTaskFunction( void *pvParameters )
                          {
                          	
                          	uint8_t c = 0;
                          	char bur[100];
                          	int cnt = 0;
                          	int err;
                          	struct UART_Device *pdev = GetUARDevice("uart4");
                          	
                          	pdev->Init(pdev , 115200, 'N', 8, 1);
                          	
                          	while(1)
                          	{
                          		err = pdev->RecvByte(pdev, &c, 100);
                          		if(err == 0)//=0表示接收完成
                          		{
                          			sprintf(bur,"receive dataset : 0x:%02x, numember:%d",c, cnt++);
                          			Draw_String(0, 0, bur, 0x0000ff00, 0);
                          		}
                          		else
                          		{
                          			//HAL_UART_DMAStop(&huart4);//超时或迅出错则调用终止中断接收的函敿
                          		}
                          		
                          	}
                          		
                          }
                          /* USER CODE END FunctionPrototypes */
                          /**
                            * @brief  FreeRTOS initialization
                            * @param  None
                            * @retval None
                            */
                          void MX_FREERTOS_Init(void) {
                            /* USER CODE BEGIN Init */
                            /* USER CODE END Init */
                            /* USER CODE BEGIN RTOS_MUTEX */
                            /* add mutexes, ... */
                            /* USER CODE END RTOS_MUTEX */
                            /* USER CODE BEGIN RTOS_SEMAPHORES */
                            /* add semaphores, ... */
                            /* USER CODE END RTOS_SEMAPHORES */
                            /* USER CODE BEGIN RTOS_TIMERS */
                            /* start timers, add new ones, ... */
                            /* USER CODE END RTOS_TIMERS */
                            /* USER CODE BEGIN RTOS_QUEUES */
                            /* add queues, ... */
                            /* USER CODE END RTOS_QUEUES */
                            /* creation of defaultTask */
                            defaultTaskHandle = osThreadNew(StartDefaultTask, NULL, &defaultTask_attributes);
                            /* USER CODE BEGIN RTOS_THREADS */
                            /* add threads, ... */
                          	xTaskCreate(
                          		SPILCDTaskFunction, // 函数指针, 任务函数
                          		"spi_lcd_task", // 任务的名孿
                          		200, // 栈大尿,单位为word,10表示40字节
                          		NULL, // 调用任务函数时传入的参数
                          		osPriorityNormal, // 优先线
                          		NULL ); // 任务句柄, 以后使用它来操作这个任务
                          		
                          	xTaskCreate(
                          		CH1_URAT2_TxTaskFunction, // 函数指针, 任务函数
                          		"ch1_uart2_tx_task", // 任务的名孿
                          		200, // 栈大尿,单位为word,10表示40字节
                          		NULL, // 调用任务函数时传入的参数
                          		osPriorityNormal, // 优先线
                          		NULL ); // 任务句柄, 以后使用它来操作这个任务
                          		
                          	xTaskCreate(
                          		CH2_URAT4_RxTaskFunction, // 函数指针, 任务函数
                          		"ch2_uart4_rx_task", // 任务的名孿
                          		200, // 栈大尿,单位为word,10表示40字节
                          		NULL, // 调用任务函数时传入的参数
                          		osPriorityNormal, // 优先线
                          		NULL ); // 任务句柄, 以后使用它来操作这个任务
                          	
                            /* USER CODE END RTOS_THREADS */
                            /* USER CODE BEGIN RTOS_EVENTS */
                            /* add events, ... */
                            /* USER CODE END RTOS_EVENTS */
                          }
                          
                          static SemaphoreHandle_t g_UART2_TX_Semaphore;
                          static uint8_t g_uart4_rx_buf[100];//定义丿个buff来存接收到的数据
                          static QueueHandle_t g_xUART4_RX_Queue;//创建队列
                          static SemaphoreHandle_t g_UART4_TX_Semaphore;
                          static uint8_t g_uart2_rx_buf[100];
                          static QueueHandle_t g_xUART2_RX_Queue;
                          struct UART_Device;//表示这是一个结构体类型
                          //send callback
                          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);
                          	}
                          	
                          }
                          //receive callback
                          void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
                          {
                          	//数据返鿁完毕,中断函数会调用这个回调函敿
                          	if(huart == &huart4)
                          	{
                          		
                          		//收到数据后把收到的数据存入buff,写队列
                          		for(int i = 0 ; i < 100; i++)
                          		{
                          			xQueueSendFromISR(g_xUART4_RX_Queue,&g_uart4_rx_buf[i], NULL);
                          		}
                          		
                          		//重新启动DMA+IDLE
                          		HAL_UARTEx_ReceiveToIdle_DMA(&huart4, g_uart4_rx_buf, 100);
                          	}
                          		
                          		
                          	if(huart == &huart2)
                          	{
                          		
                          		//收到数据后把收到的数据存入buff,写队列
                          		for(int i = 0 ; i < 100; i++)
                          		{
                          			xQueueSendFromISR(g_xUART2_RX_Queue,&g_uart2_rx_buf[i], NULL);
                          		}
                          		
                          		//重新启动DMA+IDLE
                          		HAL_UARTEx_ReceiveToIdle_DMA(&huart2, g_uart2_rx_buf, 100);	
                          	}
                          }
                          //receive  void event,接收空闿,表示数据已经接收完成,但是还没到DMA接收设置的忿
                          void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size)
                          {
                          	if(huart == &huart4)
                          	{
                          		//写队刿
                          		for(int i = 0 ; i < Size; i++)
                          		{
                          			xQueueSendFromISR(g_xUART4_RX_Queue,&g_uart4_rx_buf[i], NULL);
                          		}
                          		
                          		//重新启动DMA+IDLE
                          		HAL_UARTEx_ReceiveToIdle_DMA(&huart4, g_uart4_rx_buf, 100);	
                          	}
                          	
                          	if(huart == &huart2)
                          	{
                          		//写队刿
                          		for(int i = 0 ; i < Size; i++)
                          		{
                          			xQueueSendFromISR(g_xUART2_RX_Queue,&g_uart2_rx_buf[i], NULL);
                          		}
                          		
                          		//重新启动DMA+IDLE
                          		HAL_UARTEx_ReceiveToIdle_DMA(&huart2, g_uart2_rx_buf, 100);	
                          	}
                          }
                          //receive void error:重新启动DMA+IDLE
                          void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart)
                          {
                          	//重启DMA+IDLE
                          	if(huart == &huart4)
                          	{
                          		HAL_UARTEx_ReceiveToIdle_DMA(&huart4, g_uart4_rx_buf, 100);
                          	}
                          	
                          	if(huart == &huart2)
                          	{
                          		HAL_UARTEx_ReceiveToIdle_DMA(&huart2, g_uart2_rx_buf, 100);
                          	}
                          }
                          
                          //读数据,app从队列中读数据不从串口读数据亿
                          /**************/
                          /**************/
                          /*  uart4接收、uart2发送  */
                          int UART2_Send(struct UART_Device *pDev, uint8_t *datas,uint32_t len, int timeout)
                          {
                          		HAL_UART_Transmit_DMA(&huart2, datas, len);
                          		//wait Semaphore 信号量
                          		if(pdTRUE == xSemaphoreTake(g_UART2_TX_Semaphore,timeout))
                          			return 0;
                          		else
                          			return -1;
                          }
                          
                          int UART4_GetData(struct UART_Device *pDev,uint8_t *pData, int timeout)
                          {
                          	if(pdPASS == xQueueReceive(g_xUART4_RX_Queue,pData, timeout))
                          		return 0;
                          	else 
                          		return -1;
                          }
                          int UART4_RX_Start(struct UART_Device *pDev, int baud, char parity, int data_bit, int stop_bit)
                          {
                          	//弿始前把上面定义好的队列创建处板
                          	if(!g_xUART2_RX_Queue) 
                          	{
                          		g_xUART4_RX_Queue = xQueueCreate( 200, 1 );
                          		//启动接收
                          		HAL_UARTEx_ReceiveToIdle_DMA(&huart4, g_uart4_rx_buf, 100);
                          		//收到的数据保存在哪里,要定义1个buff;收到后回调函数就会被调用
                          	
                          		//创建信号量
                          		g_UART4_TX_Semaphore = xSemaphoreCreateBinary();
                          	}
                          	return 0;
                          }
                          /*****************/
                          /*  uart2接收、uart4发送  */
                          int UART2_GetData(struct UART_Device *pDev, uint8_t *pData, int timeout)
                          {
                          	if(pdPASS == xQueueReceive(g_xUART2_RX_Queue,pData, timeout))
                          		return 0;
                          	else 
                          		return -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);
                          		g_UART2_TX_Semaphore = xSemaphoreCreateBinary();
                          		HAL_UARTEx_ReceiveToIdle_DMA(&huart2, g_uart2_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);
                          		//wait Semaphore 信号量
                          		if(pdTRUE == xSemaphoreTake(g_UART4_TX_Semaphore,timeout))
                          			return 0;
                          		else
                          			return -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};
                          

                          编写遇到的问题

                          1、./Core/Src/usart.c(377): warning: passing ‘volatile uint8_t [100]’ to parameter of type ‘uint8_t *’ (aka ‘unsigned char *’) discards qualifiers [-Wincompatible-pointer-types-discards-qualifiers]

                          image.png

                          image.png

                          image.png

                          2、undefined symbol

                          把static去掉后就好了

                          image.png

                          image.png

                          另一个文件

                          image.png

                          寄存器

                          串口通讯不许连续发送,串口为什么一次只发一个字节?

                          1、避免累计误差;

                          2、串口通讯是异步发送,就是发送方和接受方有各自的时钟,时钟不同步,时钟同步的话可以发好多个字节;

                          波特率、比特率

                          波特率表示每秒传输信号的状态数,如果一个波形传输一个bit,那就=bit率,每秒传输的二进制位

                          一个波形传输n个比特

                          波特率= n比特率

                          image.png

                          总之:

                          波特率: 1 秒内传输信号的状态数(波形数)。比特率: 1 秒内传输数据的 bit数。如果一个波形,能表示 N 个 bit,那么:波特率 * N = 比特率。

                          通讯协议

                          并行8根线一次发8位

                          image.png

                          串行通信一根线发

                          image.png

                          单工,只能单向

                          双工双向,半双工一条通道接受和发送不能同时工作

                          全双工两个通道可以,同时收发

                          image.png

                          FIFO

                          FIFO(First In First Out,即先入先出),是一种数据缓冲器。先被写入的数据会按顺序先被读出。FIFO可看做一个管道,有数据写入端口和 数据读取端口:

                          设置异步通信

                          image.png

                          设置数据位,校验位、波特率、停止位

                          image.png

                          memset

                          image.png

转载请注明来自码农世界,本文标题:《UART基本定义、三种编程方式、freertos内怎么用、怎么封装》

百度分享代码,如果开启HTTPS请参考李洋个人博客
每一天,每一秒,你所做的决定都会改变你的人生!

发表评论

快捷回复:

评论列表 (暂无评论,87人围观)参与讨论

还没有评论,来说两句吧...

Top