1.程序设计
USART3 初始化函数代码如下:
/**
* @name RS485_Configuration(uint32_t baudrate, uint16_t wordlength,
* uint16_t stopbits, uint16_t Parity)
* @brief Configure RS485(Usart2) clock, gpio and nvic:
* RS485_TX USART2_TX PB10
* RS485_RX USART2_RX PB11
* RS485_RE PC4
* RS485_DE PC5
* @param baudrate 9600 115200
* wordlength USART_WordLength_8b/USART_WordLength_9b
* stopbits USART_StopBits_1/USART_StopBits_2
* parity USART_Parity_No/USART_Parity_Even
* @retval None
*/
void RS485_Configuration(uint32_t baudrate, uint16_t wordlength, uint16_t stopbits, uint16_t parity)
{
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOC | RCC_APB2Periph_AFIO, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3,ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4 | GPIO_Pin_5;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOC, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_Init(GPIOB, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOB, &GPIO_InitStructure);
RCC_APB1PeriphResetCmd(RCC_APB1Periph_USART3,ENABLE); // Start Reset USART2
RCC_APB1PeriphResetCmd(RCC_APB1Periph_USART3,DISABLE); // Stop Reset USART2
USART_InitStructure.USART_BaudRate = baudrate;
USART_InitStructure.USART_WordLength = wordlength;
USART_InitStructure.USART_StopBits = stopbits;
USART_InitStructure.USART_Parity = parity;
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
USART_Init(USART3, &USART_InitStructure);
NVIC_InitStructure.NVIC_IRQChannel = USART3_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
USART_ITConfig(USART3, USART_IT_RXNE, ENABLE); // 开启接收中断(字节中断)
USART_ITConfig(USART3, USART_IT_IDLE, ENABLE); // 开启空闲中断( 帧中断)
USART_Cmd(USART3, ENABLE);
RS485_TX_DISABLE; // Disable Tx Mode
}
USART3 中断函数代码如下:
uint8_t USART3_RX_BUF[80]; // 缓存最大80个字节,第1个字节为接收帧字节数量
/**
* @name USART3_IRQHandler
* @brief This function handles USART3 Handler
* @param None
* @retval None
*/
void USART3_IRQHandler(void)
{
uint8_t res;
uint8_t clear = clear; // 清除空闲中断标志位标志
static uint8_t Rx_Sta = 1; // 计数器
if(USART_GetITStatus(USART3, USART_IT_RXNE) != RESET) // 接收到字节
{
res = USART3->DR; // 读取接收到的字节,清除接收中断标志位
USART3_RX_BUF[Rx_Sta++] = res; // 缓存接收到的字节
}
else if(USART_GetITStatus(USART3, USART_IT_IDLE) != RESET) // 检测到空闲
{
clear = USART3->SR;
clear = USART3->DR; // 清除空闲中断标志位(请参照芯片参考手册)
USART3_RX_BUF[0] = Rx_Sta - 1; // 一帧字节数计算
Rx_Sta = 1;
}
}
- USART3_RX_BUF为接收缓存区,定义为80个字节,第一个字节USART3_RX_BUF[0]为接收到的字节个数,后面为接收到的数据。
- USART3_RX_BUF[0]可以作为数据帧字节长度的判断。
- res = USART3->DR清除接收中断标志位。
参考STM32F10xxx英文参考手册,当PDR移位寄存器中的数据转移到USART_DR寄存器中,该位被硬件置位。如果USART_CR1寄存器中的RXNE=1,则产生中断。对USART_DR进行读取操作可以将该标志位清除。
也可以通过写入0来清除,但这种方式只推荐用于多缓存通讯。
- clear = USART3->SR;
clear = USART3->DR;清除空闲中断标志位。
参考STM32F10xxx英文参考手册,当检测到总线空闲,该位被硬件置位。如果USART_CR1寄存器中的IDLEIE=1,则产生中断。使用软件序列可以清除该标志位(先对USART_SR读取,再对USART_DR读取)。
IDLE标志位不会再次被置高直到RXNE标志位被置高,即又检测到一次空闲总线。
通俗地讲:
空闲中断检测到一次空闲后,会自动失能,清除标志位后也不会再次触发;
当接收到新的数据时,空闲中断会自动使能,检测到空闲就产生中断。
空闲中断的使用是基于接收中断的,必须开启接收中断才能正常使用。
2. 最后
此教程由本人独立整理,如有不当之处,欢迎留言指出。
本教程只提供方法,仅供学习,未经本人同意,不得用于其他任何用途。
专注于实战经验分享的博客