莫张周刘王 发表于 2024-9-7 05:14:54

STM32基于HAL库串口printf利用和吸收

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

1.打开cubemx,选择MCU型号
https://i-blog.csdnimg.cn/direct/46a5e1c7066e4a138701b199bddce70d.png
2.我这里利用的是STM32F103C8T6,根据本身的型号选择,这里不限定型号
https://i-blog.csdnimg.cn/direct/1400ea67d6d74ef990b2d47f65d7a16e.png
3.选择时钟源
https://i-blog.csdnimg.cn/direct/ad9a58e2fd65477ab742142f8ad7563c.png
4.系统设置
https://i-blog.csdnimg.cn/direct/afff22d6519b4136a95b2419d1979f8b.png
5时钟配置
https://i-blog.csdnimg.cn/direct/60a47a8a19e044f39ad3e3d4b518e503.png

5.选择和配置串口

https://i-blog.csdnimg.cn/direct/f42a87c833b14b8281cc78e6818fd3d7.png


5.配置中断和中断优先级
https://i-blog.csdnimg.cn/direct/9aed08020e504348b395bc7a71d30e50.png
6.工程设置
https://i-blog.csdnimg.cn/direct/09315e589cd640a484d247e87875cdac.png
7.代码生成设置
https://i-blog.csdnimg.cn/direct/94798a4f59f94df7ac4c38ecab75e2ea.png

https://i-blog.csdnimg.cn/direct/a9f518ee83a3429d92be280fd98c0ce9.png
cubemx代码生成注意事项
https://i-blog.csdnimg.cn/direct/a224db53645c46b99d9edc63fd7aba61.png
添加代码

https://i-blog.csdnimg.cn/direct/16a7718e12024ee6a7920b95e753668d.png
https://i-blog.csdnimg.cn/direct/40bbc80862b346a7b5a2766fc70bf8c3.png
/* USER CODE BEGIN Prototypes */

#define RX_BUFFER_SIZE 256

typedef struct {
    uint8_t RxBuffer;
    uint8_t RxData;
    uint16_t RxDataCnt;
}UART_RxTypeDef;

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

/* USER CODE END Prototypes */ https://i-blog.csdnimg.cn/direct/59d8085cae1c4a72b68b93c7c87af984.png
 
/* 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 */ https://i-blog.csdnimg.cn/direct/b7b9f5f3beb74208817982306261f18b.png

/* USER CODE BEGIN Includes */
       
#include <stdio.h>
#include <string.h>

#include "usart.h"
/* USER CODE END Includes */ 关键的一点,如果不勾选这个选项,那么是无法运行printf代码,整个代码无法运行

https://i-blog.csdnimg.cn/direct/188de2cc1b4b4dcb83b85e82497c065f.png

然后我们如果不想每次烧录后都要按下复位键
https://i-blog.csdnimg.cn/direct/8f161dc60b464dae834e9b600de55517.png
https://i-blog.csdnimg.cn/direct/e4b2ecb2f2b34b9b891509a71088ada1.png
https://i-blog.csdnimg.cn/direct/1d8c2f493a574b75b786965f6c3a1a33.png


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

主函数while循环
 
/* 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串口助手
https://i-blog.csdnimg.cn/direct/1604e287589d4f30bc7a2577b4be9dd3.png

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

然后我们必要串口吸收
之前我们已经配置好了NVIC中断向量了
已经使能了串口中断
在HAL库中,串口如果发送中断会进入中断服务函数,然后在这个函数中他帮我们处置处罚了很多东西,我们只必要调用一个回调函数,这个回调函数是弱界说,我们可以重新界说

在usart.c最下面添加代码:
 
/* USER CODE BEGIN 1 */
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
        if (huart->Instance == USART1)
    {

                Uart1Rx.RxBuffer = Uart1Rx.RxData;   //接收数据转存
       
                if(Uart1Rx.RxDataCnt > RX_BUFFER_SIZE)
                {
                        memset(Uart1Rx.RxBuffer,0x00,sizeof(Uart1Rx.RxBuffer));
                        Uart1Rx.RxDataCnt = 0;
                }
               
                if((Uart1Rx.RxBuffer == '\r' && Uart1Rx.RxBuffer == '\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 */ 这样子还不够,还必要在代码初始化时,先开启吸收一次数据
https://i-blog.csdnimg.cn/direct/6f25ef91b61c44b8a0c300ac2a2cf112.png
/* USER CODE BEGIN 2 */
        HAL_UART_Receive_IT(&huart1, (uint8_t *)&Uart1Rx.RxData, 1);
/* USER CODE END 2 */ 烧录测试
https://i-blog.csdnimg.cn/direct/f5f1233d515b482386464b93339fd295.png

补充
1.为什么利用printf必要在编译软件中勾选Use MicroLIB?
答:MicroLIB是一个针对ARM Cortex-M系列处置处罚器优化的C库,相比尺度C库,它更实用于资源有限的嵌入式系统,提供了更高效的空间和速率性能
资源优化:MicroLIB经过优化,更适合嵌入式系统的资源限定。
重定向支持:通过MicroLIB,可以更轻易地实现printf等尺度输出函数的重定向,方便开发者利用这些函数输出调试信息到串口。

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

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

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页: [1]
查看完整版本: STM32基于HAL库串口printf利用和吸收