STM32F103系列实战之通用同步异步收发器(USART)
通用同步/异步收发器(USART)
STM32F103xC、 STM32F103xD和STM32F103xE增强型系列产品中,内置了3个通用同步/异步收发器(USART1、 USART2和USART3),和2个通用异步收发器(UART4和UART5)。这5个接口提供异步通信、支持IrDA SIR ENDEC传输编解码、多处理器通信模式、单线半双工通信模式和LIN主/从功能。USART1接口通信速率可达4.5兆位/秒,其他接口的通信速率可达2.25兆位/秒。USART1、 USART2和USART3接口具有硬件的CTS和RTS信号管理、兼容ISO7816的智能卡模式和类SPI通信模式,除了UART5之外所有其他接口都可以使用DMA操作。
1.USART主要特性
1.1.全双工的,异步通信
1.2.NRZ标准格式
1.3.分数波特率发生器系统
1.3.1发送和接收共用的可编程波特率,最高达4.5Mbits/s
1.4.可编程数据字长度(8位或9位)
1.5.可配置的停止位-支持1或2个停止位
1.6.LIN主发送同步断开符的能力以及LIN从检测断开符的能力
1.6.1当USART硬件配置成LIN时,生成13位断开符;检测10/11位断开符
1.7.发送方为同步传输提供时钟
1.8.IRDA SIR 编码器解码器
1.8.1.在正常模式下支持3/16位的持续时间
1.9.智能卡模拟功能
1.9.1.智能卡接口支持ISO7816-3标准里定义的异步智能卡协议
1.9.2.智能卡用到的0.5和1.5个停止位
1.10.单线半双工通信
1.11.可配置的使用DMA的多缓冲器通信
1.11.1.在SRAM里利用集中式DMA缓冲接收/发送字节
1.12.单独的发送器和接收器使能位
1.13.检测标志
1.13.1.接收缓冲器满
1.13.2.发送缓冲器空
1.13.3.传输结束标志
1.14.校验控制
1.14.1.发送校验位
1.14.2.对接收数据进行校验
1.15.四个错误检测标志
1.15.1.溢出错误
1.15.2.噪音错误
1.15.3.帧错误
1.15.4.校验错误
1.16.10个带标志的中断源
1.16.1.CTS改变
1.16.2.LIN断开符检测
1.16.3.发送数据寄存器空
1.16.4.发送完成
1.16.5.接收数据寄存器满
1.16.6.检测到总线为空闲
1.16.7.溢出错误
1.16.8.帧错误
1.16.9.噪音错误
1.16.10.校验错误
1.17.多处理器通信 -- 如果地址不匹配,则进入静默模式
1.18.从静默模式中唤醒(通过空闲总线检测或地址标志检测)
1.19.两种唤醒接收器的方式:地址位(MSB,第9位),总线空闲
2.USART功能概述
接口通过三个引脚与其他设备连接在一起(见下图)。任何USART双向通信至少需要两个脚:接收数据输入(RX)和发送数据输出(TX)。
RX:接收数据输入。通过过采样技术来区别数据和噪音,从而恢复数据。
TX:发送数据输出。当发送器被禁止时,输出引脚恢复到它的I/O端口配置。当发送器被激活,并且不发送数据时,TX引脚处于高电平。在单线和智能卡模式里,此I/O口被同时用于数据的发送和接收。
2.1.总线在发送或接收前应处于空闲状态
2.2.一个起始位
2.3.一个数据字(8或9位),最低有效位在前
2.4.0.5,1,1.5, 2个的停止位,由此表明数据帧的结束
2.5.使用分数波特率发生器 —— 12位整数和4位小数的表示方法。
2.6.一个状态寄存器(USART_SR)
2.7.数据寄存器(USART_DR)
2.8.一个波特率寄存器(USART_BRR), 12位的整数和4位小数
2.9.一个智能卡模式下的保护时间寄存器(USART_GTPR)
在同步模式中需要下列引脚:
CK:发送器时钟输出。此引脚输出用于同步传输的 时钟, (在Start位和Stop位上没有时钟脉冲,软件可选地,可以在最后一个数据位送出一个时钟脉冲)。数据可以在RX上同步被接收。这可以用来控制带有移位寄存器的外部设备(例如LCD驱动器)。时钟相位和极性都是软件可编程的。在智能卡模式里,CK可以为智能卡提供时钟。
在IrDA模式里需要下列引脚:
IrDA_RDI: IrDA模式下的数据输入;
IrDA_TDO: IrDA模式下的数据输出。
下列引脚在硬件流控模式中需要:
nCTS: 清除发送,若是高电平,在当前数据传输结束时阻断下一次的数据发送;
nRTS: 发送请求,若是低电平,表明USART准备好接收数据。
下面以STM32F103ZET6为例,通过库函数结合寄存器配置来介绍一下通用同步异步收发器的异步收发器使用(项目验证运行稳定)。
串口设置的一般(常规)步骤可以总结为如下几个步骤:
1) 串口时钟使能, GPIO 时钟使能;
2) 串口复位 (可省略);
3) GPIO 端口模式设置;
4) 串口参数初始化;
5) 开启中断并且初始化 NVIC(如果需要开启中断才需要这个步骤);
6) 使能串口;
7) 编写中断处理函数。
除了上述常规的配置方法,USART还可以利用DMA连续通信。 Rx缓冲器和Tx缓冲器的DMA请求是分别产生的。
利用DMA发送
使用DMA进行发送,可以通过设置USART_CR3寄存器上的DMAT位激活。当TXE位被置为’1’时, DMA就从指定的SRAM区传送数据到USART_DR寄存器。为USART的发送分配一个DMA通道的步骤如下(x表示通道号):
1. 在DMA控制寄存器上将USART_DR寄存器地址配置成DMA传输的目的地址。在每个TXE事件后,数据将被传送到这个地址。
2. 在DMA控制寄存器上将存储器地址配置成DMA传输的源地址。在每个TXE事件后,将从此存储器区读出数据并传送到USART_DR寄存器。
3. 在DMA控制寄存器中配置要传输的总的字节数。
4. 在DMA寄存器上配置通道优先级。
5. 根据应用程序的要求,配置在传输完成一半还是全部完成时产生DMA中断。
6. 在DMA寄存器上激活该通道。
当传输完成DMA控制器指定的数据量时, DMA控制器在该DMA通道的中断向量上产生一中断。
在发送模式下,当DMA传输完所有要发送的数据时, DMA控制器设置DMA_ISR寄存器的TCIF标志;监视USART_SR寄存器的TC标志可以确认USART通信是否结束,这样可以在关闭USART或进入停机模式之前避免破坏最后一次传输的数据;软件需要先等待TXE=1,再等待TC=1。
利用DMA接收
可以通过设置USART_CR3寄存器的DMAR位激活使用DMA进行接收,每次接收到一个字节,DMA控制器就就把数据从USART_DR寄存器传送到指定的SRAM区(参考DMA相关说明)。为USART的接收分配一个DMA通道的步骤如下(x表示通道号):
1. 通过DMA控制寄存器把USART_DR寄存器地址配置成传输的源地址。在每个RXNE事件后,将从此地址读出数据并传输到存储器。
2. 通过DMA控制寄存器把存储器地址配置成传输的目的地址。在每个RXNE事件后,数据将从USART_DR传输到此存储器区。
3. 在DMA控制寄存器中配置要传输的总的字节数。
4. 在DMA寄存器上配置通道优先级。
5. 根据应用程序的要求配置在传输完成一半还是全部完成时产生DMA中断。
6. 在DMA控制寄存器上激活该通道。
当接收完成DMA控制器指定的传输量时, DMA控制器在该DMA通道的中断矢量上产生一中断。
多缓冲器通信中的错误标志和中断产生
在多缓冲器通信的情况下,通信期间如果发生任何错误,在当前字节传输后将置起错误标志。如果中断使能位被设置,将产生中断。在单个字节接收的情况下,和RXNE一起被置起的帧错误、溢出错误和噪音标志,有单独的错误标志中断使能位;如果设置了,会在当前字节传输结束后,产生中断。
代码如下:
1.定义接收和发送数据缓存变量
#define COMx_RXBUFFER_SIZE 255 //串口接收缓存器长度
typedef struct COMx_RXBUFFER
{u8 buffer[COMx_RXBUFFER_SIZE]; //接收缓存器u8 RxFlag; //接收数据标志 1:接收到新数据 0:无新数据被接收u16 RxLen; //接收到数据长度
}COMx_RXBUFFER;
#define UART1_RX_LEN COMx_RXBUFFER_SIZE //USART1 DMA接收缓存器长度
uint8_t Uart1_Tx[UART1_TX_LEN] = {0}; //串口1发送DMA缓存
uint8_t Uart1_Rx[UART1_RX_LEN] = {0}; //串口1接收DMA缓存
//串口1接收DMA缓存
COMx_RXBUFFER Uart1_RxBuffer;
2.配置串口
static void BSP_USART1_Init(u32 baud)
{USART_InitTypeDef bsp_usart_init;GPIO_InitTypeDef bsp_usartpin_init; //使能USART1时钟、使能USART1引脚时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA, ENABLE); //初始化USART1引脚PA9 TXbsp_usartpin_init.GPIO_Pin = GPIO_Pin_9;bsp_usartpin_init.GPIO_Speed = GPIO_Speed_50MHz;bsp_usartpin_init.GPIO_Mode = GPIO_Mode_AF_PP;GPIO_Init(GPIOA, &bsp_usartpin_init); //初始化USART1引脚PA10 RXbsp_usartpin_init.GPIO_Pin = GPIO_Pin_10;bsp_usartpin_init.GPIO_Mode = GPIO_Mode_IN_FLOATING;GPIO_Init(GPIOA, &bsp_usartpin_init); //初始化USART1参数bsp_usart_init.USART_BaudRate = baud;bsp_usart_init.USART_WordLength = USART_WordLength_8b;bsp_usart_init.USART_StopBits = USART_StopBits_1;bsp_usart_init.USART_Parity = USART_Parity_No;bsp_usart_init.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;bsp_usart_init.USART_HardwareFlowControl = USART_HardwareFlowControl_None; USART_Init(USART1, &bsp_usart_init); //初始化中断BSP_NVIC_Init(USART1_IRQn, 1, 1); //开启USART1总线空闲中断USART_ITConfig(USART1,USART_IT_TC,DISABLE); USART_ITConfig(USART1,USART_IT_RXNE,DISABLE); USART_ITConfig(USART1,USART_IT_IDLE,ENABLE); //串口接收DMA配置BSP_DMAUsar1Rx_Init();//串口发送DMA配置BSP_DMAUsar1Tx_Init();USART_DMACmd(USART1,USART_DMAReq_Rx,ENABLE); //采用DMA方式接收//开启USART1USART_Cmd(USART1, ENABLE);
}
分析上面代码:
1.串口时钟使能。 串口是挂载在 APB2 下面的外设,所以使能函数为:
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1);
2.串口复位。 当外设出现异常的时候可以通过复位设置,实现该外设的复位,然后重新配置这个外设达到让其重新工作的目的。一般在系统刚开始配置外设的时候,都会先执行复位该外设的操作(此处省略);
3.GPIO 端口模式设置 。按照下图配置引脚,这里用的USART1 对应引脚PA9 (TX) PA10(RX);
4.串口参数配置。自定义波特率,1位起始位,1位停止位,8位数据位,无校验,无流控。使能接收和发送数据功能。
5.开启总线空闲中断,并初始化中断。关于中断参考相关内容
初始化中断代码如下:
/*
*********************************************************************************************************
* BSP_NVIC_Init()
*
* Description : 中断优先级初始化函数,用于给中断设定优先级
*
* Argument(s) : IRQChannel 中断通道.
* PreemptionPrio 中断抢占优先级
* SubPrio 中断子优先级
*
* Return(s) : none.
*
* Caller(s) : Application.
*
* Note(s) : none.
*********************************************************************************************************
*/
void BSP_NVIC_Init(u8 IRQChannel, u8 PreemptionPrio, u8 SubPrio)
{NVIC_InitTypeDef bsp_nvic_init;bsp_nvic_init.NVIC_IRQChannel = IRQChannel;bsp_nvic_init.NVIC_IRQChannelPreemptionPriority = PreemptionPrio;bsp_nvic_init.NVIC_IRQChannelSubPriority = SubPrio;bsp_nvic_init.NVIC_IRQChannelCmd = ENABLE;NVIC_Init(&bsp_nvic_init);
}
6.配置DMA方式接收串口数据。关于DMA参见DMA控制器介绍。
代码如下:
//USART1接收DMA配置
static void BSP_DMAUsar1Rx_Init(void)
{DMA_InitTypeDef DMA_InitStructure; RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE); //启动DMA时钟 DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)(&USART1->DR); //外设地址 DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)Uart1_Rx; //内存地址 DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; //dma传输方向单向 DMA_InitStructure.DMA_BufferSize = UART1_RX_LEN; //设置DMA在传输时缓冲区的长度 DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; //禁止DMA的外设递增模式,一个外设 DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; //设置DMA的内存递增模式 DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; //外设数据字长 DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; //内存数据字长 DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; //设置DMA的传输模式 DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh; //设置DMA的优先级别 DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; //禁止DMA的2个memory中的变量互相访问DMA_Init(DMA1_Channel5,&DMA_InitStructure); DMA_Cmd(DMA1_Channel5,ENABLE); //使能通道5
}
7.配置DMA方式发送串口数据。代码如下:
//USART1发送DMA配置
static void BSP_DMAUsar1Tx_Init(void)
{DMA_InitTypeDef DMA_InitStructure;RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE); //启动DMA时钟 DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)(&USART1->DR); //DMA外设基地址DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)Uart1_Tx; //DMA内存基地址DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST; //数据传输方向,从内存读取发送到外设DMA_InitStructure.DMA_BufferSize = UART1_TX_LEN; //DMA通道的DMA缓存的大小DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; //外设地址寄存器不变DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; //内存地址寄存器递增DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; //数据宽度为8位DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; //数据宽度为8位DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; //工作在正常模式DMA_InitStructure.DMA_Priority = DMA_Priority_Medium; //DMA通道 x拥有中优先级 DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; //DMA通道x没有设置为内存到内存传输DMA_Init(DMA1_Channel4, &DMA_InitStructure); //根据DMA_InitStruct中指定的参数初始化DMA的通道USART1_Tx_DMA_Channel所标识的寄存器
}
8.使能DMA方式接收数据,开启串口功能。
9.中断处理函数如下:
//USART1中断函数。
void USART1_IRQHandler(void)
{ uint16_t i = 0; OSIntEnter(); if(USART_GetITStatus(USART1, USART_IT_IDLE) != RESET) {//1.清除USART1接收完成中断//USART_ClearFlag(USART1,USART_IT_IDLE); USART1->SR; USART1->DR; //清USART_IT_IDLE标志 //2.存储收到的数据内容、长度、标志位DMA_Cmd(DMA1_Channel5,DISABLE); //关闭DMAif(!Uart1_RxBuffer.RxFlag) //判断是否有数据包在处理{Uart1_RxBuffer.RxLen = UART1_RX_LEN - DMA_GetCurrDataCounter(DMA1_Channel5); //计算接收数据包长度 for (i = 0;i < Uart1_RxBuffer.RxLen;i++) //将接收到的数据包缓存{ Uart1_RxBuffer.buffer[i] = Uart1_Rx[i]; }Uart1_RxBuffer.RxFlag = 1; //置位接收状态标志位}DMA_SetCurrDataCounter(DMA1_Channel5,UART1_RX_LEN); //设置传输数据长度DMA_Cmd(DMA1_Channel5,ENABLE); //打开DMA } // 3. Send message to task_command_processOSMboxPost(MboxCmdSet, &Uart1_RxBuffer.buffer[0]); // Inform App_TaskCommandProcess() that one command has arrived.OSIntExit();
}
因为项目基于ucos-ii系统开发的,所以中断函数里含有ucos-ii系统相关函数。中断处理步骤如下:
9.1.判断中断类型是否是总线空闲中断。否,不作任何处理退出中断;是,继续一下处理;
9.2.清除中断标志;
9.3.关闭DMA接收功能,获取接收数据长度;
9.4.根据接收数据长度从DMA接收缓存区提取接收到的数据;
9.5.重设DMA传输数据长度并打开DMA接收功能;
9.6.退出中断处理函数。
由于串口接收数据的时间点是未知的,所以采用中断来处理接收的数据。但是只有接收没有放松明显不行,下面介绍一下发送数据函数。代码如下:
//USART1 DMA发送指定长度的数据
//str:要发送的数据首地址
//cndtr:数据传输量
void BSP_DMAUsart1Puts(unsigned char *str,u8 cndtr)
{ memcpy(Uart1_Tx, str, cndtr);USART_DMACmd(USART1,USART_DMAReq_Tx,ENABLE); //使能串口1的DMA发送DMA_Cmd(DMA1_Channel4, DISABLE ); //关闭USART1 TX DMA1 所指示的通道 DMA_SetCurrDataCounter(DMA1_Channel4,cndtr); //DMA通道的DMA缓存的大小DMA_Cmd(DMA1_Channel4, ENABLE); //使能USART1 TX DMA1 所指示的通道
}
通过串口发送数据的时刻是可预知的,所以采用普通的方式发送串口数据即可。步骤如下:
1.将要发送的数据传送至DMA发送缓存区中;
2.关闭DMA串口发送数据功能;
3.设置发送数据size;
4.使能DMA串口发送功能,将数据发送出去。
到此,串口通信的内容就介绍完了。想要获取接收的数据,只要查看变量Uart1_RxBuffer.buffer[]里的数据;至于发送数据,调用下面的函数即可。
void BSP_DMAUsart1Puts(unsigned char *str,u8 cndtr);
STM32F103系列实战之通用同步异步收发器(USART)相关推荐
- 17、STM8S通用同步异步收发器(UART)
文章目录 1.概述 2.串口主要特点 3.UART功能描述 4.UART主要特点 5.异步串行通信的字符格式 6.串行通信的传送速率 1.概述 STM8S 微控制器家族的通用同步异步收发器(UAR ...
- 通用同步和异步收发器---Usart
在介绍之前,先简单介绍几种通信协议: Usart:通用同步异步收发器,这篇文章会详细讲解的. Uart:通用异步收发器,相当于Usart的异步通信功能. SPI:串行外设接口,是一种同步协议. IIC ...
- UART 和 USART 的区别 == 通用异步收发传输器 通用同步/异步串行接收/发送器
UART 通用异步收发传输器(Universal Asynchronous Receiver/Transmitter),通常称作UART,是一种异步收发传输器,是电脑硬件的一部分.它将要传输的资料在串 ...
- PIC单片机入门_同步/异步通信技术基础
1.前言 通用同步 / 异步收发器 (Universal Synchronous/Asynchronous Receiver/Transmitter, USART) 模块是两个串行 I/O 模块之一 ...
- 基于FPGA通用异步收发器UART设计
摘要 通用异步收发器(UART)是一种能同时支持近距离和远距离传输的异步串行接口,具有传输速率较高.传输距离长.抗干扰性能好.电路结构简单以及节省布线资源等优点.然而,随着社会的发展,信息传输容量越来 ...
- 面试必会系列 - 5.1 网络BIO、NIO、epoll,同步/异步模型、阻塞/非阻塞模型,你能分清吗?
本文已收录至 Github(MD-Notes),若博客中图片模糊或打不开,可以来我的 Github 仓库,包含了完整图文:https://github.com/HanquanHq/MD-Notes,涵 ...
- platform框架--Linux MISC杂项框架--Linux INPUT子系统框架--串行集成电路总线I2C设备驱动框架--串行外设接口SPI 设备驱动框架---通用异步收发器UART驱动框架
platform框架 input. pinctrl. gpio 子系统都是 Linux 内核针对某一类设备而创建的框架, input子系统是管理输入的子系统 pinctrl 子系统重点是设置 PIN( ...
- 通用异步收发器UART
UART的介绍 UART(Universal Asynchronous Receiver/Transmitter,通用异步收发器),俗称串口. 通常计算机与外部设备通信的端口分为并行与串行: a. 并 ...
- 四、s3c2440 裸机开发 通用异步收发器UARN
四.通用异步收发器UARN 原文地址 http://blog.csdn.net/woshidahuaidan2011/article/details/51137047 by jaosn Email: ...
最新文章
- php+微信开发+解绑,微信开发之解绑设备通知的方法
- Windows安装Python包下载工具pip遇到的问题
- 利用 VBA 和 HTML自制兼容 WPS及 EXCEL(32位/64位)的颜色选择器
- 弱电工程集成商_弱电工程楼宇自控系统基础知识培训资料
- 靶形数独(信息学奥赛一本通-T1447)
- 【Kafka】kafka Removed ✘✘✘ expired offsets in ✘✘✘ milliseconds.
- HTML5模拟衣服撕扯动画
- 小米笔记本桌面计算机图标,小米笔记本桌面锁定怎么解除
- 暗黑主题(皮肤)资源 (实用)
- 手机电脑同连一个wf,手机网速比电脑网速快很多,电脑网速很慢
- 微信公众号接口调用php示例,php微信公众号js-sdk开发应用_php实例
- c语言大于一小于10,C语言首先输入一个大于2且小于10的整数
- 2018永洪科技大数据技术上海峰会-唤醒数据.遇见未来
- CVPR2020 3D点云相关论文思想和方法总结
- 七大顶级Linux桌面比较
- 维谛技术(Vertiv):一切研发创新都以客户需求为核心
- 如何获取vs code中插件Waka Time的API key
- Linux查看文本中关键字的行
- e5cz温控表中文说明书_欧姆龙温控器e5cz说明书 OMRON温控表E5EC说明书
- 编译安装oh-my-zsh
热门文章
- (二)数据结构与算法-稀疏数组
- 揭阳学计算机的好学校,揭阳初中排名2020最新排名,揭阳初中排名前十的学校有哪些...
- u 去除index.php,ThinkPHP去除url中的index.php
- 从Dataframe训练数据,构造可迭代训练的batch数据
- linux中波浪线是根目录吗,linux 波浪线 ~ 使用方法
- Splash resource_timeout 属性
- javaScript从入门到精通3.md
- SQL Server索引总结二
- linux中的特殊文件权限
- 软件开发项目文档模版