打印

stm32之usart(原创)

[复制链接]
4999|11
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
wzt19910506|  楼主 | 2013-5-2 08:22 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
本帖最后由 wzt19910506 于 2013-5-2 08:28 编辑

authorwzt       2013.04.28
以前写stm32串口的程序只是简单的要么用查询要么用中断的方法来进行一些简单的发送接收。最近又用到usart,按照之前的思路进行了同样的配置,发现一个现象就是程序会一直自动的进入中断程序从而我在main函数中写到其他程序根本就没有机会运行。然后网上又对照了别人的程序代码进行配置结果依然一样。当然硬件问题我已经排除过了,所以为了解决不得又重新深入看数据手册。才发现我参考的代码本身就是误导人的。下面我贴出自己的代码然后一点点分析:
//名称:USART_Config
//功能:对串口1进行初始化,数据位8位,停止位1位,无奇偶校验位
//入口参数:波特率设定值
//出口参数:无
voidUSART_Config(u16 Baud_Rate)
{
         USART_InitTypeDef USART_InitStructure;
         GPIO_InitTypeDef GPIO_InitStructure2;  
         RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_USART1,ENABLE);//使能USART1的时钟。USART1APB2  USART1,3APB1
         GPIO_StructInit(&GPIO_InitStructure2);
         GPIO_InitStructure2.GPIO_Pin=GPIO_Pin_9;
         GPIO_InitStructure2.GPIO_Speed=GPIO_Speed_50MHz;
         GPIO_InitStructure2.GPIO_Mode=GPIO_Mode_AF_PP;               //TX引脚配置为复用输出
         GPIO_Init(GPIOA,&GPIO_InitStructure2);
         GPIO_InitStructure2.GPIO_Pin=GPIO_Pin_10;
         GPIO_InitStructure2.GPIO_Speed=GPIO_Speed_50MHz;
         GPIO_InitStructure2.GPIO_Mode=GPIO_Mode_IN_FLOATING;  //RX引脚配置为浮空输入
         GPIO_Init(GPIOA,&GPIO_InitStructure2);
         USART_StructInit(&USART_InitStructure);
         USART_InitStructure.USART_BaudRate=Baud_Rate;                                                     //波特率设定
         USART_InitStructure.USART_WordLength=USART_WordLength_8b;                     //8位数据位
         USART_InitStructure.USART_StopBits=USART_StopBits_1;                              //1位停止位
         USART_InitStructure.USART_Parity=USART_Parity_No;                                         //无奇偶校验
         USART_InitStructure.USART_HardwareFlowControl=USART_HardwareFlowControl_None;//无硬件流控制
         USART_InitStructure.USART_Mode=USART_Mode_Tx|USART_Mode_Rx;            //发送和接收双向模式
         USART_Init(USART1,&USART_InitStructure);
         USART_ITConfig(USART1,USART_IT_RXNE,ENABLE);                                                      //打开接收中断
         USART_ITConfig(USART1,USART_IT_TC,ENABLE);                                                  //打开发送完成中断
         USART_Cmd(USART1,ENABLE);                                                                               //使能串口1
         USART1_NVIC_Config();                                                      //配置USART1中断
}
//名称:USART1_NVIC_Config
//功能:串口1中断分组,配置优先级
//进出参数:无
static voidUSART1_NVIC_Config()
{
         NVIC_InitTypeDef NVIC_InitStructure;
         NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);   //优先级组设置为2(可以是0——4
         /*****************串口1中断配置******************/
         NVIC_InitStructure.NVIC_IRQChannel=USART1_IRQn;              //外部中断0
         NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2;       //抢占1
         NVIC_InitStructure.NVIC_IRQChannelSubPriority=0;          //子优先级0
         NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
         NVIC_Init(&NVIC_InitStructure);
}
先看下红色部分USART_Init(USART1,&USART_InitStructure);这个函数, USART_InitStructure这个参数是个结构体类型的指针,这个结构体内有六个参数可以按照上面的配置就行,想更改波特率停止位,奇偶校验位等等都通过它来初始化,上面的注释写的已经很清楚啦,其他更详细的其他参数就要参考库函数的参考手册啦。
然而导致程序不断进入中断的问题关键是上面蓝色那句:USART_ITConfig(USART1,USART_IT_TC,ENABLE); 这一句是我修改过的,而原来是这样写的USART_ITConfig(USART1,USART_IT_TXE,ENABLE);关键就是两个函数参数不一样:一个用到USART_IT_TC,一个用到USART_IT_TXE。为什么产生这种现象在我们再看一下中断函数后再进行分析:
void USART1_IRQHandler(void)
{
    if(USART_GetITStatus(USART1, USART_IT_RXNE)!= RESET)   //处理接收到的数据
    {
        USART_ClearITPendingBit(USART1,USART_IT_RXNE);
    }
  if (USART_GetITStatus(USART1, USART_IT_TXE)!= RESET)    //发送中断
   {
           USART_ClearITPendingBit(USART1,USART_IT_TXE);
           USART_ITConfig(USART1, USART_IT_TXE, DISABLE);
           USART_ITConfig(USART1, USART_IT_TC, ENABLE);
   }
   if (USART_GetITStatus(USART1, USART_IT_TC)!= RESET)    //发送完成
   {
            USART_ClearITPendingBit(USART1,USART_IT_TC);
            USART_ITConfig(USART1, USART_IT_TC,DISABLE);
     }
}
看到紫色的部分代码是我在网上查到资料时别人写的,后来我自己的代码都给删掉啦,因为在上面USART_Config函数中只打开啦USART_IT_TC和USART_IT_RENE中断,没有打开USART_IT_TXE中断,所以在中断处理函数中也就不需要这部分紫色的代码。另外紫色字体的代码还有一个错误USART_ClearITPendingBit(USART1,USART_IT_TXE);为什么说它错,因为这个USART_IT_TXE标志位根本就不支持软件清除,只能通过对USART_DR寄存器的写操作由硬件清除。我之前一直进入中断也就是打开了USART_IT_TXE的中断使能,然后进入中断却试图使用软件清除以至于不起作用,还是不断的进入中断函数中去。
USART一共有十个中断源,如下列表:
USART_FLAG_CTS:  CTS Change flag (not available for UART4 andUART5)
USART_FLAG_LBD: LIN Break detection flag
USART_FLAG_TXE:  Transmit data register empty flag
USART_FLAG_TC:  Transmission Complete flag
USART_FLAG_RXNE: Receive data register not empty flag
USART_FLAG_IDLE: Idle Linedetection flag
USART_FLAG_ORE:  OverRun Error flag
USART_FLAG_NE:   Noise Error flag
USART_FLAG_FE:   Framing Error flag
USART_FLAG_PE:   Parity Error flag
而中间可以使用软件清除的只有橘黄色的四个。而对于一般作为串口使用的我们一般只用到两个就够啦:USART_FLAG_TC(串口数据发送完中断,这个发送完指的是一帧的数据发送完,按我的配置也就是八个数据位一个停止位发送完),USART_IT_RXNE(串口接收数据中断)。而很多人在配置的时候使用的却是USART_FLAG_TXE,这个数据手册写的也很清楚,指的是发送寄存器空中断,并不是发送完成中断,要是打开这个中断的话只要发送的数据从发送寄存器移出就会进入中断,所以我们在不发送数据的时候一定要记得把这个中断关闭要不然就会像我最初的一样不断进入中断函数中去。
那是不是这个USART_IT_TXE就没什么用处了呢,其实不是,这个在连续发送数据的时候打开这个中断判断发送数据寄存器是否为空而能够更迅速的做出反应把数据写入发送寄存器,但是一定要在不发送的时候把它给关闭。
还有在USART发送数据之前都需要进行读取TC标志位,等待上一次发送完毕自动置1后才进行本次数据的发送。TC标志位初始值为1,一般不需要手动清零。先查询状态寄存器SR然后再写DR寄存器TC的值会自动清零,DR寄存器中的值发送完毕后TC标志位又会自动置1。
while(USART_GetFlagStatus(USART1,USART_FLAG_TC)==RESET);
USART_SendData(USART1,0x01);

沙发
cushawzsw| | 2013-5-2 11:38 | 只看该作者
学习了

使用特权

评论回复
板凳
IJK| | 2013-5-2 14:30 | 只看该作者
LZ说得是对的。
另外,这其实是简单的1件事情,但LZ说得太复杂了。

使用特权

评论回复
地板
拿起书本| | 2013-5-2 16:47 | 只看该作者
在实际应用中,不使用中断进行的输入是效率非常低的。学习一下

使用特权

评论回复
5
cjhk| | 2013-5-2 18:46 | 只看该作者
学习一下   好帖子   谢谢了   楼主    顶一个

使用特权

评论回复
6
天罡星lmy| | 2013-6-14 10:26 | 只看该作者
MARK

使用特权

评论回复
7
sun1238898| | 2013-6-14 17:26 | 只看该作者
不错,能够深入研究问题,值得学习!

使用特权

评论回复
8
djqinqing| | 2013-7-11 19:04 | 只看该作者
"因为这个USART_IT_TXE标志位根本就不支持软件清除"楼主的这句话不对吧

使用特权

评论回复
9
wzt19910506|  楼主 | 2013-7-12 13:04 | 只看该作者
djqinqing 发表于 2013-7-11 19:04
"因为这个USART_IT_TXE标志位根本就不支持软件清除"楼主的这句话不对吧

这个你可以查看数据手册上面写得很清楚

使用特权

评论回复
10
outstanding| | 2013-7-12 13:53 | 只看该作者
应该不复杂吧,写的那么多

使用特权

评论回复
11
wzt19910506|  楼主 | 2013-7-15 13:12 | 只看该作者
outstanding 发表于 2013-7-12 13:53
应该不复杂吧,写的那么多

是不复杂,可是要是不明白的时候问题也挺让人抓狂的……

使用特权

评论回复
12
it_yrj| | 2014-2-19 21:46 | 只看该作者
主要是使能了IT_TXE会自动发送一个空字符的问题

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

8

主题

134

帖子

8

粉丝