stm32学习笔记----双串口同时打开时的printf()问题

  最近因为要使用串口2外接PN532芯片实现通信,另一方面,要使用串口1来将一些提示信息输出到上位机,于是重定义了printf(),使其将打印的信息重定向至串口1。但是当在程序中调用printf()时,却发现上位机无论如何都接收不到信息,而且printf()之后的语句也不再执行,想必程序在printf()函数里面死掉了吧。当时觉得很纳闷,因为单独只使用一个串口时,printf()是没有问题的。往下说之前,先贴一下双串口的配置和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 = ;
  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 = ;
  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.  
  53. USART_Init(USART2, &USART_InitStructure);
  54. USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);
  55. USART_Cmd(USART2, ENABLE);
  56.  
  57. NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
  58. /*串口2中断配置*/
  59. NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;
  60. NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority =;
  61. NVIC_InitStructure.NVIC_IRQChannelSubPriority =;
  62. NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  63. NVIC_Init(&NVIC_InitStructure);
  64. }
  65.  
  66. /*printf()函数重定向*/
  67. int fputc(int ch, FILE *f)
  68. {
  69. //将printf()内容发往串口1
  70. USART_SendData(USART1, (unsigned char) ch);
  71. while( USART_GetFlagStatus(USART1,USART_FLAG_TC)!= SET);
  72. return (ch);
  73. }

  当只开串口1时,printf()是可以正常使用的,但是同时使用串口1和串口2时,使用printf()就会输出不了信息,并且程序无法往下执行;但如果不用printf()函数,而直接使用

  1. USART_SendData(USART1,(unsigned char) ch)时,串口1也能正常打印;但这样太麻烦辣,每次打印一个字符。
    于是网上查了一下,也有人遇到类似问题,而后评论下方有一个函数,说是可以双串口同时打开时,也可以一次性打印一串信息。抱着试一试的心态,将函数程序搬到我的工程中,没想到,还真行。下面贴出代码:
  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 = ;
  16. char *ptr = string;
  17.  
  18. /* This implementation only works for decimal numbers. */
  19. if (radix != )
  20. {
  21. *ptr = ;
  22. return string;
  23. }
  24.  
  25. if (!value)
  26. {
  27. *ptr++ = 0x30;
  28. *ptr = ;
  29. return string;
  30. }
  31.  
  32. /* if this is a negative value insert the minus sign. */
  33. if (value < )
  34. {
  35. *ptr++ = '-';
  36.  
  37. /* Make the value positive. */
  38. value *= -;
  39. }
  40.  
  41. for (i = ; i > ; i /= )
  42. {
  43. d = value / i;
  44.  
  45. if (d || flag)
  46. {
  47. *ptr++ = (char)(d + 0x30);
  48. value -= (d * i);
  49. flag = ;
  50. }
  51. }
  52.  
  53. /* Null terminate the string. */
  54. *ptr = ;
  55.  
  56. return string;
  57.  
  58. }
  59.  
  60. /*
  61. * 函数名:USART_printf
  62. * 描述 :格式化输出,类似于C库中的printf,但这里没有用到C库
  63. * 输入 :-USARTx 串口通道
  64. * -Data 要发送到串口的内容的指针
  65. * -... 其他参数
  66. * 输出 :无
  67. * 返回 :无
  68. * 调用 :外部调用
  69. * 典型应用USART_printf( USART1, "\r\n this is a demo \r\n" );
  70. * USART_printf( USART2, "\r\n %d \r\n", i );
  71. * USART_printf( USART3, "\r\n %s \r\n", j );
  72. */
  73. void USART_printf(USART_TypeDef* USARTx, uint8_t *Data,...)
  74. {
  75. const char *s;
  76. int d;
  77. char buf[];
  78. va_list ap;
  79. va_start(ap, Data);
  80.  
  81. while ( *Data != ) // 判断是否到达字符串结束符
  82. {
  83. if ( *Data == 0x5c ) //'\'
  84. {
  85. switch ( *++Data )
  86. {
  87. case 'r': //回车符
  88. USART_SendData(USARTx, 0x0d);
  89. Data ++;
  90. break;
  91.  
  92. case 'n': //换行符 //???
  93. USART_SendData(USARTx, 0x0a);
  94. Data ++;
  95. break;
  96.  
  97. default:
  98. Data ++;
  99. break;
  100. }
  101. }
  102. else if ( *Data == '%')
  103. { //
  104. switch ( *++Data )
  105. {
  106. case 's': //字符串
  107. s = va_arg(ap, const char *);
  108. for ( ; *s; s++)
  109. {
  110. USART_SendData(USARTx,*s);
  111. while( USART_GetFlagStatus(USARTx, USART_FLAG_TC) == RESET );
  112. }
  113. Data++;
  114. break;
  115.  
  116. case 'd': //十进制
  117. d = va_arg(ap, int);
  118. itoa(d, buf, );
  119. for (s = buf; *s; s++)
  120. {
  121. USART_SendData(USARTx,*s);
  122. while( USART_GetFlagStatus(USARTx, USART_FLAG_TC) == RESET );
  123. }
  124. Data++;
  125. break;
  126. default:
  127. Data++;
  128. break;
  129. }
  130. } /* end of else if */
  131. else USART_SendData(USARTx, *Data++);
  132. while( USART_GetFlagStatus(USARTx, USART_FLAG_TC) == RESET );
  133. }
  134. }

stm32学习笔记----双串口同时打开时的printf()问题的更多相关文章

  1. stm32学习笔记之串口通信

    在基础实验成功的基础上,对串口的调试方法进行实践.硬件代码顺利完成之后,对日后调试需要用到的printf重定义进行调试,固定在自己的库函数中. b) 初始化函数定义: void USART_Confi ...

  2. STM32学习笔记——USART串口

    转载自:http://www.cnblogs.com/microxiami/p/3752715.html 一.USART简介 通用同步异步收发器(USART)提供了一种灵活的方法与使用工业标准NRZ异 ...

  3. STM32学习笔记——USART串口(向原子哥和火哥学习)

    一.USART简介 通用同步异步收发器(USART)提供了一种灵活的方法与使用工业标准NRZ异步串行数据格式的外部设备之间进行全双工数据交换.USART利用分数波特率发生器提供宽范围的波特率选择. S ...

  4. STM32学习笔记:【001】时钟树与RCC

    导言 如果学过单片机的同学应该不会陌生,学习51单片机时最经常听到的就是“最小系统”. 最小系统里面少不了晶振,否则单片机无法工作. 单片机需要晶振(时钟源)来工作,那么对于STM32芯片同样如此. ...

  5. STM32学习笔记(四)——串口控制LED(中断方式)

    目录: 一.时钟使能,包括GPIO的时钟和串口的时钟使能 二.设置引脚复用映射 三.GPIO的初始化配置,注意要设置为复用模式 四.串口参数初始化配置 五.中断分组和中断优先级配置 六.设置串口中断类 ...

  6. STM32学习笔记——OLED屏

    STM32学习笔记--OLED屏 OLED屏的特点: 1.  模块有单色和双色可选,单色为纯蓝色,双色为黄蓝双色(本人选用双色): 2.  显示尺寸为0.96寸 3.  分辨率为128*64 4.   ...

  7. stm32学习笔记——外部中断的使用

    stm32学习笔记——外部中断的使用 基本概念 stm32中,每一个GPIO都可以触发一个外部中断,但是,GPIO的中断是以组为一个单位的,同组间的外部中断同一时间只能使用一个.比如说,PA0,PB0 ...

  8. STM32学习笔记-NVIC中断知识点

    STM32学习笔记-NVIC中断知识点总结 中断优先级设置步骤 1. 系统运行后先设置中断优先级分组 函数:void NVIC_PriorityGroupConfig(uint32_tNVIC_Pri ...

  9. STM32学习笔记——点亮LED

    STM32学习笔记——点亮LED 本人学习STM32是直接通过操作stm32的寄存器,使用的开发板是野火ISO-V2版本: 先简单的介绍一下stm32的GPIO: stm32的GPIO有多种模式: 1 ...

随机推荐

  1. EPROCESS 进程/线程优先级 句柄表 GDT LDT 页表 《寒江独钓》内核学习笔记(2)

    在学习笔记(1)中,我们学习了IRP的数据结构的相关知识,接下来我们继续来学习内核中很重要的另一批数据结构: EPROCESS/KPROCESS/PEB.把它们放到一起是因为这三个数据结构及其外延和w ...

  2. 用requests库实现登录遇到的问题

    想登录zhihu,然后总是得到403 foribidden的错误,各种谷歌百度,得到结论说是输入错误或者是url错误,用fldder发现的确是url错了,post的地址是错误的 ==. 开始以为是#s ...

  3. Nginx 配置文件详解

    user nginx ; #用户 worker_processes 8; #工作进程,根据硬件调整,大于等于cpu核数 error_log logs/nginx_error.log crit; #错误 ...

  4. 本地与在线图片转Base64及图片预览

    查看效果:http://sandbox.runjs.cn/show/tgvbo9nq 本地图片转Base64(从而可以预览图片): function localImgLoad() { var src ...

  5. JavaScript 上万关键字瞬间匹配——借助Hash表快速匹配

    来源: http://www.cnblogs.com/index-html/archive/2013/04/17/js_keyword_match.html http://www.etherdream ...

  6. Ten Tips for Writing CS Papers, Part 2

    Ten Tips for Writing CS Papers, Part 2 This continues the first part on tips to write computer scien ...

  7. Linux rpm 命令参数使用详解[介绍和应用](转)

    RPM是RedHat Package Manager(RedHat软件包管理工具)类似Windows里面的“添加/删除程序” rpm 执行安装包二进制包(Binary)以及源代码包(Source)两种 ...

  8. linux利用grep查看打印匹配的下几行或前后几行的命令

    转自:http://www.itokit.com/2013/0308/74883.html linux系统中,利用grep打印匹配的上下几行   如果在只是想匹配模式的上下几行,grep可以实现.   ...

  9. 如何测试本机的公网IP能否被Internet用户访问

    声明:本机的公网IP是指ADSL拨号方式取得的公网IP,并非指固定公网IP. 一.新建IIS站点 xp系统需要有安装包才能安装IIS服务 windows7及以上与系统直接在windows->控制 ...

  10. Unity3D模型的细致纹理问题解决办法

    http://hunterwang.diandian.com/post/2012-09-28/40039798509 也许有人也遇到过同样的问题,也许解决方式不同,我来介绍一下偶尔尝试发现的解决办法. ...