二 使用GPIO的复用功能 利用USART 实现printf()

参考这篇: STM32串口通信详解

1. 关于USART

USART ( universal synchronous / asynchronous receiver /transmitter) 是一种串行通讯协议 , 允许设备通过串行端口进行数据传输, USART 能够以同步或者异步的方式进行工作,在实际的运用中,我们主要使用的是它的异步通信模式

1.1 USART 工作模式 (异步)

  • 通讯方式: 异步 ,无需共享或者同步时钟信号
  • 数据格式: 发送和接受数据时, 数据被封装在帧中,通常包含起始位 数据位 可选的奇偶校验位 以及停止位
  • 波特率: 使用先双方需要设置相同的波特率
  • 流控制: 可选择硬件流控制如RTS/CTS)或者软件流控制 (如XON/XOFF)
  • 连接方式: 点对点,通常用于两个设备之间

优点: 在于简单些和点对点的通讯效率
缺点: 没有外部的时钟进行同步, 通讯双方的时钟必须精确的匹配

1.2 USART 工作模式 (同步)

在同步模式下 , USART需要使用一个外部的时钟信号来同步数据的发送和接受

  • 同步起始位: 同步模式使用特定的同步字符或位模式来标记数据帧的开始
  • 数据位: 数据以固定的数据发送, 速率由外部时钟决定
  • 奇偶校检位(可选) : 于异步模式相同, 用于错误检测
  • 停止位: 在某些同步的USART中,停止位可能不被使用,因为时钟信号已经提供了数据帧 的同步

优点:优点是速度,因为外部时钟信号允许更快的数据率和更高的数据吞吐量 , 此外 由于时钟信号的存在,接受器能够更加准确的确定何时读取数据位
缺点 : 需要额外的时钟线

1.2 USART 和 UART 的差异

  • 同步模式: USART 可以工作在同步模式下,但是需要额外的时钟信号来同步数据的发送和接受, 但是UART 不具备同步模式
  • 功能: USART 通常提供更多的特性和配置选项,如数据位的长度,奇偶校检,多种停止位等
  • 速度和效率: 在同步模式下, USART可以提供比异步模式(UART)更快的数据传输速度
  • 硬件复杂性: USART的硬件实现比UART 复杂, 因为它需要处理同步和异步两种通讯方式

1.4 工作的框图

在这里插入图片描述

2. 流程

2.1 初始化GPIO : GPIO_init(void)

  • 使能GPIO的时钟
  • 设置GPIO引脚9 和 10 为复用功能 ,方便用作 USART1 的 TX(接受) 和RX(发送) 引脚
  • 初始化GPIO 引脚设置 模式(复用) ,输出类型(推挽),上拉下拉(上拉)

2.2 USART的初始化 : USART_init(void)

  • 使能 USART1 的时钟
  • 配置USART1的参数 :波特率(115200) , 字节长度(8),硬件流控制(无),工作模式(发送),校检位(无), 停止位(1位)
  • 使能USART1 使其工作

2.3 fputc函数重写

  • 重写fputc函数以便printf可以使用USART发送数据。
    将字符ch发送到USART1。
  • 使用轮询方式等待发送完成(通过检查USART1的传输完成标志)。
  • 返回写入的字符。

3. 代码

3.1 USART.h

#ifndef USART_H 
#define USART_H

#include "stm32f4xx.h"
#include "stdio.h" 
#include "stm32f4xx_usart.h" 
#include "stm32f4xx_gpio.h" 
#include "stm32f4xx_rcc.h" 


void USART_init(void); 
int fputc(int ch , FILE*f) ; 

#endif

3.2 USART.c

#include "stm32f4xx.h"
#include "USART.h" 
#include "stdio.h" 

//#include "stm32f4xx_gpio.h" 
//#include "stm32f4xx_rcc.h" 


/*******************************************
 * 函数:void USART_init(void)
 * 功能: 初始化GPIO 以及 USART 
 * 参数: void
 * 返回值:none
 * 描述: 此函数使用STM32F411的GPIO引脚9(TX) 以及引脚10(RX) 用于USART通信
 *        并且设置波特率为115200,8位数据, 无硬件流控制, 无校检位 ,
 *        1个停止位。初始化后,UASRT1准备发送数据据
**********************************************/
void USART_init(void)
{
    //使能外设时钟 
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE) ; 
    //设置GPIOA引脚为复用功能 
    GPIO_PinAFConfig(GPIOA, GPIO_PinSource9, GPIO_AF_USART1);
    GPIO_PinAFConfig(GPIOA, GPIO_PinSource10, GPIO_AF_USART1);

    //初始化GPIOA引脚9 为复用功能输出
    GPIO_InitTypeDef GPIO_InitStruct ; 
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF ; 
    GPIO_InitStruct.GPIO_OType = GPIO_OType_PP ; 
    GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_UP ; 
    GPIO_InitStruct.GPIO_Pin = GPIO_Pin_9 ; 
    GPIO_Init( GPIOA, & GPIO_InitStruct);

    //初始化GPIOA引脚10 为复用功能输入
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF ; 
    GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_UP ; 
    GPIO_InitStruct.GPIO_Pin = GPIO_Pin_10 ; 
    GPIO_Init( GPIOA, & GPIO_InitStruct);

    USART_InitTypeDef USART_InitStruct ;
    USART_InitStruct.USART_BaudRate = 115200 ; 
    USART_InitStruct.USART_WordLength = USART_WordLength_8b ;
    USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None ; 
    USART_InitStruct.USART_Mode = USART_Mode_Tx ;  //发送模式
    USART_InitStruct.USART_Parity = USART_Parity_No ; 
    USART_InitStruct.USART_StopBits = USART_StopBits_1 ;
    USART_Init(USART1, &USART_InitStruct);
    //使能USART1
    USART_Cmd(USART1, ENABLE);

}

/*******************************************
 * 函数:int fputc(int ch, FILE *f)
 * 功能:重定向C库函数printf到USART
 * 参数:ch - 要发送的字符
 *      f - 流指针,此处未使用
 * 返回值:发送的字符
 * 描述:此函数被C库函数printf调用,用于将字符发送到USART1。
 *       使用USART1作为printf的输出。当调用printf时,每个字符
 *       都会通过这个函数发送到USART1。
**********************************************/


int fputc(int ch , FILE*f)
{   
    USART_SendData(USART1, (uint8_t) ch) ; 
    while(USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET) ; //等待发送完成 一直为0 则一直循环 
    return ch ;
}

3.3 main.c

#include "stm32f4xx.h"
#include "USART.h" 


void delay(uint32_t time) ;
int main()
{     
          GPIO_init(); 
          USART_init(); 

          while(1) 
          {

            printf("hello world\r\n") ; 

          }

}

4. 关于printf函数,scanf函数 重定向问题

MicroLib是缺省c库的备选库,它可装入少量内存中,与嵌入式应用程序配合使用,且这些应用程序不在操作系统中运行。
在这里插入图片描述

  • 7
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要在STM32USART2上使用printf函数,需要先配置相关的GPIOUSART2的参数,然后再通过重定向标准输出流的方式将printf输出到USART2上。 以下是一个简单的示例代码: ``` #include "stm32f4xx.h" #include <stdio.h> void USART2_Init(void) { GPIO_InitTypeDef GPIO_InitStructure; USART_InitTypeDef USART_InitStructure; // 使能GPIOA和USART2的时钟 RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE); RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE); // 配置PA2为USART2的TX引脚 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; GPIO_Init(GPIOA, &GPIO_InitStructure); // 将PA2复用USART2的TX引脚 GPIO_PinAFConfig(GPIOA, GPIO_PinSource2, GPIO_AF_USART2); // 配置USART2的参数 USART_InitStructure.USART_BaudRate = 115200; USART_InitStructure.USART_WordLength = USART_WordLength_8b; USART_InitStructure.USART_StopBits = USART_StopBits_1; USART_InitStructure.USART_Parity = USART_Parity_No; USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; USART_InitStructure.USART_Mode = USART_Mode_Tx; USART_Init(USART2, &USART_InitStructure); // 使能USART2 USART_Cmd(USART2, ENABLE); // 将标准输出流重定向到USART2 // 注意:需要先在stdio.h中定义__io_putchar函数 // 例如:int __io_putchar(int ch) { USART_SendData(USART2, (uint8_t)ch); while (USART_GetFlagStatus(USART2, USART_FLAG_TC) == RESET); return ch; } stdout = &USART2; } int main(void) { USART2_Init(); // 使用printf输出字符串 printf("Hello, world!\r\n"); while (1) { // 主循环 } } ``` 需要注意的是,为了能够在printf使用float类型的输出,需要在工程属性中的C/C++ Build->Settings->Tool Settings->MCU Settings->Floating-point hardware选择Use 'printf' Floating Point.

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值