stm32学习笔记-重定向printf()函数

前言

在C语言标准库中,printf()拥有十分强大的输出能力,可以输出各种类型的数据,整型、浮点型、8进制、16进制、换行符,缩进符等等。

printf()是把数据输出到屏幕,但是ARM芯片中没有屏幕,我们设想将printf()打印到串口,这样我们就可以通过printf()和串口实时的观察ARM芯片内部的工作情况,运行结果。

printf()在stdio.lib库中实现,stdio.lib依赖于FILE文件流,_sys_exit,_sys_open,int fputc(int ch,FILE *f)。
我们把 int fputc(int ch,FILE *f) 这个函数重定向,把输出的数据重定向到串口,这样我们可以在PC端的串口助手查看各种调试的情况,运行的结果。

一、底层函数改写

具体原理不清楚,大概思路就是:不把fputc()的参数 int ch 送至 FILE *f 中,而是送到串口1。
代码如下

int fputc(int ch,FILE *f)
{
	//将ch送给USART1
	USART_SendData(USART1,ch);
	//等待发送完毕
	while(USART_GetFlagStatus(USART1,USART_FLAG_TXE) == RESET);
	//返回ch
	return ch;
}

二、仿真编程

1.仿真main.c代码

#include "stm32f10x.h"
#include <stdio.h>

typedef unsigned          char u8;
typedef unsigned short     int u16;
typedef unsigned           int u32;

/*****************************************************************************************
* Function Name : fputc
* Descrption    : 重定向这个C库(stdio) printf函数 文件流->串口USART1
* Input					: ch ,*f
* Output				: None
* Return				: None 
*****************************************************************************************/
int fputc(int ch,FILE *f)
{
	//将ch送给USART1
	USART_SendData(USART1,ch);
	//等待发送完毕
	while(USART_GetFlagStatus(USART1,USART_FLAG_TXE) == RESET);
	//返回ch
	return ch;
}


void Stm32_Clock_Init(void)
{
	/*----------使用外部RC晶振----------*/
	RCC_DeInit() ;
	//初始化为缺省值
	RCC_HSEConfig(RCC_HSE_ON); //使 能外部的高速时钟
	while (RCC_GetFlagStatus(RCC_FLAG_HSERDY) == RESET); //等 待外部高速时钟使能就绪
	
	//Flash 2 wait state
	RCC_HCLKConfig (RCC_SYSCLK_Div1) ;
	//HCLK = SYSCLK
	RCC_PCLK2Config(RCC_HCLK_Div1) ;
	//PCLK2 =HCLK
	RCC_PCLK1Config(RCC_HCLK_Div2) ;
	//PCLK1 = HCLR/2
	RCC_PLLConfig (RCC_PLLSource_HSE_Div1, RCC_PLLMul_9); //PLLCLK = 8MHZ * 9 =72MHZ
	RCC_PLLCmd(ENABLE) ;
	//Enable PLLCLK
	while (RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET); //Wait till PLLCLK is ready
	RCC_SYSCLKConfig (RCC_SYSCLKSource_PLLCLK) ;
	//Select PLL as system clock
	while (RCC_GetSYSCLKSource () !=0x08) ;
	//wait till PLL is used as system clock source

	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_USART1,ENABLE);
}

void GPIO_Config()
{
	GPIOA->CRH&=0XFFFFF00F;//IO状态设置
	GPIOA->CRH|=0X000008B0;//IO状态设置,1000复用推挽输出
}

void USART_Config(u32 BaudRate)
{
	USART_InitTypeDef USARTST;
	USARTST.USART_WordLength = USART_WordLength_9b;
	USARTST.USART_StopBits = USART_StopBits_1;
	USARTST.USART_Parity = USART_Parity_No;
	USARTST.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
	USARTST.USART_Mode = USART_Mode_Tx|USART_Mode_Rx;
	USARTST.USART_BaudRate = BaudRate;
	USART_Init(USART1,&USARTST);//配置USART1
	USART_Cmd(USART1,ENABLE);//使能USART1
	
}

int main(void)
{
	u8 i;
	Stm32_Clock_Init();
	GPIO_Config();
	USART_Config(9600);

	printf("https://blog.csdn.net/weixin_43871650\n");
	for(i=0;i<10;i++)
	{
		printf("\ti value is %d.\n",i);
	}
	return 0;
}

2.仿真结果。

进入软件调试后,打开串口#1查看器。
在这里插入图片描述
仿真结果如下。
在这里插入图片描述

三、硬件编程

1.了解硬件

电路图如下,不知道原理是什么。简单来说,就是TXD,RXD通过P3与PA10,PA9连接起来。
在这里插入图片描述
在这里插入图片描述

2.main.c代码:

代码与之前的重定向代码相同。

#include "stm32f10x.h"
#include <stdio.h>

typedef unsigned          char u8;
typedef unsigned short     int u16;
typedef unsigned           int u32;

/*****************************************************************************************
* Function Name : fputc
* Descrption    : 重定向这个C库(stdio) printf函数 文件流->串口USART1
* Input					: ch ,*f
* Output				: None
* Return				: None 
*****************************************************************************************/
int fputc(int ch,FILE *f)
{
	//将ch送给USART1
	USART_SendData(USART1,ch);
	//等待发送完毕
	while(USART_GetFlagStatus(USART1,USART_FLAG_TXE) == RESET);
	//返回ch
	return ch;
}


void Stm32_Clock_Init(void)
{
	/*----------使用外部RC晶振----------*/
	RCC_DeInit() ;
	//初始化为缺省值
	RCC_HSEConfig(RCC_HSE_ON); //使 能外部的高速时钟
	while (RCC_GetFlagStatus(RCC_FLAG_HSERDY) == RESET); //等 待外部高速时钟使能就绪
	
	//Flash 2 wait state
	RCC_HCLKConfig (RCC_SYSCLK_Div1) ;
	//HCLK = SYSCLK
	RCC_PCLK2Config(RCC_HCLK_Div1) ;
	//PCLK2 =HCLK
	RCC_PCLK1Config(RCC_HCLK_Div2) ;
	//PCLK1 = HCLR/2
	RCC_PLLConfig (RCC_PLLSource_HSE_Div1, RCC_PLLMul_9); //PLLCLK = 8MHZ * 9 =72MHZ
	RCC_PLLCmd(ENABLE) ;
	//Enable PLLCLK
	while (RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET); //Wait till PLLCLK is ready
	RCC_SYSCLKConfig (RCC_SYSCLKSource_PLLCLK) ;
	//Select PLL as system clock
	while (RCC_GetSYSCLKSource () !=0x08) ;
	//wait till PLL is used as system clock source

	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_USART1,ENABLE);
}

void GPIO_Config()
{
	GPIOA->CRH&=0XFFFFF00F;//IO状态设置
	GPIOA->CRH|=0X000008B0;//IO状态设置,1000复用推挽输出
}

void USART_Config(u32 BaudRate)
{
	USART_InitTypeDef USARTST;
	USARTST.USART_WordLength = USART_WordLength_9b;
	USARTST.USART_StopBits = USART_StopBits_1;
	USARTST.USART_Parity = USART_Parity_No;
	USARTST.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
	USARTST.USART_Mode = USART_Mode_Tx|USART_Mode_Rx;
	USARTST.USART_BaudRate = BaudRate;
	USART_Init(USART1,&USARTST);//配置USART1
	USART_Cmd(USART1,ENABLE);//使能USART1
	
}

int main(void)
{
	u8 i;
	Stm32_Clock_Init();
	GPIO_Config();
	USART_Config(9600);

	printf("https://blog.csdn.net/weixin_43871650\n");
	for(i=0;i<10;i++)
	{
		printf("\ti value is %d.\n",i);
	}
	return 0;
}

3.打开串口助手查看结果。

注意:先进入调试后打开串口助手。不然会有bug,导致调试不能进入main函数。
在这里插入图片描述

四、注意勾选MicroLib

勾选MicroLib,仿真调试才能正常运行。
在这里插入图片描述

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在使用STM32printf函数时,可以通过重定向来将其输出重定向到串口或其他输出设备上。这样可以方便地在开发过程中通过串口输出调试信息。 首先,需要在代码中定义一个文件描述符,并重写该文件描述符的_write函数。在这个函数中,可以将要输出的字符通过串口发送出去。 以下是一个使用USART1作为串口输出的示例代码: ```c #include "stdio.h" // 重写文件描述符的 _write 函数 int _write(int file, char *ptr, int len) { for (int i = 0; i < len; i++) { // 将字符发送到串口 USART_SendData(USART1, (uint8_t) *ptr++); // 等待发送完毕 while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET); } return len; } int main(void) { // 初始化串口 USART_InitTypeDef USART_InitStructure; USART_InitStructure.USART_BaudRate = 9600; 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(USART1, &USART_InitStructure); USART_Cmd(USART1, ENABLE); // 使用printf输出 printf("Hello, world!\n"); while (1) { // 其他操作 } } ``` 在这个例子中,我们将USART1作为串口输出设备,并将printf函数的输出重定向到USART1。需要注意的是,在使用重定向后,printf函数会比较耗费资源,因此在实际应用中要谨慎使用。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值