小言_互联网的博客

printf重定向

222人阅读  评论(0)

 

目录

 

一、printf重定向简介

1.1、fputc函数解析

1.1.1、0x01FF 解析

串口,最大支持数据位长度为9bit。(DATA) <= 0x1FF 是断言检测数据位是否不大于9bit     0001  1111 1111

1.1.2、宏定义的参数检查函数(  assert_param())

1.1.3、USART数据寄存器(DR)

1.1.4、USART结构框图

1.2、USART_GetFlagStatus()函数

 1.3、USART_ClearFlag()

二、printf函数格式

2.1、常用格式化规定字符:

三、编写printf重定向


一、printf重定向简介

c语言中printf函数默认输出设备是显示器,如果实现在串口或者LCD上显示,必须重定义标准库函数里面调用的输出设备定义的相关函数。

如:使用printf输出到串口,需要将fputc里面的输出指向串口,这一过程称为重定向。

 


  
  1. int fputc(int ch,FILE *p)  //  函数默认的,在使用printf函数时自动调用
  2. {
  3. USART_SendDate(USART1,(u8)ch);
  4. while(USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET);
  5. return ch;
  6. }
  7. // 此函数定义在stdio.h中,调用此函数需先导入stdio.h头文件

1.1、fputc函数解析

使用此函数需要导入stdio.h头文件

 

/**
  * @brief  Transmits single data through the USARTx peripheral.   通过USARTx外设传输单个数据
  * @param  USARTx: Select the USART or the UART peripheral.  选择USART或UART外设
  *   This parameter can be one of the following values:
  *   USART1, USART2, USART3, UART4 or UART5.
  * @param  Data: the data to transmit.                                            传输的数据
  * @retval None
  */
void USART_SendData(USART_TypeDef* USARTx, uint16_t Data)

/*

 

 

*/
{
  /* Check the parameters */
  assert_param(IS_USART_ALL_PERIPH(USARTx));

/*#define IS_USART_ALL_PERIPH(PERIPH) (((PERIPH) == USART1) || \
                                     ((PERIPH) == USART2) || \
                                     ((PERIPH) == USART3) || \
                                     ((PERIPH) == UART4) || \
                                     ((PERIPH) == UART5))

    USART1, USART2, USART3, UART4 or UART5

*/
  assert_param(IS_USART_DATA(Data)); 
   /*

#define IS_USART_DATA(DATA) ((DATA) <= 0x1FF)   // 串口,最大支持数据位长度为9bit。(DATA) <= 0x1FF 是断言检测数据位是否不大于9bit     0001  1111 1111

*/
  /* Transmit Data */
  USARTx->DR = (Data & (uint16_t)0x01FF);        Data  & 0000 0001 1111 1111
}

1.1.1、0x01FF 解析

十进制:  1*16*16 + 16*15 +15 =  511

                0*16*16*16(16的3次方) +   1*16*16(16平方)+15*16(F的十进制位15,16的一次方)+15*16的0次方

 二进制      0000 0001  1111  1111

                    左边的0000  可省略不改变其真值

八进制:

串口,最大支持数据位长度为9bit。(DATA) <= 0x1FF 是断言检测数据位是否不大于9bit     0001  1111 1111

 

1.1.2、宏定义的参数检查函数(  assert_param())

#ifdef  USE_FULL_ASSERT

/**
  * @brief  The assert_param macro is used for function's parameters check.
            assert参数宏用于函数的参数检查。
  * @param  expr: If expr is false, it calls assert_failed function which reports 
  *         the name of the source file and the source line number of the call 
  *         that failed. If expr is true, it returns no value.
            expr:如果expr为false,它将调用assert失败的函数,该函数返回失败调用的源文件的名称和源行号

            如果expr为真,则不返回任何值
  * @retval None
  */
  #define assert_param(expr) ((expr) ? (void)0 : assert_failed((uint8_t *)__FILE__, __LINE__))  // 调用失败
/* Exported functions ------------------------------------------------------- */
  void assert_failed(uint8_t* file, uint32_t line);                                                                 //  调用此函数  显示调用失败的文件  与代码行
#else
  #define assert_param(expr) ((void)0)                     // 调用成功
#endif /* USE_FULL_ASSERT */

1.1.3、USART数据寄存器(DR)

1.1.4、USART结构框图

 

1.2、USART_GetFlagStatus()函数


  
  1. /**
  2. * @brief Checks whether the specified USART flag is set or not.
  3. 检测设置的串口标志是否修改
  4. * @param USARTx: Select the USART or the UART peripheral.
  5. 选择串口或串口外设
  6. * This parameter can be one of the following values:
  7. 这个参数有以下值
  8. * USART1, USART2, USART3, UART4 or UART5.
  9. * @param USART_FLAG: specifies the flag to check.
  10. 检查设置标志
  11. * This parameter can be one of the following values:
  12. * @arg USART_FLAG_CTS: CTS Change flag (not available for UART4 and UART5)
  13. CTS 改变标志 (不适合于串口2和串口4)
  14. * @arg USART_FLAG_LBD: LIN Break detection flag
  15. Lin 中断检查标志
  16. * @arg USART_FLAG_TXE: Transmit data register empty flag
  17. 发送寄存器 空的标志
  18. * @arg USART_FLAG_TC: Transmission Complete flag
  19. 发送完成标志
  20. * @arg USART_FLAG_RXNE: Receive data register not empty flag
  21. 接收数据寄存器不为空的标志
  22. * @arg USART_FLAG_IDLE: Idle Line detection flag
  23. 空闲线路探测标志
  24. * @arg USART_FLAG_ORE: OverRun Error flag
  25. 覆盖错误标志
  26. * @arg USART_FLAG_NE: Noise Error flag
  27. 噪声错误标志
  28. * @arg USART_FLAG_FE: Framing Error flag
  29. 框架错误标志
  30. * @arg USART_FLAG_PE: Parity Error flag
  31. 奇偶校验错误标志
  32. * @retval The new state of USART_FLAG (SET or RESET).
  33. */
  34. FlagStatus USART_GetFlagStatus(USART_TypeDef* USARTx, uint16_t USART_FLAG)
  35. {
  36. FlagStatus bitstatus = RESET;
  37. /* Check the parameters */
  38. assert_param(IS_USART_ALL_PERIPH(USARTx));
  39. assert_param(IS_USART_FLAG(USART_FLAG));
  40. /* The CTS flag is not available for UART4 and UART5 */
  41. if (USART_FLAG == USART_FLAG_CTS)
  42. {
  43. assert_param(IS_USART_123_PERIPH(USARTx));
  44. }
  45. if ((USARTx->SR & USART_FLAG) != ( uint16_t)RESET) // SR状态寄存器
  46. {
  47. bitstatus = SET;
  48. }
  49. else
  50. {
  51. bitstatus = RESET;
  52. }
  53. return bitstatus;
  54. }

 

USART1->SR&0X40  !=set or reset

  •  串口1操作状态寄存器的第7位  置0或置1
  • stm32中很多标记位,只能硬件置1,软件写1是没有效果的,但是可以软件写0。

while(USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET);  // USART_FLAG_TXE 发送数据寄存器空标志位

 1.3、USART_ClearFlag()

功能:清除 USARTx 的待处理标志位。

注意:

  •  PE (Parity error 奇偶错误 ), FE (Framing error帧错误), NE (Noise error噪声错误), ORE (OverRun    error 溢出错误) and IDLE (Idle line detected  检测到空闲线路错误) flags are cleared by software sequence: a read operation to USART_SR register (USART_GetFlagStatus())    followed by a read operation to USART_DR register (USART_ReceiveData()).  - RXNE flag can be also cleared by a read to the USART_DR register  (USART_ReceiveData()).
  • PE (Parity error), FE (Framing error), NE (Noise error), ORE (OverRun error)和IDLE (IDLE line detected)标志被软件序列清除:一个读操作到USART SR寄存器(USART GetFlagStatus()),然后一个读操作到USART DR。
  • TC标志也可以通过软件序列清除:一个到USART SR寄存器的读操作(USART GetFlagStatus()),接着一个到USART DR寄存器的写操作(USART SendData())。
  • TXE标志仅通过写入USART DR寄存器来清除 (USART SendData())。

  
  1. /**
  2. * @brief Clears the USARTx's pending flags.
  3. * @param USARTx: Select the USART or the UART peripheral.
  4. * This parameter can be one of the following values:
  5. * USART1, USART2, USART3, UART4 or UART5.
  6. * @param USART_FLAG: specifies the flag to clear.
  7. * This parameter can be any combination of the following values:
  8. * @arg USART_FLAG_CTS: CTS Change flag (not available for UART4 and UART5).
  9. * @arg USART_FLAG_LBD: LIN Break detection flag.
  10. * @arg USART_FLAG_TC: Transmission Complete flag.
  11. * @arg USART_FLAG_RXNE: Receive data register not empty flag.
  12. *
  13. * @note
  14. * - PE (Parity error), FE (Framing error), NE (Noise error), ORE (OverRun
  15. * error) and IDLE (Idle line detected) flags are cleared by software
  16. * sequence: a read operation to USART_SR register (USART_GetFlagStatus())
  17. * followed by a read operation to USART_DR register (USART_ReceiveData()).
  18. * - RXNE flag can be also cleared by a read to the USART_DR register
  19. * (USART_ReceiveData()).
  20. * - TC flag can be also cleared by software sequence: a read operation to
  21. * USART_SR register (USART_GetFlagStatus()) followed by a write operation
  22. * to USART_DR register (USART_SendData()).
  23. * - TXE flag is cleared only by a write to the USART_DR register
  24. * (USART_SendData()).
  25. * @retval None
  26. */
  27. void USART_ClearFlag(USART_TypeDef* USARTx, uint16_t USART_FLAG)
  28. {
  29. /* Check the parameters */
  30. assert_param(IS_USART_ALL_PERIPH(USARTx));
  31. assert_param(IS_USART_CLEAR_FLAG(USART_FLAG));
  32. /* The CTS flag is not available for UART4 and UART5 */
  33. if ((USART_FLAG & USART_FLAG_CTS) == USART_FLAG_CTS)
  34. {
  35. assert_param(IS_USART_123_PERIPH(USARTx));
  36. }

二、printf函数格式

printf("<格式化字符串>",<参量表>)

 

2.1、常用格式化规定字符:

  • %d   按照十进制整形数打印
  • %6d  按照十进制整形数打印,至少6个字符宽
  • %f     按照浮点数打印
  • %6f  按照浮点数打印,至少6个字符宽
  • %.2f  按照浮点数打印,小数点后2位小数
  • %6.2f 按照浮点数打印,至少6个字符宽,小数点后有2位小数
  • %x  按照十六进制打印
  • %c  打印字符
  • %s  打印字符串

 

三、编写printf重定向

初始化 USART1 后,就需要将 fputc 里面的输出指向 STM32 的串口

   
  1. int fputc(int ch,FILE *p) //函数默认的,在使用printf函数时自动调用
  2. {
  3. USART_SendData(USART1,(u8)ch);
  4. while(USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET); // USART_FLAG_TXE 发送数据寄存器空标志位
  5. return ch;
  6. }
当使用 printf 函数时,自动会调用 fputc 函数,而 fputc 函数内又将输出 设备重定义为 STM32 的 USART1,所以要输出的数据就会在串口 1 上输出
 
使用printf函数的keil配置 
 
 
 
主函数

    
  1. #include "system.h"
  2. #include "SysTick.h"
  3. #include "led.h"
  4. #include "usart.h"
  5. /*******************************************************************************
  6. * 函 数 名 : main
  7. * 函数功能 : 主函数
  8. * 输 入 : 无
  9. * 输 出 : 无
  10. *******************************************************************************/
  11. int main()
  12. {
  13. u8 i= 0;
  14. u16 data= 1234;
  15. float fdata= 12.34;
  16. char str[]= "Hello World!";
  17. SysTick_Init( 72);
  18. NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //中断优先级分组 分2组
  19. LED_Init();
  20. USART1_Init( 115200);
  21. while( 1)
  22. {
  23. i++;
  24. if(i% 50== 0)
  25. {
  26. LED1=!LED1;
  27. printf( "输出整型数data=%d\r\n",data);
  28. printf( "输出浮点型数fdata=%0.2f\r\n",fdata);
  29. printf( "输出十六进制数data=%X\r\n",data);
  30. printf( "输出八进制数data=%o\r\n",data);
  31. printf( "输出字符串str=%s\r\n",str);
  32. }
  33. delay_ms( 10); // i每次自加的延时时间 500ms LED状态翻转一次 50*10ms = 500ms
  34. }
  35. }

usart .c


    
  1. #include "usart.h"
  2. int fputc(int ch,FILE *p) //函数默认的,在使用printf函数时自动调用
  3. {
  4. USART_SendData(USART1,(u8)ch);
  5. while(USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET); // USART_FLAG_TXE 发送数据寄存器空标志位
  6. return ch;
  7. }
  8. //串口1中断服务程序
  9. //注意,读取USARTx->SR能避免莫名其妙的错误
  10. u8 USART1_RX_BUF[USART1_REC_LEN]; //接收缓冲,最大USART_REC_LEN个字节.
  11. //接收状态
  12. //bit15, 接收完成标志
  13. //bit14, 接收到0x0d
  14. //bit13~0, 接收到的有效字节数目
  15. u16 USART1_RX_STA= 0; //接收状态标记
  16. /*******************************************************************************
  17. * 函 数 名 : USART1_Init
  18. * 函数功能 : USART1初始化函数
  19. * 输 入 : bound:波特率
  20. * 输 出 : 无
  21. *******************************************************************************/
  22. void USART1_Init(u32 bound)
  23. {
  24. //GPIO端口设置
  25. GPIO_InitTypeDef GPIO_InitStructure;
  26. USART_InitTypeDef USART_InitStructure;
  27. NVIC_InitTypeDef NVIC_InitStructure;
  28. RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
  29. RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);
  30. /* 配置GPIO的模式和IO口 */
  31. GPIO_InitStructure.GPIO_Pin=GPIO_Pin_9; //TX //串口输出PA9
  32. GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
  33. GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP; //复用推挽输出
  34. GPIO_Init(GPIOA,&GPIO_InitStructure); /* 初始化串口输入IO */
  35. GPIO_InitStructure.GPIO_Pin=GPIO_Pin_10; //RX //串口输入PA10
  36. GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING; //模拟输入
  37. GPIO_Init(GPIOA,&GPIO_InitStructure); /* 初始化GPIO */
  38. //USART1 初始化设置
  39. USART_InitStructure.USART_BaudRate = bound; //波特率设置
  40. USART_InitStructure.USART_WordLength = USART_WordLength_8b; //字长为8位数据格式
  41. USART_InitStructure.USART_StopBits = USART_StopBits_1; //一个停止位
  42. USART_InitStructure.USART_Parity = USART_Parity_No; //无奇偶校验位
  43. USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; //无硬件数据流控制
  44. USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; //收发模式
  45. USART_Init(USART1, &USART_InitStructure); //初始化串口1
  46. USART_Cmd(USART1, ENABLE); //使能串口1
  47. USART_ClearFlag(USART1, USART_FLAG_TC);
  48. USART_ITConfig(USART1, USART_IT_RXNE, ENABLE); //开启相关中断
  49. //Usart1 NVIC 配置
  50. NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn; //串口1中断通道
  51. NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority= 3; //抢占优先级3
  52. NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; //子优先级3
  53. NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道使能
  54. NVIC_Init(&NVIC_InitStructure); //根据指定的参数初始化VIC寄存器、
  55. }
  56. /*******************************************************************************
  57. * 函 数 名 : USART1_IRQHandler
  58. * 函数功能 : USART1中断函数
  59. * 输 入 : 无
  60. * 输 出 : 无
  61. *******************************************************************************/
  62. void USART1_IRQHandler(void) //串口1中断服务程序
  63. {
  64. u8 r;
  65. if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) //接收中断
  66. {
  67. r =USART_ReceiveData(USART1); //(USART1->DR); //读取接收到的数据
  68. if((USART1_RX_STA& 0x8000)== 0) //接收未完成
  69. {
  70. if(USART1_RX_STA& 0x4000) //接收到了0x0d
  71. {
  72. if(r!= 0x0a)USART1_RX_STA= 0; //接收错误,重新开始
  73. else USART1_RX_STA|= 0x8000; //接收完成了
  74. }
  75. else //还没收到0X0D
  76. {
  77. if(r== 0x0d)USART1_RX_STA|= 0x4000;
  78. else
  79. {
  80. USART1_RX_BUF[USART1_RX_STA& 0X3FFF]=r;
  81. USART1_RX_STA++;
  82. if(USART1_RX_STA>(USART1_REC_LEN -1))USART1_RX_STA= 0; //接收数据错误,重新开始接收
  83. }
  84. }
  85. }
  86. }
  87. }

usart.h


    
  1. #ifndef _usart_H
  2. #define _usart_H
  3. #include "system.h"
  4. #include "stdio.h"
  5. #define USART1_REC_LEN 200 //定义最大接收字节数 200
  6. extern u8 USART1_RX_BUF[USART1_REC_LEN]; //接收缓冲,最大USART_REC_LEN个字节.末字节为换行符
  7. extern u16 USART1_RX_STA; //接收状态标记
  8. void USART1_Init(u32 bound);
  9. #endif

 

 


转载:https://blog.csdn.net/RONG_YAO/article/details/115746940
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场