③【蓝桥杯】STM32G4嵌入式竞赛实训平台(CT117E-M4)学习——串口

写在前面——

        本文将介绍嵌入式竞赛实训平台(CT117E-M4)开发板上串口的使用。

目录

一、硬件平台  

二、软件平台

三、串口原理图

四、配置过程

五、编写函数

(一)重定义printf函数

(二)串口发送/接收函数

(三)串口中断函数

(四)串口查询函数

六、总结


一、硬件平台  

        嵌入式竞赛实训平台(CT117E-M4)是北京国信长天科技有限公司设计、生产的一款“蓝桥杯全国软件与信息技术专业人才大赛–嵌入式设计与开发科目”专用竞赛平台,平台STM32G431RBT6为主控芯片,预留扩展板接口,可为用户提供丰富的实验场景。

CT117E-M4产片图片

  

二、软件平台

         KEIL5,STM32CubeMX

三、串口原理图

 

       由官方提供的原理图可以看出,DAP Link的串口连接在芯片的PA9和PA10引脚。查阅芯片资料,可以得知PA9和PA10分别是芯片USART1的Tx和Rx: 

PA9   ---> USART1_Tx
PA10  ---> USART1_Rx

注:这与我们平时较常用的STM32F1系列芯片是一样的

四、配置过程

         本次配置过程仅仅介绍串口的基本使用,DMA的使用将单独作为一篇博客.

基本配置步骤: 

1.点击USATR1   
2.设置MODE为异步通信(Asynchronous)       
3.波特率为115200Bits/s ;传输数据长度为8 Bit;奇偶检验无;停止位1;接收和发送都使能 
4.GPIO引脚设置 USART1_RX/USART_TX
5 .NVIC Settings 一栏使能接收中断

五、编写函数

(一)重定义printf函数

1.在 main.c中包含#include <stdio.h>并声明串口

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include <stdio.h>
/* USER CODE END Includes */
/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
extern UART_HandleTypeDef huart1;   //声明串口
/* USER CODE END 0 */

2.在 stm32f4xx_hal.c 中重写fget和fput函数 

/**
  * 函数功能: 重定向c库函数printf到DEBUG_USARTx
  * 输入参数: 无
  * 返 回 值: 无
  * 说    明:无
  */
int fputc(int ch, FILE *f)
{
  HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 0xffff);
  return ch;
}
 
/**
  * 函数功能: 重定向c库函数getchar,scanf到DEBUG_USARTx
  * 输入参数: 无
  * 返 回 值: 无
  * 说    明:无
  */
int fgetc(FILE *f)
{
  uint8_t ch = 0;
  HAL_UART_Receive(&huart1, &ch, 1, 0xffff);
  return ch;
}

(二)串口发送/接收函数

 以下共六个常用函数在stm32g4xx_hal_uart.h的最后可找到,在这里详细介绍最常用的;

/* IO operation functions *****************************************************/
HAL_StatusTypeDef HAL_UART_Transmit(UART_HandleTypeDef *huart, const uint8_t *pData, uint16_t Size, uint32_t Timeout);
HAL_StatusTypeDef HAL_UART_Receive(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout);
HAL_StatusTypeDef HAL_UART_Transmit_IT(UART_HandleTypeDef *huart, const uint8_t *pData, uint16_t Size);
HAL_StatusTypeDef HAL_UART_Receive_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size);
HAL_StatusTypeDef HAL_UART_Transmit_DMA(UART_HandleTypeDef *huart, const uint8_t *pData, uint16_t Size);
HAL_StatusTypeDef HAL_UART_Receive_DMA(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size);
/* IO operation functions *****************************************************/
  • HAL_UART_Transmit();串口发送数据,使用超时管理机制 
  • HAL_UART_Receive();串口接收数据,使用超时管理机制
  • HAL_UART_Transmit_IT();串口中断模式发送  
  • HAL_UART_Receive_IT();串口中断模式接收
  • HAL_UART_Transmit_DMA();串口DMA模式发送
  • HAL_UART_Transmit_DMA();串口DMA模式接收

串口发送数据:

HAL_UART_Transmit(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout)

功能:串口发送指定长度的数据。如果超时没发送完成,则不再发送,返回超时标志(HAL_TIMEOUT)。

参数:

  • UART_HandleTypeDef *huart  如 :UART_HandleTypeDef huart1别名就是huart1  
  • *pData:需要发送的数据 
  • Size:发送的字节数
  • Timeout :最大发送时间,发送数据超过该时间退出发送   
  • 举例:
HAL_UART_Transmit(&huart1, (uint8_t *)ZZX, 3, 0xffff);
//串口发送三个字节数据,最大传输时间0xffff


中断接收数据

HAL_UART_Receive_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)


功能:串口中断接收,以中断方式接收指定长度数据。大致过程是,设置数据存放位置,接收数据长度,然后使能串口接收中断。接收到数据时,会触发串口中断。再然后,串口中断函数处理,直到接收到指定长度数据,而后关闭中断进入中断接收回调函数不再触发接收中断。(只触发一次中断)

NOTE:我们要把我们需要的代码编写在串口中断回调函数中,可以粗略认为HAL库中的回调函数相当于标准库中的中断函数 ,我是这样想的,此外,需要强调的是这个函数还有一个重要的作用在串口初始化时需要调用一次以启用串口接收中断,在中断回调函数的最后再调用一次以开启下一次中断。

参数:

  • UART_HandleTypeDef *huart  如 :   UART_HandleTypeDef huart1 别名就是huart1  
  • *pData:接收到的数据存放地址
  • Size:接收的字节数
  • 举例:
 HAL_UART_Receive_IT(&huart1,(uint8_t *)&value,1);   
//中断接收一个字符,存储到value中

(三)串口中断函数

以下共六个常用函数在stm32g4xx_hal_uart.h的最后可找到,在这里详细介绍最常用的;

void HAL_UART_IRQHandler(UART_HandleTypeDef *huart);
void HAL_UART_TxHalfCpltCallback(UART_HandleTypeDef *huart);
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart);
void HAL_UART_RxHalfCpltCallback(UART_HandleTypeDef *huart);
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart);
void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart);
  • HAL_UART_IRQHandler(UART_HandleTypeDef *huart);  //串口中断处理函数
  • HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart);  //串口发送中断回调函数
  • HAL_UART_TxHalfCpltCallback(UART_HandleTypeDef *huart);  //串口发送一半中断回调函数(用的较少)
  • HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart);  //串口接收中断回调函数
  • HAL_UART_RxHalfCpltCallback(UART_HandleTypeDef *huart);//串口接收一半回调函数(用的较少)
  • HAL_UART_ErrorCallback();串口接收错误函数

串口中断处理函数:

HAL_UART_IRQHandler(UART_HandleTypeDef *huart);  
//串口中断处理函数

如果接收数据,则会进行接收中断处理函数 (在stm32g4xx_hal_uart.c中)

参数:

UART_HandleTypeDef *huart 如:UART_HandleTypeDef huart1别名就是huart1

/* UART in mode Receiver ---------------------------------------------------*/ 
   if (((isrflags & USART_ISR_RXNE_RXFNE) != 0U)
        && (((cr1its & USART_CR1_RXNEIE_RXFNEIE) != 0U)
            || ((cr3its & USART_CR3_RXFTIE) != 0U)))
    {
      if (huart->RxISR != NULL)
      {
        huart->RxISR(huart);
      }
      return;
    }
  }

如果发送数据,则会进行发送中断处理函数(在stm32g4xx_hal_uart.c中)

/* UART in mode Transmitter ------------------------------------------------*/
  if (((isrflags & USART_ISR_TXE_TXFNF) != 0U)
      && (((cr1its & USART_CR1_TXEIE_TXFNFIE) != 0U)
          || ((cr3its & USART_CR3_TXFTIE) != 0U)))
  {
    if (huart->TxISR != NULL)
    {
      huart->TxISR(huart);
    }
    return;
  }

串口接收中断回调函数:

HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart);  
//串口接收中断回调函数

功能:HAL库的中断进行完之后,并不会直接退出,而是会进入中断回调函数中,用户可以在其中设置代码, 串口中断接收完成之后,会进入该函数,该函数为空函数,用户需自行修改

参数: 

UART_HandleTypeDef *huart 如:UART_HandleTypeDef huart1别名就是huart1

功能:

  1.在主函数前这样定义

#define RXBUFFERSIZE  256     //最大接收字节数
char RxBuffer[RXBUFFERSIZE];   //接收数据
uint8_t aRxBuffer;			//接收中断缓冲
uint8_t Uart1_Rx_Cnt = 0;		//接收缓冲计数

  2.此函数建议写在main.c的这里

/*
0x0D(asc码是13) 指的是“回车” \r是把光标置于本行行首

0x0A(asc码是10) 指的是“换行” \n是把光标置于下一行的同一列

0x0D + 0x0A 回车换行 \r\n把光标置于下一行行首

\n是换行,英文是linefeed,ASCII码是0x0A。

\r是回车,英文是carriage return ,ASCII码是0x0D。

*/
/* USER CODE BEGIN 4 */
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
   /* Prevent unused argument(s) compilation warning */
  UNUSED(huart);
  /* NOTE: This function Should not be modified, when the callback is needed,
           the HAL_UART_TxCpltCallback could be implemented in the user file
   */
 
	if(Uart1_Rx_Cnt >= 255)  //溢出判断
	{
		Uart1_Rx_Cnt = 0;
		memset(RxBuffer,0x00,sizeof(RxBuffer));
		HAL_UART_Transmit(&huart1, (uint8_t *)"数据溢出", 10,0xFFFF); 	
        
	}
	else
	{
		RxBuffer[Uart1_Rx_Cnt++] = aRxBuffer;   //接收数据转存
	
		if((RxBuffer[Uart1_Rx_Cnt-1] == 0x0A)&&(RxBuffer[Uart1_Rx_Cnt-2] == 0x0D)) //判断结束位
		{
			HAL_UART_Transmit(&huart1, (uint8_t *)&RxBuffer, Uart1_Rx_Cnt,0xFFFF); //将收到的信息发送出去
            while(HAL_UART_GetState(&huart1) == HAL_UART_STATE_BUSY_TX);//检测UART发送结束
			Uart1_Rx_Cnt = 0;
			memset(RxBuffer,0x00,sizeof(RxBuffer)); //清空数组
		}
	}
	
	HAL_UART_Receive_IT(&huart1, (uint8_t *)&aRxBuffer, 1);   //再开启接收中断             
}
/* USER CODE END 4 */

在这里解读一下这个函数的正常情况下是怎样运行的: 串口1个字节1个字节地进行接收储存在“RxBuffer[Uart1_Rx_Cnt++]”中,出现换行(\n)和回车(\r)后,即接收完成,再发送

NOTE:

        特别的,这个函数是串口中断函数,并非某一串口特有,既是,任何一个串口中断的发生,最后都会调用这个函数中,当我们的工程有多个串口中断的时候,我们就需要区分本次中断的来源,我们可以通过huart->Instance变量来判断,示例代码如下:

... ... 
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
	if(huart->Instance == USART1)
	{
		HAL_UART_Transmit(&huart1,"串口1中断\r\n",strlen("串口1中断\r\n"),0x200);
		HAL_UART_Receive_IT(&huart1, recv_data,1);                     //再次使能接受中断
	}
	
	if(huart->Instance == USART2)
	{
		HAL_UART_Transmit(&huart1,"串口2中断\r\n",strlen("串口2中断\r\n"),0x200);
		HAL_UART_Receive_IT(&huart2, recv_data,1);
	}
	
}

(四)串口查询函数

HAL_UART_GetState();  判断UART的接收是否结束,或者发送数据是否忙碌

   举例:

while(HAL_UART_GetState(&huart4) == HAL_UART_STATE_BUSY_TX)   //检测UART发送结束

六、总结

        串口的介绍就到这里了,如果此文章对你有帮助,欢迎点赞 关注 收藏 转发.

  • 2
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

_Cui

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值