OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 5697|回复: 5

串口scanf函数重定向解决办法

[复制链接]

1

主题

6

帖子

0

精华

初级会员

Rank: 2

积分
83
金钱
83
注册时间
2019-1-23
在线时间
15 小时
发表于 2019-7-8 18:21:27 | 显示全部楼层 |阅读模式
本帖最后由 夜雨声烦Roc 于 2019-7-8 18:21 编辑

最近学习原子的stm32教程,在串口实验中看到有printf函数的重定向,想着自己写scanf的重定向,用了三天时间,终于解决,现将过程分享如下。


先说最终结论:

scanf函数重定向用到fgetc函数,检测USART_IT_RXNE标志位,同时串口中断函数USART1_IRQHandler里也要检测这个标志位,二者冲突,所以scanf函数不好使,串口初始化时不使能中断scanf函数就好使了。


建议:在调试过程中可以Disable中断,用scanf函数,实际使用时使能中断,不用scanf函数。

我觉得scanf函数有点鸡肋,明白原理即可。

接下来详细说说遇到的问题,供大家参考:

重定向fgetc函数,网上有很多种格式,看自己爱好选择

  1. int fgetc(FILE *f)
  2. {
  3.         while((USART1->SR & USART_IT_RXNE) == RESET);
  4.         //while((USART1->SR & 0X20) == RESET);                两个while函数实现的功能相同,哪个顺眼用哪个
  5.         return (int)(USART1->DR);
  6.         //return(int)USART_ReceiveData(USART1);                两个return功能返回值相同,哪个顺眼用哪个
  7. }
复制代码

复制代码

此时遇到第一个问题 Error: L6200E: Symbol __stdout multiply defined (by stdio_streams.o and usart.o).

stdout重定义,原因是没有勾选use MircoLIB


勾选以后遇到第二个问题Error: L6915E: Library reports error: __use_no_semihosting was requested, but a semihosting fgetc was linked in


原子有一段代码,可以不选择微库(use MircoLIB),既然选择了微库,那就矛盾了,所以我更改代码如下:简单来说就是不用原子这段代码,选择微库。

  1. //加入以下代码,支持printf函数,而不需要选择use MicroLIB         
  2. #if 0
  3. #pragma import(__use_no_semihosting)            
  4. //标准库需要的支持函数                 
  5. struct __FILE
  6. {
  7.         int handle;

  8. };

  9. FILE __stdout;
  10. //FILE __stdin;
  11. //定义_sys_exit()以避免使用半主机模式   
  12. _sys_exit(int x)
  13. {
  14.         x = x;
  15. }

  16. //重定义fputc函数
  17. int fputc(int ch, FILE *f)
  18. {      
  19.         while((USART1->SR&0X40)==0);//循环发送,直到发送完毕   
  20.   USART1->DR = (u8) ch;      
  21.         return ch;
  22.         //return (SendChar(ch));  
  23. }

  24. int fgetc(FILE *f)
  25. {        
  26.         while((USART1->SR & USART_FLAG_RXNE) == RESET);
  27.                 return (int)(USART1->DR);

  28. }

  29. #endif

  30. #if 1

  31. //重定向printf函数
  32. int fputc(int ch, FILE *f)
  33. {      
  34.         //USART_SendData(USART1, (uint8_t) ch);
  35.         while((USART1->SR&0X40)==0);//循环发送,直到发送完毕   
  36.     USART1->DR = (u8) ch;      
  37.         return ch;
  38. }
  39. int fgetc(FILE *f)
  40. {
  41.         while((USART1->SR & USART_IT_RXNE) == RESET);
  42.         //while((USART1->SR & 0X20) == RESET);                两个while函数实现的功能相同,哪个顺眼用哪个
  43.         return (int)(USART1->DR);
  44.         //return(int)USART_ReceiveData(USART1);                两个return功能返回值相同,哪个顺眼用哪个
  45. }

  46. #endif
复制代码

后来在发现一篇帖子,http://www.eeworld.com.cn/mcu/article_2017092034576.html可以在原子的代码上加一句:


FILE __stdin;


从而达到不用微库,重定向printf和scanf函数的目的。

到此,可以用scanf函数来读取了,但是出现新的问题:数据读取不全,且随机变化,且多次输入才能显示一次数据。

比如,我想输入12345空格,但是串口读取的可能只有34,下一次是52,再下一次是1435132。。。

这个问题困扰了我两天的时间,最终发现:

fgetc函数中检测USART_IT_RXNE标志位,同时串口中断函数USART1_IRQHandler里也要检测这个标志位,二者冲突。

将串口中断函数Disable后就可以正常使用scnaf函数了。





scanf读取有问题

scanf读取有问题
正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

0

主题

11

帖子

0

精华

初级会员

Rank: 2

积分
64
金钱
64
注册时间
2018-1-18
在线时间
17 小时
发表于 2019-8-24 17:45:56 | 显示全部楼层
回复 支持 反对

使用道具 举报

0

主题

28

帖子

0

精华

初级会员

Rank: 2

积分
50
金钱
50
注册时间
2019-6-22
在线时间
10 小时
发表于 2019-8-24 20:54:51 来自手机 | 显示全部楼层
大佬大佬,,,
回复 支持 反对

使用道具 举报

1

主题

3

帖子

0

精华

初级会员

Rank: 2

积分
114
金钱
114
注册时间
2018-12-4
在线时间
31 小时
发表于 2020-5-8 22:12:47 | 显示全部楼层
花了几个小时解决scanf问题,感谢大佬分享
回复 支持 反对

使用道具 举报

4

主题

346

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
3657
金钱
3657
注册时间
2016-2-21
在线时间
542 小时
发表于 2020-5-9 09:40:37 | 显示全部楼层
这个很6
回复 支持 反对

使用道具 举报

4

主题

12

帖子

0

精华

初级会员

Rank: 2

积分
54
金钱
54
注册时间
2020-5-10
在线时间
7 小时
发表于 2020-5-18 19:42:14 | 显示全部楼层
我想请教一下printf的重定向是在串口助手中打印出来那么scnaf的重定向是干什么用的啊
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2025-6-6 22:04

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表