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 小米 华为 单反 装机 图拉丁
 
   -> 嵌入式 -> 65 STM32F0系列 串口DMA循环接收实验记录 -> 正文阅读

[嵌入式]65 STM32F0系列 串口DMA循环接收实验记录

1.引言

????????最近因为中断冲突问题,导致串口接收数据时随机丢失一两个字节。无奈串口的中断优先级不能是最高的,所以中断冲突问题明显存在,因此需要串口使用DMA方式来接收数据,从而规避串口接收数据丢失问题。

2.DMA配置经验

? ? ? ? 首次使用dma,需要了解一下dma的知识。

? ? ? ? 1.首先最重要要了解的一点就是,dma接收数据一定要接收到指定长度的数据,或指定长度的一半数据才能产生接收中断,如果数据没有达到一半或指定长度,就无法产生dma接收数据通知。

? ? ? ? 一般解决这个问题是串口空闲中断IDE方式解决。也就是串口传完数据产生空闲中断后去读取DMA收到的数据,就能接收不定长度的数据了。

? ? ? ? 然而现实很悲催,我所使用的cortex-m0芯片,居然没有串口空闲中断,为此需要另寻它法。所以就选择了在while(1)循环中接收DMA数据了。

? ? ? ? 2.既然配置了串口的DMA接收,因此就不需要启动串口接收中断了,但串口的收发模式配置还是需要的。如下:

UART_InitStructure.UART_Mode		= UART_Mode_Rx | UART_Mode_Tx; //收发模式

? ? ? ? 3.DMA模式选择

????????DMA_Mode_Normal和DMA_Mode_Circular模式,指的是单次和多次的问题。如果是DMA_Mode_Normal模式,进行完一次DMA数据传输后,要启动第二次DMA传输,需先关闭该DMA通道,重新设置DMA传输数据个数,再开启DMA通道。而DMA_Mode_Circular模式则不需要,其会自动配置。

? ? ? ? ?下述代码中有这个体现,DMA_Mode_Normal模式下如果不重新配置,则收发就不正常。

? ? ? ? 4.查看串口对应的DMA channel

? ? ? ? 对于STM32F030单片机UART1引脚对应的DMA channel通道,可以看STM32F030参考手册,而不是芯片手册!!!!别找错文档了。然后查所使用的的引脚对应的通道选择就行。

在这里插入图片描述? ? ? ? ?我所使用的是USART1,并且没有重映射RX到其它引脚,因此是channel3,这个实际的时候要注意,别搞错了,当然搞错了也没关系,试一下就好了,花不了什么时间。

?

3.实验代码

#define UART1_RX_LEN		(64)
uint8_t tUart1_Rx[UART1_RX_LEN] = {0};


void UART1_Init(void)
{
    //GPIO端口设置
    GPIO_InitTypeDef GPIO_InitStructure = {0};
    NVIC_InitTypeDef NVIC_InitStructure = {0};
	UART_InitTypeDef UART_InitStructure = {0};

	RCC_APB2PeriphClockCmd(RCC_APB2Periph_UART1, ENABLE);	//使能UART1,GPIOA时钟
	/
	//1.引脚初始化
	GPIO_PinAFConfig(GPIOB,GPIO_PinSource6,GPIO_AF_0);
	GPIO_PinAFConfig(GPIOB,GPIO_PinSource7,GPIO_AF_0);

	GPIO_InitStructure.GPIO_Pin		= GPIO_Pin_6; //PA.9
	GPIO_InitStructure.GPIO_Speed	= GPIO_Speed_2MHz;
	GPIO_InitStructure.GPIO_Mode	= GPIO_Mode_AF_PP; //复用推挽输出
	GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化GPIOA.9
	
	GPIO_InitStructure.GPIO_Pin 	= GPIO_Pin_7;//PA10
	GPIO_InitStructure.GPIO_Speed 	= GPIO_Speed_2MHz;
	GPIO_InitStructure.GPIO_Mode	= GPIO_Mode_IPU;//浮空输入
	GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化GPIOA.10 

	/
	//2.串口初始化
	UART_InitStructure.UART_BaudRate 	= 115200;//串口波特率
	UART_InitStructure.UART_WordLength	= UART_WordLength_8b;//字长为8位数据格式
	UART_InitStructure.UART_StopBits	= UART_StopBits_1;//一个停止位
	UART_InitStructure.UART_Parity		= UART_Parity_No;//无奇偶校验位
	UART_InitStructure.UART_HardwareFlowControl = UART_HardwareFlowControl_None;//无硬件数据流控制
	UART_InitStructure.UART_Mode		= UART_Mode_Rx | UART_Mode_Tx; //收发模式
	UART_Init(UART1, &UART_InitStructure); //初始化串口1
	UART_DMACmd(UART1, UART_DMAReq_EN, ENABLE); 
	UART_Cmd(UART1, ENABLE);

	//dma配置
    UART1_DMAInit();
}

void UART1_DMAInit(void)
{
	RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);

	/
	//dma初始化 p -> m
	DMA_DeInit(DMA1_Channel3);	
	DMA_Cmd(DMA1_Channel3, DISABLE);
	DMA_InitStructure.DMA_PeripheralBaseAddr 	= (uint32_t)&UART1->RDR;//外设数据地址
	DMA_InitStructure.DMA_MemoryBaseAddr 		= (uint32_t)tUart1_Rx;  //自己的接收buf
	DMA_InitStructure.DMA_BufferSize			= UART1_RX_LEN;  // 缓存大小
	DMA_InitStructure.DMA_M2M 					= DMA_M2M_Disable;	 // 内存到内存关闭
	DMA_InitStructure.DMA_Mode 					= DMA_Mode_Normal;	// 普通模式
	DMA_InitStructure.DMA_DIR 					= DMA_DIR_PeripheralSRC;	 // 外设到内存
	DMA_InitStructure.DMA_Priority 				= DMA_Priority_High; // DMA通道优先级
	DMA_InitStructure.DMA_MemoryInc 			= DMA_MemoryInc_Enable;// 内存地址递增
	DMA_InitStructure.DMA_PeripheralInc			= DMA_PeripheralInc_Disable;//外设基地址不需要递增
	DMA_InitStructure.DMA_MemoryDataSize 		= DMA_MemoryDataSize_Byte; 
	DMA_InitStructure.DMA_PeripheralDataSize 	= DMA_PeripheralDataSize_Byte;
	DMA_Init(DMA1_Channel3,&DMA_InitStructure);
	DMA_Cmd(DMA1_Channel3, ENABLE); 
	/
}

//因为该单片机没有串口空闲中断
//所以只能使用poll接收dma数据
//该函数放在while(1)中即可
void UART1_DMAChannel3_rcvTask(void)
{
	uint16_t rxSize = 0;

	//获取当前接收到的数据大小
	rxSize = UART1_RX_LEN - DMA_GetCurrDataCounter(DMA1_Channel3);
	//如果数据大于0,说明开始接收数据了
	if(rxSize>0)
	{
		//休眠10ms,是因为让串口dma继续接收数据
		//根据115200波特率计算,10ms足够传输1024字节大小的数据
		//所以delay 10ms基本满足单次数据的收
		delay_ms(50);
		DMA_Cmd (DMA1_Channel3,DISABLE);//重新配置DMA时,需要先disableDMA

		//接收完成,再获取一次实际的数据长度
		rxSize = UART1_RX_LEN - DMA_GetCurrDataCounter(DMA1_Channel3);

		//接收数据,写入buf
		BleClient_RcvDataBufIn(tUart1_Rx, rxSize);
		
		memset(tUart1_Rx,0,UART1_RX_LEN);    //清空数组
		DMA_Init(DMA1_Channel3, &DMA_InitStructure); //重新配置一次DMA
		DMA_Cmd (DMA1_Channel3,ENABLE); 
	}
}

over!

  嵌入式 最新文章
基于高精度单片机开发红外测温仪方案
89C51单片机与DAC0832
基于51单片机宠物自动投料喂食器控制系统仿
《痞子衡嵌入式半月刊》 第 68 期
多思计组实验实验七 简单模型机实验
CSC7720
启明智显分享| ESP32学习笔记参考--PWM(脉冲
STM32初探
STM32 总结
【STM32】CubeMX例程四---定时器中断(附工
上一篇文章      下一篇文章      查看所有文章
加:2022-04-04 12:27:28  更:2022-04-04 12:29:31 
 
开发: 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/26 4:47:04-

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