当前位置:首页 > 单片机 > 单片机
[导读]串口DMA发送:发送数据的流程:前台程序中有数据要发送,则需要做如下几件事1. 在数据发送缓冲区内放好要发送的数据,说明:此数据缓冲区的首地址必须要在DMA初始化的时候写入到DMA配置中去。2. 将数据缓冲区内要发

串口DMA发送:

发送数据的流程:

前台程序中有数据要发送,则需要做如下几件事

1. 在数据发送缓冲区内放好要发送的数据,说明:此数据缓冲区的首地址必须要在DMA初始化的时候写入到DMA配置中去。

2. 将数据缓冲区内要发送的数据字节数赋值给发送DMA通道,(串口发送DMA和串口接收DAM不是同一个DMA通道)

3. 开启DMA,一旦开启,则DMA开始发送数据,说明一下:在KEIL调试好的时候,DMA和调试是不同步的,即不管Keil 是什么状态,DMA总是发送数据。

4. 等待发送完成标志位,即下面的终端服务函数中的第3点设置的标志位。或者根据自己的实际情况来定,是否要一直等待这个标志位,也可以通过状态机的方式来循环查询也可以。或者其他方式。

判断数据发送完成:

启动DMA并发送完后,产生DMA发送完成中断,在中断函数中做如下几件事:

1.清DMA发送完成中断标志位

2.关闭串口发送DMA通道

3.给前台程序设置一个软件标志位,说明数据已经发送完毕

串口DMA接收:

接收数据的流程:

串口接收DMA在初始化的时候就处于开启状态,一直等待数据的到来,在软件上无需做任何事情,只要在初始化配置的时候设置好配置就可以了。

判断数据数据接收完成:

这里判断接收完成是通过串口空闲中断的方式实现,即当串口数据流停止后,就会产生IDLE中断。这个中断里面做如下几件事:

1. 关闭串口接收DMA通道,2点原因:1.防止后面又有数据接收到,产生干扰。2.便于DMA的重新配置赋值,下面第4点。

2. 清除DMA 所有标志位

3. 从DMA寄存器中获取接收到的数据字节数

4. 重新设置DMA下次要接收的数据字节数,注意,这里是给DMA寄存器重新设置接收的计数值,这个数量只能大于或者等于可能接收的字节数,否则当DMA接收计数器递减到0的时候,又会重载这个计数值,重新循环递减计数,所以接收缓冲区的数据则会被覆盖丢失。

5.开启DMA通道,等待下一次的数据接收,注意,对DMA的相关寄存器配置写入,如第4条的写入计数值,必须要在关闭DMA的条件进行,否则操作无效。

说明一下,STM32的IDLE的中断在串口无数据接收的情况下,是不会一直产生的,产生的条件是这样的,当清除IDLE标志位后,必须有接收到第一个数据后,才开始触发,一断接收的数据断流,没有接收到数据,即产生IDLE中断。


/**********************************************************************************************纯属搬运***********************************************************************************************/


上面文字性的分析已经写的很好了,我就不累赘了。原作者给了个例子,我移植到了战舰上,就帖个工程吧。

再附送一个F207上的例子(同理F4),这个跟F1系列的差异还是蛮大的。

/*******************************************************************************
* 函数名 : dma_uart2_init
* 描述 : 初始化DMA串口2
* DMA1
* DMA_Channel_4 通道4
* DMA2_Stream4数据流6
* 参数 :
* 返回值 : 无
*******************************************************************************/
voiddma_uart2_init(void)
{
DMA_InitTypeDef DMA_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;

/* DMA clock enable */
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1, ENABLE); // 开启DMA2时钟

//=DMA_Configuration==============================================================================//
// DMA_Cmd(DMA2_Stream7, DISABLE); // 关DMA通道

DMA_DeInit(DMA1_Stream6); // 恢复缺省值
while(DMA_GetCmdStatus(DMA1_Stream6) != DISABLE){}//等待DMA可配置

DMA_InitStructure.DMA_Channel = DMA_Channel_4; //通道4
DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)(&USART2->DR); // 设置串口发送数据寄存器
DMA_InitStructure.DMA_Memory0BaseAddr = (u32)DMA_UART2_SendBuf; // 设置发送缓冲区首地址
DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral; // 设置外设位目标,内存缓冲区 -> 外设寄存器
DMA_InitStructure.DMA_BufferSize = 0; // 需要发送的字节数,这里其实可以设置为0,因为在实际要发送的时候,会重新设置次值
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; // 外设地址不做增加调整,调整不调整是DMA自动实现的
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; // 内存缓冲区地址增加调整
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; // 外设数据宽度8位,1个字节
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; // 内存数据宽度8位,1个字节
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; // 单次传输模式,不循环
DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh; // 优先级设置
DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;//DMA_FIFOMode_Disable
DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;
DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
DMA_Init(DMA1_Stream6, &DMA_InitStructure); // 写入配置

/* Enable the DMA Interrupt */
NVIC_InitStructure.NVIC_IRQChannel = DMA1_Stream6_IRQn; // 发送DMA通道的中断配置
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 9;// 优先级设置
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);

DMA_ITConfig(DMA1_Stream6, DMA_IT_TC, ENABLE);// 开启DMA通道传输完成中断
USART_DMACmd(USART2, USART_DMAReq_Tx, ENABLE);// 开启串口DMA发送
}

/*******************************************************************************
* 函数名 : uart2_init
* 描述 : 初始化串口2
* 参数 : bound:波特率
* 返回值 : 无
*******************************************************************************/
voiduart2_init(u32 bound)//初始化串口2
{
//GPIO端口设置
NVIC_InitTypeDef NVIC_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;

RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);//使能GPIOb时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);//USART2

GPIO_PinAFConfig(GPIOA, GPIO_PinSource2, GPIO_AF_USART2);//重映射,TX
GPIO_PinAFConfig(GPIOA, GPIO_PinSource3, GPIO_AF_USART2);//重映射,RX

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2 | GPIO_Pin_3;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //翻转速度
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; //输入输出设置,输入/输出/复用/模拟
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; //输出模式,开漏/推挽
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; //输入模式,浮空/上拉/下拉
GPIO_Init(GPIOA, &GPIO_InitStructure);

//USART 初始化设置
USART_InitStructure.USART_BaudRate = bound;//一般设置为9600;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字长为8位数据格式
USART_InitStructure.USART_StopBits = USART_StopBits_1;//一个停止位
USART_InitStructure.USART_Parity = USART_Parity_No;//无奇偶校验位
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;//收发模式
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//无硬件数据流控制

USART_Init(USART2, &USART_InitStructure);//初始化串口

//Usart1 NVIC 配置
NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3;//抢占优先级2
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; //子优先级3,子优先级不能为0???
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道使能
NVIC_Init(&NVIC_InitStructure);//根据指定的参数初始化VIC寄存器

USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);//开启中断
USART_Cmd(USART2, ENABLE);//使能串口

dma_uart2_init();//初始化串口DMA发送
}

/*******************************************************************************
* 函数名 : USART2_IRQHandler
* 描述 : 串口2中断服务函数,接收采集板数据
* 参数 : 无
* 返回值 : 无
*******************************************************************************/
voidUSART2_IRQHandler(void)//串口2中断服务程序
{
u8 c;

if(USART_GetITStatus(USART2, USART_IT_RXNE) == SET)//接收中断
{
USART_ClearITPendingBit(USART2, USART_IT_RXNE);

LED2 = !LED2;
c = USART_ReceiveData(USART2);//读取接收寄存器,读数据会清除中断
write_loop_2_buf(c);
}
}

//DMA 发送应用源码
voidDMA1_Stream6_IRQHandler(void)
{
staticportBASE_TYPE xHigherPriorityTaskWoken;

xHigherPriorityTaskWoken = pdFALSE;

if(DMA_GetITStatus(DMA1_Stream6, DMA_IT_TCIF6))
{
// printf("DMA1中断rn");
DMA_ClearFlag(DMA1_Stream6, DMA_IT_TCIF6);// 清除标志
DMA_Cmd(DMA1_Stream6, DISABLE); // 关闭DMA通道

//发送信号量
xSemaphoreGiveFromISR(xSemaphoreHandle_DMA_USART2_SendFlag, &xHigherPriorityTaskWoken);//发送完成标志

if(xHigherPriorityTaskWoken == pdTRUE) //给出信号量使任务解除阻塞,如果解除阻塞的任务的优先级高于当前任务的优先级——强制进行一次任务切换
{
portEND_SWITCHING_ISR(xHigherPriorityTaskWoken);
}
}
}

voidDMA_USART2_SendData(u8 *buf, u16 size)//DMA串口2发送数据
{
memcpy(DMA_UART2_SendBuf, buf, size);//拷贝到DMA缓冲区

DMA1_Stream6->NDTR = (u16)size; // 设置要发送的字节数目
// printf("发送字节数=%drn",size);
DMA_Cmd(DMA1_Stream6, ENABLE);//开始DMA发送

xSemaphoreTake(xSemaphoreHandle_DMA_USART2_SendFlag, portMAX_DELAY);//使用信号量等待发送完成,无超时

本站声明: 本文章由作者或相关机构授权发布,目的在于传递更多信息,并不代表本站赞同其观点,本站亦不保证或承诺内容真实性等。需要转载请联系该专栏作者,如若文章内容侵犯您的权益,请及时联系本站删除。
换一批
延伸阅读

智能合灯控制系统由环境光照检测、人体接近检测、语音识别、按键控制、合灯控制、数据显示、蓝牙通信、报警提示功能模块组成。

关键字: STM32 智能台灯

捡球机的移动装置以直流电机驱动,寻球装置以摄像头图像传感器模块构成,并搭配以图像检测算法。避障装置以红外检测和报警模块为主,以防在行动过程中触碰障碍物。

关键字: STM32 捡球机

ST于近期发布了“STM32WBA”无线MCU、“STM32U0”超低功耗入门级MCU、“STM32H7R/S”高性能MCU和“STM32MP2”四大重磅新品,还透露将会在今年推出18nm的STM32新品。

关键字: STM32 MCU NPU AI 超低功耗

在微控制器领域,MSP430与STM32无疑是两颗璀璨的明星。它们各自凭借其独特的技术特点和广泛的应用领域,在市场上占据了重要的位置。本文将深入解析MSP430与STM32之间的区别,探讨它们在不同应用场景下的优势和局限...

关键字: MSP430 STM32 单片机

STM32是由意法半导体公司(STMicroelectronics)推出的基于ARM Cortex-M内核的32位微控制器系列,以其高性能、低功耗、丰富的外设接口和强大的生态系统深受广大嵌入式开发者喜爱。本文将详细介绍S...

关键字: STM32 单片机

STM32与51单片机之间有什么差异呢?两者可以说是一场科技与性能的较量了。在科技飞速发展的今天,微控制器(MCU)已广泛应用于各类电子设备和系统中,发挥着举足轻重的作用。其中,STM32和51单片机作为两种常见的微控制...

关键字: STM32 51单片机 MCU

电磁铁是一种利用电流产生磁场的装置,具有快速响应、易于控制等特点,在工业自动化、电子设备、科学实验等领域有着广泛的应用。STM32是一款功能强大的微控制器,具有高性能、低功耗、易于编程等优点,是控制电磁铁的理想选择。本文...

关键字: 电磁铁 微控制器 STM32

边缘人工智能的实现涉及到三个基本 要素:安全性,连接性、自主性,而其中自主性是AI能力的体现,也是边缘AI有别于其他传统的物联网的关键。而通过ST Edge AI套件,就可以帮助各种不同类型的开发者实现覆盖全硬件平台的全...

关键字: 边缘人工智能 AI STM32

今天,小编将在这篇文章中为大家带来STM32单片机最小系统的有关报道,通过阅读这篇文章,大家可以对它具备清晰的认识,主要内容如下。

关键字: 单片机 单片机最小系统 STM32

STM32是一款由STMicroelectronics生产的微控制器系列,具有高性能、低功耗和丰富的外设资源。其中,串口通信是一种常用的通信方式,可以实现与其他设备之间的数据传输。

关键字: STM32 串口通信 微控制器
关闭
关闭