1
完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
扫一扫,分享给好友
一、利用DMA接受串口任意长数据
1、简介
在上面的文章中有一点没有讲清楚,就是DMA的循环模式(DMA_Mode_Circular)和普通模式(DMA_Mode_Normal)
//开启一次DMA传输 //DMA_Streamx:DMA数据流,DMA1_Stream0~7/DMA2_Stream0~7 //ndtr:数据传输量 void DMA_Transfer_Enable(DMA_Stream_TypeDef *DMA_Streamx,u16 ndtr) { DMA_Cmd(DMA_Streamx, DISABLE); //关闭DMA传输 while (DMA_GetCmdStatus(DMA_Streamx) != DISABLE){} //确保DMA可以被设置 DMA_SetCurrDataCounter(DMA_Streamx,ndtr); //数据传输量 DMA_Cmd(DMA_Streamx, ENABLE); //开启DMA传输 } DMA_Mode_Circular[color=rgba(0, 0, 0, 0.75)]:在循环模式下,最后一次传输结束时, DMA_SxNDTR寄存器的内容会自动地被重新加载为其初始数值,内部的当前外设/存储器地址寄存器也被重新加载为初始基地址。 二、DMA接受数据错位问题 1、程序设置
//全局变量 #define USART3_RX_BUFFER_SIZE 8 #define USART3_TX_BUFFER_SIZE 5 uint8_t USART3_Rx_Buffer[USART3_RX_BUFFER_SIZE] = {0}; uint8_t USART3_Tx_Buffer[USART3_TX_BUFFER_SIZE] = {0}; uint8_t USART3_Rx_DMA_Buffer[USART3_RX_BUFFER_SIZE] = {0}; uint8_t USART3_Tx_DMA_Buffer[USART3_TX_BUFFER_SIZE] = {'1','2','3','4','n'}; //DMA_Streamx:DMA数据流,DMA1_Stream0~7/DMA2_Stream0~7 //chx:DMA通道选择,@ref DMA_channel DMA_Channel_0~DMA_Channel_7 //par:外设地址 //mar:存储器地址 //ndtr:数据传输量 void DMA_Config(DMA_Stream_TypeDef *DMA_Streamx,uint32_t chx,uint32_t par,uint32_t mar,uint32_t dir,u16 ndtr) { DMA_InitTypeDef DMA_InitStructure; if((u32)DMA_Streamx>(u32)DMA2)//得到当前stream是属于DMA2还是DMA1 RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2,ENABLE);//DMA2时钟使能 else RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1,ENABLE);//DMA1时钟使能 DMA_DeInit(DMA_Streamx); while (DMA_GetCmdStatus(DMA_Streamx) != DISABLE){}//等待DMA可配置 /* 配置 DMA Stream */ DMA_InitStructure.DMA_Channel = chx; //通道选择 DMA_InitStructure.DMA_PeripheralBaseAddr = par; //DMA外设地址 DMA_InitStructure.DMA_Memory0BaseAddr = mar; //DMA 存储器0地址 DMA_InitStructure.DMA_DIR = dir; //direction of transmit. DMA_InitStructure.DMA_BufferSize = ndtr; //数据传输量 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_High; //中等优先级 DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable; //不用FIFO DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full; DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single; //存储器突发单次传输 DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single; //外设突发单次传输 DMA_Init(DMA_Streamx, &DMA_InitStructure); DMA_Cmd(DMA_Streamx,ENABLE); } //开启一次DMA传输 //DMA_Streamx:DMA数据流,DMA1_Stream0~7/DMA2_Stream0~7 //ndtr:数据传输量 void DMA_Transfer_Enable(DMA_Stream_TypeDef *DMA_Streamx,u16 ndtr) { DMA_Cmd(DMA_Streamx, DISABLE); //关闭DMA传输 while (DMA_GetCmdStatus(DMA_Streamx) != DISABLE){} //确保DMA可以被设置 DMA_SetCurrDataCounter(DMA_Streamx,ndtr); //数据传输量 DMA_Cmd(DMA_Streamx, ENABLE); //开启DMA传输 } //配置usart3 void USART3_Init(uint32_t bound) { //GPIO端口设置 GPIO_InitTypeDef GPIO_InitStructure; USART_InitTypeDef USART_InitStructure; NVIC_InitTypeDef NVIC_InitStructure; RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD,ENABLE); RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3,ENABLE); GPIO_PinAFConfig(GPIOD,GPIO_PinSource8,GPIO_AF_USART3); //GPIOD8复用为USART3_TX GPIO_PinAFConfig(GPIOD,GPIO_PinSource9,GPIO_AF_USART3); //GPIOD9复用为USART3_RX GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8| GPIO_Pin_9; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz; GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; GPIO_Init(GPIOD,&GPIO_InitStructure); USART_InitStructure.USART_BaudRate = bound; USART_InitStructure.USART_WordLength = USART_WordLength_8b; 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; USART_Init(USART3, &USART_InitStructure); NVIC_InitStructure.NVIC_IRQChannel = USART3_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3; NVIC_InitStructure.NVIC_IRQChannelSubPriority =0; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); USART_ClearFlag(USART3, USART_FLAG_TC); // USART_ITConfig(USART3, USART_IT_RXNE, ENABLE); USART_ITConfig(USART3, USART_IT_IDLE, ENABLE); //串口空闲中断 USART_ITConfig(USART3, USART_IT_TC, ENABLE); //发送完成中断 USART_DMACmd(USART3,USART_DMAReq_Rx | USART_DMAReq_Tx,ENABLE); DMA_Cmd(DMA1_Stream1,ENABLE); USART_Cmd(USART3, ENABLE); //DMA for rx DMA_Config(DMA1_Stream1,DMA_Channel_4, (uint32_t)&(USART3->DR), (uint32_t)USART3_Rx_DMA_Buffer, DMA_DIR_PeripheralToMemory, USART3_RX_BUFFER_SIZE); //DMA for tx DMA_Config(DMA1_Stream3,DMA_Channel_4, (uint32_t)&(USART3->DR), (uint32_t)USART3_Tx_DMA_Buffer, DMA_DIR_MemoryToPeripheral, USART3_TX_BUFFER_SIZE); usart3.update=0; usart3.locked=0; usart3.tx_length=0; usart3.rx_length=0; usart3.rx_size=USART3_RX_BUFFER_SIZE; usart3.tx_size=USART3_TX_BUFFER_SIZE; usart3.tx_buf=USART3_Tx_DMA_Buffer; usart3.rx_buf=USART3_Rx_DMA_Buffer; DMA_Transfer_Enable(DMA1_Stream1,USART3_RX_BUFFER_SIZE); //开启一次DMA接收 // DMA_Transfer_Enable(DMA1_Stream3,USART3_TX_BUFFER_SIZE); //开启一次DMA发送 } //中断服务函数 void USART3_IRQHandler(void) { uint8_t rc_tmp; uint16_t rc_len; //空闲中断(接收)--------------------------------------------------------------------------------------- if(USART_GetITStatus(USART3,USART_IT_IDLE)!=RESET) { //清除IDLE标志 rc_tmp=USART3->SR; rc_tmp=USART3->DR; DMA_Cmd(DMA1_Stream1, DISABLE); DMA_ClearITPendingBit(DMA1_Stream1, DMA_IT_TCIF1); //清除发送完成标志 DMA_ClearITPendingBit(DMA1_Stream1, DMA_IT_TEIF1); //清除发送错误标志 rc_len = USART3_RX_BUFFER_SIZE - DMA_GetCurrDataCounter(DMA1_Stream1); //计算本次收到的数据帧长度 if(!usart3.locked) { usart3.rx_length=rc_len; Data_Decode(USART3_Rx_DMA_Buffer); DMA_Transfer_Enable(DMA1_Stream1,USART3_RX_BUFFER_SIZE); } } //发送完成中断(发送)--------------------------------------------------------------------------------------- if(USART_GetITStatus(USART3,USART_IT_TC)!=RESET) { DMA_ClearFlag(DMA1_Stream3, DMA_FLAG_TCIF3); //清除DMA发送完成标志 USART_ClearITPendingBit(USART3, USART_IT_TC); //清除发送完成标志 DMA_Cmd(DMA1_Stream3, DISABLE); } } 2、数据缓冲错位问题 (1)问题描述: 发送数据部分没什么问题,之前我设置的接收缓冲buf比传输数据长度多一点,接收也没问题,但今天调DMA的时候我把二者长度设成一样了(都是8字节),于是遇到以下问题
(2)调试过程 注意,DMA是不受cpu控制的,一旦设置好后就会自动搬运数据,在debug过程中它导致的赋值操作不会在断点停下,所以对DMA进行debug要特别注意
出现这种错位,本质上还是在于对底层寄存器了解太少,又没怎么看数据手册。我以前只是简单地顾名思义把DMA_Transfer_Enable函数当成转移使能了,还以为每次传输都要加,导致了这种错位。 所以说知其然还要知其所以然,做技术还是要踏实一点,急于求成不关注细节总会出问题,这次也算给自己提个醒吧。 |
|
|
|
只有小组成员才能发言,加入小组>>
调试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| 德赢Vwin官网 ( 湘ICP备2023018690号 )
GMT+8, 2024-12-22 21:27 , Processed in 0.923000 second(s), Total 45, Slave 39 queries .
Powered by 德赢Vwin官网 网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
德赢Vwin官网 观察
版权所有 © 湖南华秋数字科技有限公司
德赢Vwin官网 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号