1.串口空闲中断的理解
其实发送的两个字符之间间隔非常短,所以在两个字符之间不叫空闲。空闲的定义是总线上在一个字节的时间内没有再接收到数据,空闲中断是检测到有数据被接收后,总线上在一个字节的时间内没有再接收到数据的时候发生的。
而总线在什么情况时,会有一个字节时间内没有接收到数据呢?一般就只有一个数据帧发送完成的情况,所以串口的空闲中断也叫帧中断。
2. 代码实现
相关变量声明
#define USART1_EN 1//串口使能标志
#if USART1_EN == 1
uint8_t RxBuffer1[24];//串口数据接收缓冲区
__IO uint8_t RxCounter1; //串口接收数据长度记录
bool RX1_flag = false;//串口接收完成标志
#endif
串口IO口初始化
static void InitHardUart()//串口IO口初始化
{
GPIO_InitType GPIO_InitStructure;
#if USART1_EN == 1
/* Connect PXx to USART1_Tx
GPIO_PinAFConfig(GPIOB, GPIO_PinsSource6, GPIO_AF_0); */
/* Connect PXx to USART1_Rx
GPIO_PinAFConfig(GPIOB, GPIO_PinsSource7, GPIO_AF_0);*/
/* Configure USART1 Tx/Rx amd USART2 Tx/Rx */
/*GPIO_InitStructure.GPIO_Pins = GPIO_Pins_6 | GPIO_Pins_7;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_MaxSpeed = GPIO_MaxSpeed_50MHz;
GPIO_InitStructure.GPIO_OutType = GPIO_OutType_PP;
GPIO_InitStructure.GPIO_Pull = GPIO_Pull_NOPULL;
GPIO_Init(GPIOB, &GPIO_InitStructure); */
//=====================寄存器代码===start========
//设置复用输出类型
GPIOB->AFR[0] &= ~(0xff000000);
GPIOB->AFR[0] |= (0x00000000);
GPIOB->MODER &= ~(0XF000);
GPIOB->MODER |= (0XA000);//设置复用输出
GPIOB->OTYPER &= ~(0xC0);
GPIOB->OTYPER |= (0x00);//设置推挽输出
//设置输出速度
GPIOB->HDRV &= ~(0x00C0);
GPIOB->HDRV |= (0x00C0);//设置速度为高
GPIOB->ODRVR &= ~(0XF000);
GPIOB->PUPDR &= ~(0XF000);//设置上拉/下拉
GPIOB->PUPDR |= (0X0000);
//=====GPIOB->ot================寄存器代码===end========
#endif
#if USART2_EN == 1
#endif
}
串口时钟初始化
//时钟初始化
static void UART_RCC_Config(void)
{
/* Enable GPIO clock */
RCC_AHBPeriphClockCmd(RCC_AHBPERIPH_GPIOB, ENABLE);//串口IO口时钟使能
#if USART1_EN == 1
/* Enable USART1 Clock
RCC_APB2PeriphClockCmd(RCC_APB2PERIPH_USART1, ENABLE); */
RCC->APB2EN &= ~(0X4000);
RCC->APB2EN |= (0X4000);//串口时钟使能
#endif
}
串口中断优先级设置
//串口中断优先级初始化
static void UART_NVIC_Config(void)
{
#if USART1_EN == 1
NVIC_InitType NVIC_InitStructure;
/* Configure the NVIC Preemption Priority Bits */
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);
/* Enable the USART2 Interrupt */
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);
#endif
}
串口参数设置
//串口参数初始化
/* 函 数 名: SetBaudrate
* 功能说明: 配置串口波特率
* 形 参: USARTx.串口 Value.波特率*/
static void SetBaudrate(USART_Type *USARTx, uint32_t Value)
{
/* USART_InitType USART_InitStructure;
USART_InitStructure.USART_BaudRate = UART1_BAUD; //设置波特率
USART_InitStructure.USART_WordLength = USART_WordLength_8b;//设置数据位为8位
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;//工作模式:发送和接收
Configure USART1
USART_Init(USARTx, &USART_InitStructure);*/
//=====================寄存器代码===start========
//设置波特率 USART_BaudRate
float temp;
float fraction; //小数部分
u16 mantissa;//整数部分
//计算出USARTDIV
temp = UART1_BAUD;//不能直接将UART1_BAUD代入计算 USARTDIV 的公式
temp = (120*1000*1000)/(temp*16);//at32的时钟频率为120M
//取波特率整数部分
mantissa = temp;
//计算波特率小数部分
fraction = (temp - mantissa)*16+1;
//计算波特率的值
mantissa=(mantissa<<4)+fraction;
USARTx->BAUDR = mantissa;//波特率赋值
//设置数据形式 USART_WordLength
USARTx->CTRL1 &= ~(0x1000);
USARTx->CTRL1 |= (0x0000);//一个起始位,8 个数据位,n 个停止位
//设置停止位 USART_StopBits
USARTx->CTRL2 &= ~(0x3000);
USARTx->CTRL2 |= (0x0000);//1 个停止位
//设置校验位 USART_Parity
USARTx->CTRL1 &= ~(0x0400);
USARTx->CTRL1 |= (0x0000);//禁止校验控制;
//设置硬件流控制 USART_HardwareFlowControl
USARTx->CTRL3 &= ~(0x0030);
USARTx->CTRL3 |= (0x0000);//禁止 RTS 硬件流控制,0:禁止 CTS 硬件流控制;
//设置传输模式 USART_Mode
USARTx->CTRL1 &= ~(0x000C);
USARTx->CTRL1 |= (0x000C);//使能接收,并开始搜寻 RX 引脚上的起始位。使能发送。
//=====================寄存器代码===end========
/* Clear USART1 Interrupt Flag
USART_ClearFlag(USART1, USART_FLAG_RDNE);*/
//清除接收标志
USARTx->STS = ~(USART_FLAG_RDNE);
/* 串口接收中断和串口空闲中断使能 */
USART_INTConfig(USARTx, USART_INT_RDNE, ENABLE);//接收中断
USART_INTConfig(USARTx, USART_INT_IDLEF, ENABLE);//空闲中断
//接收中断使能
// USARTx->CTRL1 |= (1<<5);
//空闲中断使能
// USARTx->CTRL1 |= (1<<4);
/* Enable the USART1
USART_Cmd(USART1, ENABLE); */
//串口使能
USARTx->CTRL1 |= 0x2000;
}
View Code
串口初始化
//功能说明: 串口初始化
void bsp_InitUsart(void)
{
UART_RCC_Config();//串口时钟使能
UART_NVIC_Config();//中断优先级初始化
InitHardUart();//IO口初始化
#if USART1_EN == 1
SetBaudrate(USART1, UART1_BAUD);
#endif
}
串口中断函数编写
/**
* @brief This function handles USART1 global interrupt request.
* @param None
* @retval None
*/
void USART1_IRQHandler(void)
{
if(USART_GetITStatus(USART1, USART_INT_RDNE) != RESET)//触发串口接收中断
{
/* Read one byte from the receive data register */
// if(RxCounter1 < DATA_SIZE)
RxBuffer1[RxCounter1++] = USART_ReceiveData(USART1);//串口数据存储
}
else if(USART_GetITStatus(USART1, USART_INT_IDLEF) != RESET)//触发串口空闲中断
{
uint8_t DR_text = USART1->DT;//读取串口数据寄存器(只有读取了串口数据寄存器,串口空闲中断才会清除)
RxCounter1 = 0;//串口接收数据字节数清零
RX1_flag = true;//串口接收完成标志置位
}
}
所有代码
#define USART1_EN 1
#if USART1_EN == 1
uint8_t RxBuffer1test[12];
uint8_t RxBuffer1[24];
__IO uint8_t RxCounter1;
bool RX1_flag = false;//串口接收完成标志
#endif
#if USART2_EN == 1
#endif
static void InitHardUart()//串口IO口初始化
{
GPIO_InitType GPIO_InitStructure;
#if USART1_EN == 1
/* Connect PXx to USART1_Tx
GPIO_PinAFConfig(GPIOB, GPIO_PinsSource6, GPIO_AF_0); */
/* Connect PXx to USART1_Rx
GPIO_PinAFConfig(GPIOB, GPIO_PinsSource7, GPIO_AF_0);*/
/* Configure USART1 Tx/Rx amd USART2 Tx/Rx */
/*GPIO_InitStructure.GPIO_Pins = GPIO_Pins_6 | GPIO_Pins_7;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_MaxSpeed = GPIO_MaxSpeed_50MHz;
GPIO_InitStructure.GPIO_OutType = GPIO_OutType_PP;
GPIO_InitStructure.GPIO_Pull = GPIO_Pull_NOPULL;
GPIO_Init(GPIOB, &GPIO_InitStructure); */
//=====================寄存器代码===start========
//设置复用输出类型
GPIOB->AFR[0] &= ~(0xff000000);
GPIOB->AFR[0] |= (0x00000000);
GPIOB->MODER &= ~(0XF000);
GPIOB->MODER |= (0XA000);//设置复用输出
GPIOB->OTYPER &= ~(0xC0);
GPIOB->OTYPER |= (0x00);//设置推挽输出
//设置输出速度
GPIOB->HDRV &= ~(0x00C0);
GPIOB->HDRV |= (0x00C0);//设置速度为高
GPIOB->ODRVR &= ~(0XF000);
GPIOB->PUPDR &= ~(0XF000);//设置上拉/下拉
GPIOB->PUPDR |= (0X0000);
//=====GPIOB->ot================寄存器代码===end========
#endif
#if USART2_EN == 1
#endif
}
//时钟初始化
static void UART_RCC_Config(void)
{
/* Enable GPIO clock */
RCC_AHBPeriphClockCmd(RCC_AHBPERIPH_GPIOB, ENABLE);//串口IO口时钟使能
#if USART1_EN == 1
/* Enable USART1 Clock
RCC_APB2PeriphClockCmd(RCC_APB2PERIPH_USART1, ENABLE); */
RCC->APB2EN &= ~(0X4000);
RCC->APB2EN |= (0X4000);//串口时钟使能
#endif
}
//串口中断优先级初始化
static void UART_NVIC_Config(void)
{
#if USART1_EN == 1
NVIC_InitType NVIC_InitStructure;
/* Configure the NVIC Preemption Priority Bits */
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);
/* Enable the USART2 Interrupt */
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);
#endif
}
//串口参数初始化
/* 函 数 名: SetBaudrate
* 功能说明: 配置串口波特率
* 形 参: USARTx.串口 Value.波特率*/
static void SetBaudrate(USART_Type *USARTx, uint32_t Value)
{
/* USART_InitType USART_InitStructure;
USART_InitStructure.USART_BaudRate = UART1_BAUD; //设置波特率
USART_InitStructure.USART_WordLength = USART_WordLength_8b;//设置数据位为8位
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;//工作模式:发送和接收
Configure USART1
USART_Init(USARTx, &USART_InitStructure);*/
//=====================寄存器代码===start========
//设置波特率 USART_BaudRate
float temp;
float fraction; //小数部分
u16 mantissa;//整数部分
//计算出USARTDIV
temp = UART1_BAUD;//不能直接将UART1_BAUD代入计算 USARTDIV 的公式
temp = (120*1000*1000)/(temp*16);//at32的时钟频率为120M
//取波特率整数部分
mantissa = temp;
//计算波特率小数部分
fraction = (temp - mantissa)*16+1;
//计算波特率的值
mantissa=(mantissa<<4)+fraction;
USARTx->BAUDR = mantissa;//波特率赋值
//设置数据形式 USART_WordLength
USARTx->CTRL1 &= ~(0x1000);
USARTx->CTRL1 |= (0x0000);//一个起始位,8 个数据位,n 个停止位
//设置停止位 USART_StopBits
USARTx->CTRL2 &= ~(0x3000);
USARTx->CTRL2 |= (0x0000);//1 个停止位
//设置校验位 USART_Parity
USARTx->CTRL1 &= ~(0x0400);
USARTx->CTRL1 |= (0x0000);//禁止校验控制;
//设置硬件流控制 USART_HardwareFlowControl
USARTx->CTRL3 &= ~(0x0030);
USARTx->CTRL3 |= (0x0000);//禁止 RTS 硬件流控制,0:禁止 CTS 硬件流控制;
//设置传输模式 USART_Mode
USARTx->CTRL1 &= ~(0x000C);
USARTx->CTRL1 |= (0x000C);//使能接收,并开始搜寻 RX 引脚上的起始位。使能发送。
//=====================寄存器代码===end========
/* Clear USART1 Interrupt Flag
USART_ClearFlag(USART1, USART_FLAG_RDNE);*/
//清除接收标志
USARTx->STS = ~(USART_FLAG_RDNE);
/* 串口接收中断和串口空闲中断使能 */
USART_INTConfig(USARTx, USART_INT_RDNE, ENABLE);//接收中断
USART_INTConfig(USARTx, USART_INT_IDLEF, ENABLE);//空闲中断
//接收中断使能
// USARTx->CTRL1 |= (1<<5);
//空闲中断使能
// USARTx->CTRL1 |= (1<<4);
/* Enable the USART1
USART_Cmd(USART1, ENABLE); */
//串口使能
USARTx->CTRL1 |= 0x2000;
}
//功能说明: 串口初始化
void bsp_InitUsart(void)
{
UART_RCC_Config();//串口时钟使能
UART_NVIC_Config();//中断优先级初始化
InitHardUart();//IO口初始化
#if USART1_EN == 1
SetBaudrate(USART1, UART1_BAUD);
#endif
}
/**
* @brief This function handles USART1 global interrupt request.
* @param None
* @retval None
*/
void USART1_IRQHandler(void)
{
if(USART_GetITStatus(USART1, USART_INT_RDNE) != RESET)//触发串口接收中断
{
/* Read one byte from the receive data register */
// if(RxCounter1 < DATA_SIZE)
RxBuffer1[RxCounter1++] = USART_ReceiveData(USART1);
}
else if(USART_GetITStatus(USART1, USART_INT_IDLEF) != RESET)//触发串口空闲中断
{
uint8_t DR_text = USART1->DT;//读取串口数据寄存器(只有读取了串口数据寄存器,串口空闲中断才会清除)
RxCounter1 = 0;
RX1_flag = true;
}
}
View Code
3.程序运行效果
每次接收完成一帧数据(不定长度)之后,就会触发串口空闲中断;串口接收完成标志置位;
4.串口空闲中断DMA接收不定长度
参考:
串口参数配置修改
修改函数:SetBaudrate();
修改内容:取消串口接收中断
//串口参数初始化
/* 函 数 名: SetBaudrate
* 功能说明: 配置串口波特率
* 形 参: USARTx.串口 Value.波特率*/
static void SetBaudrate(USART_Type *USARTx, uint32_t Value)
{
/* USART_InitType USART_InitStructure;
USART_InitStructure.USART_BaudRate = UART1_BAUD; //设置波特率
USART_InitStructure.USART_WordLength = USART_WordLength_8b;//设置数据位为8位
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;//工作模式:发送和接收
Configure USART1
USART_Init(USARTx, &USART_InitStructure);*/
//=====================寄存器代码===start========
//设置波特率 USART_BaudRate
float temp;
float fraction; //小数部分
u16 mantissa;//整数部分
//计算出USARTDIV
temp = UART1_BAUD;//不能直接将UART1_BAUD代入计算 USARTDIV 的公式
temp = (120*1000*1000)/(temp*16);//at32的时钟频率为120M
//取波特率整数部分
mantissa = temp;
//计算波特率小数部分
fraction = (temp - mantissa)*16+1;
//计算波特率的值
mantissa=(mantissa<<4)+fraction;
USARTx->BAUDR = mantissa;//波特率赋值
//设置数据形式 USART_WordLength
USARTx->CTRL1 &= ~(0x1000);
USARTx->CTRL1 |= (0x0000);//一个起始位,8 个数据位,n 个停止位
//设置停止位 USART_StopBits
USARTx->CTRL2 &= ~(0x3000);
USARTx->CTRL2 |= (0x0000);//1 个停止位
//设置校验位 USART_Parity
USARTx->CTRL1 &= ~(0x0400);
USARTx->CTRL1 |= (0x0000);//禁止校验控制;
//设置硬件流控制 USART_HardwareFlowControl
USARTx->CTRL3 &= ~(0x0030);
USARTx->CTRL3 |= (0x0000);//禁止 RTS 硬件流控制,0:禁止 CTS 硬件流控制;
//设置传输模式 USART_Mode
USARTx->CTRL1 &= ~(0x000C);
USARTx->CTRL1 |= (0x000C);//使能接收,并开始搜寻 RX 引脚上的起始位。使能发送。
//=====================寄存器代码===end========
/* Clear USART1 Interrupt Flag
USART_ClearFlag(USART1, USART_FLAG_RDNE);*/
//清除接收标志
USARTx->STS = ~(USART_FLAG_RDNE);
/* 串口接收中断和串口空闲中断使能 */
//USART_INTConfig(USARTx, USART_INT_RDNE, ENABLE);//接收中断 DMA模式下不使用
USART_INTConfig(USARTx, USART_INT_IDLEF, ENABLE);//空闲中断
//接收中断使能
// USARTx->CTRL1 |= (1<<5);
//空闲中断使能
// USARTx->CTRL1 |= (1<<4);
/* Enable the USART1
USART_Cmd(USART1, ENABLE); */
//串口使能
USARTx->CTRL1 |= 0x2000;
}
View Code
DMA配置添加
添加函数:UsartRX_DmaConfigure();DMA_Channel_ON_OFF();
添加内容:串口接收DMA配置,串口接收DMA配置使能/关闭
DMA通道设置说明:
由图可知,我们需要配置的外设串口1RX的DMA通道为通道3;
DMA设置代码:
//功能说明: 配置串口DMA
//DMA_CHx:DMA通道CHx
//cpar:外设地址
//cmar:存储器地址
//cndtr:数据传输量
//On_Off:0x01:开启DMA,0x02:关闭DMA
static void UsartRX_DmaConfigure(DMA_Channel_Type* DMA_CHx,u32 cpar,u32 cmar,u16 cndtr, u8 On_Off)
{
DMA_InitType DMA_InitStructure;
NVIC_InitType NVIC_InitStructure;
/* DMA clock enable */
RCC_AHBPeriphClockCmd(RCC_AHBPERIPH_DMA1, ENABLE);
#if USART1_EN == 1
/* USART1_Tx_DMA_Channel (triggered by USART1 Tx event) Config */
DMA_Reset(DMA_CHx);
DMA_DefaultInitParaConfig(&DMA_InitStructure);
DMA_InitStructure.DMA_PeripheralBaseAddr = cpar; /* DMA外设基地址 */
DMA_InitStructure.DMA_MemoryBaseAddr = cmar; /* DMA内存基地址 */
DMA_InitStructure.DMA_Direction = DMA_DIR_PERIPHERALSRC; /* 传输方向,外设->内存*/
DMA_InitStructure.DMA_BufferSize = cndtr; /* 数据大小 */
DMA_InitStructure.DMA_PeripheralInc = DMA_PERIPHERALINC_DISABLE; /* 外设地址寄存器不变 */
DMA_InitStructure.DMA_MemoryInc = DMA_MEMORYINC_ENABLE; /* 内存地址寄存器递增 */
DMA_InitStructure.DMA_PeripheralDataWidth = DMA_PERIPHERALDATAWIDTH_BYTE; /* 外设数据宽度为8位 */
DMA_InitStructure.DMA_MemoryDataWidth = DMA_MEMORYDATAWIDTH_BYTE; /* 存储器数据宽度为8位 */
DMA_InitStructure.DMA_Mode = DMA_MODE_NORMAL; /* 非循环模式 */
DMA_InitStructure.DMA_Priority = DMA_PRIORITY_VERYHIGH; /* 非常高优先级 */
DMA_InitStructure.DMA_MTOM = DMA_MEMTOMEM_DISABLE; /* 非内存到内存 */
DMA_Init(DMA_CHx, &DMA_InitStructure);
/* Enable USART1 DMA TX Channel */
DMA_ChannelEnable(DMA_CHx, ENABLE);
/* Enable USART1 DMA RX request */
USART_DMACmd(USART1, USART_DMAReq_Rx, ENABLE);
#endif
}
//功能说明: DMA通道开关
//DMA_CHx:DMA通道CHx
//cpar:外设地址
//cmar:存储器地址
//cndtr:数据传输量
//On_Off:0x01:开启DMA,0x02:关闭DMA
void DMA_Channel_ON_OFF(DMA_Channel_Type* DMA_CHx,u32 cpar,u32 cmar,u16 cndtr, u8 On_Off)
{
if(On_Off == 0X01)//开启DMA
{
DMA_CHx->TCNT = 24;//设置数据长度
DMA_ChannelEnable(DMA_CHx, ENABLE);//开启DMA通道
}
else if(On_Off == 0x02)
{
DMA_ChannelEnable(DMA_CHx, DISABLE);//关闭DMA通道
}
}
串口初始化函数修改
修改函数:bsp_InitUsart();
修改内容:添加DMA配置;
//功能说明: 串口初始化
void bsp_InitUsart(void)
{
UART_RCC_Config();//串口时钟使能
UART_NVIC_Config();//中断优先级初始化
InitHardUart();//IO口初始化
#if USART1_EN == 1
SetBaudrate(USART1, UART1_BAUD);
#endif
UsartRX_DmaConfigure(DMA1_Channel3, (uint32_t)&USART1->DT, (uint32_t)RxBuffer1, DATA_SIZE, 0X01);//配置串口DMA
}
外设配置所有代码:
#if USART1_EN == 1
uint8_t RxBuffer1test[12];
uint8_t RxBuffer1[24];
__IO uint8_t RxCounter1;
bool RX1_flag = false;//串口接收完成标志
#endif
#if USART2_EN == 1
#endif
static void InitHardUart()//串口IO口初始化
{
GPIO_InitType GPIO_InitStructure;
#if USART1_EN == 1
/* Connect PXx to USART1_Tx
GPIO_PinAFConfig(GPIOB, GPIO_PinsSource6, GPIO_AF_0); */
/* Connect PXx to USART1_Rx
GPIO_PinAFConfig(GPIOB, GPIO_PinsSource7, GPIO_AF_0);*/
/* Configure USART1 Tx/Rx amd USART2 Tx/Rx */
/*GPIO_InitStructure.GPIO_Pins = GPIO_Pins_6 | GPIO_Pins_7;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_MaxSpeed = GPIO_MaxSpeed_50MHz;
GPIO_InitStructure.GPIO_OutType = GPIO_OutType_PP;
GPIO_InitStructure.GPIO_Pull = GPIO_Pull_NOPULL;
GPIO_Init(GPIOB, &GPIO_InitStructure); */
//=====================寄存器代码===start========
//设置复用输出类型
GPIOB->AFR[0] &= ~(0xff000000);
GPIOB->AFR[0] |= (0x00000000);
GPIOB->MODER &= ~(0XF000);
GPIOB->MODER |= (0XA000);//设置复用输出
GPIOB->OTYPER &= ~(0xC0);
GPIOB->OTYPER |= (0x00);//设置推挽输出
//设置输出速度
GPIOB->HDRV &= ~(0x00C0);
GPIOB->HDRV |= (0x00C0);//设置速度为高
GPIOB->ODRVR &= ~(0XF000);
GPIOB->PUPDR &= ~(0XF000);//设置上拉/下拉
GPIOB->PUPDR |= (0X0000);
//=====GPIOB->ot================寄存器代码===end========
#endif
#if USART2_EN == 1
#endif
}
//时钟初始化
static void UART_RCC_Config(void)
{
/* Enable GPIO clock */
RCC_AHBPeriphClockCmd(RCC_AHBPERIPH_GPIOB, ENABLE);//串口IO口时钟使能
#if USART1_EN == 1
/* Enable USART1 Clock
RCC_APB2PeriphClockCmd(RCC_APB2PERIPH_USART1, ENABLE); */
RCC->APB2EN &= ~(0X4000);
RCC->APB2EN |= (0X4000);//串口时钟使能
#endif
}
//串口中断优先级初始化
static void UART_NVIC_Config(void)
{
#if USART1_EN == 1
NVIC_InitType NVIC_InitStructure;
/* Configure the NVIC Preemption Priority Bits */
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);
/* Enable the USART2 Interrupt */
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);
#endif
}
//串口参数初始化
/* 函 数 名: SetBaudrate
* 功能说明: 配置串口波特率
* 形 参: USARTx.串口 Value.波特率*/
static void SetBaudrate(USART_Type *USARTx, uint32_t Value)
{
/* USART_InitType USART_InitStructure;
USART_InitStructure.USART_BaudRate = UART1_BAUD; //设置波特率
USART_InitStructure.USART_WordLength = USART_WordLength_8b;//设置数据位为8位
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;//工作模式:发送和接收
Configure USART1
USART_Init(USARTx, &USART_InitStructure);*/
//=====================寄存器代码===start========
//设置波特率 USART_BaudRate
float temp;
float fraction; //小数部分
u16 mantissa;//整数部分
//计算出USARTDIV
temp = UART1_BAUD;//不能直接将UART1_BAUD代入计算 USARTDIV 的公式
temp = (120*1000*1000)/(temp*16);//at32的时钟频率为120M
//取波特率整数部分
mantissa = temp;
//计算波特率小数部分
fraction = (temp - mantissa)*16+1;
//计算波特率的值
mantissa=(mantissa<<4)+fraction;
USARTx->BAUDR = mantissa;//波特率赋值
//设置数据形式 USART_WordLength
USARTx->CTRL1 &= ~(0x1000);
USARTx->CTRL1 |= (0x0000);//一个起始位,8 个数据位,n 个停止位
//设置停止位 USART_StopBits
USARTx->CTRL2 &= ~(0x3000);
USARTx->CTRL2 |= (0x0000);//1 个停止位
//设置校验位 USART_Parity
USARTx->CTRL1 &= ~(0x0400);
USARTx->CTRL1 |= (0x0000);//禁止校验控制;
//设置硬件流控制 USART_HardwareFlowControl
USARTx->CTRL3 &= ~(0x0030);
USARTx->CTRL3 |= (0x0000);//禁止 RTS 硬件流控制,0:禁止 CTS 硬件流控制;
//设置传输模式 USART_Mode
USARTx->CTRL1 &= ~(0x000C);
USARTx->CTRL1 |= (0x000C);//使能接收,并开始搜寻 RX 引脚上的起始位。使能发送。
//=====================寄存器代码===end========
/* Clear USART1 Interrupt Flag
USART_ClearFlag(USART1, USART_FLAG_RDNE);*/
//清除接收标志
USARTx->STS = ~(USART_FLAG_RDNE);
/* 串口接收中断和串口空闲中断使能 */
//USART_INTConfig(USARTx, USART_INT_RDNE, ENABLE);//接收中断 DMA模式下不使用
USART_INTConfig(USARTx, USART_INT_IDLEF, ENABLE);//空闲中断
//接收中断使能
// USARTx->CTRL1 |= (1<<5);
//空闲中断使能
// USARTx->CTRL1 |= (1<<4);
/* Enable the USART1
USART_Cmd(USART1, ENABLE); */
//串口使能
USARTx->CTRL1 |= 0x2000;
}
//功能说明: 配置串口DMA
//DMA_CHx:DMA通道CHx
//cpar:外设地址
//cmar:存储器地址
//cndtr:数据传输量
//On_Off:0x01:开启DMA,0x02:关闭DMA
static void UsartRX_DmaConfigure(DMA_Channel_Type* DMA_CHx,u32 cpar,u32 cmar,u16 cndtr, u8 On_Off)
{
DMA_InitType DMA_InitStructure;
NVIC_InitType NVIC_InitStructure;
/* DMA clock enable */
RCC_AHBPeriphClockCmd(RCC_AHBPERIPH_DMA1, ENABLE);
#if USART1_EN == 1
/* USART1_Tx_DMA_Channel (triggered by USART1 Tx event) Config */
DMA_Reset(DMA_CHx);
DMA_DefaultInitParaConfig(&DMA_InitStructure);
DMA_InitStructure.DMA_PeripheralBaseAddr = cpar; /* DMA外设基地址 */
DMA_InitStructure.DMA_MemoryBaseAddr = cmar; /* DMA内存基地址 */
DMA_InitStructure.DMA_Direction = DMA_DIR_PERIPHERALSRC; /* 传输方向,外设->内存*/
DMA_InitStructure.DMA_BufferSize = cndtr; /* 数据大小 */
DMA_InitStructure.DMA_PeripheralInc = DMA_PERIPHERALINC_DISABLE; /* 外设地址寄存器不变 */
DMA_InitStructure.DMA_MemoryInc = DMA_MEMORYINC_ENABLE; /* 内存地址寄存器递增 */
DMA_InitStructure.DMA_PeripheralDataWidth = DMA_PERIPHERALDATAWIDTH_BYTE; /* 外设数据宽度为8位 */
DMA_InitStructure.DMA_MemoryDataWidth = DMA_MEMORYDATAWIDTH_BYTE; /* 存储器数据宽度为8位 */
DMA_InitStructure.DMA_Mode = DMA_MODE_NORMAL; /* 非循环模式 */
DMA_InitStructure.DMA_Priority = DMA_PRIORITY_VERYHIGH; /* 非常高优先级 */
DMA_InitStructure.DMA_MTOM = DMA_MEMTOMEM_DISABLE; /* 非内存到内存 */
DMA_Init(DMA_CHx, &DMA_InitStructure);
/* Enable USART1 DMA TX Channel */
DMA_ChannelEnable(DMA_CHx, ENABLE);
/* Enable USART1 DMA RX request */
USART_DMACmd(USART1, USART_DMAReq_Rx, ENABLE);
#endif
}
//功能说明: DMA通道开关
//DMA_CHx:DMA通道CHx
//cpar:外设地址
//cmar:存储器地址
//cndtr:数据传输量
//On_Off:0x01:开启DMA,0x02:关闭DMA
void DMA_Channel_ON_OFF(DMA_Channel_Type* DMA_CHx,u32 cpar,u32 cmar,u16 cndtr, u8 On_Off)
{
if(On_Off == 0X01)//开启DMA
{
DMA_CHx->TCNT = 24;//设置数据长度
DMA_ChannelEnable(DMA_CHx, ENABLE);//开启DMA通道
}
else if(On_Off == 0x02)
{
DMA_ChannelEnable(DMA_CHx, DISABLE);//关闭DMA通道
}
}
//功能说明: 串口初始化
void bsp_InitUsart(void)
{
UART_RCC_Config();//串口时钟使能
UART_NVIC_Config();//中断优先级初始化
InitHardUart();//IO口初始化
#if USART1_EN == 1
SetBaudrate(USART1, UART1_BAUD);
#endif
UsartRX_DmaConfigure(DMA1_Channel3, (uint32_t)&USART1->DT, (uint32_t)RxBuffer1, DATA_SIZE, 0X01);//配置串口DMA
}
View Code
串口中断函数修改
/**
* @brief This function handles USART1 global interrupt request.
* @param None
* @retval None
*/
void USART1_IRQHandler(void)
{
if(USART_GetITStatus(USART1, USART_INT_IDLEF) != RESET)//触发串口空闲中断
{
uint8_t DR_text = USART1->DT;//读取串口数据寄存器(只有读取了串口数据寄存器,串口空闲中断才会清除)
DR_text = USART1->STS;//清除IDLE标记位
DMA_ChannelEnable(DMA1_Channel3, DISABLE);//关闭DMA通道
RxCounter1 = 0;//串口接收数据字节数清零
RX1_flag = true;//串口接收完成标志置位
}
}
注意:在每次接收完成之后都需要经过关闭DMA通道->处理串口数据->再次开启DMA通道的过程,如下图:
在接收完成之后的代码:
if(BLE_Massage_Buffer_Refresh == true&&Con_State_get() == true)//一帧数据接收完成
{
BLE_Massage_Buffer_Refresh = false;
BLE_Command_Handler(BLE_Massage_Buffer); //串口命令处理
DMA_Channel_ON_OFF(DMA1_Channel3, (uint32_t)&USART1->DT, (uint32_t)BLE_Massage_Buffer, 12, 0x01);//开启DMA通道
}
运行效果和串口空闲中断一样,只是串口空闲中断需要我们自己手动将串口数据存储到数组。