历史上的今天
返回首页

历史上的今天

今天是:2024年12月23日(星期一)

正在发生

2021年12月23日 | STM32串口通信-USART全面讲解

2021-12-23 来源:eefocus

通用同步异步收发器(Universal Synchronous Asynchronous Receiver and Transmitter)是一个全双工的串行通信设备;UART(Universal Asynchronous Receiver and Transmitter)是在USART基础上裁掉了同步通信功能,只有异步通信。


USART满足外部设备对工业标准NRZ异步串行数据格式的要求,并且使用了小数波特率发生器,可以提供多种波特率。USART支持同步单向通信和半双工单线通信;还支持局域互连网络、智能卡协议与LrDA SIR ENDEC规范;还支持DMA,可实现高速数据通信。


如下图是USART功能框图,我们将对此框图进行分析。

1.功能引脚

TX:发送数据输出引脚


RX:接收数据输入引脚


SW_RX:数据接收引脚,内部引脚,只用于单线和智能卡模式


nRTS:发送请求输出端,n表示低电平有效。如果是能RTS流控制,当USART接收器准备好接收新的数据时会将nRTS编程低电平;当接收寄存器已满时,nRTS将会被设置为高电平,该引脚至适用于硬件流控制。


nCTS:请求发送输入端,n表示低电平有效。如果使能CTS流控制,发送器在发送下一帧数据之前会检测nCTS引脚,如果为低电平则发送数据,如果为高电平则在发送完当前数据之后停止发送,该引脚只适用于硬件流控制。


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


注意:UART只有异步传输功能,故没有SCLK、nRTS和nCTS引脚。


2.数据寄存器

USART数据寄存器(USART_DR)包含TDR和RDR,两者是介于系统总线和移位寄存器之间,只有低9位或低8有效,两者选择取决于USART控制寄存器1(USART_CR1)的M位,M=0为8位数据字长,M=1为9位数据字长。


3.控制器

USART有专门的控制发送的发送器、控制接收的接收器,还有唤醒单元、中断控制等。使用USART之前,需要将USART_CR1的UE置1,使能串口时钟供给。


发送器:


USART_CR1的TE置1,启动数据发送,发送移位寄存器的数据会以低位在前、高位在后的形式从TX引脚输出,如果是同步模式SCLK也将输出时钟信号。


如下,字符发送时序图所示,一个字符帧发送需要三个部分:起始位+数据帧+停止位。起始位是一个位周期的低电平;数据帧是我们发送的8位或9位数据;停止位是一定时间周期的高电平,可以设置为0.5、1、1.5、2个停止位,默认使用1个停止位,2个停止位适用于USART模式、单线模式和调制解调器模式,0.5和1.5适用于智能卡模式。

发送数据重要的标志位

image.png?imageView2/2/w/550

接收器


如果USART_CR1的RE置位,使能USART接受,使得接收器在RX线开始搜索起始位。接收数据时,几个比较重要的标志位如下

image.png?imageView2/2/w/550

4.小波特率生成

波特率指数据信号对载波的调制速率,它用单位时间内载波调制状态改变次数来表示,单位为波特。比特率指单位时间内传播的比特数。对于USART波特率与比特率相等。


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

其中,f为USART时钟,USARTDIV是一个放在波特率寄存器(USART_BRR)的一个无符号定点数。其中 DIV_Mantissa[11:0]位定义USARTDIV的整数部分,DIV_Fraction[3:0]位定义USARTDIV 的小数部分。


5.校验控制

USART支持奇偶校验。使用校验位时,串口传输的数据长度将是在8位的数据帧基础上加上1位,此时需要将USART_CR1的M为置1,然后将USART_CR1的PCE置1启动奇偶校验。


奇偶校验在发送和接收都是由硬件自动完成,如果在接收出现奇偶校验失败,会将USART_SR的PE置1,并可以产生奇偶校验中断。


6.中断控制

USART有多个中断请求事件,如下

image.png?imageView2/2/w/550

7.USART初始化结构体详解

HAL库函数对每个外设都建立了一个初始化结构体和初始化配置函数,如USART_InitTypeDef和USART_Init(),USART_InitTypeDef用于配置外设工作参数,USART_Init()则将参数配置到相应的寄存器。


typedef struct {

 uint32_t BaudRate; //波特率

 uint32_t WordLength; //字长

 uint32_t StopBits; //停止位

 uint32_t Parity; //校验位

 uint32_t Mode; //UART 模式

 uint32_t HwFlowCtl; //硬件流控制

 uint32_t OverSampling; // 过采样模式

 uint32_t CLKLastBit; // 最尾位时钟脉冲

} USART_InitTypeDef;

BaudRate:波特率设置。一般设置为 2400、9600、19200、115200。HAL 库函数会根据设定值计算得到 UARTDIV 值。

WordLength:数据帧字长,可选 8 位或 9 位。

StopBits:停止位设置,可选 0.5 个、1 个、1.5 个和 2 个停止位。

Parity : 奇 偶 校 验 控 制 选 择 , 可 选 USART_PARITY_NONE ( 无校验 ) 、USART_PARITY_EVEN (偶校验)以及 USART_PARITY_ODD (奇校验)。

Mode:UART 模式选择,有 USART_MODE_RX 和 USART_MODE_TX,允许使用逻辑或运算选择两个,它设定 USART_CR1 寄存器的 RE 位和 TE 位。

8.编程要点

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


2) 初始化 GPIO,并将 GPIO 复用到 USART 上;


3) 配置 USART 参数;


4) 配置中断控制器并使能 USART 接收中断;


5) 使能 USART;


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


9.代码分析

GPIO和USART宏定义


//串口波特率

#define DEBUG_USART_BAUDRATE                    115200

 

//引脚定义

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

#define DEBUG_USART                             USART1

#define DEBUG_USART_CLK_ENABLE()                __HAL_RCC_USART1_CLK_ENABLE();

 

#define DEBUG_USART_RX_GPIO_PORT                GPIOA

#define DEBUG_USART_RX_GPIO_CLK_ENABLE()        __HAL_RCC_GPIOA_CLK_ENABLE()

#define DEBUG_USART_RX_PIN                      GPIO_PIN_10

 

#define DEBUG_USART_TX_GPIO_PORT                GPIOA

#define DEBUG_USART_TX_GPIO_CLK_ENABLE()       __HAL_RCC_GPIOA_CLK_ENABLE()

#define DEBUG_USART_TX_PIN                      GPIO_PIN_9

 

#define DEBUG_USART_IRQHandler                  USART1_IRQHandler

#define DEBUG_USART_IRQ                      USART1_IRQn

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

 

void Usart_SendString(uint8_t *str);

void DEBUG_USART_Config(void);

int fputc(int ch, FILE *f);

int fgetc(FILE *f);

extern UART_HandleTypeDef UartHandle;

USART初始化配置。函数体中UartHandle 是定义为 UART_HandleTypeDef 结构体类型的全局变量,它管理着串口的所有配置,该函数与硬件无关。


具体的MCU底层硬件相关的配置如引脚、时钟、DMA、中断等等是在HAL_UART_MspInit(UART_HandleTypeDef *huart)中完成,该函数被HAL_UART_Init 函数所调用,所以我们只需要重新定义HAL_UART_MspInit函数即可完成底层硬件的配置。


/**

  * @brief  DEBUG_USART GPIO 配置,工作模式配置。115200 8-N-1

  * @param  无

  * @retval 无

  */  

void DEBUG_USART_Config(void)

  

  UartHandle.Instance          = DEBUG_USART;

  

  UartHandle.Init.BaudRate     = DEBUG_USART_BAUDRATE;

  UartHandle.Init.WordLength   = UART_WORDLENGTH_8B;

  UartHandle.Init.StopBits     = UART_STOPBITS_1;

  UartHandle.Init.Parity       = UART_PARITY_NONE;

  UartHandle.Init.HwFlowCtl    = UART_HWCONTROL_NONE;

  UartHandle.Init.Mode         = UART_MODE_TX_RX;

  

  HAL_UART_Init(&UartHandle);

   

 /*使能串口接收断 */

  __HAL_UART_ENABLE_IT(&UartHandle,UART_IT_RXNE);  

}

/**

  * @brief UART MSP 初始化 

  * @param huart: UART handle

  * @retval 无

  */

void HAL_UART_MspInit(UART_HandleTypeDef *huart)

{  

  GPIO_InitTypeDef  GPIO_InitStruct;

  

  DEBUG_USART_CLK_ENABLE();

DEBUG_USART_RX_GPIO_CLK_ENABLE();

  DEBUG_USART_TX_GPIO_CLK_ENABLE();

  

/**USART1 GPIO Configuration    

  PA9     ------> USART1_TX

  PA10    ------> USART1_RX 

  */

  /* 配置Tx引脚为复用功能  */

  GPIO_InitStruct.Pin = DEBUG_USART_TX_PIN;

  GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;

  GPIO_InitStruct.Pull = GPIO_PULLUP;

  GPIO_InitStruct.Speed =  GPIO_SPEED_FREQ_HIGH;

  HAL_GPIO_Init(DEBUG_USART_TX_GPIO_PORT, &GPIO_InitStruct);

  

  /* 配置Rx引脚为复用功能 */

  GPIO_InitStruct.Pin = DEBUG_USART_RX_PIN;

  GPIO_InitStruct.Mode=GPIO_MODE_AF_INPUT; //模式要设置为复用输入模式!

  HAL_GPIO_Init(DEBUG_USART_RX_GPIO_PORT, &GPIO_InitStruct); 

 

  HAL_NVIC_SetPriority(DEBUG_USART_IRQ ,0,1); //抢占优先级0,子优先级1

  HAL_NVIC_EnableIRQ(DEBUG_USART_IRQ );     //使能USART1中断通道  

}

字符发送函数


/*****************  发送字符串 **********************/

void Usart_SendString(uint8_t *str)

{

unsigned int k=0;

  do 

  {

      HAL_UART_Transmit(&UartHandle,(uint8_t *)(str + k) ,1,1000);

      k++;

  } while(*(str + k)!='');

  

}

中断服务函数


void  DEBUG_USART_IRQHandler(void)

{

  uint8_t ch=0; 

  

if(__HAL_UART_GET_FLAG( &UartHandle, UART_FLAG_RXNE ) != RESET)

{

    ch=( uint16_t)READ_REG(UartHandle.Instance->DR);

    WRITE_REG(UartHandle.Instance->DR,ch); 

 

}

}

在嵌入式中,串口经常用作日志打印工具,下面代码功能是重定向printf和scanf函数,fputc是printf的内部函数,而fgetc是scanf的内部函数。


//重定向c库函数printf到串口DEBUG_USART,重定向后可使用printf函数

int fputc(int ch, FILE *f)

{

/* 发送一个字节数据到串口DEBUG_USART */

HAL_UART_Transmit(&UartHandle, (uint8_t *)&ch, 1, 1000);

return (ch);

}

 

//重定向c库函数scanf到串口DEBUG_USART,重写向后可使用scanf、getchar等函数

int fgetc(FILE *f)

{

int ch;

HAL_UART_Receive(&UartHandle, (uint8_t *)&ch, 1, 1000);

return (ch);

}

推荐阅读

史海拾趣

Altmustech公司的发展小趣事

创新是Altmustech公司发展的核心动力。公司不断投入研发资金,引进优秀人才,推动技术创新和产品升级。从最初的半导体芯片到后来的智能设备、物联网解决方案,Altmustech始终站在技术前沿,引领行业发展趋势。这种持续的创新精神使得公司在激烈的市场竞争中始终保持领先地位。

德艺隆(DEALON)公司的发展小趣事

在激烈的市场竞争中,德艺隆始终坚持诚信经营的原则。他们严格遵守承诺,对客户提供的商业信息严格保密,不向任何第三方泄露。这种高度的诚信度赢得了客户的信任,许多客户都愿意与德艺隆建立长期合作关系。同时,德艺隆还积极参与社会公益活动,回馈社会,进一步提升了公司的品牌形象。

Comus_International公司的发展小趣事

在过去几十年里,Comus International通过持续的有机增长和收购增长相结合的方式,实现了公司的快速发展。这种增长策略不仅使公司规模不断扩大,也使其业务范围更加广泛。最终,Comus International成功发展成为一家集团公司,成为电子行业中的佼佼者。

以上就是Comus International在电子行业中的五个发展故事。这些故事充分展示了公司在创新、质量、服务以及市场拓展等方面的卓越表现,也揭示了其能够在竞争激烈的电子行业中脱颖而出的原因。

Crystal Semiconductor Corp公司的发展小趣事

在快速发展的同时,Crystal Semiconductor Corp也注重可持续发展。公司积极推行环保理念,采用环保材料和工艺生产产品。同时,公司还加大了对教育和公益事业的投入,培养了一批批优秀的半导体人才。展望未来,Crystal Semiconductor Corp将继续秉承创新、务实、高效的理念,不断推动半导体行业的发展。

请注意,这些故事是虚构的,旨在展示一个半导体公司可能经历的发展阶段和挑战。如果您需要关于Crystal Semiconductor Corp的真实故事,建议您查阅相关公司资料或新闻报道。

昆泰(CHRONTEL)公司的发展小趣事

进入21世纪后,昆泰的创始人Dr. Gillings不满足于CRO企业的平稳收益和稳定现金流,他开始寻求与药企建立更加紧密的战略合作伙伴关系。为此,昆泰在2000年成立了PharmaBio部门,通过资金、技术和销售团队为客户提供全方位的支持。这一战略转型不仅使昆泰与药企建立了深厚的合作关系,还为其带来了丰厚的回报。

北京人民电器厂公司的发展小趣事

近年来,随着新能源产业的快速发展,北京人民电器紧跟时代步伐,在新能源领域取得了重要突破。公司推出的真安型零飞弧直流断路器,解决了直流低压系统中长期存在的外喷电弧问题,为新能源行业的发展提供了重要的技术支持。这一创新成果不仅得到了行业的广泛认可,也为公司在新能源领域的发展打开了新的局面。

这五个故事只是北京人民电器在电子行业发展历程中的一部分,但它们足以展现出公司在技术创新、产品应用、生产自动化、人才队伍建设以及新能源领域发展等方面的努力和成就。这些故事不仅记录了北京人民电器的成长轨迹,也见证了中国电子行业的蓬勃发展。

问答坊 | AI 解惑

发展嵌入式软件企业要练好“内功”

嵌入式系统无疑已成为当前业界看好的巨大“蛋糕”。数据显示,2007年中国嵌入式软件产业规模已达到1803.6亿元。而日前,财政部、国家税务总局发布的《关于嵌入式软件增值税政策的通知》(以下简称《通知》),对嵌入式软件的相关增值税政策进行了调 ...…

查看全部问答>

车牌颜色识别

能告诉我几个简单的颜色识别 算法吗?  或者告诉我去哪里找? 我到处找但找不到啊…

查看全部问答>

driver於何時被啟動?

當執行oeminit時drvier是這段期間被執行嗎 還是在何時? thx…

查看全部问答>

eZ430学习笔记之一在Win7下使用

拿到板子后想在Win7下使用eZ430—RF2500,折腾了差不多两天的时间,但出现问题最后的UART不能安装上,出现的错误如下:       首先我专门去找用于USB通信的TUSB3410驱动,结果到TI的官网找到http://focus.ti.com/docs/toolsw ...…

查看全部问答>

DIY MSP430 系列USB接口的 JTAG 器件采购问题

USB的JTAG里有些精密电阻不好吗? TAOBAO里问了些都没有,希望那位朋友有什么好的店家可以透露透露啊! 特别里面的哪些0。1%的电阻 3    1K5                    & ...…

查看全部问答>

万方数据免费下载方法

新年带给大家个好消息!万方数据是中国最全的学术资料库(论文、期刊、图书),但通常需收费用才能其官方网站下载文献。现寻得一种免费下载万方数据的方法与各位研友共同分享,在“上海研发公共服务平台”(政府公益性质)注册审核通过后,便可在“上 ...…

查看全部问答>

有关430的定时器捕获,出现程序卡死

大致是这样的,我用430的定时器捕获,来获取脉冲的宽度,在上下边沿捕获沿,加了捕获中断,运行一会儿,就会出现程序卡死的现象,这是怎么回事啊,详细描述一下:用430的定时器捕获功能来获取超声波模块的测距的时间差,就是在时间差脉冲的两个沿都 ...…

查看全部问答>

【Hanker M4】 第11篇 645规约简单uart通信+LCD+EEPROM

本帖最后由 常见泽1 于 2015-6-7 15:35 编辑 【Hanker M4】 第11篇 645规约简单uart通信+LCD+EEPROM 1.前言前面几篇简单的实现了IIC——EEPROM数据的读写,LCD的按键和循环显示,以及简单的645规约,现在将这些整合起来 实现如下大致功能: (1) ...…

查看全部问答>

EEWORLD大学堂----斩波电路(3) - 电荷泵电路

斩波电路(3) - 电荷泵电路:https://training.eeworld.com.cn/course/2273…

查看全部问答>