目录
|
详见STM32F10XXX英文版参考手册RM0008-Reference Manual
通用同步异步收发器(USART)提供了一种灵活的方法与使用工业标准NRZ异步串行数据格式的外部设备之间进行全双工数据交换。USART利用小数波特率发生器提供宽范围的波特率选择。
它支持同步单向通信和半双工单线通信,也支持LIN(局部互连网),智能卡协议和IrDA(红外数据组织)SIR ENDEC规范,以及调制解调器(CTS/RTS)操作。它还允许多处理器通信。
使用多缓冲器配置的DMA方式,可以实现高速数据通信。
任何USART双向通信至少需要两个引脚:接收数据输入(RX)和发送数据输出(TX)。
在同步模式中需要下列引脚:
在IrDA模式里需要下列引脚:
在硬件流控模式中需要下列引脚:
(表) USART引脚配置
关于以上寄存器中每个位的具体定义,请参考USART寄存器描述。
下表列出了USART寄存器的地址映射和复位值。可以以半字(16位)或字(32位)的方式访问这些外设寄存器。
rc_w0:软件可以读此位,也可以通过写’0’清除此位,写’1’对此位无影响。
位31:10 保留位,由硬件强制为0
位9 CTS:CTS 标志
位8 LBD:LIN断开检测标志
位7 TXE:发送数据寄存器(TDR)空
位6 TC:发送完成
位5 RXNE:读数据寄存器(RDR)非空 (Read data register not empty)
位4 IDLE:监测到总线空闲 (IDLE line detected)
位3 ORE:溢出错误 (Overrun error)
位2 NE:噪声错误标志 (Noise error)
位1 FE:帧错误 (Framing error)
位0 PE:校验错误 (Parity error)
位31:9 保留位,由硬件强制为0
位8:0 DR[8:0]:数据值 (Data value)
位31:16 保留位,硬件强制为0
位15:4 DIV_Mantissa[11:0]:USARTDIV的整数部分
位3:0 DIV_Fraction[3:0]:USARTDIV的小数部分
位31:14 保留位,硬件强制为0
位13 UE:USART使能 (USART enable)
位12 M:字长 (Word length)
位11 WAKE:唤醒的方法 (Wakeup method)
位10 PCE:检验控制使能 (Parity control enable)
位9 PS:校验选择 (Parity selection)
位8 PEIE:PE中断使能 (PE interrupt enable)
位7 TXEIE:发送缓冲区空中断使能 (TXE interrupt enable)
位6 TCIE:发送完成中断使能 (Transmission complete interrupt enable)
位5 RXNEIE:接收缓冲区非空中断使能 (RXNE interrupt enable)
位4 IDLEIE:IDLE中断使能 (IDLE interrupt enable)
位3 TE:发送使能 (Transmitter enable)
位2 RE:接收使能 (Receiver enable)
位1 RWU:接收唤醒 (Receiver wakeup)
位0 SBK:发送断开帧 (Send break)
位31:15 保留位,硬件强制为0。
位14 LINEN:LIN模式使能 (LIN mode enable)
位13:12 STOP:停止位 (STOP bits)
位11 CLKEN:时钟使能 (Clock enable)
位10 CPOL:时钟极性 (Clock polarity)
位9 CPHA: 时钟相位 (Clock phase)
位8 LBCL:最后一位时钟脉冲 (Last bit clock pulse)
位7 保留位,硬件强制为0
位6 LBDIE:LIN断开符检测中断使能 (LIN break detection interrupt enable)
位5 LBDL:LIN断开符检测长度 (LIN break detection length)
位4 保留位,硬件强制为0
位3:0 ADD[3:0]:本设备的USART节点地址
位31:11 保留位,硬件强制为0
位10 CTSIE:CTS中断使能 (CTS interrupt enable)
位9 CTSE:CTS使能 (CTS enable)
位8 RTSE:RTS使能 (RTS enable)
位7 DMAT:DMA使能发送 (DMA enable transmitter)
位6 DMAR: DMA使能接收 (DMA enable receiver)
位5 SCEN: 智能卡模式使能 (Smartcard mode enable)
位4 NACK:智能卡NACK使能 (Smartcard NACK enable)
位3 HDSEL:半双工选择 (Half-duplex selection)
位2 IRLP:红外低功耗 (IrDA low-power)
位1 IREN:红外模式使能 (IrDA mode enable)
位0 EIE:错误中断使能 (Error interrupt enable)
位31:16 保留位,由硬件强制为0
位15:8 GT[7:0]:保护时间值 (Guard time value)
位7:0 PSC[7:0]:预分频器值 (Prescaler value)
USART有三种帧格式:数据帧、空闲帧和断开帧。
由一个低电平的起始位,8位或9位数据位,和0.5/1/1.5/2个高电平的停止位组成。
其中,数据位长度(字长)取决于USART_CR1寄存器中的M位;发送和接收时,最低有效位在前;当USART_CR1寄存器中的校验控制使能位PCE=1时,最高有效位被校验位代替;在同步模式下,CK引脚是否为最高有效位提供时钟脉冲取决于USART_CR2中的LBCL位 ;停止位数取决于USART_CR2寄存器中的STOP[1:0]。
在一个帧周期内,全部为高电平。
在一个帧周期内,全部为低电平。在断开帧结束后,再发送1或2个高电平的停止位,以识别下一个低电平的起始位。
发送和接收由一共用的波特率发生器驱动,当发送器和接收器的使能位分别(TE和RE)置位时,分别为其产生时钟。接收器和发送器的波特率应设置成相同。
PCLKx可以是APB1的时钟PCLK1(用于USART1),也可以是APB2的时钟PCLK2(用于USART2、3、4、5) 。
USARTDIV是一个无符号的定点数,转换成对应的二进制小数后,整数部分存放在USART_BRR寄存器中的DIV_Maintissa[11:0],小数部分存放在USART_BRR寄存器中的DIV_Fraction[3:0]。
注:在写入USART_BRR之后,波特率计数器会被波特率寄存器的新值替换。因此,不要在通信进行中改变波特率寄存器的数值。
如果采用多缓冲器通信,需配置USART_CR3中的DMA使能位(DMAT)。按多缓冲器通信中的描述配置DMA寄存器。
如果需要产生中断,则还要设置相应中断的使能位。
完成上述配置后,就可以进行数据的发送和接收了。
如果在收发模式配置中,发送器被使能了,即TE=1,则可以进行数据的发送。
置位TE将使得USART在第一个数据帧前发送一空闲帧。
如果设置SBK=1,在完成当前数据发送后,将在TX线上发送一个断开帧。断开帧发送完成时(在断开帧的停止位时)SBK被硬件复位。USART在最后一个断开帧的结束处插入一逻辑‘1’,以保证能识别下一帧的起始位。
注意:如果在开始发送断开帧之前,软件又复位了SBK位,断开符号将不被发送。如果要发送两个连续的断开帧,SBK位应该在前一个断开符号的停止位之后置起。
在数据传输期间不能复位TE位,否则将破坏TX脚上的数据,因为波特率计数器停止计数。正在传输的当前数据将丢失。
如果在收发模式配置中,接收被使能了,即RE=1,则可以进行数据的接收。
在USART中,如果辨认出一个特殊的采样序列,那么就认为侦测到一个起始位。
该序列为:1 1 1 0 X 0 X 0 X 0 0 0 0
注意:
由于发送器在发送第一个数据帧前会发送一个空闲帧,因此接收器会接收到一个空闲帧。当一空闲帧被检测到时,其处理步骤和接收到普通数据帧一样,但如果IDLEIE位被设置将产生一个中断。
在接收期间如果检测到帧错误,噪声或溢出错误,错误标志将被置起,
在多缓冲器通信时,RXNE在每个字节接收后被置起,并由DMA对数据寄存器的读操作而清零。
在单缓冲器模式里,由软件读USART_DR寄存器完成对RXNE位清除。RXNE标志也可以通过对它写0来清除。RXNE位必须在下一字符接收结束前被清零,以避免溢出错误。
注意:在接收数据时,RE位不应该被复位。如果RE位在接收时被清零,当前接收的 数据会丢失。
当接收到一个断开帧时,USART像处理帧错误一样处理它。
如果RXNE还没有被复位,又接收到一个字符,则发生溢出错误。数据只有当RXNE位被清零后才能从移位寄存器转移到RDR寄存器。
RXNE标记是接收到每个字节后被置位的。如果下一个数据已被收到或先前DMA请求还没被服务时,RXNE标志仍是置起的,溢出错误产生。当溢出错误产生时:
注意: 当ORE位置位时,表明至少有1个数据已经丢失。有两种可能性:
使用过采样技术(同步模式除外),通过区别有效输入数据和噪声来进行数据恢复。
如果三个采样数据为000,并且接收到的数据位为0,则认为是有效数据。
如果三个采样数据为111,并且接收到的数据位为1,也认为是有效数据。
其他情况都认为是噪声。当在接收帧中检测到噪声时:
顺序执行对USART_SR和USART_DR寄存器的读操作,可复位NE位。
当以下情况发生时检测到帧错误:
由于没有同步上或大量噪音的原因,停止位没有在预期的时间内识别出来。
当帧错误被检测到时:
顺序执行对USART_SR和USART_DR寄存器的读操作,可复位FE位。
如果USART_CR1中的校验控制使能位PCE=1,发送时,写进数据寄存器的数据的MSB位被校验位替换后发送出去(PS=0,选择偶校验偶数个’1’;PS=1,选择奇校验奇数个’1’)。接收时,如果奇偶校验失败,USART_SR寄存器中的PE标志被置’1’,如果USART_CR1寄存器的PEIE=1,则中断产生。
(表) USART中断请求
USART的各种中断事件被连接到同一个中断向量(见下图),有以下各种中断事件:
如果设置了对应的使能控制位,这些事件就可以产生各自的中断。
(图) USART中断映射图
\stm32f10x_usart.h文件中
typedef struct { uint32_t USART_BaudRate; //波特率 uint16_t USART_WordLength; //字长(数据位数) uint16_t USART_StopBits; //停止位 uint16_t USART_Parity; //校验方式 uint16_t USART_Mode; //收发模式 uint16_t USART_HardwareFlowControl; //硬件流控制 } USART_InitTypeDef; /* USART_BaudRate 用于配置USART_BRR */ /* USART_WordLength 用于配置M位(USART_CR1[12]) */ #define USART_WordLength_8b ((uint16_t)0x0000) #define USART_WordLength_9b ((uint16_t)0x1000) /* USART_StopBits 用于配置STOP[1:0](USART_CR2[13:12]) */ #define USART_StopBits_1 ((uint16_t)0x0000) #define USART_StopBits_0_5 ((uint16_t)0x1000) #define USART_StopBits_2 ((uint16_t)0x2000) #define USART_StopBits_1_5 ((uint16_t)0x3000) /* USART_Parity 用于配置PCE位(USART_CR1[10])和PS位(USART_CR1[9]) */ #define USART_Parity_No ((uint16_t)0x0000) #define USART_Parity_Even ((uint16_t)0x0400) #define USART_Parity_Odd ((uint16_t)0x0600) /* USART_Mode 用于配置RE位(USART_CR1[2])和TE位(USART_CR1[3]) */ #define USART_Mode_Rx ((uint16_t)0x0004) #define USART_Mode_Tx ((uint16_t)0x0008) /* USART_HardwareFlowControl 用于配置RTSE位(USART_CR3[8])和CTSE位(USART_CR3[9]) */ #define USART_HardwareFlowControl_None ((uint16_t)0x0000) #define USART_HardwareFlowControl_RTS ((uint16_t)0x0100) #define USART_HardwareFlowControl_CTS ((uint16_t)0x0200) #define USART_HardwareFlowControl_RTS_CTS ((uint16_t)0x0300)
此处介绍的库函数只是一些比较常用的,详见\stm32f10x_usart.c文件
/*----------------------------------------------------------------------------------------------------- // 功能描述 将外设USARTx寄存器重设为缺省值 // 输入参数 USARTx:选择USART或 UART 外设 // 可以是下列值之一: // USART1, USART2, USART3, UART4 或 UART5 // 返回值 无 -----------------------------------------------------------------------------------------------------*/ void USART_DeInit(USART_TypeDef* USARTx) { /* 检查输入参数 */ assert_param(IS_USART_ALL_PERIPH(USARTx)); if (USARTx == USART1) { /* 强制或者释放APB2外设复位 */ RCC_APB2PeriphResetCmd(RCC_APB2Periph_USART1, ENABLE); RCC_APB2PeriphResetCmd(RCC_APB2Periph_USART1, DISABLE); } /* 强制或者释放APB1外设复位 */ else if (USARTx == USART2) { RCC_APB1PeriphResetCmd(RCC_APB1Periph_USART2, ENABLE); RCC_APB1PeriphResetCmd(RCC_APB1Periph_USART2, DISABLE); } else if (USARTx == USART3) { RCC_APB1PeriphResetCmd(RCC_APB1Periph_USART3, ENABLE); RCC_APB1PeriphResetCmd(RCC_APB1Periph_USART3, DISABLE); } else if (USARTx == UART4) { RCC_APB1PeriphResetCmd(RCC_APB1Periph_UART4, ENABLE); RCC_APB1PeriphResetCmd(RCC_APB1Periph_UART4, DISABLE); } else { if (USARTx == UART5) { RCC_APB1PeriphResetCmd(RCC_APB1Periph_UART5, ENABLE); RCC_APB1PeriphResetCmd(RCC_APB1Periph_UART5, DISABLE); } } }
/*----------------------------------------------------------------------------------------------------- // 功能描述 根据USART_InitStruct中指定的参数初始化外设USARTx寄存器 // 输入参数 USARTx:选择USART或 UART 外设 // 可以是下列值之一: // USART1, USART2, USART3, UART4 或 UART5 // 输入参数 USART_InitStruct:指向结构USART_InitTypeDef的指针,包含了外设USART的配置信息 // 返回值 无 -----------------------------------------------------------------------------------------------------*/ void USART_Init(USART_TypeDef* USARTx, USART_InitTypeDef* USART_InitStruct) { uint32_t tmpreg = 0x00, apbclock = 0x00; uint32_t integerdivider = 0x00; uint32_t fractionaldivider = 0x00; uint32_t usartxbase = 0; RCC_ClocksTypeDef RCC_ClocksStatus; /* 检查输入参数 */ assert_param(IS_USART_ALL_PERIPH(USARTx)); assert_param(IS_USART_BAUDRATE(USART_InitStruct->USART_BaudRate)); assert_param(IS_USART_WORD_LENGTH(USART_InitStruct->USART_WordLength)); assert_param(IS_USART_STOPBITS(USART_InitStruct->USART_StopBits)); assert_param(IS_USART_PARITY(USART_InitStruct->USART_Parity)); assert_param(IS_USART_MODE(USART_InitStruct->USART_Mode)); assert_param(IS_USART_HARDWARE_FLOW_CONTROL(USART_InitStruct->USART_HardwareFlowControl)); /* 硬件流控制只对USART1, USART2 和 USART3 有效 */ if (USART_InitStruct->USART_HardwareFlowControl != USART_HardwareFlowControl_None) { assert_param(IS_USART_123_PERIPH(USARTx)); } usartxbase = (uint32_t)USARTx; /*---------------------------- USART CR2 配置-----------------------*/ tmpreg = USARTx->CR2; /* 清除STOP[13:12] */ tmpreg &= CR2_STOP_CLEAR_Mask; /* 配置USART 停止位,时钟,时钟极性,时钟相位和最后一位------------*/ /* 根据USART_StopBits设置STOP[13:12] */ tmpreg |= (uint32_t)USART_InitStruct->USART_StopBits; /* 写USART CR2 */ USARTx->CR2 = (uint16_t)tmpreg; /*---------------------------- USART CR1 配置-----------------------*/ tmpreg = USARTx->CR1; /* 清除M, PCE, PS, TE 和 RE */ tmpreg &= CR1_CLEAR_Mask; /* 配置USART 字长,校验和模式 ----------------------- */ /* 根据USART_WordLength设置M */ /* 根据USART_Parity设置PCE和PS */ /* 根据USART_Mode设置TE和RE */ tmpreg |= (uint32_t)USART_InitStruct->USART_WordLength | USART_InitStruct->USART_Parity | USART_InitStruct->USART_Mode; /* 写USART CR1 */ USARTx->CR1 = (uint16_t)tmpreg; /*---------------------------- USART CR3 配置 -----------------------*/ tmpreg = USARTx->CR3; /* 清除CTSE和RTSE */ tmpreg &= CR3_CLEAR_Mask; /* 配置USART硬件流控制 -------------------------------------------------*/ /* 根据USART_HardwareFlowControl设置CTSE和RTSE */ tmpreg |= USART_InitStruct->USART_HardwareFlowControl; /* 写USART CR3 */ USARTx->CR3 = (uint16_t)tmpreg; /*---------------------------- USART BRR 配置 -----------------------*/ /* 配置USART波特率 -------------------------------------------*/ RCC_GetClocksFreq(&RCC_ClocksStatus); if (usartxbase == USART1_BASE) { apbclock = RCC_ClocksStatus.PCLK2_Frequency; } else { apbclock = RCC_ClocksStatus.PCLK1_Frequency; } /* 整数部分 */ if ((USARTx->CR1 & CR1_OVER8_Set) != 0) { /* 在过采样模式为8次采样下的整数部分的计算 */ integerdivider = ((25 * apbclock) / (2 * (USART_InitStruct->USART_BaudRate))); } else /* if ((USARTx->CR1 & CR1_OVER8_Set) == 0) */ { /*在过采样模式为16次采样下的整数部分的计算 */ integerdivider = ((25 * apbclock) / (4 * (USART_InitStruct->USART_BaudRate))); } tmpreg = (integerdivider / 100) << 4; /* 小数部分 */ fractionaldivider = integerdivider - (100 * (tmpreg >> 4)); /* Implement the fractional part in the register */ if ((USARTx->CR1 & CR1_OVER8_Set) != 0) { tmpreg |= ((((fractionaldivider * 8) + 50) / 100)) & ((uint8_t)0x07); } else /* if ((USARTx->CR1 & CR1_OVER8_Set) == 0) */ { tmpreg |= ((((fractionaldivider * 16) + 50) / 100)) & ((uint8_t)0x0F); } /* 写USART BRR */ USARTx->BRR = (uint16_t)tmpreg; }
/*----------------------------------------------------------------------------------------------------- // 功能描述 把USART_InitStruct中的每一个参数按缺省值填入 // 输入参数 USART_InitStruct:指向结构USART_InitTypeDef的指针,待初始化 // 返回值 无 -----------------------------------------------------------------------------------------------------*/ void USART_StructInit(USART_InitTypeDef* USART_InitStruct) { /* USART_InitStruct 成员缺省值 */ USART_InitStruct->USART_BaudRate = 9600; //波特率9600 USART_InitStruct->USART_WordLength = USART_WordLength_8b; //字长8位 USART_InitStruct->USART_StopBits = USART_StopBits_1; //停止位1位 USART_InitStruct->USART_Parity = USART_Parity_No ; //不校验 USART_InitStruct->USART_Mode = USART_Mode_Rx | USART_Mode_Tx; //收发模式 USART_InitStruct->USART_HardwareFlowControl = USART_HardwareFlowControl_None; //没有硬件流控制 }
/*----------------------------------------------------------------------------------------------------- // 功能描述 使能或者失能USART外设 // 输入参数 USARTx:选择USART或 UART 外设 // 可以是下列值之一: // USART1, USART2, USART3, UART4 或 UART5 // 输入参数 NewState:外设USARTx的新状态 // 可以是:ENABLE或DISABLE // 返回值 无 -----------------------------------------------------------------------------------------------------*/ void USART_Cmd(USART_TypeDef* USARTx, FunctionalState NewState) { /* 检查输入参数 */ assert_param(IS_USART_ALL_PERIPH(USARTx)); assert_param(IS_FUNCTIONAL_STATE(NewState)); if (NewState != DISABLE) { /* 通过设置CR1中的UE使能选择的USART */ USARTx->CR1 |= CR1_UE_Set; } else { /* 通过设置CR1中的UE失能选择的USART */ USARTx->CR1 &= CR1_UE_Reset; } }
/*----------------------------------------------------------------------------------------------------- // 功能描述 使能或失能指定的USART中断 // 输入参数 USARTx:选择USART或 UART 外设 // 可以是下列值之一: // USART1,USART2,USART3,UART4 或 UART5 // 输入参数 USART_IT:待使能或者失能的USART中断源 // 可以是下列值之一: // USART_IT_CTS: CTS 变化中断(UART4 和 UART5不可用) // USART_IT_LBD: LIN 断开检测中断 // USART_IT_TXE: 发送数据寄存器空中断 // USART_IT_TC: 发送完成中断 // USART_IT_RXNE: 接收数据寄存器非空中断 // USART_IT_IDLE: 空闲帧检测中断 // USART_IT_PE: 校验错误中断 // USART_IT_ERR: 错误中断(帧错误,噪声错误,上溢错误) // 输入参数 NewState:外设USARTx的新状态 // 可以是:ENABLE或DISABLE // 返回值 无 -----------------------------------------------------------------------------------------------------*/ void USART_ITConfig(USART_TypeDef* USARTx, uint16_t USART_IT, FunctionalState NewState) { uint32_t usartreg = 0x00, itpos = 0x00, itmask = 0x00; uint32_t usartxbase = 0x00; /* 检查输入参数 */ assert_param(IS_USART_ALL_PERIPH(USARTx)); assert_param(IS_USART_CONFIG_IT(USART_IT)); assert_param(IS_FUNCTIONAL_STATE(NewState)); /* CTS中断对UART4和UART5是无效的 */ if (USART_IT == USART_IT_CTS) { assert_param(IS_USART_123_PERIPH(USARTx)); } usartxbase = (uint32_t)USARTx; /* 获得USART寄存器索引 */ usartreg = (((uint8_t)USART_IT) >> 0x05); /* 获得中断位置 */ itpos = USART_IT & IT_Mask; itmask = (((uint32_t)0x01) << itpos); if (usartreg == 0x01) /* The IT is in CR1 register */ { usartxbase += 0x0C; } else if (usartreg == 0x02) /* The IT is in CR2 register */ { usartxbase += 0x10; } else /* 在CR3中的中断 */ { usartxbase += 0x14; } if (NewState != DISABLE) { *(__IO uint32_t*)usartxbase |= itmask; } else { *(__IO uint32_t*)usartxbase &= ~itmask; } }
/*----------------------------------------------------------------------------------------------------- // 功能描述 通过外设USARTx发送单个数据 // 输入参数 USARTx:选择USART或 UART 外设 // 可以是下列值之一: // USART1, USART2, USART3, UART4 或 UART5 // 输入参数 Data:待发送的数据 // 返回值 无 -----------------------------------------------------------------------------------------------------*/ void USART_SendData(USART_TypeDef* USARTx, uint16_t Data) { /* 检查输入参数 */ assert_param(IS_USART_ALL_PERIPH(USARTx)); assert_param(IS_USART_DATA(Data)); /* 发送数据 */ USARTx->DR = (Data & (uint16_t)0x01FF); }
/*----------------------------------------------------------------------------------------------------- // 功能描述 返回USARTx最近接收到的数据 // 输入参数 USARTx:选择USART或 UART 外设 // 可以是下列值之一: // USART1, USART2, USART3, UART4 或 UART5 // 返回值 接收到的数据 -----------------------------------------------------------------------------------------------------*/ uint16_t USART_ReceiveData(USART_TypeDef* USARTx) { /* 检查输入参数 */ assert_param(IS_USART_ALL_PERIPH(USARTx)); /* 接收数据 */ return (uint16_t)(USARTx->DR & (uint16_t)0x01FF); }
/*----------------------------------------------------------------------------------------------------- // 功能描述 检查指定的USART标志位设置与否 // 输入参数 USARTx:选择USART或 UART 外设 // 可以是下列值之一: // USART1,USART2,USART3,UART4 或 UART5 // 输入参数 USART_FLAG:待检查的USART标志位 // 可以是下列值之一: // USART_ FLAG _CTS: CTS 变化标志(UART4 和 UART5不可用) // USART_ FLAG _LBD: LIN 断开检测标志 // USART_ FLAG _TXE: 发送数据寄存器空标志 // USART_ FLAG _TC: 发送完成标志 // USART_ FLAG _RXNE: 接收数据寄存器非空标志 // USART_ FLAG _IDLE: 空闲帧检测标志 // USART_ FLAG _ORE: 上溢错误标志 // USART_ FLAG _NE: 噪声错误标志 // USART_ FLAG _FE: 帧错误标志 // USART_ FLAG _PE: 校验错误标志 // 返回值 USART_FLAG的新状态(SET或者RESET) -----------------------------------------------------------------------------------------------------*/ FlagStatus USART_GetFlagStatus(USART_TypeDef* USARTx, uint16_t USART_FLAG) { FlagStatus bitstatus = RESET; /* 检查输入参数 */ assert_param(IS_USART_ALL_PERIPH(USARTx)); assert_param(IS_USART_FLAG(USART_FLAG)); /* CTS标志对UART4和UART5是无效的 */ if (USART_FLAG == USART_FLAG_CTS) { assert_param(IS_USART_123_PERIPH(USARTx)); } if ((USARTx->SR & USART_FLAG) != (uint16_t)RESET) { bitstatus = SET; } else { bitstatus = RESET; } return bitstatus; }
/*----------------------------------------------------------------------------------------------------- // 功能描述 清除USARTx的挂起标志 // 输入参数 USARTx:选择USART或 UART 外设 // 可以是下列值之一: // USART1,USART2,USART3,UART4 或 UART5 // 输入参数 USART_FLAG:待清除的USART标志 // 可以是下列值的任意组合: // USART_ FLAG _CTS: CTS 变化标志(UART4 和 UART5不可用) // USART_ FLAG _LBD: LIN 断开检测标志 // USART_ FLAG _TC: 发送完成标志 // USART_ FLAG _RXNE: 接收数据寄存器非空标志 // // 注意 // - PE(校验错误),FE(帧错误),NE(噪声错误),ORE(上溢错误) // 和IDLE(空闲帧检测)标志通过软件时序被清除: // 一个对USART_SR 寄存器的读操作(USART_GetFlagStatus()) // 后跟一个对USART_DR 寄存器的读操作 (USART_ReceiveData())。 // - RXNE 标志也可以通过读USART_DR 寄存器被清除(USART_ReceiveData())。 // - TC 标志也可以通过软件时序被清除: // 一个对USART_SR 寄存器的读操作(USART_GetFlagStatus()) // 后跟一个对USART_DR 寄存器的写操作(USART_SendData())。 // - TXE标志只能通过写USART_DR 寄存器被清除(USART_SendData())。 // 返回值 无 -----------------------------------------------------------------------------------------------------*/ void USART_ClearFlag(USART_TypeDef* USARTx, uint16_t USART_FLAG) { /* 检查输入参数 */ assert_param(IS_USART_ALL_PERIPH(USARTx)); assert_param(IS_USART_CLEAR_FLAG(USART_FLAG)); /* CTS标志对UART4和UART5是无效的 */ if ((USART_FLAG & USART_FLAG_CTS) == USART_FLAG_CTS) { assert_param(IS_USART_123_PERIPH(USARTx)); } USARTx->SR = (uint16_t)~USART_FLAG; }
/*----------------------------------------------------------------------------------------------------- // 功能描述 检查指定的USART中断发生与否 // 输入参数 USARTx:选择USART或 UART 外设 // 可以是下列值之一: // USART1,USART2,USART3,UART4 或 UART5 // 输入参数 USART_IT:待检查的USART中断源 // 可以是下列值之一: // USART_ IT _CTS: CTS 变化中断(UART4 和 UART5不可用) // USART_ IT _LBD: LIN 断开检测中断 // USART_ IT _TXE: 发送数据寄存器空中断 // USART_ IT _TC: 发送完成中断 // USART_ IT _RXNE: 接收数据寄存器非空中断 // USART_ IT _IDLE: 空闲帧检测中断 // USART_ IT _ORE: 上溢错误中断 // USART_ IT _NE: 噪声错误中断 // USART_ IT _FE: 帧错误中断 // USART_ IT _PE: 校验错误中断 // 返回值 USART_FLAG的新状态(SET或者RESET) -----------------------------------------------------------------------------------------------------*/ ITStatus USART_GetITStatus(USART_TypeDef* USARTx, uint16_t USART_IT) { uint32_t bitpos = 0x00, itmask = 0x00, usartreg = 0x00; ITStatus bitstatus = RESET; /* 检查输入参数 */ assert_param(IS_USART_ALL_PERIPH(USARTx)); assert_param(IS_USART_GET_IT(USART_IT)); /* CYS中断对UART4和UART5是无效的 */ if (USART_IT == USART_IT_CTS) { assert_param(IS_USART_123_PERIPH(USARTx)); } /* 获得USART寄存器索引 */ usartreg = (((uint8_t)USART_IT) >> 0x05); /* 获得中断位置 */ itmask = USART_IT & IT_Mask; itmask = (uint32_t)0x01 << itmask; if (usartreg == 0x01) /* The IT is in CR1 register */ { itmask &= USARTx->CR1; } else if (usartreg == 0x02) /* The IT is in CR2 register */ { itmask &= USARTx->CR2; } else /* 在CR3中的中断 */ { itmask &= USARTx->CR3; } bitpos = USART_IT >> 0x08; bitpos = (uint32_t)0x01 << bitpos; bitpos &= USARTx->SR; if ((itmask != (uint16_t)RESET)&&(bitpos != (uint16_t)RESET)) { bitstatus = SET; } else { bitstatus = RESET; } return bitstatus; }
/*----------------------------------------------------------------------------------------------------- // 功能描述 清除USARTx的中断挂起位 // 输入参数 USARTx:选择USART或 UART 外设 // 可以是下列值之一: // USART1,USART2,USART3,UART4 或 UART5 // 输入参数 USART_IT:待清除的USART中断挂起位 // 可以是下列值之一: // USART_ IT _CTS: CTS 变化中断(UART4 和 UART5不可用) // USART_ IT _LBD: LIN 断开检测中断 // USART_ IT _TC: 发送完成中断 // USART_ IT _RXNE: 接收数据寄存器非空中断 // // 注意 // - PE(校验错误),FE(帧错误),NE(噪声错误),ORE(上溢错误) // 和IDLE(空闲帧检测)挂起位通过软件时序被清除: // 一个对USART_SR 寄存器的读操作(USART_GetFlagStatus()) // 后跟一个对USART_DR 寄存器的读操作 (USART_ReceiveData())。 // - RXNE 挂起位也可以通过读USART_DR 寄存器被清除(USART_ReceiveData())。 // - TC 挂起位也可以通过软件时序被清除: // 一个对USART_SR 寄存器的读操作(USART_GetFlagStatus()) // 后跟一个对USART_DR 寄存器的写操作(USART_SendData())。 // - TXE标志只能通过写USART_DR 寄存器被清除(USART_SendData())。 // 返回值 无 -----------------------------------------------------------------------------------------------------*/ void USART_ClearITPendingBit(USART_TypeDef* USARTx, uint16_t USART_IT) { uint16_t bitpos = 0x00, itmask = 0x00; /* 检查输入参数 */ assert_param(IS_USART_ALL_PERIPH(USARTx)); assert_param(IS_USART_CLEAR_IT(USART_IT)); /* CTS中断对UART4和UART5是无效的 */ if (USART_IT == USART_IT_CTS) { assert_param(IS_USART_123_PERIPH(USARTx)); } bitpos = USART_IT >> 0x08; itmask = ((uint16_t)0x01 << (uint16_t)bitpos); USARTx->SR = (uint16_t)~itmask; }
实例USART_HyperTerminal_Interrupt
int main(void) { /* NVIC 配置 */ NVIC_Configuration(); /* USARTx 配置 ------------------------------------------------------*/ /* USARTx 配置如下: - 波特率9600 - 字长8位 - 停止位2位 - 奇校验 - 不使用硬件流控制 (RTS 和 CTS 信号) - 收发使能 */ USART_InitStructure.USART_BaudRate = 9600; USART_InitStructure.USART_WordLength = USART_WordLength_8b; USART_InitStructure.USART_StopBits = USART_StopBits_2; USART_InitStructure.USART_Parity = USART_Parity_Odd; USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; STM_EVAL_COMInit(COM1, &USART_InitStructure); /* 使能 EVAL_COM1 发送中断:当EVAL_COM1 发送数据寄存器空,产生该中断 */ USART_ITConfig(EVAL_COM1, USART_IT_TXE, ENABLE); /* 使能 EVAL_COM1 接收中断:当EVAL_COM1 接收数据寄存器非空,产生该中断 */ USART_ITConfig(EVAL_COM1, USART_IT_RXNE, ENABLE); while (1) { } }
/*----------------------------------------------------------------------------------------------------- // 功能描述 配置NVIC // 输入参数 无 // 返回值 无 -----------------------------------------------------------------------------------------------------*/ void NVIC_Configuration(void) { NVIC_InitTypeDef NVIC_InitStructure; /* 使能 USARTx 中断 */ NVIC_InitStructure.NVIC_IRQChannel = USARTx_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); }
#define COMn 2 // 描述 COM1口的定义,连接到 USART1 #define EVAL_COM1 USART1 #define EVAL_COM1_CLK RCC_APB2Periph_USART1 #define EVAL_COM1_TX_PIN GPIO_Pin_9 #define EVAL_COM1_TX_GPIO_PORT GPIOA #define EVAL_COM1_TX_GPIO_CLK RCC_APB2Periph_GPIOA #define EVAL_COM1_RX_PIN GPIO_Pin_10 #define EVAL_COM1_RX_GPIO_PORT GPIOA #define EVAL_COM1_RX_GPIO_CLK RCC_APB2Periph_GPIOA #define EVAL_COM1_IRQn USART1_IRQn // 描述 COM2口的定义,连接到 USART2 (USART2 引脚被映射到 GPIOD) #define EVAL_COM2 USART2 #define EVAL_COM2_CLK RCC_APB1Periph_USART2 #define EVAL_COM2_TX_PIN GPIO_Pin_5 #define EVAL_COM2_TX_GPIO_PORT GPIOD #define EVAL_COM2_TX_GPIO_CLK RCC_APB2Periph_GPIOD #define EVAL_COM2_RX_PIN GPIO_Pin_6 #define EVAL_COM2_RX_GPIO_PORT GPIOD #define EVAL_COM2_RX_GPIO_CLK RCC_APB2Periph_GPIOD #define EVAL_COM2_IRQn USART2_IRQn
USART_TypeDef* COM_USART[COMn] = {EVAL_COM1, EVAL_COM2}; GPIO_TypeDef* COM_TX_PORT[COMn] = {EVAL_COM1_TX_GPIO_PORT, EVAL_COM2_TX_GPIO_PORT}; GPIO_TypeDef* COM_RX_PORT[COMn] = {EVAL_COM1_RX_GPIO_PORT, EVAL_COM2_RX_GPIO_PORT}; const uint32_t COM_USART_CLK[COMn] = {EVAL_COM1_CLK, EVAL_COM2_CLK}; const uint32_t COM_TX_PORT_CLK[COMn] = {EVAL_COM1_TX_GPIO_CLK, EVAL_COM2_TX_GPIO_CLK}; const uint32_t COM_RX_PORT_CLK[COMn] = {EVAL_COM1_RX_GPIO_CLK, EVAL_COM2_RX_GPIO_CLK}; const uint16_t COM_TX_PIN[COMn] = {EVAL_COM1_TX_PIN, EVAL_COM2_TX_PIN}; const uint16_t COM_RX_PIN[COMn] = {EVAL_COM1_RX_PIN, EVAL_COM2_RX_PIN}; /*----------------------------------------------------------------------------------------------------- // 功能描述 配置COM口 // 输入参数 COM:指定待配置的COM口 // 该参数可以是下列参数之一: // COM1 // COM2 // 输入参数 USART_InitStruct:指向结构USART_InitTypeDef的指针,包含USART外设的配置信息 // 返回值 无 -----------------------------------------------------------------------------------------------------*/ void STM_EVAL_COMInit(COM_TypeDef COM, USART_InitTypeDef* USART_InitStruct) { GPIO_InitTypeDef GPIO_InitStructure; /* 使能 GPIO 时钟 */ RCC_APB2PeriphClockCmd(COM_TX_PORT_CLK[COM] | COM_RX_PORT_CLK[COM] | RCC_APB2Periph_AFIO, ENABLE); /* 使能 UART 时钟 */ if (COM == COM1) { RCC_APB2PeriphClockCmd(COM_USART_CLK[COM], ENABLE); } else { /* 使能 USART2 引脚软件重映射 */ GPIO_PinRemapConfig(GPIO_Remap_USART2, ENABLE); RCC_APB1PeriphClockCmd(COM_USART_CLK[COM], ENABLE); } /* 配置 USART Tx 为复用推挽输出模式 */ GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_InitStructure.GPIO_Pin = COM_TX_PIN[COM]; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(COM_TX_PORT[COM], &GPIO_InitStructure); /* 配置 USART Rx 为浮空输入模式 */ GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; GPIO_InitStructure.GPIO_Pin = COM_RX_PIN[COM]; GPIO_Init(COM_RX_PORT[COM], &GPIO_InitStructure); /* USART 配置 */ USART_Init(COM_USART[COM], USART_InitStruct); /* 使能 USART */ USART_Cmd(COM_USART[COM], ENABLE); }
#ifdef USE_STM3210C_EVAL #define USARTx_IRQHandler USART2_IRQHandler #else #define USARTx_IRQHandler USART1_IRQHandler #endif #define TxBufferSize (countof(TxBuffer) - 1) #define RxBufferSize 0x20 #define countof(a) (sizeof(a) / sizeof(*(a))) uint8_t TxBuffer[] = "\n\rUSART Hyperterminal Interrupts Example: USART-Hyperterminal\ communication using Interrupt\n\r"; uint8_t RxBuffer[RxBufferSize]; uint8_t NbrOfDataToTransfer = TxBufferSize; uint8_t NbrOfDataToRead = RxBufferSize; uint8_t TxCounter = 0; uint16_t RxCounter = 0; /*----------------------------------------------------------------------------------------------------- // 功能描述 该函数处理 USARTx 总的中断请求 // 输入参数 无 // 返回值 无 -----------------------------------------------------------------------------------------------------*/ void USARTx_IRQHandler(void) { if(USART_GetITStatus(EVAL_COM1, USART_IT_RXNE) != RESET) { /* 读一个字节从数据寄存器 */ RxBuffer[RxCounter++] = (USART_ReceiveData(EVAL_COM1) & 0x7F); if(RxCounter == NbrOfDataToRead) { /* 关闭 EVAL_COM1 接收中断 */ USART_ITConfig(EVAL_COM1, USART_IT_RXNE, DISABLE); } } if(USART_GetITStatus(EVAL_COM1, USART_IT_TXE) != RESET) { /* 写一个字节到数据寄存器 */ USART_SendData(EVAL_COM1, TxBuffer[TxCounter++]); if(TxCounter == NbrOfDataToTransfer) { /* 关闭 EVAL_COM1 发送中断 */ USART_ITConfig(EVAL_COM1, USART_IT_TXE, DISABLE); } } }
文件:TB 串口实验系统框图.png
USART1的初始化大致分为下面4个步骤: 1、RCC配置
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
2、GPIO配置
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &GPIO_InitStructure); ::配置 USART1 Rx 为浮空输入模式 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; GPIO_Init(GPIOA, &GPIO_InitStructure);
3、NVIC配置
NVIC_InitTypeDef NVIC_InitStructure; NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0); NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure);
4、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_Rx | USART_Mode_Tx; USART_Init(USART1, &USART_InitStructure);
USART_ITConfig(USART1, USART_IT_TXE, ENABLE); ::使能RXNE中断 USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
USART_Cmd(USART1, ENABLE);
实验要求开发板先向PC发送数据,表示开发板已经做好了接收数据的准备。PC接收后,就可以向开发板发送数据了。开发板接收到PC发来的数据后,立即将数据再发回给PC,以实现回显功能。当PC向开发板发送的数据是回车(\r')时,PC端要实现回车的功能(回到下一行行首),开发板就要发回'\n'和'\r'。只有在开始时,开发板向PC发送数据时,使用了TXE中断,在回显时,并没有使用到TXE中断,因此,在开发板发送完提示信息后,必须将TXE中断关闭。使用LED3指示数据正在传输。
文件:TB 串口实验主程序流程图.png
文件:TB 串口实验中断服务程序流程图.png
int main(void) { /* 初始化TB开发板上的LED3 */ TB_LEDInit(LED3); /* 初始化TB开发板上的COM(USART1) */ TB_COMInit(); while (1) { } }
/*----------------------------------------------------------------------------------------------------- // 功能描述 初始化TB开发板上的COM口(USART1) // 输入参数 无 // 返回值 无 -----------------------------------------------------------------------------------------------------*/ void TB_COMInit(void) { GPIO_InitTypeDef GPIO_InitStructure; /* RCC 配置 -----------------------------------------------------------------*/ /* 使能 GPIOA 和 AFIO 时钟,USART1 Tx 和 PA9 复用,USART1 Rx 和 PA10 复用 */ RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO, ENABLE); /* 使能 USART1 时钟 */ RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE); /* GPIO 配置 ----------------------------------------------------------------*/ /* 配置 USART1 Tx 为复用推挽输出模式 */ GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &GPIO_InitStructure); /* 配置 USART1 Rx 为浮空输入模式 */ GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; GPIO_Init(GPIOA, &GPIO_InitStructure); /* NVIC 配置 ----------------------------------------------------------------*/ /* 使能 USART1 中断 */ NVIC_InitTypeDef NVIC_InitStructure; NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0); NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); /* USART1 配置 ---------------------------------------------------------------*/ /* USART1 配置如下: - 波特率9600 - 字长8位 - 停止位1位 - 不使用校验 - 不使用硬件流控制 (RTS 和 CTS 信号) - 收发使能 */ 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_Rx | USART_Mode_Tx; USART_Init(USART1, &USART_InitStructure); /* 使能 USART1 发送中断:当 USART1 发送数据寄存器空,产生该中断 */ USART_ITConfig(USART1, USART_IT_TXE, ENABLE); /* 使能 USART1 接收中断:当 USART1 接收数据寄存器非空,产生该中断 */ USART_ITConfig(USART1, USART_IT_RXNE, ENABLE); /* 使能 USART1 */ USART_Cmd(USART1, ENABLE); }
uint8_t TX[] = "Connection is successful! Please input:\n\r"; uint8_t Counter = 0; void Delay(__IO uint32_t nCount); /*----------------------------------------------------------------------------------------------------- // 功能描述 该函数处理 USART1 总的中断请求 // 输入参数 无 // 返回值 无 -----------------------------------------------------------------------------------------------------*/ void USART1_IRQHandler(void) { if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) { uint16_t c; TB_LEDOn(LED3); c = USART_ReceiveData(USART1); if(c == '\r') { USART_SendData(USART1, '\n'); while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET); } USART_SendData(USART1, c); Delay(0xffff); TB_LEDOff(LED3); } if(USART_GetITStatus(USART1, USART_IT_TXE) != RESET) { TB_LEDOn(LED3); USART_SendData(USART1, TX[Counter++]); if(Counter == sizeof(TX)) USART_ITConfig(USART1, USART_IT_TXE, DISABLE); Delay(0xffff); EM_TB_LEDOff(LED3); } } /*----------------------------------------------------------------------------------------------------- // 功能描述 插入一段延迟 // 输入参数 nCount:指定延迟时间长度 // 返回值 无 -----------------------------------------------------------------------------------------------------*/ void Delay(__IO uint32_t nCount) { for(; nCount != 0; nCount--); }