STM32基于HAL库串口printf使用和接收

我们这里使用HAL库直接用cubemx生成代码配置串口

1.打开cubemx,选择MCU型号

2.我这里使用的是STM32F103C8T6,根据自己的型号选择,这里不限制型号

3.选择时钟源

4.系统设置

5时钟配置

5.选择和配置串口

5.配置中断和中断优先级

6.工程设置

7.代码生成设置

cubemx代码生成注意事项

添加代码


cpp 复制代码
/* USER CODE BEGIN Prototypes */

#define RX_BUFFER_SIZE 256

typedef struct {
    uint8_t RxBuffer[RX_BUFFER_SIZE];
    uint8_t RxData;
    uint16_t RxDataCnt;
}UART_RxTypeDef;

extern UART_RxTypeDef Uart1Rx;   // 为UART1声明外部结构体变量

/* USER CODE END Prototypes */
cpp 复制代码
/* USER CODE BEGIN 0 */

UART_RxTypeDef Uart1Rx = {{0}, 0, 0};  // 为UART1初始化结构体

// 重定向c库函数printf到huart1
int fputc(int ch, FILE *f) {
    HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 0xFFFF);
    return ch;
}
int fgetc(FILE *f)
{
  uint8_t ch = 0;
  HAL_UART_Receive(&huart1, &ch, 1, 0xffff);
  return ch;
}
/* USER CODE END 0 */
cpp 复制代码
/* USER CODE BEGIN Includes */
	
#include <stdio.h>
#include <string.h>

#include "usart.h"
/* USER CODE END Includes */

关键的一点,如果不勾选这个选项,那么是无法运行printf代码,整个代码无法运行

然后我们如果不想每次烧录后都要按下复位键

然后我们就测试一下代码是否可以正常运行

主函数while循环

cpp 复制代码
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
	  printf("Hello World!\r\n");
	  HAL_Delay(1000);
  }
  /* USER CODE END 3 */

烧录后,打开我们的串口工具

我这里用的是正点原子的xcom串口助手

现在说明我们的串口发送是可以的了

然后我们需要串口接收

之前我们已经配置好了NVIC中断向量了

已经使能了串口中断

在HAL库中,串口如果发送中断会进入中断服务函数,然后在这个函数中他帮我们处理了很多东西,我们只需要调用一个回调函数,这个回调函数是弱定义,我们可以重新定义

在usart.c最下面添加代码:

cpp 复制代码
/* USER CODE BEGIN 1 */
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
	if (huart->Instance == USART1)
    {

		Uart1Rx.RxBuffer[Uart1Rx.RxDataCnt++] = Uart1Rx.RxData;   //接收数据转存
	
		if(Uart1Rx.RxDataCnt > RX_BUFFER_SIZE) 
		{
			memset(Uart1Rx.RxBuffer,0x00,sizeof(Uart1Rx.RxBuffer));
			Uart1Rx.RxDataCnt = 0;
		}
		
		if((Uart1Rx.RxBuffer[Uart1Rx.RxDataCnt - 2] == '\r' && Uart1Rx.RxBuffer[Uart1Rx.RxDataCnt - 1] == '\n')) //判断结束位
		{
			HAL_UART_Transmit(&huart1, (uint8_t *)&Uart1Rx.RxBuffer, Uart1Rx.RxDataCnt,0xFFFF); //将收到的信息发送出去
            while(HAL_UART_GetState(&huart1) == HAL_UART_STATE_BUSY_TX);//检测UART发送结束
			Uart1Rx.RxDataCnt = 0;
			memset(Uart1Rx.RxBuffer,0x00,sizeof(Uart1Rx.RxBuffer)); //清空数组
		}
	
	HAL_UART_Receive_IT(&huart1, (uint8_t *)&Uart1Rx.RxData, 1);   //再开启接收中断

	}
}
/* USER CODE END 1 */

这样子还不够,还需要在代码初始化时,先开启接收一次数据

cpp 复制代码
  /* USER CODE BEGIN 2 */
	HAL_UART_Receive_IT(&huart1, (uint8_t *)&Uart1Rx.RxData, 1);
  /* USER CODE END 2 */

烧录测试

补充

1.为什么使用printf需要在编译软件中勾选Use MicroLIB?

答:MicroLIB是一个针对ARM Cortex-M系列处理器优化的C库,相比标准C库,它更适用于资源有限的嵌入式系统,提供了更高效的空间和速度性能

资源优化:MicroLIB经过优化,更适合嵌入式系统的资源限制。

重定向支持 :通过MicroLIB,可以更容易地实现printf等标准输出函数的重定向,方便开发者使用这些函数输出调试信息到串口。

2.什么是重定向?

在编程中,重定向是指改变一个操作(比如输入输出)的默认行为,将其指向另一个方向或者设备。例如,将标准输出(通常是屏幕)重定向到打印机或文件。在STM32等嵌入式设备上,将printf的输出重定向到串口通讯,使得通过串口可以发送调试或其他信息到外部设备,如电脑终端。

printf通常不能直接使用来输出信息,因为标准的printf函数是用于在计算机上向终端或文件输出信息的,而微控制器一般使用串口(UART)作为与外界通信的手段。为了能够在串口上使用printf输出调试或其他信息,需要将printf重定向到串口,这就是"重定向"的含义。

相关推荐
Mortal_hhh2 分钟前
VScode的C/C++点击转到定义,不是跳转定义而是跳转声明怎么办?(内附详细做法)
ide·vscode·stm32·编辑器
深圳市青牛科技实业有限公司15 分钟前
【青牛科技】应用方案|D2587A高压大电流DC-DC
人工智能·科技·单片机·嵌入式硬件·机器人·安防监控
Mr.谢尔比1 小时前
电赛入门之软件stm32keil+cubemx
stm32·单片机·嵌入式硬件·mcu·信息与通信·信号处理
LightningJie1 小时前
STM32中ARR(自动重装寄存器)为什么要减1
stm32·单片机·嵌入式硬件
鹿屿二向箔1 小时前
STM32外设之SPI的介绍
stm32
西瓜籽@2 小时前
STM32——毕设基于单片机的多功能节能窗控制系统
stm32·单片机·课程设计
远翔调光芯片^138287988724 小时前
远翔升压恒流芯片FP7209X与FP7209M什么区别?做以下应用市场摄影补光灯、便携灯、智能家居(调光)市场、太阳能、车灯、洗墙灯、舞台灯必看!
科技·单片机·智能家居·能源
极客小张5 小时前
基于STM32的智能充电桩:集成RTOS、MQTT与SQLite的先进管理系统设计思路
stm32·单片机·嵌入式硬件·mqtt·sqlite·毕业设计·智能充电桩
Thanks_ks7 小时前
探索计算机互联网的奇妙世界:从基础到前沿的无尽之旅
物联网·云计算·区块链·tcp/ip协议·计算机互联网·万维网·未来科技
m0_739312878 小时前
【STM32】项目实战——OV7725/OV2604摄像头颜色识别检测(开源)
stm32·单片机·嵌入式硬件