3853|2

111

帖子

0

TA的资源

一粒金砂(中级)

楼主
 

F350串口那些事 [复制链接]

本帖最后由 tinnu 于 2018-9-27 19:40 编辑

(一)丰富的串口功能
首先必须承认GD的USART做得相当丰富,LIN、ModBus有类似断开帧检测功能,开起来相当有意思,不过这个阶段还展示不打算尝鲜,首要目标是事先串口普通发送和接收中断。
(二)串口使能
demo里面已经有了串口使能的示例程序:
  1. void EvbUart1Config(void)
  2. {
  3.     rcu_periph_clock_enable(RCU_GPIOA);
  4.     rcu_periph_clock_enable(RCU_USART1);

  5.     /* connect port to USART1_Tx */
  6.     gpio_af_set(GPIOA, GPIO_AF_1, GPIO_PIN_2);

  7.     /* connect port to USARTx_R1 */
  8.     gpio_af_set(GPIOA, GPIO_AF_1, GPIO_PIN_3);

  9.     /* configure USART1 Tx as alternate function push-pull */
  10.     gpio_mode_set(GPIOA, GPIO_MODE_AF, GPIO_PUPD_PULLUP,GPIO_PIN_2);
  11.     gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ,GPIO_PIN_2);

  12.     /* configure USART2 Rx as alternate function push-pull */
  13.     gpio_mode_set(GPIOA, GPIO_MODE_AF, GPIO_PUPD_PULLUP,GPIO_PIN_3);
  14.     gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ,GPIO_PIN_3);

  15.     /* USART2 configure */
  16.     usart_deinit(USART1);
  17.     usart_baudrate_set(USART1,115200);
  18.     usart_receive_config(USART1, USART_RECEIVE_ENABLE);
  19.     usart_transmit_config(USART1, USART_TRANSMIT_ENABLE);
  20.     usart_enable(USART1);
  21. }
复制代码



(三)printf的重定向输出,把原子的直接搬过来改一下发送函数就可以了
  1. //////////////////////////////////////////////////////////////////
  2. //加入以下代码,支持printf函数,而不需要选择use MicroLIB         
  3. #if 1
  4. #pragma import(__use_no_semihosting)            
  5. //标准库需要的支持函数                 
  6. struct __FILE
  7. {
  8.         int handle;

  9. };

  10. FILE __stdout;      
  11. //定义_sys_exit()以避免使用半主机模式   
  12. _sys_exit(int x)
  13. {
  14.         x = x;
  15. }
  16. //重定义fputc函数
  17. int fputc(int ch, FILE *f)
  18. {      
  19.         usart_data_transmit(USART1, (uint8_t)ch);
  20.     while(RESET == usart_flag_get(USART1, USART_FLAG_TBE));
  21.         return ch;
  22. }
  23. #endif
复制代码



(四)USART接收器
用户手册里面这样解释接收器:

当一个数据帧接收完成,USART_STAT寄存器中的RBNE置位,如果设置了USART_CTL0寄存器中相应的中断使能位RBNEIE,将会产生中断。在USART_STAT寄存器中可以观察接收状态标志。
当接收到一帧数据,而RBNE位还没有被清零,随后的数据帧将不会存储在数据接收缓冲区中。
USART_STAT 寄存器中的溢出错误标志位ORERR 将置位。如果使能DMA 并置位
USART_CTL2寄存器中ERRIE位或者置位RBNEIE,将产生中断。
在一个接收过程中,RBNE、NERR、PERR、FERR和ORERR总是同时置位。如果没有使能
DMA,软件需检查RBNE中断是否由NERR、PERR、FERR或者ORERR置位产生。[/quote]
里面涉及了很多寄存器,也可以参考:

总的来说,就是接收器完了之后,置位RBNE(接收完成)寄存器。
再看看USART接收器寄存器,发现只有9个位,也就是接收器一帧只有一个字节。
那怎么操作就很明显了:接收一个字节置位一次,把RBNEIE(中断使能位)使能之后就会进入中断服务函数!


(五)中断服务函数
那么中断服务函数是什么呢?
因为GD跟ST的库各种相似,我们可以参考一下ST的代码形式:
[quote]stm32的启动文件startup_stm32f10x_md.s中有:DCD USART1_IRQHandler

那GD的启动文件也类似的找到,在88行:

原来也是USART1_IRQHandler
接下来依然是借鉴原子的服务函数:
  1. #define USART_REC_LEN                          200          //定义最大接收字节数 200
  2. #define u8 unsigned char
  3. #define u16 unsigned short
复制代码


  1. //串口1中断服务程序
  2. //注意,读取USARTx->SR能避免莫名其妙的错误          
  3. u8 USART_RX_BUF[USART_REC_LEN];     //接收缓冲,最大USART_REC_LEN个字节.
  4. u16 USART_RX_STA=0;                        //接收状态标记       

  5. void USART1_IRQHandler(void)                        //串口1中断服务程序
  6. {
  7.         u8 Res;
  8.         if(usart_interrupt_flag_get(USART1, USART_INT_FLAG_RBNE) != RESET)  //接收中断(接收到的数据必须是0x0d 0x0a结尾)
  9.         {
  10.                 Res =usart_data_receive(USART1);        //读取接收到的数据
  11.                 usart_interrupt_flag_clear(USART1, USART_INT_FLAG_RBNE);        //清除标志位,否则不会读取下一帧
  12.                
  13.                 if((USART_RX_STA&0x8000)==0)//接收未完成
  14.                 {
  15.                         if(USART_RX_STA&0x4000)//接收到了0x0d
  16.                         {
  17.                                 if(Res!=0x0a)USART_RX_STA=0;//接收错误,重新开始
  18.                                 else USART_RX_STA|=0x8000;        //接收完成了
  19.                         }
  20.                         else //还没收到0X0D
  21.                         {       
  22.                                 if(Res==0x0d)USART_RX_STA|=0x4000;
  23.                                 else
  24.                                 {
  25.                                         USART_RX_BUF[USART_RX_STA&0X3FFF]=Res ;
  26.                                         USART_RX_STA++;
  27.                                         if(USART_RX_STA>(USART_REC_LEN-1))USART_RX_STA=0;//接收数据错误,重新开始接收          
  28.                                 }                 
  29.                         }
  30.                 }                    
  31.         }
  32. }
复制代码



(六)中断使能
根据上面的表格,可以发现,需要使能的控制位是RBNEIE(中断使能位);
在USART的库里面我们发现了这个函数:

因此调用方法:

  1.         usart_interrupt_enable(USART1,USART_INT_RBNE);
复制代码



但是程序运行后发现并不能进入中断,百般思量没有头绪,又去翻了一下ST的例程,终于发现还有个NVIC的东西需要设置!
GD的库跟ST还是有些出入的,NVIC的设置形式可以借鉴systick里面的调用形式:

  1.     NVIC_SetPriority(USART1_IRQn, 0x00U);
  2.         NVIC_EnableIRQ(USART1_IRQn);
复制代码

接收中断成功!


补充内容 (2018-10-2 20:54):
关于最后中断分组处,值得注意:
NVIC_SetPriority、NVIC_EnableIRQ都属于弱定义的函数,在core_cm4里面。
gd有专门封装了nvic相关函数,在"gd32f3x0_misc.h"里面,nvic_irq_enable一个函数拥有以上两个函数的作用

补充内容 (2018-10-2 20:55):
此外还要用nvic_priority_group_set函数设置一下抢断优先级和子优先级
此帖出自GD32 MCU论坛

最新回复

我的串口接收一直没有调出来,最后只好用SPI来接收,正好可以借鉴楼主的经验继续调试串口,谢谢楼主分享!  详情 回复 发表于 2018-9-30 19:35
点赞 关注(1)
 

回复
举报

935

帖子

1

TA的资源

禁止发言

沙发
 
此帖出自GD32 MCU论坛
 
个人签名存储芯片/MCU/SRAM/PSRAM/DDR/FLASH/MRAM。web.www.sramsun.com  QQ3161422826 TEL:13751192923
 
 

回复

932

帖子

3

TA的资源

纯净的硅(中级)

板凳
 
我的串口接收一直没有调出来,最后只好用SPI来接收,正好可以借鉴楼主的经验继续调试串口,谢谢楼主分享!
此帖出自GD32 MCU论坛
 
 
 

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

随便看看
查找数据手册?

EEWorld Datasheet 技术支持

相关文章 更多>>
关闭
站长推荐上一条 1/6 下一条

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

站点相关: 国产芯 安防电子 汽车电子 手机便携 工业控制 家用电子 医疗电子 测试测量 网络通信 物联网

北京市海淀区中关村大街18号B座15层1530室 电话:(010)82350740 邮编:100190

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2025 EEWORLD.com.cn, Inc. All rights reserved
快速回复 返回顶部 返回列表