1.DMA辅助串口数据接收
1.1 DMA简介
直接存储器存取(DMA)用来提供在外设和存储器之间或者存储器和存储器之间的高速数据传输。无须CPU干预,数据可以通过DMA快速地移动,这就节省了CPU的资源来做其他操作。
两个DMA控制器有12个通道(DMA1有7个通道,DMA2有5个通道),每个通道专门用来管理来自于一个或多个外设对存储器访问的请求。还有一个仲裁器来协调各个DMA请求的优先权。
DMA控制器和Cortex™-M3核心共享系统数据总线,执行直接存储器数据传输。当CPU和DMA同时访问相同的目标(RAM或外设)时,DMA请求会暂停CPU访问系统总线达若干个周期,总线
仲裁器执行循环调度,以保证CPU至少可以得到一半的系统总线(存储器或外设)带宽。
1.2 DMA特性
● 12个独立的可配置的通道(请求):DMA1有7个通道,DMA2有5个通道。
● 每个通道都直接连接专用的硬件DMA请求,每个通道都同样支持软件触发。这些功能通过软件来配置。
● 在同一个DMA模块上,多个请求间的优先权可以通过软件编程设置(共有四级:很高、高、中等和低),优先权设置相等时由硬件决定(请求0优先于请求1,依此类推) 。
● 独立数据源和目标数据区的传输宽度(字节、半字、全字),模拟打包和拆包的过程。源和目标地址必须按数据传输宽度对齐。
● 支持循环的缓冲器管理。
● 每个通道都有3个事件标志(DMA半传输、DMA传输完成和DMA传输出错),这3个事件标志逻辑或成为一个单独的中断请求。
● 存储器和存储器间的传输。
● 外设和存储器、存储器和外设之间的传输。
● 闪存、SRAM、外设的SRAM、APB1、APB2和AHB外设均可作为访问的源和目标。
● 可编程的数据传输数目:最大为65535。
1.3 串口1接收与DMA1的通道接口
从外设(TIMx[x=1、2、3、4]、ADC1、SPI1、SPI/I2S2、I2Cx[x=1、2]和USARTx[x=1、2、3])产生的7个请求,通过逻辑或输入到DMA1控制器,这意味着同时只能有一个请求有效。参见下图的DMA1请求映像。
外设的DMA请求,可以通过设置相应外设寄存器中的控制位,被独立地开启或关闭。
2.串口1接收使能DMA配置
2.1串口基本功能配置
串口1配置:全双工异步通信、波特率为115200、8个数据位、1个停止位、无校验位
打开STM32CbeMX软件,配置串口串口、开启串口中断
优先级分组设置:2位抢占优先级2位副优先级
2.2 串口基本功能配置
配置串口1接收DMA通道
3.代码配置
3.1 修改usart.c文件
1.开启空闲帧中断
c
huart1.Instance->CR1|=1<<4;//开启串口空闲帧中断
2.添加DMA处理代码
c
DMA1_Channel5->CPAR=(uint32_t )&USART1->DR;//外设地址
DMA1_Channel5->CMAR=(uint32_t )usart1_rx_buff;//存储器地址
DMA1_Channel5->CCR&=~(1<<0);//关闭通道传输
DMA1_Channel5->CNDTR=1024;//设置传输数量
DMA1_Channel5->CCR|=1<<0;//开启通道传输
3.2 修改stm32f1xx.it.c文件
1.DMA数据接收处理:
c
extern DMA_HandleTypeDef hdma_usart1_rx;
extern UART_HandleTypeDef huart1;
/* USER CODE BEGIN EV */
uint8_t usart1_rx_buff[1024];//串口1接收数据缓冲区
uint16_t usart1_cnt=0;//保存数组下班
uint8_t usart1_flag;//接收完成标志符
/*************************串口接收数据函数********************/
static void Usart1_Receive_Data(void)
{
DMA1_Channel5->CCR&=~(1<<0);//关闭通道传输
usart1_cnt=1024-DMA1_Channel5->CNDTR;//获取接收到是字符长度
if(usart1_cnt>=1024)usart1_cnt=0;
DMA1->IFCR|=1<<17;//清除标志位
DMA1_Channel5->CNDTR=1024;//从新赋值
DMA1_Channel5->CCR|=1<<0;//开启通道传输
usart1_flag=1;
}
/* USER CODE END EV */
2.串口中断服务函数
c
void USART1_IRQHandler(void)
{
/* USER CODE BEGIN USART1_IRQn 0 */
uint8_t c;
/* USER CODE END USART1_IRQn 0 */
HAL_UART_IRQHandler(&huart1);
/* USER CODE BEGIN USART1_IRQn 1 */
if(__HAL_UART_GET_FLAG(&huart1,UART_FLAG_IDLE))
{
c=huart1.Instance->DR;
c=c;
Usart1_Receive_Data();
//huart1.Instance->DR=c;
}
/* USER CODE END USART1_IRQn 1 */
}
4.运行示例
c
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_DMA_Init();
MX_USART1_UART_Init();
/* USER CODE BEGIN 2 */
printf("初始化完成\r\n");
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
if(usart1_flag && usart1_cnt)
{
usart1_rx_buff[usart1_cnt]='\0';
printf("usart1:%s,%d\r\n",usart1_rx_buff,usart1_cnt);
//*20230223141731,15
usart1_flag=0;
}
}
/* USER CODE END 3 */
}