IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 嵌入式 -> STM32串口空闲中断加DMA传输不定长数据 -> 正文阅读

[嵌入式]STM32串口空闲中断加DMA传输不定长数据

决定开始在CSDN上记录学习单片机的过程了

想讲讲我对串口空闲中断加DMA的理解

1.DMA传输的好处

一般的数据通过串口传输都会经过CPU的读取 当模块多起来(比如五六个激光测距模块读取再加上MPU的解算)CPU会负荷过重而致使程序卡顿造成干扰??

而DMA可以当成传输数据的桥梁 (介于外设到存储器 /存储器到外设 /存储器到存储器?)

桥梁的作用是自身开辟一个通道使数据传输无需经过CPU从而减少CPU消耗

2.串口空闲中断

串口空闲中断顾名思义 在串口空闲时(发完一帧数据)产生中断

3.串口空闲中断加DMA接受不定长度数据过程

  • 0、开启串口DMA接收
  • 1、串口收到数据,DMA不断传输数据到存储buf(在DMA配置了外设地址与存储器地址,如果是外设到存储器,则这个存储buf就是存储器地址)
  • 2、一帧数据发送完毕,串口暂时空闲,触发串口空闲中断
  • 3、在中断服务函数中,可以计算刚才收到了多少个字节的数据(收到字节长度? =? DMA设定的数据接受量-DMA_GetCurrDataCounter(dma中剩余长度))
  • 4、解码存储buf,清除标志位,开始下一帧接收

?

unsigned char ucRxFinish=0;
unsigned char ucRxData[100];
int uiData;
u8 usart6_rx_buf[DMA_REC_LEN] = {0};
u8 dma_rec_buff[DMA_REC_LEN] = {0};
u16 uart6_rec_cnt = 0;?? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ?//串口接收数据长度
?
u8 data_backup[DMA_REC_LEN] = {0}; ?? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ?//数据备份
_Bool receiveOK_flag = 0;?? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ?//接收完成标志位

//DMAx的各通道配置
//这里的传输形式是固定的,这点要根据不同的情况来修改
//从存储器->外设模式/8位数据宽度/存储器增量模式
//DMA_Streamx:DMA数据流,DMA1_Stream0~7/DMA2_Stream0~7
//chx:DMA通道选择,@ref DMA_channel DMA_Channel_0~DMA_Channel_7?

void MYDMA_Config(DMA_Stream_TypeDef *DMA_Streamx) ?//DMA配置

{?
? ?? ?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 = DMA_Channel_5; ?//通道选择 ?5
? DMA_InitStructure.DMA_PeripheralBaseAddr = ( u32 )&USART6->DR;//DMA外设地址
? DMA_InitStructure.DMA_Memory0BaseAddr = ( u32 )dma_rec_buff;//DMA 存储器0地址
? DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;//外设模式到存储器
? DMA_InitStructure.DMA_BufferSize = DMA_REC_LEN;//数据传输量?
? 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_Circular ;// 使用普通模式?
? DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;//中等优先级
? DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable; ? ? ? ??
? 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 Stream
?? ?DMA_Cmd(DMA_Streamx,ENABLE);?? ??? ?

}?


//开启一次DMA传输
//DMA_Streamx:DMA数据流,DMA1_Stream0~7/DMA2_Stream0~7?
//ndtr:数据传输量 ?
void MYDMA_Enable(DMA_Stream_TypeDef *DMA_Streamx,u16 ndtr) ? ? //使能DMA
{
?
?? ?DMA_Cmd(DMA_Streamx, DISABLE); ? ? ? ? ? ? ? ? ? ? ?//关闭DMA传输?
?? ?
?? ?while (DMA_GetCmdStatus(DMA_Streamx) != DISABLE){}?? ?//确保DMA可以被设置 ?
?? ??? ?
?? ?DMA_SetCurrDataCounter(DMA_Streamx,ndtr); ? ? ? ? ?//数据传输量 ?
?
?? ?DMA_Cmd(DMA_Streamx, ENABLE); ? ? ? ? ? ? ? ? ? ? ?//开启DMA传输?
}?? ? ?


void USART6_Init(uint32_t bound)//DMA2_Stream2
{
?? ?GPIO_InitTypeDef GPIO_Initstructure;
?? ?USART_InitTypeDef USART_Initstructure;
?? ?NVIC_InitTypeDef NVIC_Initstrcuture;
?? ?
?? ?RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART6,ENABLE );
?? ?RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOG ,ENABLE );
?? ?
?? ?GPIO_PinAFConfig(GPIOG,GPIO_PinSource14,GPIO_AF_USART6);
?? ?GPIO_PinAFConfig(GPIOG,GPIO_PinSource9,GPIO_AF_USART6);
?? ?
? GPIO_Initstructure.GPIO_Pin = GPIO_Pin_9;
?? ?GPIO_Initstructure.GPIO_Mode = GPIO_Mode_AF;
?? ?GPIO_Initstructure.GPIO_OType = GPIO_OType_PP;
?? ?GPIO_Initstructure.GPIO_PuPd = GPIO_PuPd_UP;
?? ?GPIO_Initstructure.GPIO_Speed = GPIO_Speed_100MHz;
?? ?GPIO_Init(GPIOG,&GPIO_Initstructure);
?? ?GPIO_Initstructure.GPIO_Pin = GPIO_Pin_14;
?? ?GPIO_Initstructure.GPIO_Mode = GPIO_Mode_AF;
?? ?GPIO_Initstructure.GPIO_OType = GPIO_OType_PP;
?? ?GPIO_Initstructure.GPIO_PuPd = GPIO_PuPd_UP;
?? ?GPIO_Initstructure.GPIO_Speed = GPIO_Speed_100MHz;
?? ?GPIO_Init(GPIOG,&GPIO_Initstructure);
?? ?
?? ?USART_Initstructure.USART_BaudRate = bound;
?? ?USART_Initstructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
?? ?USART_Initstructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
?? ?USART_Initstructure.USART_Parity = USART_Parity_No;
?? ?USART_Initstructure.USART_StopBits = USART_StopBits_1;
?? ?USART_Initstructure.USART_WordLength = USART_WordLength_8b;
?? ?USART_Init(USART6,&USART_Initstructure);
?? ?
?? ?NVIC_Initstrcuture.NVIC_IRQChannel = USART6_IRQn;
?? ?NVIC_Initstrcuture.NVIC_IRQChannelPreemptionPriority=1;
?? ?NVIC_Initstrcuture.NVIC_IRQChannelSubPriority =2;?? ??? ?
?? ?NVIC_Initstrcuture.NVIC_IRQChannelCmd = ENABLE;?? ??? ?
?? ?NVIC_Init(&NVIC_Initstrcuture);?? ?
?? ?
?? ?USART_ITConfig(USART6, USART_IT_IDLE, ENABLE);//开启空闲中断
?? ?USART_DMACmd(USART6, USART_DMAReq_Rx, ENABLE);//开启DMA接收
?? ?USART_Cmd(USART6, ENABLE);
?? ?
?? ?//initialize the DMA channel.
?? ?MYDMA_Config(DMA2_Stream1);?
?? ?

}

void USART6_IRQHandler(void)?
{
?? ?uint8_t rc_tmp;
?? ?uint16_t rc_len;

?? ?if(USART_GetITStatus(USART6,USART_IT_IDLE)!=RESET)
?? ?{
?? ? ? ?rc_tmp=USART6->SR;
? ? ? rc_tmp=USART6->DR;//软件序列清除IDLE标志位
? ? ? DMA_Cmd(DMA2_Stream1, DISABLE); //关闭DMA,准备重新配置
? ? ? DMA_ClearITPendingBit(DMA2_Stream1, DMA_IT_TCIF1);?? ?// Clear Transfer Complete flag
? ? ? DMA_ClearITPendingBit(DMA2_Stream1, DMA_IT_TEIF1);?? ?// Clear Transfer error flag?? ?
? ? ? rc_len = DMA_REC_LEN - DMA_GetCurrDataCounter(DMA2_Stream1);//计算接收数据长度

// ? ? ?Data_Decode(USART1_Rx_Buffer);//解码收到的数据
?? ? ?}
?? ? MYDMA_Enable(DMA2_Stream1,DMA_REC_LEN);//开启下一次DMA接收

}

这份代码是用在激光测距上的

最重要的调试

代码csdn上都有其实就难在调试

1.首先要注意的是串口的配置? 第一次调试怎么也读不到值困惑了好久 后边把串口2换成串口6就行了

因为用的是正点原子的模板 串口1和串口6的时钟配置是一样的 而串口2345时钟又是另外的配置 我没有仔细去深究有兴趣的可以自己去查查看

2.移植程序时一定要细心 如果你串口的DR寄存器一直没值或者有个1 emmmm你可以看看是不是外设地址( u32 )&USART6->DR 这? 串口没有改成你用的串口

3.还要注意主程序初始化的顺序? 在CSDN上偶然看到一位博主说 DMA的初始化要在串口6之前

反过来会读不到第一位数据

OOOOOO

有点小感言? 调试这份代码用了很久 是比赛要用的代码 队长一直在催进度哈哈? 其实那会配置都已经好啦 但我太粗心了有个地方疏忽了然后一直没好 ,而没好=不会 ........

所以真正厉害的人不止是会写代码啊 调试也很厉害 (苦哈哈)
?

  嵌入式 最新文章
基于高精度单片机开发红外测温仪方案
89C51单片机与DAC0832
基于51单片机宠物自动投料喂食器控制系统仿
《痞子衡嵌入式半月刊》 第 68 期
多思计组实验实验七 简单模型机实验
CSC7720
启明智显分享| ESP32学习笔记参考--PWM(脉冲
STM32初探
STM32 总结
【STM32】CubeMX例程四---定时器中断(附工
上一篇文章      下一篇文章      查看所有文章
加:2021-08-16 11:54:30  更:2021-08-16 11:55:26 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/25 21:36:16-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码