前言
在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,仿真调试才能正常运行。