[应用相关] stm32学习笔记----双串口同时打开时的printf()问题

[复制链接]
 楼主| operating 发表于 2019-6-18 10:37 | 显示全部楼层 |阅读模式
最近因为要使用串口2外接PN532芯片实现通信,另一方面,要使用串口1来将一些提示信息输出到上位机,于是重定义了printf(),使其将打印的信息重定向至串口1。但是当在程序中调用printf()时,却发现上位机无论如何都接收不到信息,而且printf()之后的语句也不再执行,想必程序在printf()函数里面死掉了吧。当时觉得很纳闷,因为单独只使用一个串口时,printf()是没有问题的。
 楼主| operating 发表于 2019-6-18 10:37 | 显示全部楼层
往下说之前,先贴一下双串口的配置和printf()的书写,mark一下。
  1. void USART_Config()
  2. {
  3.     GPIO_InitTypeDef GPIO_InitStructure;
  4.     USART_InitTypeDef USART_InitStructure;
  5.     //配置串口1时钟
  6.     RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA, ENABLE);
  7.     //配置串口2时钟,使用复用功能,打开AFIO,管脚重映射到PD5,PD6
  8.     RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
  9.     RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);
  10.    GPIO_PinRemapConfig(GPIO_Remap_USART2, ENABLE);
  11.     RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD, ENABLE);
  12.    
  13.     /*配置串口1(USART1 Tx(PA.09))*/
  14.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
  15.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
  16.     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  17.     GPIO_Init(GPIOA, &GPIO_InitStructure);   
  18.     /* 配置串口1(USART1 Tx(PA.10))*/
  19.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
  20.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
  21.     GPIO_Init(GPIOA, &GPIO_InitStructure);
  22.    
  23.         /*串口1工作模式(USART1 mode)配置 */
  24.     USART_InitStructure.USART_BaudRate = 115200;
  25.     USART_InitStructure.USART_WordLength = USART_WordLength_8b;
  26.     USART_InitStructure.USART_StopBits = USART_StopBits_1;
  27.     USART_InitStructure.USART_Parity = USART_Parity_No ;
  28.     USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
  29.     USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
  30.     USART_Init(USART1, &USART_InitStructure);
  31.     USART_Cmd(USART1, ENABLE);//使能串口
  32.    
  33.     /*配置串口2(USART2 Tx(PD.05))*/
  34.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;
  35.     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  36.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
  37.     GPIO_Init(GPIOD, &GPIO_InitStructure);
  38.    
  39.     /*配置串口2(USART2 Tx(PD.05))*/
  40.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
  41.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
  42.     GPIO_Init(GPIOD, &GPIO_InitStructure);
  43.    
  44.     /*串口2工作模式(USART2 mode)配置 */
  45.    
  46.     USART_InitStructure.USART_BaudRate = 115200;
  47.     USART_InitStructure.USART_WordLength = USART_WordLength_8b;
  48.     USART_InitStructure.USART_StopBits = USART_StopBits_1;
  49.     USART_InitStructure.USART_Parity = USART_Parity_No;
  50.     USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
  51.     USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;   

  52.     USART_Init(USART2, &USART_InitStructure);
  53.     USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);
  54.     USART_Cmd(USART2, ENABLE);
  55.    
  56.     NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
  57.               /*串口2中断配置*/                                
  58.     NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;
  59.     NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority =2;
  60.     NVIC_InitStructure.NVIC_IRQChannelSubPriority =2;
  61.     NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  62.     NVIC_Init(&NVIC_InitStructure);
  63. }

  64. /*printf()函数重定向*/
  65. int fputc(int ch, FILE *f)
  66. {
  67.     //将printf()内容发往串口1
  68.     USART_SendData(USART1, (unsigned char) ch);
  69.     while( USART_GetFlagStatus(USART1,USART_FLAG_TC)!= SET);   
  70.     return (ch);
  71. }
 楼主| operating 发表于 2019-6-18 10:38 | 显示全部楼层
当只开串口1时,printf()是可以正常使用的,但是同时使用串口1和串口2时,使用printf()就会输出不了信息,并且程序无法往下执行;但如果不用printf()函数,而直接使用USART_SendData(USART1,(unsigned char) ch)时,串口1也能正常打印;但这样太麻烦辣,每次打印一个字符。
 楼主| operating 发表于 2019-6-18 10:38 | 显示全部楼层
于是网上查了一下,也有人遇到类似问题,而后评论下方有一个函数,说是可以双串口同时打开时,也可以一次性打印一串信息。抱着试一试的心态,将函数程序搬到我的工程中,没想到,还真行。下面贴出代码:
  1. /*
  2. * 函数名:itoa
  3. * 描述  :将整形数据转换成字符串
  4. * 输入  :-radix =10 表示10进制,其他结果为0
  5. *         -value 要转换的整形数
  6. *         -buf 转换后的字符串
  7. *         -radix = 10
  8. * 输出  :无
  9. * 返回  :无
  10. * 调用  :被USART_printf()调用
  11. */
  12. static char *itoa(int value, char *string, int radix)
  13. {
  14.         int     i, d;
  15.         int     flag = 0;
  16.         char    *ptr = string;

  17.     /* This implementation only works for decimal numbers. */
  18.         if (radix != 10)
  19.         {
  20.             *ptr = 0;
  21.             return string;
  22.         }

  23.         if (!value)
  24.         {
  25.             *ptr++ = 0x30;
  26.             *ptr = 0;
  27.             return string;
  28.         }

  29.     /* if this is a negative value insert the minus sign. */
  30.         if (value < 0)
  31.         {
  32.             *ptr++ = '-';

  33.             /* Make the value positive. */
  34.             value *= -1;
  35.         }

  36.         for (i = 10000; i > 0; i /= 10)
  37.        {
  38.             d = value / i;

  39.             if (d || flag)
  40.             {
  41.                 *ptr++ = (char)(d + 0x30);
  42.                 value -= (d * i);
  43.                 flag = 1;
  44.             }
  45.         }

  46.         /* Null terminate the string. */
  47.         *ptr = 0;

  48.         return string;

  49. }

  50. /*
  51. * 函数名:USART_printf
  52. * 描述  :格式化输出,类似于C库中的printf,但这里没有用到C库
  53. * 输入  :-USARTx 串口通道
  54. *                     -Data   要发送到串口的内容的指针
  55. *                           -...    其他参数
  56. * 输出  :无
  57. * 返回  :无
  58. * 调用  :外部调用
  59. *         典型应用USART_printf( USART1, "\r\n this is a demo \r\n" );
  60. *                             USART_printf( USART2, "\r\n %d \r\n", i );
  61. *                             USART_printf( USART3, "\r\n %s \r\n", j );
  62. */
  63. void USART_printf(USART_TypeDef* USARTx, uint8_t *Data,...)
  64. {
  65.       const char *s;
  66.       int d;   
  67.       char buf[16];
  68.       va_list ap;
  69.       va_start(ap, Data);

  70.       while ( *Data != 0)     // 判断是否到达字符串结束符
  71.       {                                                         
  72.                 if ( *Data == 0x5c )  //'\'
  73.                 {                                                                          
  74.                         switch ( *++Data )
  75.                         {
  76.                                 case 'r':                   //回车符                                                   
  77.                                         USART_SendData(USARTx, 0x0d);
  78.                                         Data ++;
  79.                                         break;

  80.                                 case 'n':                 //换行符                                                          //???
  81.                                         USART_SendData(USARTx, 0x0a);        
  82.                                         Data ++;
  83.                                         break;
  84.                                 
  85.                                 default:
  86.                                         Data ++;
  87.                                     break;
  88.                         }                        
  89.                 }
  90.                 else if ( *Data == '%')
  91.                 {                                                                          //
  92.                         switch ( *++Data )
  93.                         {                                
  94.                                 case 's':                //字符串                                                                  
  95.                                         s = va_arg(ap, const char *);
  96.           for ( ; *s; s++)
  97.                                         {
  98.                                                 USART_SendData(USARTx,*s);
  99.                                                 while( USART_GetFlagStatus(USARTx, USART_FLAG_TC) == RESET );
  100.           }
  101.                                         Data++;
  102.           break;

  103.         case 'd':                      //十进制                                                         
  104.           d = va_arg(ap, int);
  105.           itoa(d, buf, 10);
  106.           for (s = buf; *s; s++)
  107.                                         {
  108.                                                 USART_SendData(USARTx,*s);
  109.                                                 while( USART_GetFlagStatus(USARTx, USART_FLAG_TC) == RESET );
  110.           }
  111.                                         Data++;
  112.           break;
  113.                                  default:
  114.                                                 Data++;
  115.                                     break;
  116.                         }                 
  117.                 } /* end of else if */
  118.                 else USART_SendData(USARTx, *Data++);
  119.                 while( USART_GetFlagStatus(USARTx, USART_FLAG_TC) == RESET );
  120.         }
  121. }
keaibukelian 发表于 2019-7-8 11:23 | 显示全部楼层
感谢楼主分享啊
labasi 发表于 2019-7-8 11:32 | 显示全部楼层

非常感谢楼主分享
paotangsan 发表于 2019-7-8 11:36 | 显示全部楼层

非常感谢楼主分享
renzheshengui 发表于 2019-7-8 11:41 | 显示全部楼层

非常感谢楼主分享
kayman 发表于 2019-10-21 08:29 | 显示全部楼层
特意回来评论。

使用楼主方法不要忘了添加一下include
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
您需要登录后才可以回帖 登录 | 注册

本版积分规则

12

主题

255

帖子

0

粉丝
快速回复 在线客服 返回列表 返回顶部