STM32 printf函数重定向到USATR1输出打印

printf重定向

  • fputc函数实现
  • 使用 Use MicroLIB

usart.h

复制代码
#ifndef __USART_H
#define __USART_H

#include "system.h"
#include "stdio.h"  //要实现int fputc(int ch,FILE *p) 原型,需要包含该头文件

void USART1_Init(u32 bound);

#endif

usart.c

复制代码
#include "usart.h"

int fputc(int ch,FILE *p)  //函数默认的,函数原型不能改变,在使用printf函数时自动调用
{
	USART_SendData(USART1,(u8)ch);	
	while(USART_GetFlagStatus(USART1,USART_FLAG_TXE) == RESET); //USART_FLAG_TXE状态标志表示可以发送下一个数据了,发送数据寄存器已经空了(发送移位寄存器数据可能没有发完)
	return ch;
}

//bound:参数为输入波特率
void USART1_Init(u32 bound)
{
	GPIO_InitTypeDef MY_GPIO_Init; //定义结构体变量
	USART_InitTypeDef USART_InitStructure; 
	NVIC_InitTypeDef NVIC_InitStructure;
	
	//默认引脚 PA9/PA10,没有重映射 → 不需要使能 AFIO 时钟!
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE); //使能串口1时钟
	
	MY_GPIO_Init.GPIO_Pin = GPIO_Pin_9; //TX -- PA9
	MY_GPIO_Init.GPIO_Mode = GPIO_Mode_AF_PP; //设置复用推挽输出模式
	MY_GPIO_Init.GPIO_Speed = GPIO_Speed_50MHz; //设置传输速率
	GPIO_Init(GPIOA, &MY_GPIO_Init); 	 

	MY_GPIO_Init.GPIO_Pin = GPIO_Pin_10; //RX -- PA10
	MY_GPIO_Init.GPIO_Mode = GPIO_Mode_IN_FLOATING; //设置浮空输入
	MY_GPIO_Init.GPIO_Speed = GPIO_Speed_50MHz; //设置传输速率
	GPIO_Init(GPIOA, &MY_GPIO_Init); 

	
	USART_InitStructure.USART_BaudRate = bound; //设置波特率
	USART_InitStructure.USART_WordLength = USART_WordLength_8b; //设置数据位为8位 
	USART_InitStructure.USART_StopBits = USART_StopBits_1; //设置停止位为1位
	USART_InitStructure.USART_Parity = USART_Parity_No; //无奇偶校验
	USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; //无硬件流控 
	USART_InitStructure.USART_Mode = USART_Mode_Tx | USART_Mode_Rx; //发送使能和接收使能
	USART_Init(USART1, &USART_InitStructure);	
	USART_Cmd(USART1, ENABLE); //使能 USART1串口
	
	//清除USART_FLAG_TC发送完成标志位,这个是状态标志位,并非中断标志位
	USART_ClearFlag(USART1, USART_FLAG_TC); //清除USART_FLAG_TC发送完成标志位
	
	//设置串口中断类型并使能
	//USART_IT_RXNE ------ 接收数据寄存器非空中断,"我收到了一个字节数据,已经放进接收寄存器了,快来读!"
	USART_ITConfig(USART1, USART_IT_RXNE, ENABLE); //我们选择的是接收中断
	
	NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn; //在"stm32f10x.h"查看
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2; 
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; 
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;	//IRQ通道使能
	NVIC_Init(&NVIC_InitStructure);	
}

void USART1_IRQHandler(void)
{
	u8 data = 0;
	
	if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) //串口接收中断标志位,检查指定的 USART 中断发生与否,当调用接收函数时会被自动清除。
	{
		//当你调用 USART_ReceiveData() 读取数据时,硬件会自动清除 USART_IT_RXNE!
		data = USART_ReceiveData(USART1);
		USART_SendData(USART1, data); //将接收的数据发送出去
		//USART_FLAG_TC发送完成标志位,表示当移位寄存器的最后一位数据被发送到 TX 引脚,且总线空闲时,才置 1。表示数据已经完全发完,总线已经空闲。
		//USART_FLAG_TXE发送数据寄存器空,当 TDR 寄存器的数据被转移到移位寄存器后,立刻置 1,表示 "我可以写下一个数据了"。
		while(USART_GetFlagStatus(USART1,USART_FLAG_TC) != SET); //USART_FLAG_TC发送完成标志位
		//while(USART_GetITStatus(USART1, USART_FLAG_TC) != SET); //开始错用了这个函数,导致中断程序在这里卡死!!!
	}
	USART_ClearFlag(USART1, USART_FLAG_TC); //清除USART_FLAG_TC发送完成标志位,这个是状态标志位,并非中断标志位
}	

main.c

复制代码
#include "system.h"  //已经包含了"stm32f10x.h" 以及定义了位带操作的宏,后续只包含该头文件就可以了
#include "SysTick.h" //使用delay_ms和delay_us
#include "usart.h"
#include "led.h" //需要调用Led_Init()对8个LED GPIO初始化
#include "stdio.h" //使用printf函数时需要包含

//这里不用定义SystemInit函数,是因为在system_stm32f10x.c中已有实现

int main()
{
	u8 i = 0;
	u16 j = 0;
	u16 data = 1234;
	float fdata=12.34;
	char str[]="Hello World!";	
	
	SysTick_Init(72); //72为SYSCLK delay_ms延时函数需要使用
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //设置中断分组2:2 在使用中断回调函数时都需要调用
	Led_Init();
	USART1_Init(9600); //在之后才能使用printf函数
	
	while(1)
	{
		i++;
		if(i%20 == 0)
		{
			PCout(4) = !PCout(4); //LED5状态取反 20*10ms = 200ms
			
			j++;
			if(j%25 == 0) //5S打印一次
			{
				printf("打印整数类型 data = %d\r\n", data);
				printf("打印浮点数 fdata = %f\r\n", fdata);
				printf("打印字符串 str = %s\r\n", str);
			}
		}
		delay_ms(10);	
	}	
}

现象,每间隔5S打印一次,如图:

相关推荐
广州灵眸科技有限公司7 小时前
瑞芯微(EASY EAI)RV1126B 核心板供电电路
linux·运维·服务器·单片机·嵌入式硬件·电脑
浩浩测试一下7 小时前
汇编 16位32位64位通用寄存器(逆向分析)
汇编·windows·stm32·单片机·嵌入式硬件·逆向·二进制
潜创微科技9 小时前
IT68353:双 DP1.4a+HDMI2.0 转 HDMI2.0 单芯片 KVM 切换方案
嵌入式硬件·音视频
踏着七彩祥云的小丑10 小时前
嵌入式测试学习第 17 天:常见接口:USB、Type-C、排针
单片机·嵌入式硬件
szxinmai主板定制专家11 小时前
电力设备RK3568/RK3576+FPGA,多系统混合部署Linux+RTOS RT-THREAD,强实时性
linux·运维·服务器·人工智能·嵌入式硬件·fpga开发
振南的单片机世界12 小时前
EXTI边沿触发:按键一按就通知CPU,不用轮询
stm32·单片机·嵌入式硬件
jllllyuz12 小时前
STM32 BMP280 I2C通信驱动程序
stm32·单片机·嵌入式硬件
优信电子13 小时前
基于STM32F103C8T6单片机驱动ACS712模块进行电流检测
stm32·单片机·嵌入式硬件·嵌入式·电流检测·acs712·电流采集
崇山峻岭之间14 小时前
单片机外部中断实验
单片机·嵌入式硬件
chipsense14 小时前
工业UPS电流传感器选型实战指南:AS1V系列如何应对工业配电特殊挑战
单片机·嵌入式硬件·ups·电流传感器