在之前的博客中分析了stm32串口的结构,和详细的发送、接受过程。现在来分析固件库中对于USART的标准函数
typedef struct
{
uint32_t USART_BaudRate; // 波特率
uint16_t USART_WordLength; // 帧数据长度(8位还是9位)
uint16_t USART_StopBits; // 停止位
uint16_t USART_Parity; // 校验
uint16_t USART_Mode; // 模式:单收、单发或收发
uint16_t USART_HardwareFlowControl; // 硬件流控
} USART_InitTypeDef;
固件库中初始化函数,就是往前一篇博客中提到的控制寄存器USART_CR1 USART_CR2中写入相应的数据,并计算波特率的值,然后写入BRR寄存器。
/**
* @brief Initializes the USARTx peripheral according to the specified
* parameters in the USART_InitStruct .
* @param USARTx: Select the USART or the UART peripheral.
* This parameter can be one of the following values:
* USART1, USART2, USART3, UART4 or UART5.
* @param USART_InitStruct: pointer to a USART_InitTypeDef structure
* that contains the configuration information for the specified USART
* peripheral.
* @retval None
*/
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;
/* The hardware flow control is available only for USART1, USART2 and USART3 */
// 硬件流控只有在USART中才能使用,UART中不能用
if (USART_InitStruct->USART_HardwareFlowControl != USART_HardwareFlowControl_None)
{
assert_param(IS_USART_123_PERIPH(USARTx));
}
usartxbase = (uint32_t)USARTx;
/*---------------------------- USART CR2 Configuration -----------------------*/
// 先保存USART_CR2寄存器的状态
tmpreg = USARTx->CR2;
/* Clear STOP[13:12] bits */
// 清除CR2的停止位,其他位保持不变
tmpreg &= CR2_STOP_CLEAR_Mask;
/* Configure the USART Stop Bits, Clock, CPOL, CPHA and LastBit ------------*/
/* Set STOP[13:12] bits according to USART_StopBits value */
// 根据配置的停止位,写入到相应的位置
tmpreg |= (uint32_t)USART_InitStruct->USART_StopBits;
/* Write to USART CR2 */
// 八停止位配置写进CR2寄存器
USARTx->CR2 = (uint16_t)tmpreg;
/*---------------------------- USART CR1 Configuration -----------------------*/
tmpreg = USARTx->CR1;
/* Clear M, PCE, PS, TE and RE bits */
// 清除字长、校验、校验使能、发送和接收使能的位,再根据配置写入
tmpreg &= CR1_CLEAR_Mask;
/* Configure the USART Word Length, Parity and mode ----------------------- */
/* Set the M bits according to USART_WordLength value */
/* Set PCE and PS bits according to USART_Parity value */
/* Set TE and RE bits according to USART_Mode value */
tmpreg |= (uint32_t)USART_InitStruct->USART_WordLength | USART_InitStruct->USART_Parity |
USART_InitStruct->USART_Mode;
/* Write to USART CR1 */
// 把配置的字长、校验、模式写入到CR1寄存器
USARTx->CR1 = (uint16_t)tmpreg;
/*---------------------------- USART CR3 Configuration -----------------------*/
tmpreg = USARTx->CR3;
/* Clear CTSE and RTSE bits */
// 清除串口的发送、接收硬件流控
tmpreg &= CR3_CLEAR_Mask;
/* Configure the USART HFC -------------------------------------------------*/
/* Set CTSE and RTSE bits according to USART_HardwareFlowControl value */
tmpreg |= USART_InitStruct->USART_HardwareFlowControl;
/* Write to USART CR3 */
// 把配置的硬件流控制写入到CR3寄存器(通常不适用硬件流控)
USARTx->CR3 = (uint16_t)tmpreg;
/*---------------------------- USART BRR Configuration -----------------------*/
/* Configure the USART Baud Rate -------------------------------------------*/
RCC_GetClocksFreq(&RCC_ClocksStatus);
if (usartxbase == USART1_BASE)
{
apbclock = RCC_ClocksStatus.PCLK2_Frequency;
}
else
{
apbclock = RCC_ClocksStatus.PCLK1_Frequency;
}
/* Determine the integer part */
if ((USARTx->CR1 & CR1_OVER8_Set) != 0)
{
/* Integer part computing in case Oversampling mode is 8 Samples */
integerdivider = ((25 * apbclock) / (2 * (USART_InitStruct->USART_BaudRate)));
}
else /* if ((USARTx->CR1 & CR1_OVER8_Set) == 0) */
{
/* Integer part computing in case Oversampling mode is 16 Samples */
integerdivider = ((25 * apbclock) / (4 * (USART_InitStruct->USART_BaudRate)));
}
tmpreg = (integerdivider / 100) << 4;
/* Determine the fractional part */
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);
}
/* Write to USART BRR */
USARTx->BRR = (uint16_t)tmpreg;
}
接下来是在同步串口通信中使用的结构体,虽然这个用的很少,但学习时还是应该全面,因此也分析一下
typedef struct
{
uint16_t USART_Clock; // 时钟使能
uint16_t USART_CPOL; // 时钟极性(High或者Low)
// 表示串口空闲时时钟是高电平还是低电平
uint16_t USART_CPHA; // 时钟相位(USART_CPHA_1Edge或者USART_CPHA_2Edge)
// 表示在时钟的第一个边沿采集数据还是第二个边沿采集数据
// 时钟的极性和相位一定是配合使用的
uint16_t USART_LastBit; // 选择最后一位数据的时钟会不会发出
} USART_ClockInitTypeDef;
我们再看以一下固件库中的其他常用的配置函数
// 使能串口,配置的是CR1_UE位
void USART_Cmd(USART_TypeDef* USARTx, FunctionalState NewState)
{
/* Check the parameters */
assert_param(IS_USART_ALL_PERIPH(USARTx));
assert_param(IS_FUNCTIONAL_STATE(NewState));
if (NewState != DISABLE)
{
/* Enable the selected USART by setting the UE bit in the CR1 register */
USARTx->CR1 |= CR1_UE_Set;
}
else
{
/* Disable the selected USART by clearing the UE bit in the CR1 register */
USARTx->CR1 &= CR1_UE_Reset;
}
}
// DMA请求
void USART_DMACmd(USART_TypeDef* USARTx, uint16_t USART_DMAReq, FunctionalState NewState)
{
/* Check the parameters */
assert_param(IS_USART_ALL_PERIPH(USARTx));
assert_param(IS_USART_DMAREQ(USART_DMAReq));
assert_param(IS_FUNCTIONAL_STATE(NewState));
if (NewState != DISABLE)
{
/* Enable the DMA transfer for selected requests by setting the DMAT and/or
DMAR bits in the USART CR3 register */
USARTx->CR3 |= USART_DMAReq;
}
else
{
/* Disable the DMA transfer for selected requests by clearing the DMAT and/or
DMAR bits in the USART CR3 register */
USARTx->CR3 &= (uint16_t)~USART_DMAReq;
}
}
然后是中断配置函数,有很多个中断可以选择。这个函数写的还是有点复杂,仔细看,起始可以发现,基本就是如下过程。通过中断标志,来判断该中断由CR1(偏移地址0X0C)还是CR2(偏移0X10),或者是CR3(偏移0X14)。然后把相应寄存器的中断使能标志位置1。
/**
* @brief Enables or disables the specified USART interrupts.
* @param USARTx: Select the USART or the UART peripheral.
* This parameter can be one of the following values:
* USART1, USART2, USART3, UART4 or UART5.
* @param USART_IT: specifies the USART interrupt sources to be enabled or disabled.
* This parameter can be one of the following values:
* @arg USART_IT_CTS: CTS change interrupt (not available for UART4 and UART5)
* @arg USART_IT_LBD: LIN Break detection interrupt
* @arg USART_IT_TXE: Transmit Data Register empty interrupt
* @arg USART_IT_TC: Transmission complete interrupt
* @arg USART_IT_RXNE: Receive Data register not empty interrupt
* @arg USART_IT_IDLE: Idle line detection interrupt
* @arg USART_IT_PE: Parity Error interrupt
* @arg USART_IT_ERR: Error interrupt(Frame error, noise error, overrun error)
* @param NewState: new state of the specified USARTx interrupts.
* This parameter can be: ENABLE or DISABLE.
* @retval None
*/
void USART_ITConfig(USART_TypeDef* USARTx, uint16_t USART_IT, FunctionalState NewState)
{
uint32_t usartreg = 0x00, itpos = 0x00, itmask = 0x00;
uint32_t usartxbase = 0x00;
/* Check the parameters */
assert_param(IS_USART_ALL_PERIPH(USARTx));
assert_param(IS_USART_CONFIG_IT(USART_IT));
assert_param(IS_FUNCTIONAL_STATE(NewState));
/* The CTS interrupt is not available for UART4 and UART5 */
if (USART_IT == USART_IT_CTS)
{
assert_param(IS_USART_123_PERIPH(USARTx));
}
usartxbase = (uint32_t)USARTx;
/* Get the USART register index */
usartreg = (((uint8_t)USART_IT) >> 0x05);
/* Get the interrupt position */
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 */
设计资源 培训 开发板 精华推荐
- 12元星球大战无人机改装2.5寸FPV空心杯机架
- LTC6263IMS 音频耳机桥式驱动器运算放大器的典型应用
- ADR280 低成本电流源的典型应用
- 用于指纹认证支付交易的卡片概念证明的生物识别系统
- 使用 Diodes Incorporated 的 PT8A 3518CPE 的参考设计
- 使用 Analog Devices 的 LTC1479CG 的参考设计
- REF193 具有限流功能的精密微功耗、低压差、电压基准的典型应用
- NB4N840MMNEVB:双路 2x2 交叉点开关评估板
- AXP173【电源管理芯片】超详细注释
- 采用双层 TO-220 封装的 3.3V 1A、低 EMI、效率达 92% 的直流/直流模块参考设计