完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
stm32的DMA收发原理,和stm32F4 + USART2 +DMA +IDLE使用,见另一篇:https://blog.csdn.net/Mark_md/article/details/107243054
stm32F1的串口DMA和stm32F4的大同小异,使用时要区分通道和数据流区别。 stm32F1的usart1-DMA-IDLE收发 直接上代码 usart.c #include "usart.h" uint8_t Uart1_Rx_Buff[DMA_UART1_RX_SIZE]; uint8_t Uart1_Tx_Buff[DMA_UART1_TX_SIZE]; uint16_t Uart1_RxLength; //Uart1 DMA 一次接收到的数据长度 void uart1_init(u32 bound){ /*定义串口初始化结构体*/ GPIO_InitTypeDef GPIO_InitStructure; USART_InitTypeDef USART_InitStructure; NVIC_InitTypeDef NVIC_InitStructure; /*使能内部外设时钟*/ RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOA, ENABLE); //使能USART1,GPIOA时钟 /*GPIO端口设置*/ /*USART1_TX GPIOA.9*/ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //PA.9 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //输出最大速率 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出 GPIO_Init(GPIOA, &GPIO_InitStructure); //初始化GPIOA.9 /*USART1_RX GPIOA.10*/ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; //PA.10 //GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //浮空输入 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //上拉输入 GPIO_Init(GPIOA, &GPIO_InitStructure); //初始化GPIOA.10 /*USART1 参数设置*/ USART_InitStructure.USART_BaudRate = bound; //串口波特率 USART_InitStructure.USART_WordLength = USART_WordLength_8b; //字长为8位数据格式 USART_InitStructure.USART_StopBits = USART_StopBits_1; //停止位 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; //收发模式 USART_Init(USART1, &USART_InitStructure); //初始化串口1 /*Usart1 NVIC 配置*/ NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn; //串口1中断通道 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=6 ; //抢占优先级6 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; //子优先级0 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道使能 NVIC_Init(&NVIC_InitStructure); //根据指定的参数初始化VIC寄存器 /*设置UART1 中断触发模式*/ USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//RX NO Empty,RX非空,RX有数据中断。开启串口接受中断,使用DMA接收时要失能这个,使能空闲中断 //USART_ITConfig(USART1, USART_IT_TC, ENABLE);// Transmit Complete,发送完成中断。开启串口发送完成中断,发送一个字节就会进入中断,只需要清除中断标志位,不需要关闭中断 //USART_IT_TXE TX Empty,TX为空,发送寄存器DR清零。发送寄存器空闲中断,发送完一个字节后,必须关闭这个中断,否则只要寄存器为空值,就会反复进入中断 //USART_ITConfig(USART1, USART_IT_IDLE, ENABLE);//开启串口空闲中断??发送会不会触发空闲中断 /*开启UART1 */ USART_Cmd(USART1, ENABLE); //使能串口1 } void uart1_dma_rx_configuration(void) { /*定义DMA初始化结构体*/ DMA_InitTypeDef DMA_InitStructure; /*使能内部外设时钟*/ RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE); //使能DMA时钟 /*DMA 通道5 接收配置*/ DMA_DeInit(DMA1_Channel5); DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)&USART1->DR; //DMA外设基地址 DMA_InitStructure.DMA_MemoryBaseAddr = (u32)Uart1_Rx_Buff; //DMA内存基地址,把接收到的数据放到哪儿 DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; //数据传输方向,从内存从外设读取,外设作为数据来源 DMA_InitStructure.DMA_BufferSize = DMA_UART1_RX_SIZE; //DMA通道的缓存的大小,一次接收的最大字节数 DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; //外设地址寄存器不递增 DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; //内存地址寄存器递增 DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; //外设数据宽度为8位 DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; //内存数据宽度为8位 DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; //工作在正常模式,即满了不再接收,而不是循环储存 DMA_InitStructure.DMA_Priority = DMA_Priority_Medium; //DMA通道 中优先级 // DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh; //DMA通道 优先级很高 DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; //DMA通道为内存与内存通信,而非内存到内存 DMA_Init(DMA1_Channel5, &DMA_InitStructure); //启动DMA /*设置UART1 中断触发模式*/ USART_ITConfig(USART1, USART_IT_RXNE, DISABLE);//RX NO Empty,RX非空,RX有数据中断。开启串口接受中断,使用DMA接收时要失能这个,使能空闲中断 //USART_ITConfig(USART1, USART_IT_TC, ENABLE);// Transmit Complete,发送完成中断。开启串口发送完成中断,发送一个字节就会进入中断,只需要清除中断标志位,不需要关闭中断 //USART_IT_TXE TX Empty,TX为空,发送寄存器DR清零。发送寄存器空闲中断,发送完一个字节后,必须关闭这个中断,否则只要寄存器为空值,就会反复进入中断 USART_ITConfig(USART1, USART_IT_IDLE, ENABLE);//开启串口空闲中断??发送会不会触发空闲中断 /*开启DMA接收*/ DMA_Cmd(DMA1_Channel5, ENABLE); //开启DMA 通道5传输,即接收传输 USART_DMACmd(USART1,USART_DMAReq_Rx,ENABLE); //使能UART1的DMA接收 } void uart1_dma_rxtx_configuration(void) { /*定义DMA初始化结构体*/ DMA_InitTypeDef DMA_InitStructure; /*使能内部外设时钟*/ RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE); //使能DMA时钟 /*DMA 通道5 接收配置*/ DMA_DeInit(DMA1_Channel5); DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)&USART1->DR; //DMA外设基地址 DMA_InitStructure.DMA_MemoryBaseAddr = (u32)Uart1_Rx_Buff; //DMA内存基地址,把接收到的数据放到哪儿 DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; //数据传输方向,从内存读取发送到外设,外设作为数据来源 DMA_InitStructure.DMA_BufferSize = DMA_UART1_RX_SIZE; //DMA通道的缓存的大小,一次接收的最大字节数 DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; //外设地址寄存器不递增 DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; //内存地址寄存器递增 DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; //外设数据宽度为8位 DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; //内存数据宽度为8位 DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; //工作在正常模式,即满了不再接收,而不是循环储存 DMA_InitStructure.DMA_Priority = DMA_Priority_Medium; //DMA通道 中优先级 // DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh; //DMA通道 优先级很高 DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; //DMA通道为内存与外设通信,而非内存到内存 DMA_Init(DMA1_Channel5, &DMA_InitStructure); //配置DMA 通道5 /*DMA 通道4 发送配置*/ DMA_DeInit(DMA1_Channel4); DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)&USART1->DR; //DMA外设基地址 DMA_InitStructure.DMA_MemoryBaseAddr = (u32)Uart1_Tx_Buff; //DMA发送的内存地址 DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST; //数据传输方向,从内存到外设发送,外设作为数据传输目的地 //因为刚开始初始化时候不需要发送数据,所以发送长度为0 DMA_InitStructure.DMA_BufferSize = 0; //发送长度为0 DMA_Init(DMA1_Channel4, &DMA_InitStructure); //配置DMA 通道4 /*设置UART1 中断触发模式*/ USART_ITConfig(USART1, USART_IT_RXNE, DISABLE);//RX NO Empty,RX非空,RX有数据中断。开启串口接受中断,使用DMA接收时要失能这个,使能空闲中断 //USART_ITConfig(USART1, USART_IT_TC, ENABLE);// Transmit Complete,发送完成中断。开启串口发送完成中断,发送一个字节就会进入中断,只需要清除中断标志位,不需要关闭中断 //USART_IT_TXE TX Empty,TX为空,发送寄存器DR清零。发送寄存器空闲中断,发送完一个字节后,必须关闭这个中断,否则只要寄存器为空值,就会反复进入中断 USART_ITConfig(USART1, USART_IT_IDLE, ENABLE);//开启串口空闲中断??发送会不会触发空闲中断 /*开启DMA接收 因为刚开始初始化时候不需要发送数据,所以 DMA发送通道4 不开启*/ DMA_Cmd(DMA1_Channel5, ENABLE); //开启DMA 通道5传输,即接收传输 USART_DMACmd(USART1,USART_DMAReq_Tx|USART_DMAReq_Rx,ENABLE); //使能UART1的DMA发送和接收 } uint16_t Uart1_DMA_Send_Data(void * buffer, u16 size) { if(!size) return 0;// 判断长度是否有效 while (DMA_GetCurrDataCounter(DMA1_Channel4));// 检查DMA发送通道内是否还有数据 if(buffer) memcpy(Uart1_Tx_Buff, buffer,(size > DMA_UART1_TX_SIZE?DMA_UART1_TX_SIZE:size));//判断发送长度是否大于DMA可传输长度 //DMA发送数据-要先关DMA,再设置发送长度,最后开启DMA DMA_Cmd(DMA1_Channel4, DISABLE);//开启DMA 通道4传输,即发送传输 DMA1_Channel4->CNDTR = size;// 设置发送长度 DMA_Cmd(DMA1_Channel4, ENABLE);// 启动DMA发送 return size; } //验证uart1的DMA,在不清除接收队列的情况下,后来的数据会覆盖原来的数据,未覆盖的数据会保留。所以接收一次数据并使用完成后,想要接收下一次数据,必须将接收缓存区清零 //验证清除uart1 IDLE中断,正确的方法是先读SR,再度DR void USART1_IRQHandler(void) //串口1中断服务程序 { uint8_t temp; if(USART_GetITStatus(USART1, USART_IT_IDLE) != RESET) { DMA_Cmd(DMA1_Channel5,DISABLE);//关闭DMA通道 //没用,不过还是加上吧 DMA_ClearFlag(DMA1_FLAG_TC5);//DMA 通道5 清中断标志,否则会一直中断 USART_ClearITPendingBit(USART1, USART_IT_IDLE);//清除空闲中断标志 //IDLE标志位清零的过程是:先读SR,再读DR寄存器 //注意:这句必须要,否则不能够清除中断标志位。 temp = USART1->SR;//先读SR,然后读DR才能清除 temp = USART1->DR;//清除DR temp = temp; /*在这里处理数据长度 及数据处理事件*/ Uart1_RxLength = DMA_UART1_RX_SIZE - DMA_GetCurrDataCounter(DMA1_Channel5); //DMA接收完数据后,不会将Uart1_Rx_Buff任何数据清零,下一次数据会重新覆盖,没有覆盖的数据会保留,所以获取数据长度和清零接收缓冲区是必要的 /*清零本次DMA接收缓冲区*/ //清零接收缓存区,可以不全部清空,提高运行效率;全部清空,确保长时间稳定性 //memset(Uart1_Rx_Buff,0,Uart1_RxLength); memset(Uart1_Rx_Buff,0,DMA_UART1_RX_SIZE);//待uart接收缓存区项目处理完后,清除数据接收缓冲区USART_RX_BUF,用于下一次数据接 /*重新开启下一次DMA接收*/ DMA_SetCurrDataCounter(DMA1_Channel5,DMA_UART1_RX_SIZE);//DMA通道的DMA缓存的大小。重置传输数目,当再次达到这个数目就会进中断 DMA_Cmd(DMA1_Channel5,ENABLE);//开启DMA通道 } } usart.h #ifndef __USART_H #define __USART_H #include "stdio.h" #include "sys.h" /************************************************ ************************************************/ #define DMA_UART1_RX_SIZE 20 #define DMA_UART1_TX_SIZE 20 extern uint8_t Uart1_Rx_Buff[DMA_UART1_RX_SIZE]; extern uint8_t Uart1_Tx_Buff[DMA_UART1_TX_SIZE]; extern uint16_t Uart1_RxLength; //Uart1 DMA 一次接收到的数据长度 void uart1_init(u32 bound); void uart1_dma_rx_configuration(void); void uart1_dma_rxtx_configuration(void); uint16_t Uart1_DMA_Send_Data(void * buffer, u16 size); #endif |
|
|
|
只有小组成员才能发言,加入小组>>
调试STM32H750的FMC总线读写PSRAM遇到的问题求解?
1804 浏览 1 评论
X-NUCLEO-IHM08M1板文档中输出电流为15Arms,15Arms是怎么得出来的呢?
1629 浏览 1 评论
1097 浏览 2 评论
STM32F030F4 HSI时钟温度测试过不去是怎么回事?
736 浏览 2 评论
ST25R3916能否对ISO15693的标签芯片进行分区域写密码?
1686 浏览 2 评论
1944浏览 9评论
STM32仿真器是选择ST-LINK还是选择J-LINK?各有什么优势啊?
748浏览 4评论
STM32F0_TIM2输出pwm2后OLED变暗或者系统重启是怎么回事?
582浏览 3评论
604浏览 3评论
stm32cubemx生成mdk-arm v4项目文件无法打开是什么原因导致的?
565浏览 3评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-12-28 21:03 , Processed in 0.759250 second(s), Total 76, Slave 60 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号