STM32重载printf

前一段时间工作中进行软件调试的时候,将写的程序烧到芯片中,最终总是达不到预期的效果,甚至是就不工作,也不知道具体死在了哪里,这是硬件调试根本查不出来的地方(单步调试又太慢),想起在LINUX开发的时候用到的printf()函数,在合适的地方添加打印信息,并将其打印到终端上,能够很方便的定位到出错的地方,在网上一查果然在STM32中也可以通过某种啥藕断==

对于printf()函数,大家都不陌生,printf()函数是格式化输出函数,一般用于向标准设备按规定格式输出信息,于是终端(显示器、控制台等)输出字符,格式控制由要输出的字符和数据格式组成。要输出的字符除了可以使字母、数字、空格和一些字符号以外,还可以使用转义字符表示特殊的含义。

在STM32中不能够直接使用printf()函数,所以在做嵌入式的开发的时候,虽然可以进行JTAGE调试与软件的仿真,但是有时候还是比较的麻烦,所以这里要对printf()函数进行重定位,以便开发调试人员在STM32的嵌入式的开发的时候调试更加的方便 。

首先初始化一个串口,这里我使用的库函数初始化的USART1

/************************************************
函数名称 : USART_GPIO_Configuration
功    能 : USART所使用管脚输出输入定义
参    数 : 无
返 回 值 : 无
*************************************************/
void USART_GPIO_Configuration(void)
{
  GPIO_InitTypeDef GPIO_InitStructure;

  /* 定义 USART-TX 引脚为复用输出 */
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;                          //IO口的第9脚
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;                  //IO口速度
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;                    //IO口复用推挽输出
  GPIO_Init(GPIOA, &GPIO_InitStructure);                             //USART输出IO口

  /* 定义 USART-Rx 引脚为悬空输入 */
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;                         //IO口的第10脚
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;              //IO口悬空输入
  GPIO_Init(GPIOA, &GPIO_InitStructure);                             //USART输入IO口
}

/************************************************
函数名称 : USART_Configuration
功    能 : 配置USART
参    数 : 无
返 回 值 : 无
*************************************************/
void USART_Configuration(void)
{
  USART_InitTypeDef USART_InitStructure;
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_USART1, ENABLE);    //开启时钟

  /******************************************************************
   USART参数初始化:  波特率     传输位数   停止位数  校验位数
                    115200         8          1      0(NO)
  *******************************************************************/
  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_Rx | USART_Mode_Tx;    //使用接收和发送功能
  USART_Init(USART1, &USART_InitStructure);                          //初始化USART1

  USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);                     //使能USART1接收中断

  USART_Cmd(USART1, ENABLE);                                         //使能USART1
}

然后将标准库函数中的fputc(),与fgetc()函数重定位到USART1上去,方法如下:

/************************************************
函数名称 : fputc
功    能 : 重定义putc函数
参    数 : ch --- 字符
            *f --- 文件指针
返 回 值 : 字符
*************************************************/
int fputc(int ch, FILE *f)
{
  while((USART1->SR & USART_FLAG_TXE) == RESET);
  USART1->DR = (ch & (uint16_t)0x01FF);
  return ch;
}

/************************************************
函数名称 : fgetc
功    能 : 重定义getc函数
参    数 : *f --- 文件指针
返 回 值 : 字符
*************************************************/
int fgetc(FILE *f)
{
  while(USART_GetFlagStatus(USART1, USART_FLAG_RXNE) == RESET);

  return (int)USART_ReceiveData(USART1);
}

当然做完这两步还是不够的,需要添加如下代码,以支持printf()函数,(这里具体为什么要添加这些代码,我也不甚清楚,望各位博友拍砖)

//加入以下代码,支持printf函数,而不需要选择use MicroLIB(在魔术棒,target)	  
#pragma import(__use_no_semihosting)             
//标准库需要的支持函数                 
struct __FILE 
{ 
	int handle; 
	/* Whatever you require here. If the only file you are using is */ 
	/* standard output using printf() for debugging, no file handling */ 
	/* is required. */ 
}; 
/* FILE is typedef’ d in stdio.h. */ 
FILE __stdout;       
//定义_sys_exit()以避免使用半主机模式    
_sys_exit(int x) 
{ 
	x = x; 
} 

上面三步完成之后,就可通过串口助手将printf()函数中的信息答应在屏幕上啦。

注:以上是参看博友的博客,再根据自己的理解总结的。


猜你喜欢

转载自blog.csdn.net/david_361/article/details/79836647