第十三届蓝桥杯嵌入式备赛-STM32G431-进阶模块调试⑧USART串口收发

目录

0.前言

1.功能要求

电路原理图

2.STM32Cubemx初始化

  3.程序实现

main.c相关初始化

中断处理函数编写 

 4.工程文件


0.前言

这套教程针对于蓝桥杯嵌入式比赛的底层模块调试,针对于比赛进行每个模块的调试,低层模块调试好,对于赛题的实现就会方便很多,虽然有一些应试教育的意味,不过准备这个比赛对于程序整体实现思维还是有着很大帮助,我也从中受益颇多!

1.功能要求

调试串口进行数据收发。数据发送要在一定时间内间隔发送,串口接收要实现不定长接收,这里我们使用DMA空闲中断来接收数据。

电路原理图

第十三届蓝桥杯嵌入式备赛-STM32G431-进阶模块调试⑧USART串口收发_第1张图片

2.STM32Cubemx初始化

开启USART1,将PA10设置为USART1_RX,将PA9设置为USART1_TX

第十三届蓝桥杯嵌入式备赛-STM32G431-进阶模块调试⑧USART串口收发_第2张图片

USART1详细设置

第十三届蓝桥杯嵌入式备赛-STM32G431-进阶模块调试⑧USART串口收发_第3张图片

 开启USART1中断

第十三届蓝桥杯嵌入式备赛-STM32G431-进阶模块调试⑧USART串口收发_第4张图片

使能DMA

第十三届蓝桥杯嵌入式备赛-STM32G431-进阶模块调试⑧USART串口收发_第5张图片

  3.程序实现

任意长度字符接收主要是靠IDLE空闲中断实现的,当DMA接收产生空闲时,即接收已经完成,就会使能空闲中断标志位IDLE,然后停止DMA ,处理已经接收到的数据,清空中断标志位,当下次数据来时,继续接收,达到接收任意长度的目的。(程序是没问题的,这是我的理解,有不对的请纠正)。该程序也有一个问题,没有解决,当这次接收的字符长长度小于上一次接收的字符串时。接收字符串的数组RX后几位仍然保留上一次接收的数据,没法清除,这里我也没有好的方法解决,还请大佬指点。

main.c相关初始化

函数功能均在注释中

main.c中创建USART相关变量

/*main.c*/

uint16_t TX_tt=0;//串口发送计时标志位
uint16_t TX_Ref=0;//串口发送标志位
uint16_t RX_Deal=0;//串口接收处理标志位
uint8_t RX[50];//串口接收数组
uint8_t TX[50]="Hello world!\r\n";//串口发送数组

Task_Time()函数扩充,定时发送串口数据(移步②,查看该函数)

/*main.c*/

void Task_Time(void)
{
	if(++Key_tt==10)		{Key_tt=0;Key_Ref=1;}//按键扫描计时
	if(++Lcd_tt==200)		{Lcd_tt=0;Lcd_Ref=1;}//LCD刷新计时
	if(++ADC_tt==300)		{ADC_tt=0;ADC_Ref=1;}//ADC读取计时
	if(++MCP_tt==200)		{MCP_tt=0;MCP_Ref=1;}//MCP写入计时
	if(++DAC_tt==200)		{DAC_tt=0;DAC_Ref=1;}//DAC输出计时
	if(++RTC_tt==1000)	{RTC_tt=0;RTC_Ref=1;}//RTC获取计时
	if(++TX_tt==1000)		{TX_tt=0;TX_Ref=1;}	 //串口发送计时
}

主循环中添加判断程序

/*main.c*/
	
while(1)
{
        if(TX_Ref==1)
	{
		TX_Ref=0;//清除标志位
		HAL_UART_Transmit_DMA(&huart1, TX, strlen((char*)TX));//串口DMA发送数据
	}
}

在主循环前添加初始化函数

/*main.c*/

    __HAL_UART_ENABLE_IT(&huart1, UART_IT_IDLE);//使能IDLE空闲中断
	HAL_UART_Receive_DMA(&huart1, RX, 50);//开启DMA接收

中断处理函数编写 

在stm32g4xx_it.c中的void USART1_IRQHandler(void)函数中编写以下逻辑,用来判断是否执行IDLE空闲中断

/*stm32g4xx_it.c*/

void USART1_IRQHandler(void)
{
  /* USER CODE BEGIN USART1_IRQn 0 */

    /*用户函数*/
	if(__HAL_UART_GET_FLAG(&huart1, UART_FLAG_IDLE)!=RESET)//判断空闲中断标志位
	{
		__HAL_UART_CLEAR_IDLEFLAG(&huart1);//清空空闲中断标志位
		HAL_UART_DMAStop(&huart1);//停止DMA接收
		HAL_UART_IdleCpltCallback(&huart1);//执行IDLE空闲中断
	}



  /* USER CODE END USART1_IRQn 0 */
  HAL_UART_IRQHandler(&huart1);
  /* USER CODE BEGIN USART1_IRQn 1 */

  /* USER CODE END USART1_IRQn 1 */
}

 在usart.c中编写HAL_UART_IdleCpltCallback()回调函数,并在usart.h中声明

/*usart.h*/

void HAL_UART_IdleCpltCallback(UART_HandleTypeDef *huart);

在usart.c中声明外部变量并创建变量RecCount

/*usart.c*/

extern uint8_t RX[50];//串口接收数组
extern uint16_t RX_Deal;//串口接收处理标志位
uint16_t RecCount=0;

 编写HAL_UART_IdleCpltCallback()函数,该函数没有在定义中找到,但是我测试了一下,只有这个函数名是能正常使用的,所以需要记一下,可以使用stm32g4xx_usart.c中已知的回调函数HAL_UART_RxCpltCallback()修改

/*usart.c*/

void HAL_UART_IdleCpltCallback(UART_HandleTypeDef *huart)
{
	RecCount=__HAL_DMA_GET_COUNTER(&hdma_usart1_rx);//对接收数据计数
	RecCount=0;
	HAL_UART_Receive_DMA(&huart1, RX, 50);//开启DMA接收
	RX_Deal=1;
}

相关函数定义位置stm43g4xx_hal_usart.c、stm43g4xx_hal_usart.h和stm43g4xx_hal_dma.c中

/*stm32g4xx_usart.c*/

HAL_UART_Transmit_DMA(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size);
HAL_UART_Receive_DMA(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size);
HAL_UART_DMAStop(UART_HandleTypeDef *huart);
/*stm32g4xx_usart.h*/

__HAL_UART_ENABLE_IT(__HANDLE__, __INTERRUPT__);//使能空闲中断
__HAL_UART_CLEAR_IDLEFLAG(__HANDLE__);//清除中断标志位
__HAL_UART_GET_FLAG(__HANDLE__, __FLAG__);//获取中断标志位的状态
/*stm32g4xx_dma.h*/

__HAL_DMA_GET_COUNTER(__HANDLE__);

在Task.c中声明外部变量,就可以接收和发送信息啦

/*Task.c*/

extern uint8_t RX[50];//串口接收数组
extern uint16_t RX_Deal;//串口接收处理标志位
extern uint8_t TX[50];//串口发送数组

 4.工程文件

该工程文件为全10讲所有内容,可以作为参考,不过还是希望读者能够自己手敲一遍,加深记忆

链接:https://pan.baidu.com/s/1LcNszc7_oHWvXcucCezlxg?pwd=hw07 
提取码:hw07

第十三届蓝桥杯嵌入式备赛-STM32G431-进阶模块调试⑧USART串口收发_第6张图片

 

 自己做的笔记,也希望能对你有帮助! 

你可能感兴趣的:(蓝桥杯,嵌入式硬件,stm32,单片机)