历史上的今天
返回首页

历史上的今天

今天是:2024年09月05日(星期四)

正在发生

2019年09月05日 | STM32基础知识3-STM32串口USART1的使用方法和程序

2019-09-05 来源:eefocus

通用同步异步收发器(USART)提供了一种灵活的方法来与使用工业标准NR 异步串行数据格式的外部设备之间进行全双工数据交换。 USART利用分数波特率发生器提供宽范围的波特率选择,支持同步单向通信和半双工单线通信。


1、STM32固件库使用外围设备的主要思路


在STM32中,外围设备的配置思路比较固定。首先是使能相关的时钟,一方面是设备本身的时钟,另一方面如果设备通过IO口输出还需要使能IO口的时钟;最后如果对应的IO口是复用功能的IO口,则还必须使能AFIO的时钟。


其次是配置GPIO,GPIO的各种属性由硬件手册的AFIO一章详细规定,较为简单。


接着相关设备需要如果需要使用中断功能,必须先配置中断优先级,后文详述。


然后是配置外围设备的相关属性,视具体设备而定,如果设备需要使用中断方式,必须使能相应设备的中断,之后需要使能相关设备。


最后如果设备使用了中断功能,则还需要填写相应的中断服务程序,在服务程序中进行相应操作。


2、UART的配置步骤(查询方式)


2.1、打开时钟


由于UART的TX和RX和AFIO都挂在APB2桥上,因此采用固件库函数RCC_APB2PeriphClockCmd()进行初始化。UARTx需要分情况讨论,如果是UART1,则挂在APB2桥上,因此采用RCC_APB2PeriphClockCmd()进行初始化,其余的UART2~5均挂在APB1上。


    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_USART1, ENABLE);

2.2、GPIO初始化


GPIO的属性包含在结构体GPIO_InitTypeDef,其中对于TX引脚,GPIO_Mode字段设置为GPIO_Mode_AF_PP(复用推挽输出),GPIO_Speed切换速率设置为GPIO_Speed_50MHz;对于RX引脚,GPIO_Mode字段设置为GPIO_Mode_IN_FLOATING(浮空输入),不需要设置切换速率。最后通过GPIO_Init()使能IO口。


以下是GPIO设置的实例代码:



    GPIO_InitTypeDef GPIO_InitStructure;


    //USART1 Tx(PA.09) 

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; 

    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; 

    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; 

    GPIO_Init(GPIOA, &GPIO_InitStructure);

    //USART1 Rx(PA.10) 

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; 

    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; 

    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; 

    GPIO_Init(GPIOA, &GPIO_InitStructure);


2.3、配置UART相关属性


通过结构体USART_InitTypeDef来确定。UART模式下的字段如下


USART_BaudRate:波特率,视具体设备而定


USART_WordLength:字长


USART_StopBits:停止位


USART_Parity:校验方式


USART_HardwareFlowControl:硬件流控制


USART_Mode:单/双工


最后设置。实例代码为:



   //USART1配置

  USART_InitTypeDef USART_InitStructure;


   USART_InitStructure.USART_BaudRate = 9600; 

    USART_InitStructure.USART_WordLength = USART_WordLength_8b; 

    USART_InitStructure.USART_StopBits = USART_StopBits_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_Cmd(USART1, ENABLE); 


别忘了最后要使用USART_Cmd()来启动设备UART1。


2.4、重定向print()函数。



int fputc(int ch,FILE *f)

{

    USART1->SR;  //USART_GetFlagStatus(USART1, USART_FLAG_TC) 解决第一个字符发送失败的问题

    //一个一个发送字符

    USART_SendData(USART1, (unsigned char) ch);

    //等待发送完成

    while(USART_GetFlagStatus(USART1,USART_FLAG_TC)!=SET);

    

    return(ch);

}


最后通过主函数直接输出即可。



int main(void)

{

    // USART1 config 9600 8-N-1 

    USART1_Config();

    

    printf("hello world!");

}

3、UART的配置步骤(中断方式)


打开时钟、GPIO初始化、配置UART相关属性、重定向print()函数 与上面的相同。


3.1、中断优先级的配置


这是STM32比较奇怪的地方,在只有一个中断的情况下,仍然需要配置优先级,其作用是使能某条中断的触发通道。STM32的中断有至多两个层次,分别是先占优先级和从优先级,而整个优先级设置参数的长度为4位,因此需要首先划分先占优先级位数和从优先级位数,通过NVIC_PriorityGroupConfig()实现;


特定设备的中断优先级NVIC的属性包含在结构体NVIC_InitTypeDef中,其中字段NVIC_IRQChannel包含了设备的中断向量,保存在启动代码中;字段NVIC_IRQChannelPreemptionPriority为主优先级,NVIC_IRQChannelSubPriority为从优先级,取值的范围应根据位数划分的情况而定;最后NVIC_IRQChannelCmd字段是是否使能,一般定位ENABLE。最后通过NVIC_Init()来使能这一中断向量。实例代码如下:



//配置UART1接收中断

void NVIC_Configuration(void)

{

    NVIC_InitTypeDef NVIC_InitStructure; 

    /* Configure the NVIC Preemption Priority Bits */  

    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);

    

    /* Enable the USARTy Interrupt */

    NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;     

    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;

    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;

    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;

    NVIC_Init(&NVIC_InitStructure);

}



3.2、中断的服务程序的设计


目前使用了UART的两个中断USART_IT_RXNE(接收缓存补空中断)和USART_IT_TXE(发送缓存空中断),前一个中断保证了一旦有数据接收到就进入中断以接收特定长度的数据,后一个中断表示一旦发完一个数据就进入中断函数,保证连续发送一段数据。一个设备的所有中断都包含在一个中断服务程序中,因此必须首先分清楚这次响应的是哪一个中断,使用USART_GetITStatus()函数确定;采用USART_ReceiveData()函数接收一个字节数据,采用USART_SendData()函数发送一个字节数据,当关闭中断时采用USART_ITConfig()失能响应的中断。实例程序:



void USART1_IRQHandler(void)

{

    uint8_t ch;

    

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

    {     

        //ch = USART1->DR;

            ch = USART_ReceiveData(USART1);     //接受数据

          printf( "%c", ch );    //返回打印

    } 

     

}


 


3.3、接收数据函数:



//重定向scanf函数到USART1

int fgetc(FILE *f)

{

        /*等待串口1输入数据*/

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


        return (int)USART_ReceiveData(USART1);

}



4、 STM32串口在首次发送字符的时候,首字符丢失解决办法


网上关于发送字符的代码大多如下:


USART_SendData(USART1, (uint8_t)ch);

while( USART_GetFlagStatus(USART1, USART_FLAG_TC) != SET);


其实咋一看是说的通的,但是在仔细看手册的时候发现 TC 和 TXE 标志位在复位的时候被置1 ,这样第一次while循环就是没有用的。这样导致了首次第一个字符还没有被输出,就被后面的字符覆盖掉,造成实际看到的丢失现象。解决办法就很简单:在前面加上一句 USART1->SR;


具体代码如下:


USART1->SR;

USART_SendData(USART1, (uint8_t)ch);

while( USART_GetFlagStatus(USART1, USART_FLAG_TC) != SET);


下面我来说说原因: 第一句读取SR寄存器,第二句写DR寄存器 刚好清除了TC标志位 。第一次while循环就起作用了。


也可将USART1->SR;替换为USART_GetFlagStatus(USART1, USART_FLAG_TC


本实验所有程序《STM32串口USART1的查询和中断方式程序》


补充:一直有一个疑问是关于接受和发送数据的问题:对于“hello”这样的字符串是一个一个接受还是整个接受显示,下面的实验可以验证是一个一个进行的。

推荐阅读

史海拾趣

High Voltage Semiconductor Inc公司的发展小趣事

面对日益激烈的市场竞争和不断变化的市场需求,美高测始终保持着对技术创新的执着追求。公司不断投入研发资源,探索新的测试技术和应用场景,如微电网、新能源汽车等领域的高压半导体测试。同时,美高测还积极构建开放式的创新生态体系,与众多合作伙伴共同推动行业的进步和发展。通过这些努力,美高测在高压半导体测试领域持续保持着领先地位,为电子行业的未来发展贡献着重要力量。

Herley New York公司的发展小趣事

为了更好地服务全球客户,美高测积极寻求与国际知名企业的合作。通过与半导体制造巨头台积电、英特尔等公司的合作,美高测不仅获得了先进的制造技术和市场洞察能力,还成功将其高压测试产品打入了这些巨头的供应链体系。同时,公司还与多个国家的科研机构建立了长期合作关系,共同开展前沿技术的研发和应用,进一步提升了公司的国际影响力。

Globaltech Semiconductor Co Ltd公司的发展小趣事

为了保持技术领先地位,Globaltech持续加大研发投入,建立了先进的研发中心和测试实验室。公司不断引进国内外顶尖的研发人才,并与多所知名高校和研究机构建立产学研合作关系。这些努力使得Globaltech在电源管理IC领域取得了多项技术突破,并成功拓展了产品线,涵盖了ESD保护器件、MOSFET等多个领域。这些新产品不仅丰富了公司的产品线,也为客户提供了更加全面的解决方案。

Flexxon Pte Ltd公司的发展小趣事

面对全球对环境保护和可持续发展的日益关注,Flextronics(Flexxon Pte Ltd)积极响应,将绿色制造理念融入企业运营的每一个环节。公司采用环保材料、优化生产工艺、实施节能减排措施,努力降低对环境的影响。同时,Flextronics还积极参与国际环保标准的制定和推广工作,与上下游合作伙伴共同构建绿色供应链体系。这些努力不仅提升了企业的社会责任形象,也为公司的可持续发展奠定了坚实基础。

ABECO公司的发展小趣事

在1950年代的英国,ABECO的创始人凭借对电子行业的热爱和对手工工具的独特见解,开始了他的创业之路。初创时期,资金匮乏,人员稀少,但创始人凭借着对品质的执着和对创新的追求,不断研发出满足市场需求的高质量工具。他亲自走访客户,了解需求,不断完善产品,逐渐在电子行业中树立起了良好的口碑。

HCC Industries公司的发展小趣事

近年来,随着全球对环境保护和可持续发展的重视,HCC Industries积极响应号召,制定了绿色可持续发展战略。公司加大了对环保技术和绿色产品的研发投入,推出了一系列符合环保标准的微电子部件产品。同时,HCC还通过优化生产工艺和节能减排措施,降低了生产过程中的能源消耗和污染排放。这一战略不仅赢得了客户和消费者的广泛赞誉,也为公司带来了更加可持续的发展前景。

问答坊 | AI 解惑

四创GPS定位lll型汽车行驶记录仪(附图)

GPS定位III型汽车行驶记录仪将汽车行驶记录仪、语音通话、语音图像、调度、导航、娱乐、防暴等功能融为一体的新款产品。您可以通过调度中心传来的信息,了解道路情况。在对道路不是很熟悉的情况下,通过电子地图,了解您身在何处,并且很容易就找到 ...…

查看全部问答>

在PLD开发中提高VHDL的综合质量

摘 要:介绍可编程逻辑器件的开发流程,叙述EDA工具Quartus II和LeonardoSpectrum在Altera公司CPLD器件开发中的应用,给出提高VHDL综合质量的几点经验。 关键词:电子设计自动化 可编程逻辑器件 硬件描述语言 逻辑综合 引 言   随着计算机与 ...…

查看全部问答>

周立功 我的25年嵌入式生涯(转)

《程序员》杂志的编辑约我写一篇命题作文,想了几天都无从下手不知道写什么才好。在这篇文章里,我不打算将创业的艰辛与喜悦重新回忆一遍,我确实不想去误导大家,因为我所处的年代是一个物质缺乏的年代,成功相对来说要容易得多。每个人的成长 ...…

查看全部问答>

同步与异步

同步逻辑和异步逻辑之间的区别:同步逻辑是时钟之间有固定的因果关系,异步逻辑是时钟之间没有固定的因果关系。异步电路主要是组合逻辑电路,用于产生地址译码、FIFO或者RAM的读写控制信号,其逻辑与任何时钟信号都没有关系,译码输出产生的毛刺 ...…

查看全部问答>

出售华清远见代金券400元,售价180

地址:海淀五道口,电话13810712845 QQ:370030183…

查看全部问答>

如何在eVC下用__try来捕获文件异常?急在线等...

如何在eVC下用__try来捕获文件异常?是用序列化的方式来读取文件数据的.提供的SDK只能用__try. try catch不可以用,在微软上下载了ritti.exe,但是对我这个wince的SDK没有作用. 我用的是工控机…

查看全部问答>

提议厂家再弄个LED灯DIY活动,但不要限于应急灯,而是让网友自由发挥,创意无限的。

发挥各位网友的创意,说不定那家LED生产厂家看中了,还可以在市场上大火。…

查看全部问答>

熟悉430的做过无线电子作品的,有兴趣参加利尔达全国物联网应用设计大赛的 请进

不知道大家是否知道利尔达举办的  利尔达杯 首届全国物联网应用设计大赛?   具体大家可以看这个链接,奖品什么的还是很优厚的,而且还有挺丰富的开发板芯片等免费申请或者优惠价格购买的优惠政策。 http://www.lierda.com/topic/iot ...…

查看全部问答>

用usb线直接给单片机供电和下载

小弟现在遇到一点小问题,就是我想在单片机开发板上用一根usb线供电和下载程序到单片机上,我们看到的是用ch340和max232芯片完成的,我想问的是不是max232是多余的,有没有大虾发个电路图来看看。…

查看全部问答>

求助

ADC12的datasheet中提到Ax输入电压的范围是0到AVCC,那如果参考电压选的不是AVCC的话,范围还是这个吗?…

查看全部问答>