本帖最后由 夜雨声烦Roc 于 2019-7-8 18:21 编辑
最近学习原子的stm32教程,在串口实验中看到有printf函数的重定向,想着自己写scanf的重定向,用了三天时间,终于解决,现将过程分享如下。
先说最终结论:
scanf函数重定向用到fgetc函数,检测USART_IT_RXNE标志位,同时串口中断函数USART1_IRQHandler里也要检测这个标志位,二者冲突,所以scanf函数不好使,串口初始化时不使能中断scanf函数就好使了。
建议:在调试过程中可以Disable中断,用scanf函数,实际使用时使能中断,不用scanf函数。
我觉得scanf函数有点鸡肋,明白原理即可。接下来详细说说遇到的问题,供大家参考:重定向fgetc函数,网上有很多种格式,看自己爱好选择
- int fgetc(FILE *f)
- {
- while((USART1->SR & USART_IT_RXNE) == RESET);
- //while((USART1->SR & 0X20) == RESET); 两个while函数实现的功能相同,哪个顺眼用哪个
- return (int)(USART1->DR);
- //return(int)USART_ReceiveData(USART1); 两个return功能返回值相同,哪个顺眼用哪个
- }
复制代码
复制代码此时遇到第一个问题 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),既然选择了微库,那就矛盾了,所以我更改代码如下:简单来说就是不用原子这段代码,选择微库。
- //加入以下代码,支持printf函数,而不需要选择use MicroLIB
- #if 0
- #pragma import(__use_no_semihosting)
- //标准库需要的支持函数
- struct __FILE
- {
- int handle;
- };
- FILE __stdout;
- //FILE __stdin;
- //定义_sys_exit()以避免使用半主机模式
- _sys_exit(int x)
- {
- x = x;
- }
- //重定义fputc函数
- int fputc(int ch, FILE *f)
- {
- while((USART1->SR&0X40)==0);//循环发送,直到发送完毕
- USART1->DR = (u8) ch;
- return ch;
- //return (SendChar(ch));
- }
- int fgetc(FILE *f)
- {
- while((USART1->SR & USART_FLAG_RXNE) == RESET);
- return (int)(USART1->DR);
- }
- #endif
- #if 1
- //重定向printf函数
- int fputc(int ch, FILE *f)
- {
- //USART_SendData(USART1, (uint8_t) ch);
- while((USART1->SR&0X40)==0);//循环发送,直到发送完毕
- USART1->DR = (u8) ch;
- return ch;
- }
- int fgetc(FILE *f)
- {
- while((USART1->SR & USART_IT_RXNE) == RESET);
- //while((USART1->SR & 0X20) == RESET); 两个while函数实现的功能相同,哪个顺眼用哪个
- return (int)(USART1->DR);
- //return(int)USART_ReceiveData(USART1); 两个return功能返回值相同,哪个顺眼用哪个
- }
- #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函数了。
一周热门 更多>