完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
STM32串口空闲中断
接收数据的流程: 串口接收DMA在初始化的时候就处于开启状态,一直等待数据的到来,在软件上无需做任何事情,只要在初始化配置的时候设置好配置就可以了。 判断数据数据接收完成: 这里判断接收完成是通过串口空闲中断的方式实现,即当串口数据流停止后,就会产生IDLE中断。这个中断里面做如下几件事:
void My_UART_Init(void) { GPIO_InitTypeDef GPIO_InitStruct; USART_InitTypeDef USART_InitStruct; NVIC_InitTypeDef NVIC_InitStruct; DMA_InitTypeDef DMA_InitStruct; RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE); // 使能DMA RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); // 使能GPIOA RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE); // 使能时钟 复用USART GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_InitStruct.GPIO_Pin = GPIO_Pin_9; GPIO_InitStruct.GPIO_Speed = GPIO_Speed_10MHz; GPIO_Init(GPIOA,&GPIO_InitStruct); //初始化 USART_TX 即 GPIOA.9 GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING; GPIO_InitStruct.GPIO_Pin = GPIO_Pin_10; GPIO_InitStruct.GPIO_Speed = GPIO_Speed_10MHz; GPIO_Init(GPIOA,&GPIO_InitStruct); //初始化 USART_RX 即 GPIOA.10 USART_InitStruct.USART_BaudRate = 115200; USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None; USART_InitStruct.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; USART_InitStruct.USART_Parity = USART_Parity_No; USART_InitStruct.USART_StopBits = USART_StopBits_1; USART_InitStruct.USART_WordLength = USART_WordLength_8b; USART_Init(USART1,&USART_InitStruct); //初始化 USART // USART_ITConfig(USART1, USART_IT_RXNE, ENABLE); // 开启 USART 接收缓冲区非空中断 // USART_ITConfig(USART1, USART_IT_TXE, ENABLE); // 开启 USART 发送缓冲区空中断 USART_ITConfig(USART1, USART_IT_IDLE, ENABLE); //开启 USART1 总线空闲中断 USART_Cmd(USART1, ENABLE);//使能USART中断 DMA_DeInit(DMA1_Channel5); DMA_InitStruct.DMA_PeripheralBaseAddr = (uint32_t)(&USART1->DR); //外设--->内存 DMA_InitStruct.DMA_MemoryBaseAddr = (uint32_t)RxBuffer; DMA_InitStruct.DMA_MemoryInc = DMA_MemoryInc_Enable; DMA_InitStruct.DMA_PeripheralInc = DMA_PeripheralInc_Disable; DMA_InitStruct.DMA_BufferSize = BufferSize; DMA_InitStruct.DMA_DIR = DMA_DIR_PeripheralSRC; DMA_InitStruct.DMA_M2M = DMA_M2M_Disable; DMA_InitStruct.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; DMA_InitStruct.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; DMA_InitStruct.DMA_Priority = DMA_Priority_Medium; DMA_InitStruct.DMA_Mode = DMA_Mode_Normal; DMA_Init(DMA1_Channel5, &DMA_InitStruct); DMA_Cmd(DMA1_Channel5, ENABLE); USART_DMACmd(USART1, USART_DMAReq_Rx, ENABLE); // 使能 USART1接收DMA NVIC_InitStruct.NVIC_IRQChannel = USART1_IRQn; NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE; NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0x01; //抢占优先级 2位 00 01 10 11 NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0x01; //响应优先级 2位 00 01 10 11 NVIC_Init(&NVIC_InitStruct); //初始化中断 } 当MCU通过USART接收外部发来的数据时,在进行第①②③步的时候,主程序可以不用管,DMA直接将接收到的数据写入缓存RxBuffer,程序此时也不会进入接收中断,当数据接收完成之后产生接收空闲中断,在中断服务函数中将接收完成标志位置1,计算出接收缓存中的数据长度,清除中断位,失能DMA防止在处理数据时候接收数据。主程序中检测到接收完成标志被置1,进入数据处理程序,现将接收完成标志位置0,重新设置DMA下次要接收的数据字节数,使能DMA进入接收数据状态。 void USART1_IRQHandler(void) { uint8_t clear = clear; // 用来消除编译器的“没有用到”的提醒 uint8_t data = 0; if(USART_GetITStatus(USART1, USART_IT_IDLE) != RESET) { clear = USART1->SR; clear = USART1->DR; // RxCounter = BufferSize - DMA1_Channel5->CNDTR;//缓存中的字节数 RxCounter = BufferSize - DMA_GetCurrDataCounter(DMA1_Channel5);//缓存中的字节数 // USART_ITConfig(USART1, USART_IT_IDLE, ENABLE); RxStatus = 1; //标记接收到一帧 USART_ClearITPendingBit(USART1, USART_IT_IDLE); // 清除空闲中断 DMA_Cmd(DMA1_Channel5, DISABLE); // 停止DMA,清除DMA缓存 } } int main(void) { uint8_t i = 0; NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); // 初始化中断优先级分组 My_UART_Init(); while(1) { if(RxStatus == 1) { RxStatus = 0; i = 0; while(RxCounter--) { USART_SendData(USART1, RxBuffer[i++]); while(USART_GetFlagStatus(USART1, USART_FLAG_TC) != SET); } memset(RxBuffer, 0, i); // 清除缓存 RxCounter = 0; // DMA1_Channel5->CNDTR = BufferSize; DMA_SetCurrDataCounter(DMA1_Channel5, BufferSize); DMA_Cmd(DMA1_Channel5, ENABLE); } } } DMA介绍 DMA的定义 直接存储器存取(Direct Memory Access,DMA)是计算机科学中的一种内存访问技术。它允许某些电脑内部的硬体子系统(电脑外设),可以独立地直接读写系统存储器,而不需绕道 CPU。在同等程度的CPU负担下,DMA是一种快速的数据传送方式。它允许不同速度的硬件装置来沟通,而不需要依于 CPU的大量中断请求。 DMA有什么用? 直接存储器存取用来提供在外设和存储器之间或者存储器和存储器之间的高速数据传输。无须CPU的干预,通过DMA数据可以快速地移动。这就节省了CPU的资源来做其他操作。 有多少个DMA资源? 有两个DMA控制器,DMA1有7个通道,DMA2有5个通道。 数据从什么地方送到什么地方?
传统的DMA的概念是用于大批量数据的传输,但是我理解,在STM32中,它的概念被扩展了,也许更多的时候快速是其应用的重点。数据可以从1~65535个。 DMA控制器与仲裁器 现在越来越多的单片机采用DMA技术,提供外设和存储器之间或者存储器之间的高速数据传输。当 CPU 初始化这个传输动作,传输动作本身是由 DMA 控制器 来实行和完成。STM32就有一个DMA控制器,它有7个通道,每个通道专门用来管理一个或多个外设对存储器访问的请求,还有一个仲裁器来协调各个DMA请求的优先权。 DMA 控制器和Cortex-M3核共享系统数据总线执行直接存储器数据传输。当CPU和DMA同时访问相同的目标(RAM或外设)时,DMA请求可能会停止 CPU访问系统总线达若干个周期,总线仲裁器执行循环调度,以保证CPU至少可以得到一半的系统总线(存储器或外设)带宽。 在发生一个事件后,外设发送一个请求信号到DMA控制器。DMA控制器根据通道的优先权处理请求。当DMA控制器开始访问外设的时候,DMA控制器立即发送给外设一个应答信号。当从DMA控制器得到应答信号时,外设立即释放它的请求。一旦外设释放了这个请求,DMA控制器同时撤销应答信号。如果发生更多的请求时,外设可以启动下次处理。 代码展示 基于HAL库的串口空闲+DMA主要接收代码 下面是头文件 #ifndef DMAT_H #define DMAT_H #include "stm32f1xx_hal.h" #include "usart.h" extern uint8_t usart2_rx_buffer[33]; extern uint8_t usart3_rx_buffer[25]; void MyU2Init(void); void MyU3Init(void); void USART2Handle(void); void USART3Handle(void); void MyUsartHandle(UART_HandleTypeDef *HUART); #endif 下面是源文件 #include "dmat.h" uint8_t usart2_rx_buffer[33]={0}; uint8_t usart3_rx_buffer[25]={0}; float ROLL_ANGLE=0; float PITCH_ANGLE=0; float YAW_ANGLE=0; void MyU2Init(void) { __HAL_UART_CLEAR_IDLEFLAG(&huart2); __HAL_UART_ENABLE_IT(&huart2,UART_IT_IDLE); HAL_UART_Receive_DMA(&huart2,usart2_rx_buffer,33); } void MyU3Init(void) { __HAL_UART_CLEAR_IDLEFLAG(&huart3); __HAL_UART_ENABLE_IT(&huart3,UART_IT_IDLE); HAL_UART_Receive_DMA(&huart3,usart3_rx_buffer,25); } //可以在里面加上想要的功能 //以及数据处理的代码 //这是采用串口+DMA+空闲中断来处理串口接收的数据 void USART2Handle(void) { if(usart2_rx_buffer[0]==0x55&&usart2_rx_buffer[11]==0x55&&usart2_rx_buffer[22]==0x55) { //总共33个字节的数据,每11个字节的数据算一个数据包,三个数据包分别是加速度包,角速度包和角度包 if(usart2_rx_buffer[23]==0x53) { //下面的数据是针对角度包来解析的,得到三个角度 ROLL_ANGLE=((int16_t)(usart2_rx_buffer[25]<<8|usart2_rx_buffer[24]))/32768.0*180; PITCH_ANGLE=((int16_t)(usart2_rx_buffer[27]<<8|usart2_rx_buffer[26]))/32768.0*180; YAW_ANGLE=((int16_t)(usart2_rx_buffer[29]<<8|usart2_rx_buffer[28]))/32768.0*180; } } } void USART3Handle(void) { } void MyUsartHandle(UART_HandleTypeDef *HUART) { if(HUART==&huart2) { if(__HAL_UART_GET_FLAG(HUART,UART_FLAG_IDLE)) { __HAL_UART_CLEAR_IDLEFLAG(HUART); HAL_UART_DMAStop(HUART); USART2Handle(); HAL_UART_Receive_DMA(HUART,(uint8_t*) usart2_rx_buffer,33); } } else if(HUART==&huart3) { if(__HAL_UART_GET_FLAG(HUART,UART_FLAG_IDLE)) { __HAL_UART_CLEAR_IDLEFLAG(HUART); HAL_UART_DMAStop(HUART); USART3Handle(); HAL_UART_Receive_DMA(HUART,(uint8_t*) usart2_rx_buffer,25); } } } |
|
|
|
只有小组成员才能发言,加入小组>>
调试STM32H750的FMC总线读写PSRAM遇到的问题求解?
1771 浏览 1 评论
X-NUCLEO-IHM08M1板文档中输出电流为15Arms,15Arms是怎么得出来的呢?
1619 浏览 1 评论
1070 浏览 2 评论
STM32F030F4 HSI时钟温度测试过不去是怎么回事?
724 浏览 2 评论
ST25R3916能否对ISO15693的标签芯片进行分区域写密码?
1673 浏览 2 评论
1936浏览 9评论
STM32仿真器是选择ST-LINK还是选择J-LINK?各有什么优势啊?
729浏览 4评论
STM32F0_TIM2输出pwm2后OLED变暗或者系统重启是怎么回事?
569浏览 3评论
594浏览 3评论
stm32cubemx生成mdk-arm v4项目文件无法打开是什么原因导致的?
552浏览 3评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-12-22 22:17 , Processed in 0.761805 second(s), Total 47, Slave 40 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号