起初

stm32 v3.5 库函数里面,对于串口USART有这样两个函数:

                USART_ClearFlag()和USART_ClearITPendingBit()



查库函数定义,说一个是清除标志,一个是清除中断预处理位。然后我看了stm32f10x_usart.c文件,发现两个函数都操作的是USART->SR寄存器,但是这个寄存器只有一组标志位,没有什么中断预处理位。。


实际上两个函数实现的功能是一样的,都是清除相对应的标志位,只是标志位和中断位含义不一样,是标志位但

是不一定会产生中断。例如:

#define USART_IT_TXE                         ((uint16_t)0x0727)

#define USART_IT_TC                          ((uint16_t)0x0626)

#define USART_IT_RXNE                        ((uint16_t)0x0525)

这是中断位,可以产生中断

 

#define USART_FLAG_TXE                       ((uint16_t)0x0080)

#define USART_FLAG_TC                        ((uint16_t)0x0040)

#define USART_FLAG_RXNE                      ((uint16_t)0x0020)

这是标志位,有的标志位不能产生中断

 

标志位在程序中可以作为判定条件,支持程序的运行,中断则是跳转到中断函数执行。两个函数实现的功能是一

样的,在中断程序中可以用两个中的任一个。我想区分两个函数是为了更清晰吧。

还有

#define USART_IT_TC                          ((uint16_t)0x0626)

#define USART_FLAG_TC                        ((uint16_t)0x0040)

 

这两个数值不同是因为标志位只是为了清除标志位而设的,而中断位设置成这个值是因为在其他函数中这一位还

有其他用途。而且还要注意:

void USART_ClearFlag(USART_TypeDef* USARTx, uint16_t USART_FLAG)

{

  /* Check the parameters */

  assert_param(IS_USART_ALL_PERIPH(USARTx));

  assert_param(IS_USART_CLEAR_FLAG(USART_FLAG));

  assert_param(IS_USART_PERIPH_FLAG(USARTx, USART_FLAG)); /* The CTS flag is not available for UART4 and UART5 */   

   

  USARTx->SR = (uint16_t)~USART_FLAG;

}

 

 这一步 USARTx->SR = (uint16_t)~USART_FLAG; 似乎应该是  USARTx->SR &= (uint16_t)~USART_FLAG;

其实状态位只能有硬件置位,软件只能读和清零,所以这样写也是正确的。

没有很明白,所以转在这里,等我哪天灵光乍现了,再来加上我的理解

上面的内容是别人的,我略作修改,下面的内容是我原创。不知道本文到底是属于原创还是转载,但是......我的更简洁、精辟


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


灵光乍现了

我是在使用TC的时候遇见这个问题的,所以这里就只分析TC这个位


先研究简单点的USART_ClearFlag函数


//调用形式

USART_ClearFlag(USART3,USART_FLAG_TC);

 

//USART_FLAG_TC的定义

#define USART_FLAG_TC               ((uint16_t)0x0040)

 

//USART_ClearFlag函数的原型

void USART_ClearFlag(USART_TypeDef* USARTx, uint16_t USART_FLAG)

{

  /* Check the parameters */

  assert_param(IS_USART_ALL_PERIPH(USARTx));

  assert_param(IS_USART_CLEAR_FLAG(USART_FLAG));

  assert_param(IS_USART_PERIPH_FLAG(USARTx, USART_FLAG)); /* The CTS flag is not available for UART4 and UART5 */   

   

  USARTx->SR = (uint16_t)~USART_FLAG;

}

一目了然,最后USARTx->SR = ~(0100'0000);


再来研究复杂点的USART_ClearITPendingBit函数(注意,这两个函数的第二个参数,是不一样的)


//调用形式

USART_ClearITPendingBit(USART3,USART_IT_TC);

 

//USART_IT_TC的定义

#define USART_IT_TC           ((uint16_t)0x0626)//=0000'0110'0010'0110

 

//USART_ClearITPendingBit的函数原型

void USART_ClearITPendingBit(USART_TypeDef* USARTx, uint16_t USART_IT)

{

  uint16_t bitpos = 0x00, itmask = 0x00;

  /* Check the parameters */

  assert_param(IS_USART_ALL_PERIPH(USARTx));

  assert_param(IS_USART_CLEAR_IT(USART_IT));

  assert_param(IS_USART_PERIPH_IT(USARTx, USART_IT)); /* The CTS interrupt is not available for UART4 and UART5 */

  

  bitpos = USART_IT >> 0x08;                     //=0000'0110

  itmask = (uint16_t)((uint16_t)0x01 << bitpos); //=0100'0000

  USARTx->SR = (uint16_t)~itmask;                //=~(0100'0000)

}

可以看到最后还是USARTx->SR=~(0100'0000);


对比一下USART_ClearFlag和USART_ClearITPendingBit的参数

image.png

USART_ClearFlag的参数 USART_ClearITPendingBit的参数

USART_FLAG_CTS    = 0x0200 USART_IT_CTS   = 0x096A

USART_FLAG_LBD    = 0x0100 USART_IT_LBD    = 0x0846

USART_FLAG_TC      = 0x0040 USART_IT_TC      = 0x0626

USART_FLAG_RXNE = 0x0020 USART_IT_RXNE = 0x0525

这里可以发现一个规律USART_ClearFlag参数只有一个位是“1”,其位置正好等于USART_ClearITPendingBit的参数左移八位后的结果,所以这里可以非常非常肯定的讲:函数USART_ClearFlag和函数USART_ClearITPendingBit的功能totally一样


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


涉及内容扩展:

STM32的USART发送数据时如何使用TXE和TC标志


在USART的发送端有2个寄存器,一个是程序可以看到的寄存器——发送数据寄存器(通过USART_DR查看),另一个是程序看不到的寄存器——发送移位寄存器,对应的有两个USART数据发送标志,一个是TXE=发送数据寄存器空,另一个是TC=发送移位寄存器空。

(这粗箭头和这细箭头,简直不要太形象哦,粗箭头是八位八位的传,细箭头是一位一位的传)


    当USART_DR中的数据传送到移位寄存器后,TXE被设置,此时移位寄存器开始向TX信号线按位传输数据,但因为TDR已经变空,所以程序可以把下一个要发送的字节(操作USART_DR)写入TDR中,而不必等到移位寄存器中所有位发送结束,所有位发送结束时(送出停止位后)硬件会设置TC标志。


  另一方面,在刚刚初始化好USART还没有发送任何数据时,也会有TXE标志,因为这时发送数据寄存器是空的。TXEIE和TCIE的意义很简单,TXEIE允许在TXE标志为'1'时产生中断,而TCIE允许在TC标志为'1'时产生中断。


  至于什么时候使用哪个标志,需要根据你的需要自己决定。但我认为TXE允许程序有更充裕的时间填写TDR寄存器,保证发送的数据流不间断。TC可以让程序知道发送结束的确切时间,有利于程序控制外部数据流的时序。

image.png


三种发送方法

1、不开发送完成中断:

/*******************************************************************************

* 函数名  : UART1_SendString

* 描述    : USART1发送字符串

* 输入    : *s字符串指针

* 注释    :0==RESET,表示发送还未完成

USART_FLAG_TC!=RESET,就是=SET,表示发送完成,此时执行USART_GetFlagStatus会把USART_FLAG_TC清零(未证实)

*******************************************************************************/

void UART1_SendString(u8* s)

{

  while(*s)//检测字符串结束符

  {

   //USART_FLAG_TC==RESET时,表示发送还未完成。

    while(USART_GetFlagStatus(USART1, USART_FLAG_TC)==RESET); 

    USART_SendData(USART1 ,*s++);//发送当前字符

  }

}

2、开中断,额外设置一个标志:

u8 FLAG_TC=0;//定义全局变量

/*******************************************************************************

* 函数名  : UART1_SendString

* 描述    : USART1发送字符串

* 输入    : *s字符串指针

*******************************************************************************/

void UART1_SendString(char* s)

{

  FLAG_TC=0;//提前准备一下

  while(*s)//检测字符串结束符

  {

    USART_SendData(USART1 ,*s++);//发送当前字符

    while( FLAG_TC==0); //0:发送还未完成;1:发送完成

    FLAG_TC=0;

  }

}

 

 

void USART1_IRQHandler(void)

{

  if (USART_GetITStatus(USART1, USART_IT_TC) != RESET)//发送完成中断,= SET

  {

    USART_ClearITPendingBit(USART1,USART_IT_TC);

    FLAG_TC=1;

  }

}

 


开中断时,就不能通过简单的判断标志位USART_FLAG_TC的状态去决定能否发送下一个字符。比方说,使用 


while(*s)

{

 

   USART_SendData(USART1 ,*s++);//发送字符

 

   while(USART_GetFlagStatus(USART1, USART_FLAG_TC)==RESET); 

 

   ...

}

执行完发送字符的语句后,因为不可能这么快完成发送,所以程序接下来执行的是while语句。在等待期间,字符发送完毕,这时就会进入到中断,如果在中断里清除标志位,退出中断后,标志位USART_FLAG_TC仍然是RESET;如果不在中断里清除标志位,就不能退出中断。所以程序就会死在while里。


所以这里就需要额外设置一个标志。


3、开中断,数据发送由函数启动,在中断里完成:

//定义全局变量。也可以为了简化,把这四个参数结合起来包含在一个结构体里

u8 TxLength;   //发送数据长度

u8 TxIndicator;//发送指示器,表示目前发送完成哪一位了,下面要发送的是第(TxIndicator+1)位

u8 TxBuff[256];//Data 

u8 TxFnd;      //发送完成标志

     

/*************************************************************************

*程序名称    :   SendFirstByte

*功能        :   启动发送第一个字节

*@Notes     :   鸡贼啊,剩下的都放在USART_FLAG_TC中断里面,因为这个中断是

                 发送完成中断,是利用“发送第一个字节”来“启动发送”

*@Notes     :   需要注意,如果发送结果是乱码的话,一种供参考的解决方案是

                把数据直接赋值给TxBuff,而不要通过函数的形参传递

*输入参数    :   u8 txbuf[]: 需要发送的数据,u8 len : 数据中的字节数

*返回值      :   无

*************************************************************************/

void SendFirstByte( u8 txbuf[], u8 len )

{

TxBuff      = txbuf;//需要发送的数据

TxLength    = len  ;//发送数据长度

TxIndicator = 1    ;//0已经发送,也是用来启动发送的

 

USART_SendData(USART1, txbuf[0]);  /**@Notes:只发送了txbuf的第一个字节*/

}

 

/*************************************************************************

*程序名称    :   USART1_IRQHandler

*功能        :   完成发送数据   

*************************************************************************/

void USART1_IRQHandler(void)

{

if (USART_GetITStatus(USART1, USART_IT_TC) != RESET)

{

USART_ClearITPendingBit(USART1,USART_IT_TC);

if( TxIndicator < TxLength  )//数组的索引max永远小于数组元素的个数

{

USART_SendData(USART1, TxBuff[TxIndicator++]);

}

else//最后一字节数据发送完成

{

TxFnd = 0;

TxIndicator = 0;

}

}

}

USART收发过程中常遇问题总结:

Q:为什么使用USART发送一串字符,最后自接收到了最后一个?

A:是因为发送的间隔太短了,可以在发送每个字符之前先判断一下上一个字符是否发送完成,可以参考上面的“三种发送方法”


Q:为什么使用USART发送一串字符,有时候接收不到第一个字符,有时候又可以接收得到?

A:解决方案是把判断能否发送的语句放在发送数据之前

关键字:USART_ClearITPendingBith  USART_ClearFlag  区别 引用地址:USART_ClearITPendingBith和 USART_ClearFlag的区别

上一篇:stm32串口的flag和it标志位
下一篇:STM32F1x系列——外部中断

推荐阅读

随着人们生活水平的不断提高,对产品服务的要求也发生了变化,消费端开始升级并带来新的挑战和机遇。而服务机器人似乎为新的时代而生,逐步开始进入社会,进入家庭,服务于平民大众。在2018世界机器人大会上,北京康力优蓝机器人科技有限公司创始人兼首席执行官刘雪楠认为,服务机器人最大的市场是面向家庭的服务机器人,如果从商业价值的角度来讲,最大的...
新能源汽车是指采用非常规的车用燃料作为动力来源(或使用常规的车用燃料、采用新型车载动力装置),综合车辆的动力控制和驱动方面的先进技术,形成的技术原理先进、具有新技术、新结构的汽车。2016年9月8日,财政部曝光了苏州吉姆西客车制造有限公司等5家新能源汽车生产企业意图骗补国家财政补贴超10亿元,个别企业已被取消整车生产资质。 今年,国内新能...
国家发改委等四部门23日发布《关于扩大战略性新兴产业投资 培育壮大新增长点增长极的指导意见》,要求加大5G建设投资,加快5G商用发展步伐,将各级政府机关、企事业单位、公共机构优先向基站建设开放,研究推动将5G基站纳入商业楼宇、居民住宅建设规范。加快基础材料、关键芯片、高端元器件、新型显示器件、关键软件等核心技术攻关,大力推动重点工程和重...
2021年9月29日-30日,由深圳市工信局、深圳市福田区人民政府指导,中国高科技门户OFweek维科网主办、OFweek机器人网承办的“OFweek 2021中国机器人系统集成商峰会”将在深圳会展中心举办。本届OFweek机器人系统集成商峰会以“赋能新产业,构建新生态”为主题,设有机器人系统集成商专场、机器人创新应用赋能行业转型升级、3C行业制造专场三大板块,内容...

史海拾趣

问答坊 | AI 解惑

【教你一招】做好采购的N种技巧和途径

最近网站上有很多朋友问\"如何去采购,怎样才能做好采购\",希望我的这篇文章会对大家有所帮助! 采购分为很多类,最直接的两大类就是在终端运营商作采购(直接采购加工或生产某种产品的零件)和在贸易公司作采购.而我们这行主要是在贸易公司作采购!我 ...…

查看全部问答∨

异步电动机直接转矩控制分析与展望(zz)

一、引言 电动机调速是各行各业中电动机应用系统的必需环节。直流电动机因其磁链与转矩电流各自独立,不存在耦合关系,能够获得很好的调速范围和调速精度,静、动态特性均比较好而获得广泛应用。 交流(异步)电动机结构简单却因其磁链与电 ...…

查看全部问答∨

请大家推荐一款内置彩信模块的GPRS模块啊,TR800如何啊?

大家好,最近做一个GPRS彩信猫相关的课题,开始老板让用simcom的模块,说便宜,可是我要自己实现彩信协议,好晕啊。公司现在让我选择一款内置彩信模块的GPRS模块,这样我就可以不用自己实现彩信协议了,哪位大虾用过这方面应用给我推荐一款好吗?现 ...…

查看全部问答∨

仿真中使用.vo文件和使用源文件编辑的区别

QII可以产生.VO文件,对于功能仿真而言,我们可以注释掉其中一句关于sdo延迟文件加载的代码,也就是说可以将.vo变成针对功能仿真的文件而不加入时序内容,那么这样一来,可以用.VO文件做功能仿真,但是使用Modelsim直接编译verilog源文件,也可以做 ...…

查看全部问答∨

用W801G模块实现的单模块DTU方案

W801G模块外形小巧能够满足实际应用中对狭小空间的要求 ? 适合客户应用的SMT封装形式 ? 内嵌强大的TCP/IP协议栈 ? 基于成熟并已被验证的平台 ? GPRS multi-slot(Class 10/8)标准 ? GPRS mobile station(Class B)标准 ? 满足GSM 2/2+ ...…

查看全部问答∨

请问谁有STC16C554DCJ68芯片的手册?

只要是这个系列的也行,这个芯片有68个引脚,但我在网上找到一个16c554的芯片资料却是18引脚的 请问哪位大侠有此芯片资料?项目比较紧急!先谢谢了!…

查看全部问答∨

使用max3232 双工时,收发出现干扰现象!望达人指点!!

具体现象是这样,当我从max3232向PC机发数据时,此时如果从上位机PC 发数据到max3232,那么刚才从max3232发送到PC的数据就会被干扰。     用示波器观察过了,确实有一个字节的数据失真了,后面的字节没错。而且捕捉到的这个失真的数据 ...…

查看全部问答∨

4X4键盘矩阵代码分享

module key(   input         clk,   input         rst,   input   [3:0] row,            &nbs ...…

查看全部问答∨

STM指令不是一般的笨,

读个IO的值,要好几个指令才能完成. 而且,连位变量都没有.真的是超级难受啊.…

查看全部问答∨

LPC1114/LPC11U14和LPC1343对比学习(五)UART

终于把支持3种芯片的板子焊接完成了,累死我了,可以继续学习下面的内容了。。。 开发板贴:https://bbs.eeworld.com.cn/viewthread.php?tid=299669&page=1&extra=page%3D1   LPC1114/LPC1343串口特点:    16字节收发 ...…

查看全部问答∨
小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件
随便看看

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京ICP证060456号 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved