你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

在MDK-ARM5.17对STM32的USART1进行软件仿真时串口界面收不到数据

[复制链接]
吐息间丶时光中 发布时间:2017-2-14 16:34
本帖最后由 吐息间丶时光中 于 2017-2-21 00:01 编辑

小白是STM32初学者,遇到的一些问题在大神们面前太小儿科,还请大神不吝赐教

【问题一:TE置位自动发送一个空闲帧】
    前几天看刘凯老师的STM32培训视频第18集学习USART这一模块,在MDK-ARM5.17上进行软件仿真过程遇到一个坎硬是过不去:按照参考手册配置完寄存器后,软件仿真调试时(无论是单步一条一条的运行程序,还是全速运行程序),TXE一直处于低电平(
也就导致串口窗口收不到数据)
    代码如下(与刘凯老师视频上的一致):

  1. #include"stm32f10x.h"

  2. #define RCC_APB2ENR_Addr        (RCC_BASE + 0x18)

  3. #define BitBind(Addr,BitNum)        *((__IO uint32_t *)((Addr&0xF0000000)+ 0x2000000 +\
  4.                                                                 ((Addr&0x000FFFFF)<<5)+ (BitNum<<2)))

  5. #define RCC_APB2ENR(n)        BitBind(RCC_APB2ENR_Addr,n)

  6. /**********************************************************************
  7. * Function Name : MAIN
  8. * Description         : main program
  9. * Input                 : None
  10. * Output                 : None
  11. * Return                 : None
  12. **********************************************************************/
  13. int main(void)
  14. {/***UART寄存器方式编程***/
  15.         uint32_t BAUD=9600;                                //波特率9600bps
  16.         uint16_t DIV_Mantissa=0x00,DIV_Fraction=0x00;        //未经显示初始化的自动变量的值为未定义值(外部变量与静态变量将被初始化为0)
  17.         float USARTDIV=0.0;                                //浮点型(如果单精度能解决,尽量用单精度,双精度算术运算特别费时)
  18.         
  19.         //寄存器配置:USART使能、字长、停止位、波特率、发送使能
  20.         RCC_APB2ENR(14)=1;                                //USART1时钟使能
  21. //        RCC_APB2ENR(2)=1;                                //GPIOA时钟使能(软件仿真不开启无影响)
  22. //        GPIOA->CRH |= (3<<4);                        //软件仿真选择通用推挽输出也有效果(但不建议)
  23.         GPIOA->CRH |= (11<<4);                        //PA9复用功能推挽输出(最大速度50MHz)【注意:此时实际是复用功能开漏输出模式】,PA10默认浮空输入模式
  24.         GPIOA->CRH &= ~(1<<6);                        //PA9复用功能推挽输出(最大速度50MHz)
  25.         
  26.         USART1->CR1 |= (1<<13);                        //USART使能
  27.         USART1->CR1 &= ~(1<<12);                //1个起始位、8个数据位
  28.         USART1->CR1 &= ~(1<<10);                //禁止校验
  29.         USART1->CR2 &= ~(7<<11);                //1个停止位、禁止CK引脚(即异步)
  30.         //波特率算法
  31.         USARTDIV = (72000000)/(16.0*BAUD);                                //注:整数除法会截掉右边的小数部分
  32.         DIV_Mantissa = USARTDIV;                                                //取整
  33.         DIV_Fraction = (USARTDIV-DIV_Mantissa)*16+0.5;        //小数部分四舍五入并取整
  34.         USART1->BRR = (DIV_Mantissa<<4)+DIV_Fraction;        //也即:USART1->BRR = 0x1D4C;               

  35.         USART1->CR1 |= (1<<3);                        //发送使能
  36.         USART1->DR  = 0x66;                                //注意:DR只有9位有效位(调试时,串口窗口选择Mixed HEX ASCII Mode——混合十六进制和ASCII模式)
  37.         
  38.         return 0;
  39. }
复制代码
调试界面:
1.png

    起初以为是寄存器配置出错,所以把参考手册相关章节又看了一遍,后来发现并没有配置失误,于是又去查看了固件库里的USART配置函数,发现与自己的配置确实无异,就这样来来去去地鼓捣了两天……后来,在某一次调试时,小白将那全速运行按钮点了两次,奇迹出现——数据显示出来了!
    那么问题是出现在这吗——因为刘凯老师视频里用的Keil版本是Ver4,而我的是Ver5,所以不同?而且网上也有很多吐槽Ver5有很多bug。怀着这种心态,刚开始那会小白也相信是这样。但小白的性格有点追求小小的完美,于是对自己刚发现的持半信半疑的态度,打算再看一看参考手册……或许是功夫不负有心人吧(实际是自己总是看视频,动脑太少),最终总算有了一个较满意的发现:将上面代码中的以下两句

  1. USART1->CR1 |= (1<<3);                        //发送使能
  2.         USART1->DR  = 0x66;                                //注意:DR只有9位有效位(调试时,串口窗口选择Mixed HEX ASCII Mode——混合十六进制和ASCII模式)
复制代码
进行如下更改
  1. USART1->CR1 |= (1<<3);                                                        //发送使能
  2.         while((USART1->SR & 0x40) != 0x40);                                //置位TE将使得USART在第一个数据帧前发送一空闲帧
  3.         USART1->DR  = 0x66;                                //注意:DR只有9位有效位(调试时,串口窗口选择Mixed HEX ASCII Mode——混合十六进制和ASCII模式)
  4.         while((USART1->SR & 0x40) != 0x40);
  5.         USART1->CR1 &= ~(1<<3);                        //发送失能
复制代码
   经过以上更改后,再次在MDK-ARM5.17里进行软件仿真时,仅点击一次全速运行即可完成任务。如果是点击单步运行,仅在语句“while((USART1->SR & 0x40) != 0x40);”处单步一次无法单步到下一条语句(应该是MDK仿真发送完一个数据设定有一定的时间段),此处可以将光标定位在下一条语句后点击调试按钮“Run to Cursor Line”(Ctrl+F10)即可。

更正后的完整代码如下:

  1. #include"stm32f10x.h"

  2. #define RCC_APB2ENR_Addr        (RCC_BASE + 0x18)

  3. #define BitBind(Addr,BitNum)        *((__IO uint32_t *)((Addr&0xF0000000)+ 0x2000000 +\
  4.                                                                 ((Addr&0x000FFFFF)<<5)+ (BitNum<<2)))

  5. #define RCC_APB2ENR(n)        BitBind(RCC_APB2ENR_Addr,n)

  6. /**********************************************************************
  7. * Function Name : MAIN
  8. * Description         : main program
  9. * Input                 : None
  10. * Output                 : None
  11. * Return                 : None
  12. **********************************************************************/
  13. int main(void)
  14. {/***UART寄存器方式编程***/
  15.         uint32_t BAUD=9600;                                //波特率9600bps
  16.         uint16_t DIV_Mantissa=0x00,DIV_Fraction=0x00;        //未经显示初始化的自动变量的值为未定义值(外部变量与静态变量将被初始化为0)
  17.         float USARTDIV=0.0;                                //浮点型(如果单精度能解决,尽量用单精度,双精度算术运算特别费时)
  18.         
  19.         //寄存器配置:USART使能、字长、停止位、波特率、发送使能
  20.         RCC_APB2ENR(14)=1;                                //USART1时钟使能
  21. //        RCC_APB2ENR(2)=1;                                //GPIOA时钟使能(软件仿真不开启无影响)
  22. //        GPIOA->CRH |= (3<<4);                        //软件仿真选择通用推挽输出也有效果(但不建议)
  23.         GPIOA->CRH |= (11<<4);                        //PA9复用功能推挽输出(最大速度50MHz)【注意:此时实际是复用功能开漏输出模式】,PA10默认浮空输入模式
  24.         GPIOA->CRH &= ~(1<<6);                        //PA9复用功能推挽输出(最大速度50MHz)
  25.         
  26.         USART1->CR1 |= (1<<13);                        //USART使能
  27.         USART1->CR1 &= ~(1<<12);                //1个起始位、8个数据位
  28.         USART1->CR1 &= ~(1<<10);                //禁止校验
  29.         USART1->CR2 &= ~(7<<11);                //1个停止位、禁止CK引脚(即异步)
  30.         //波特率算法
  31.         USARTDIV = (72000000)/(16.0*BAUD);                                //注:整数除法会截掉右边的小数部分
  32.         DIV_Mantissa = USARTDIV;                                                //取整
  33.         DIV_Fraction = (USARTDIV-DIV_Mantissa)*16+0.5;        //小数部分四舍五入并取整
  34.         USART1->BRR = (DIV_Mantissa<<4)+DIV_Fraction;        //也即:USART1->BRR = 0x1D4C;               

  35.         USART1->CR1 |= (1<<3);                                                        //发送使能
  36.         while((USART1->SR & 0x40) != 0x40);                                //置位TE将使得USART在第一个数据帧前发送一空闲帧
  37.         USART1->DR  = 0x66;                                //注意:DR只有9位有效位(调试时,串口窗口选择Mixed HEX ASCII Mode——混合十六进制和ASCII模式)
  38.         while((USART1->SR & 0x40) != 0x40);
  39.         USART1->CR1 &= ~(1<<3);                        //发送失能
  40.         
  41.         return 0;
  42. }
复制代码
   问题的根源也就是置位TE将使得USART在第一个数据帧前发送一空闲帧(参考手册有说明。截图如下),由于版本不同导致MDK仿真发送完一个数据设定的时间段或许有所区别,所以在MDK-ARM5.17上缺少了以上检测语句就达不到刘凯老师视频上的调试效果。
2.png

    同理,该视频刘凯老师给的第二个带有for语句的例子,也必须加上如上检测语句:
  1. #include"stm32f10x.h"

  2. #define RCC_APB2ENR_Addr        (RCC_BASE + 0x18)

  3. #define BitBind(Addr,BitNum)        *((__IO uint32_t *)((Addr&0xF0000000)+ 0x2000000 +\
  4.                                                                 ((Addr&0x000FFFFF)<<5)+ (BitNum<<2)))

  5. #define RCC_APB2ENR(n)        BitBind(RCC_APB2ENR_Addr,n)

  6. /**********************************************************************
  7. * Function Name : MAIN
  8. * Description         : main program
  9. * Input                 : None
  10. * Output                 : None
  11. * Return                 : None
  12. **********************************************************************/
  13. int main(void)
  14. {/***UART寄存器方式编程***/
  15.         uint8_t num=0x00,data=0x00;
  16.         uint32_t BAUD=9600;                                //波特率9600bps
  17.         uint16_t DIV_Mantissa=0x00,DIV_Fraction=0x00;        //未经显示初始化的自动变量的值为未定义值(外部变量与静态变量将被初始化为0)
  18.         float USARTDIV=0.0;                                //浮点型(如果单精度能解决,尽量用单精度,双精度算术运算特别费时)
  19.         
  20.         //寄存器配置:USART使能、字长、停止位、波特率、发送使能
  21.         RCC_APB2ENR(14)=1;                                //USART1时钟使能
  22. //        RCC_APB2ENR(2)=1;                                //GPIOA时钟使能(软件仿真不开启无影响)
  23. //        GPIOA->CRH |= (3<<4);                        //软件仿真选择通用推挽输出也有效果(但不建议)
  24.         GPIOA->CRH |= (11<<4);                        //PA9复用功能推挽输出(最大速度50MHz)【注意:此时实际是复用功能开漏输出模式】,PA10默认浮空输入模式
  25.         GPIOA->CRH &= ~(1<<6);                        //PA9复用功能推挽输出(最大速度50MHz)
  26.         
  27.         USART1->CR1 |= (1<<13);                        //USART使能
  28.         USART1->CR1 &= ~(1<<12);                //1个起始位、8个数据位
  29.         USART1->CR1 &= ~(1<<10);                //禁止校验
  30.         USART1->CR2 &= ~(7<<11);                //1个停止位、禁止CK引脚(即异步)
  31.         //波特率算法
  32.         USARTDIV = (72000000)/(16.0*BAUD);                                //注:整数除法会截掉右边的小数部分
  33.         DIV_Mantissa = USARTDIV;                                                //取整
  34.         DIV_Fraction = (USARTDIV-DIV_Mantissa)*16+0.5;        //小数部分四舍五入并取整
  35.         USART1->BRR = (DIV_Mantissa<<4)+DIV_Fraction;        //也即:USART1->BRR = 0x1D4C;               

  36.         data = '@';
  37.         USART1->CR1 |= (1<<3);                                                        //发送使能
  38.         while((USART1->SR & 0x40) != 0x40);                                //置位TE将使得USART在第一个数据帧前发送一空闲帧
  39.         for( ; num < 64 ; num++)                                                //发送64个数据        40H~7FH(ASCII码表)
  40.         {
  41.                 USART1->DR  = data;
  42.                 while((USART1->SR & 0x40) != 0x40);
  43.                 data++;
  44.         }//跳出for循环时data为0x80
  45.         
  46.         return 0;
  47. }
复制代码
   经过小白测试,如果不加将导致第二个数据“41H”无法发送。
如下图所示:
3.png



【问题二:使用printf函数】
    用fputc重定向stdio库的printf函数后:文件流→串口USART1。使用printf函数将数据输出,如果没有提前进行代码配置(关于如何配置各论坛上有类似贴),或者将下图的“USE MicroLIB”勾选:
1.PNG

将导致:在Keil上进行软件仿真时,点击全速运行至少要点击三次(或者将光标定位在主函数里的某条语句,点击“Run to Cursor Line”也至少要点击三次);若是将程序烧进硬件跑,程序短时间未见能工作(未测试时间过久些是否会工作),串口助手收不到输出的数据。

------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

    问题很简单,但困扰了小白好几天,写下来希望其他初学者遇到相同问题时有所参考。
    32初学之路,还请各位大神大大多多指教。


------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
收藏 3 评论7 发布时间:2017-2-14 16:34

举报

7个回答
zoomdy 回答时间:2017-2-14 16:54:41
100块买块开发板,谁知道模拟器有什么幺蛾子在里头。
吐息间丶时光中 回答时间:2017-2-14 21:27:52
这个只是软件仿真,不涉及硬件哈。
吐息间丶时光中 回答时间:2017-2-15 18:54:25
今天尝试用固件库函数编程,最终结果仍证明:在MDK-ARM5.17上,必须要在使能TE位后,加上如下语句
  1. while(!USART_GetFlagStatus(USART1, USART_FLAG_TC));
  2. 等价于寄存器方式编程中的:
  3. while((USART1->SR & 0x40) != 0x40);
复制代码


后面的发送才正常。
队长shiwo 回答时间:2017-2-16 08:48:26
谢谢分享 学习
吐息间丶时光中 回答时间:2017-2-17 11:44:22

初学过程,还请多赐教
j923187522 回答时间:2019-1-21 08:33:19
现在应该很厉害了吧 最近在弄lora通信 有没有弄过?想找人交流一下 其实就是串口通信
j923187522 回答时间:2019-1-21 08:38:52
对了 你这种软件仿真是怎么仿真USART的?我仿真不了的?

所属标签

STM32团队

意法半导体微控制器和微处理器拥有广泛的产品线,包含低成本的8位单片机和基于ARM® Cortex®-M0、M0+、M3、M4、M33、M7及A7内核并具备丰富外设选择的32位微控制器及微处理器


最新内容

相似技术帖

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
微信公众号二维码 微信公众号
手机版二维码 手机版