历史上的今天
返回首页

历史上的今天

今天是:2024年12月21日(星期六)

2018年12月21日 | STM32串口USART通讯

2018-12-21 来源:eefocus

1. USART和UART


USART(Universal Synchronous Asynchronous Receiver and Transmitter)即通用同步异步收发器,它是一个串行通信设备,与外部设备可灵活进行全双工数据交换。在这之前我们常用到的是UART(Universal Asynchronous Receiver and Transmitter),它是在USART基础上裁剪掉了同步通信功能,只有异步通信。区分同步和异步最简单的方法就是看通信时需不需要对外提供时钟输出,我们平时使用的串口通信基本都是UART。关于串口通信其他基本概念,在上一篇文章http://blog.csdn.net/qq_29344757/article/details/75246263已有详细解析,这里不再赘述。


2. STM32中USART功能框图


这里写图片描述


2.1 功能引脚


(1)TX:输出引脚,用于发送数据 


(2)RX:输入引脚,用于接收数据 


(3)SW_RX:输入引脚,用于单线和智能卡模式,属于内部引脚,没有具体外部引脚引出 


(4)IRDA_OUT:输出引脚,用于发送红外数据 


(5)IRDA_IN:输入引脚,用于接收红外数据 


(6)nRTS:请求以发送(Request To Send),n表低电平有效。若使能RTS硬件流控制,当USART接收器准备好接收数据时,nRTS有效,即它为低电平;当接收寄存器已满时,nRTS被设置为高电平 


(7)nCTS:请求以发送(Clean To Send),n表低电平有效。若使能CTS硬件流控制,发送器在发送下一帧数据前会检测nCTS引脚状态,若为低电平表可以发送数据,若为高电平则在发送完当前数据帧之后停止发送。 


(8)SCLK:发送器时钟输出引脚,仅适用于同步模式。


2.2 数据寄存器


USART数据寄存器(USART_DR)只有低9位有效, 

 

这里写图片描述 


第9位数据是否有效要取决于USART_CR1(USART控制寄存器1)的M位设置, 


这里写图片描述


当M位为0时表示8位数据字长,当M位为1时表9位数据字长,一般我们使用8位数据字长。 


USART_DR实际是包含了两个寄存器,一个专门用于发送的TDR,一个专门用于接收的RDR。进行发送数据操作时,往USART_DR写入数据会自动存储在TDR内,当进行读取数据操作时,向USART_DR读取数据会自动提取RDR数据。串行通信时一位一位传输的,所以TDR和RDR寄存器都是介于系统总线和移位寄存器间的:发送数据时把TDR内容转移到发送移位寄存器上,接收数据时则是把接收到的每一位顺序保存在接收移位寄存器内进而转移到RDR。


2.3 控制器


STM32的USART有专门用于控制发送、接收、唤醒单元和中断等的寄存器。例如: 


(1)USART_CR1寄存器的UE位用于开启/关闭给串口的时钟源的,使用USART之前向该位写1用于使能USART。 


(2)USART_CR1寄存器的M位用于控制发送/接收数据字长可选8位/9位。 


(3)USART_CR1寄存器的TE位用于启停数据发送,向该位写1时发送移位寄存器上的数据会从TX引脚输出,低位在前,高位在后。如果设置USART为同步模式,SCLK引脚将会输出时钟信号。 


(4)USART_CR1寄存器的RE位用于开启/关闭USART的接收,若为1,接收器在RX线开始接收数据帧的起始位,确定到起始位后就根据RX线电平状态把数据存放在接收移位寄存器内,接收完成后就要接收移位寄存器移到RDR内,并将USART_SR寄存器的RXNE位置1(若USART_CR2寄存器的RXNEIE置1的话此时可以产生中断)


一般在我们编程中较为重要的USART_CR1寄存器标志位有: 


在发送数据时,


TE:发送使能

TXE:发送寄存器为空

TC: 发送完成

TXIE:发送完成中断使能


接收数据时,


RE:接收使能

RXNE:读数据寄存器非空

RXNEIE:发送完成中断使能


2.4 波特率设置

USART的发送器和接收器使用相同的波特率,计算公式为:


Tx/Rx波特率 = USART的时钟频率 / (16 * USARTDIV)


USARTDIV是一个存放波特率寄存器(USART_BRR)的无符号浮点数 


这里写图片描述


DIV_Mantissa[11:0]表示USARTDIV的整数部分 

DIV_Fraction[3:0]表示USARTDIV的小数部分。 


例如:DIV_Mantissa = 26(0x1a),DIV_Fraction = 12(0x0c),那么USART_CRR的值为0x26c。USARTDIV的小数位12 / 16 = 0.75,整数位26,最终USARTDIV的值为26.75。 

假设知道USARTDIV的值为22.63,那么,DIV_Fraction = 16 * 0.63 = 10.08,最接近的整数位10,即DIV_Fraction = 0x0a,DIV_Mantissa = 22,即为0x16。 


以USART1为例,它是挂接在APB2总线上的: 


这里写图片描述


即USART1的时钟源频率为72MHz,那么如果要得到115200的波特率,即: 

115200 = 72000000 / (16 * USARTDIV),USARTDIV = 39.0625, 

同理计算可得,DIV_Fraction = 0.0625 * 16 = 1,DIV_Mantissa = 39,USART_BRR的值设置为0x271。


2.5 校验控制


STM32F103系列单片机的USART支持奇偶校验,USART_CR1寄存器的PCE位置1就可以启动奇偶校验,奇偶检验由硬件自动完成。使能奇偶校验控制后,每个字符帧的格式变为:


起始位 + 数据帧 + 校验位 + 停止位


注意,当使用校验位时,USART_CR1寄存器的M位需要设置为1,即9位模式,因为串口传输的长度为8位数据帧加上1位校验位共9位。启动奇偶校验控制后,在发送数据帧时会自动添加校验位,接收数据帧时自动验证校验位。接收数据时若出现奇偶校验位验证失败,USART_SR寄存器的PE位会被置1并可以产生奇偶校验中断。


2.6 中断控制


USART有多个中断请求事件,常用中断请求有: 


这里写图片描述


3. USART初始化数据结构


有了标准库,我们的编程变得十分简单,若上面讲到的寄存器操作及原理不清晰,也不是我们要动手编程的阻碍了,不过了解下总归是好的。 


初始化结构体定义在标准外设库的stm32f10x_usart.h文件中:


typedef struct

{

  uint32_t USART_BaudRate;            //波特率,标准库会根据此值计算得到USARTDIV的值,从而设置USART_BRR的值。

  uint16_t USART_WordLength;          //字长,可选8位或9位(多一位表带奇偶校验)

  uint16_t USART_StopBits;            //停止位,0.5、1、1.5、2个停止位可选。设置在USART_CR2的STOP[1:0]位

  uint16_t USART_Parity;              //校验位,可设置USART_Parity_No,USART_Parity_Even(偶校验),USART_Parity_Odd(奇校验)。

                                      //设置在USART_CR1的PCE、PS位

  uint16_t USART_Mode;                //USART模式,USART_Mode_Rx和USART_Mode_Tx可选,可或

  uint16_t USART_HardwareFlowControl; //硬件流控制,可使能RTS/使能CTS/同时使能RTS和CTS,不使能硬件流

} USART_InitTypeDef;


4. USART编程使用到的外设库函数

4.1 USART时钟使能

以USART1为例,它是挂接在APB2总线在的外设,使能函数为


RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1);


4.2 USART复位


当外设出现异常时可通过复位设置实现对外设的复位,然后重新配置该外设使其重新工作。一般系统在刚开始配置外设时,都会先执行复位外设操作。USART的复位函数为


void USART_DeInit(USART_TypeDef* USARTx);


复位USART1时


USART_DeInit(USART1);


4.3 串口初始化

void USART_Init(USART_TypeDef* USARTx, USART_InitTypeDef* USART_InitStruct);


参数一为待初始化的串口标号 

参数二为USART_InitTypeDef类型的结构体指针,原型及其意义在前面已讲


4.4 USART发送数据

void USART_SendData(USART_TypeDef* USARTx, uint16_t Data);


该函数向USART_DR写入一个数据,串口会自动发送。


4.5 接收数据

uint16_t USART_ReceiveData(USART_TypeDef* USARTx);


该函数是操作USART_DR读取串口接收到的数据


4.6 串口状态

串口的状态是保存在USART_SR寄存器中,读取串口状态寄存器的函数为】


FlagStatus USART_GetFlagStatus(USART_TypeDef* USARTx, uint16_t USART_FLAG);


参数二表示我们要查看串口的哪种状态,可取值为:


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 Line detection flag

USART_FLAG_ORE:  OverRun Error flag

arg USART_FLAG_NE:   Noise Error flag

arg USART_FLAG_FE:   Framing Error flag

arg USART_FLAG_PE:   Parity Error flag


4.7 串口使能

void USART_Cmd(USART_TypeDef* USARTx, FunctionalState NewState);


4.8 串口响应中断

void USART_ITConfig(USART_TypeDef* USARTx, uint16_t USART_IT, FunctionalState NewState);


参数二表示使能串口哪种中断。串口能产生中断的中断源有许多,取值为:


USART_IT_CTS:  CTS change interrupt (not available for UART4 and UART5)

USART_IT_LBD:  LIN Break detection interrupt

USART_IT_TXE:  Transmit Data Register empty interrupt

USART_IT_TC:   Transmission complete interrupt

USART_IT_RXNE: Receive Data register not empty interrupt(接收数据中断)

USART_IT_IDLE: Idle line detection interrupt

USART_IT_PE:   Parity Error interrupt

USART_IT_ERR:  Error interrupt(Frame error, noise error, overrun error)


4.9 获取相应中断状态

使能某中断后,当该中断发生了就会设置状态寄存器的某个标志位。在中断服务函数中我们经常要去判断是哪个中断源,


ITStatus USART_GetITStatus(USART_TypeDef* USARTx, uint16_t USART_IT);


若使能了串口发送完成中断,判断是否产生该中断时用


USART_GetITStatus(USART1, USART_IT_TC);


返回值等于SET,说明发生串口发送完成中断。


5. 编程实践

硬件平台采用MiniSTM32开发板,要实现板载USART和计算机通讯,需要用到一个USB转USART的芯片,MiniSTM32开发板采用的转换芯片为CH340G。硬件接线图为: 


这里写图片描述


需要注意的是,STM32的USART1的引脚和CH340的接线。USART1的发送、接收引脚分别是PA9和PA10: 

 

这里写图片描述 


通过跳线帽将PA9(U1_TXD)、PA10(U1_RXD)连接到CH340G的RXD、TXD。这个在配置GPIO功能的时候要注意是以STM32芯片原理图上的引脚功能为准。


程序实现功能:开发板上电后通过USART发送字符串到计算机(计算机用串口调试助手接收),进而开发板进入等待中断状态,若计算机通过串口调试助手向开发板发数据就会触发STM32的接收数据终中断,在中断服务函数中接收数据并将数据发回给计算机。


STM32的串口编程关键点在于: 


(1)使能RX和TX引脚GPIO时钟和USART时钟 


(2)初始化GPIO,并将GPIO复用到USART上。参照《STM32中文参考手册_V10.pdf》-P110 外设的GPIO配置-USART部分 


这里写图片描述


(3)配置USART初始化参数 

(4)配置终端控制器NVIC并使能USART接收中断 

(5)使能USART 

(6)在USART1中断服务函数中实现数据接收和发送


编程环境采用MDK5,工程结构如图: 


这里写图片描述


BSP/BSP_USART.c中实现对USART的所有操作及NVIC初始化操作,相关声明在BSP/BSP_USART.h中:


//BSP_USART.h

#ifndef __BSP_UART_H__

#define __BSP_UART_H__


#include


void NVIC_Configuration(void);

void USART_Configuration(void);

void USART_SendChar(USART_TypeDef* pUSARTx, uint8_t c);

void USART_SendString(USART_TypeDef* pUSARTx, char* str);


#endif /* __BSP_UART_H__ */


//BSP_USART.c

#include "BSP_USART.h"


//配置NVIC

void NVIC_Configuration(void)

{

    NVIC_InitTypeDef NVIC_InitStu;


    //设置中断分组寄存器

    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);


    NVIC_InitStu.NVIC_IRQChannel = USART1_IRQn;

    NVIC_InitStu.NVIC_IRQChannelPreemptionPriority = 1;

    NVIC_InitStu.NVIC_IRQChannelSubPriority = 1;

    NVIC_InitStu.NVIC_IRQChannelCmd = ENABLE;


    NVIC_Init(&NVIC_InitStu);

}


void USART_Configuration(void)

{

    GPIO_InitTypeDef GPIO_InitStu;

    USART_InitTypeDef USART_InitStu;


    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);


    //PA9用作串口1输入引脚,配置为浮空输入

    GPIO_InitStu.GPIO_Mode = GPIO_Mode_AF_PP;

    GPIO_InitStu.GPIO_Pin = GPIO_Pin_9;

    GPIO_InitStu.GPIO_Speed = GPIO_Speed_50MHz;

    GPIO_Init(GPIOA, &GPIO_InitStu);


    //PA10用作串口1输出引脚,配置为复用推挽输出

    GPIO_InitStu.GPIO_Mode = GPIO_Mode_IN_FLOATING;

    GPIO_InitStu.GPIO_Pin = GPIO_Pin_10;

    GPIO_Init(GPIOA, &GPIO_InitStu);


    //设置USART初始化结构体

    USART_InitStu.USART_BaudRate = 115200;

    USART_InitStu.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;

    USART_InitStu.USART_Parity = USART_Parity_No;

    USART_InitStu.USART_StopBits = USART_StopBits_1;

    USART_InitStu.USART_WordLength = USART_WordLength_8b;

    USART_InitStu.USART_HardwareFlowControl = USART_HardwareFlowControl_None;

    USART_Init(USART1, &USART_InitStu);


    //配置NVIC

    NVIC_Configuration();


    //使能串口接收中断

    USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);


    //开启

    USART_Cmd(USART1, ENABLE);

}


//发送一个字符

void USART_SendChar(USART_TypeDef* pUSARTx, uint8_t c)

{

    USART_SendData(pUSARTx, c);


    //等待发送结束标志

    while (USART_GetFlagStatus(pUSARTx, USART_FLAG_TXE) == RESET);

}


//发送字符串

void USART_SendString(USART_TypeDef* pUSARTx, char* str)

{

    uint32_t n = 0;


    while (*(str + n) != '\0')

    {

        USART_SendChar(pUSARTx, *(str + n));

        n++;

    }

    //等待发送结束标志

    while (USART_GetFlagStatus(pUSARTx, USART_FLAG_TXE) == RESET);

}



USART1的接收数据产生的中断的中断服务函数在stm32f10x_it.c中实现:


void USART1_IRQHandler(void)

{

    uint16_t c;


    //判断是否为USART1的接收中断

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

    {

        c = USART_ReceiveData(USART1);

        USART_SendData(USART1, c);

    }   

}


在main函数中:


#include


int main(void)

{


    USART_Configuration();

    USART_SendString(USART1, "HelloWorld\n");

    //USART_SendChar(USART1, 'h');

    while (1);  


    return 0;

}


发送完”HelloWorld\n”后进入等待中断中。


下载运行,注意若使用板载的串口下载方式下载程序,就会占用了USART1发送/接收数据用的串口,所以需要下载完程序后再用串口调试助手测试。另外,计算机串口调试助手的波特率、停止位、数据位等要跟在代码中的设置一致。运行如图:


这里写图片描述

推荐阅读

史海拾趣

AMICC [AMIC TECHNOLOGY]公司的发展小趣事

AMICC的创立之初,面临着资金短缺、市场竞争激烈等多重困难。创始人凭借对半导体技术的深刻理解和敏锐的市场洞察力,带领团队夜以继日地研发新产品,积极寻找合作伙伴。经过不懈的努力,AMICC逐渐在行业中崭露头角,其产品质量和性能得到了市场的认可。

Gigavac LLC公司的发展小趣事

随着产品线的不断丰富和技术实力的不断提升,AMICC开始积极拓展国内外市场。公司通过与大型电子企业建立战略合作关系,成功打入国际市场。同时,AMICC还积极参加各类行业展会和交流活动,提升品牌知名度和影响力。在市场拓展的过程中,AMICC始终坚持客户至上的原则,为客户提供优质的产品和服务,赢得了客户的信任和好评。

GAPTEC Electronic GmbH & Co. KG公司的发展小趣事

背景:随着全球对环保和可持续发展的重视,Galaxy Microelectronics也开始关注其生产过程中的环保问题。

发展:公司投入巨资建设绿色工厂,采用先进的环保技术和设备,减少生产过程中的能源消耗和废弃物排放。同时,Galaxy Microelectronics还积极推广环保理念,与供应商和客户共同构建绿色供应链。这些举措不仅提升了公司的社会形象,还为其在竞争激烈的市场中赢得了更多客户的青睐。

Deutron Electronics Corp公司的发展小趣事

为了进一步提升竞争力,Deutron Electronics Corp积极寻求国际合作与并购机会。公司与多家国际知名电子企业建立了战略合作关系,共同研发新产品和技术。同时,公司还成功收购了几家具有核心技术的电子企业,增强了自身的研发和生产能力。这些合作与并购为Deutron Electronics Corp带来了更多的发展机遇和市场空间。

EG & G Inc公司的发展小趣事

随着电子技术的不断发展,EG & G Inc公司不断进行技术创新和产品升级。公司投入大量资源进行研发,成功推出了一系列具有竞争力的电子产品。其中,某款高精度测量仪器在市场上获得了广泛认可,成为了公司的明星产品。此外,公司还积极开拓新的应用领域,将电子技术应用于医疗、环保等多个领域,为公司带来了新的增长点。

Grayhill公司的发展小趣事
如汽车音响、车载充电器等需要稳定电压和电流的电子设备。

问答坊 | AI 解惑

大型设计中FPGA的多时钟设计策略

利用FPGA实现大型设计时,可能需要FPGA具有以多个时钟运行的多重数据通路,这种多时钟FPGA设计必须特别小心,需要注意最大时钟速率、抖动、最大时钟数、异步时钟设计和时钟/数据关系。设计过程中最重要的一步是确定要用多少个不同的时钟,以及如何 ...…

查看全部问答>

很多WinCE平台的手机上,都有字库或字库芯片,它有何作用?

很多WinCE平台的手机上,都有字库或字库芯片,它有何作用?…

查看全部问答>

VS 2005编译 tcpmp 0.72中的common出现module machine type 'THUMB' conflicts with target

我设置自己的SDK就出现这个错误: module machine type \'THUMB\' conflicts with target machine type \'ARM\' 使用PPC 2003的就可以,这个是怎么回事? …

查看全部问答>

windows不是通过int13来操作磁盘?

求教,    windows不是通过int13来操作磁盘,那么现在那些硬盘还原卡的工作原理就不应该像下面介绍的那样:   还原精灵与还原卡的工作原理分析:           还原精灵的工作原理:它 ...…

查看全部问答>

利用文件系统过滤驱动实现 类似还原卡功能 的原理是什么?

用文件系统过滤驱动实现C盘还原功能,类似还原卡这样的功能,原理是什么? 我知道当捕获到 写操作 时把写操作 重定向到另外一个文件;但是当 删除,移动 一个文件时要做什么操作呢? 就是如何实现 文件删除恢复, 文件移动恢复,文件写操作恢复 ...…

查看全部问答>

fat32文件系统读写

哪位有FAT32读写的程序?支持CD,DIR命令的!比较急!有的话传我一份:hongjiujing@126.com!有会的,可以留个QQ给我.…

查看全部问答>

请问关于GPRS模块通信的问题

  小弟想用ARM做一个无线通信的项目,有些思路不太清楚。 我的ARM板的串口接一个GPRS模块(比如西门子的MC55),板子的usb口接一个摄像头,我想把摄像头采集到的图像通过板子上外接的gprs模块发送到我的pc机上,因为我实验室里的电脑是 ...…

查看全部问答>

急救:WM5注册表问题,在线等!!

我用EVC4写的程序 可以修改WM5的注册表 就是Today下面的 用我写的程序修改后 用EVC自带的注册表编辑器查看显示修改是正确地 但是 只要一重启 就还原了 不知道这个问题怎么解决 谢谢了 ps 最好不要用破解注册表这种办法…

查看全部问答>

求助:JTAG调试没问题,下载到目标板却不能正确运行

用F149做了数据采集程序,用JTAG download到目标板上,调试运行正确。退出调试后,拔掉JTAG连线,让目标板自带电源运行(3.3V),好像程序运行不了,反正结果不正确。请个位大虾指点!…

查看全部问答>

u盘扩容检测工具

u盘扩容检测工具…

查看全部问答>