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 小米 华为 单反 装机 图拉丁
 
   -> 嵌入式 -> STM32F103ZET6串口使用USAR_TFLAG_IDLE空闲中断实现UART_DMA接收和发送不定长数据 -> 正文阅读

[嵌入式]STM32F103ZET6串口使用USAR_TFLAG_IDLE空闲中断实现UART_DMA接收和发送不定长数据

本文是实现STM32F103ZET6串口通过使用STM32的IDLE空闲中断(USAR_TFLAG_IDLE)实现UART_DMA接收和发送(Rx和Tx均通过DMA通道)不定长数据。本文实现了UART1_DMA、UART2_DMA、UART3_DMA、UART4_DMA,文末均有代码下载

本文以UART1_DMA为例。

一、为什么要使用 UART DMA 传输

直接存储器存取(DMA)用来提供在外设和存储器之间或者存储器和存储器之间的高速数据传输。无须CPU干预,数据可以通过DMA快速地移动,这就节省了CPU的资源来做其他操作。通俗的讲就是CPU不需要负责具体数据的收发,只要告诉DMA将一块数据从某处搬运到某处,搬完后,CPU再去使用。

二、STM32F103ZET6 DMA控制器

STM32F103ZET6有2个DMA控制器,UART1/2/3在DMA1控制器,UART4在DMA2控制器,UART5不支持DMA功能。

外设的DMA请求,可以通过设置相应外设寄存器中的控制位,被独立地开启或关闭。查询手册,STM32F103ZET6的DMA通道如下表,由表可知,UART1的TX是通道4,RX是通道5。

如图:

?代码:

(1)串口初始化

/**********************************************************************
  * @brief  USART1初始化
  * @param  null
  * @retval null
  **********************************************************************/
void USART1_Config(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	USART_InitTypeDef USART_InitStructure;
	//打开串口GPIO时钟
	USART1_GPIO_APBxClkCmd(USART1_GPIO_CLK, ENABLE);
	//打开串口外设时钟
	USART1_APBxClkCmd(USART1_CLK, ENABLE);
	//将USART_Tx的GPIO配置为推挽复用模式
	GPIO_InitStructure.GPIO_Pin = USART1_TX_GPIO_PIN;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(USART1_TX_GPIO_PORT, &GPIO_InitStructure);
	//将USART_Rx的GPIO配置为浮空输入模式
	GPIO_InitStructure.GPIO_Pin = USART1_RX_GPIO_PIN;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
	GPIO_Init(USART1_RX_GPIO_PORT, &GPIO_InitStructure);
	//配置串口工作参数
	//配置波特率
	USART_InitStructure.USART_BaudRate = USART1_BAUDRATE;
	//配置针数数据字长
	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(USART1, &USART_InitStructure);
	//配置串口中断优先级
	NVIC_Configuration(USART1_IRQ);
	//使能串口接收中断,接收一帧数据产生USART_IT_IDLE中断
	USART_ITConfig(USART1, USART_IT_IDLE, ENABLE); 
    //使能串口接收中断,发送完一帧数据产生USART_IT_TC中断
	USART_ITConfig(USART1, USART_IT_TC,   ENABLE);
	//使能串口
	USART_Cmd(USART1, ENABLE);	    
}

?

(2)USARTx_TX DMA初始化

/**
  * @brief  USARTx TX DMA 配置,内存到外设(USART1->DR)
  * @param  null
  * @retval null
  */
void USART1_TX_DMA_Config(void)
{
	DMA_InitTypeDef DMA_InitStructure;
	DMA_DeInit(USART1_TX_DMA_CHANNEL);		//USART_TX_DMA

	//开启DMA时钟,DMA1
	RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
	//设置DMA源地址,串口数据寄存器地址
	DMA_InitStructure.DMA_PeripheralBaseAddr = USART1_DR_ADDRESS;
	//内存地址(要传输的变量的指针)
	DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)USART1_TX_BUF;
	//方向:从内存到外设
	DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;
	//传输大小
	DMA_InitStructure.DMA_BufferSize = 0;
	//外设地址不增    
	DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
	//内存地址自增
	DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable ;
	//外设数据单位
	DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
	//内存数据单位
	DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;	 
	//DMA模式,一次或者循环模式
	DMA_InitStructure.DMA_Mode = DMA_Mode_Normal ;
	//优先级:中
	DMA_InitStructure.DMA_Priority = DMA_Priority_Medium; 
	//禁止内存到内存传输
	DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
	//配置DMA UART TX通道   
	DMA_Init(USART1_TX_DMA_CHANNEL, &DMA_InitStructure);		
	USART_DMACmd(USART1, USART_DMAReq_Tx , ENABLE);
	//使能DMA TX通道
	DMA_Cmd(USART1_TX_DMA_CHANNEL,DISABLE);
}

(3)USARTx_RX DMA初始化

/**
  * @brief  USARTx RX DMA 配置,外设到内存(USART1->DR)
  * @param  null
  * @retval null
  */
void USART1_RX_DMA_Config(void)
{
	DMA_InitTypeDef DMA_InitStructure;
	DMA_DeInit(USART1_RX_DMA_CHANNEL);  // USART_TX_DMA

	//开启DMA时钟
	RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
	//设置DMA源地址,串口数据寄存器地址
	DMA_InitStructure.DMA_PeripheralBaseAddr = USART1_DR_ADDRESS;
	//内存地址(要传输的变量的指针)
	DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)USART1_RX_BUF;
	//方向:外设到内存
	DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC ;
	//传输大小
	DMA_InitStructure.DMA_BufferSize = sizeof(USART1_RX_BUF);
	//外设地址不增   
	DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;//
	//内存地址不增
	DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable ;//
	//外设数据单位
	DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;//
	//内存数据单位
	DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;	 
	//DMA模式,一次或者循环模式
	DMA_InitStructure.DMA_Mode = DMA_Mode_Normal ;
	//优先级:中
	DMA_InitStructure.DMA_Priority = DMA_Priority_Medium; 
	//禁止内存到内存的传输  
	DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
	// 配置DMA通道
	DMA_Init(USART1_RX_DMA_CHANNEL , &DMA_InitStructure);	
	USART_DMACmd(USART1, USART_DMAReq_Rx, ENABLE);
	//使能DMA_Rx通道
	DMA_Cmd(USART1_RX_DMA_CHANNEL,ENABLE);
}

(4)串口中断&DMA接收数据

/***********************************************************************
  * @brief  配置嵌套向量中断控制器NVIC
  * @param  null
  * @retval null
  **********************************************************************/
static void NVIC_Configuration(uint8_t NVIC_IRQChannel)
{
	NVIC_InitTypeDef NVIC_InitStructure;
	/* 嵌套向量中断控制器组选择 */
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); 
	/* 配置USART为中断源 */
	NVIC_InitStructure.NVIC_IRQChannel = NVIC_IRQChannel;
	/* 抢断优先级 */
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
	/* 子优先级 */
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
	/*使能中断 */
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	/* 初始化配置NVIC */
	NVIC_Init(&NVIC_InitStructure);
}





 /***********************************************************************
  * @brief  USART1中断
  * @param  null
  * @retval null
  **********************************************************************/
void USART1_IRQHandler(void)
{
	uint8_t clear = clear;
	//串口接收一次数据结束
	if(USART_GetFlagStatus(USART1,USART_FLAG_IDLE) !=RESET )
	{
		clear = USART1->SR;
		clear = USART1->DR;
		//清除USART1空闲中断标志
		USART_ClearITPendingBit(USART1, USART_FLAG_IDLE);  
		USART1_Rx_Len = UART_BUF_SIZE - DMA_GetCurrDataCounter(USART1_RX_DMA_CHANNEL);
		//清除RX_DMA的传输寄存器
		USART1_DMA_RX_CLC(USART1_RX_DMA_CHANNEL);//RX
		
		//Todo
		//...
		//对收到的数据再此进行解析
		//本Demo将接收到的数据复制到发送数据,发送出去。即收发的数据原封不动发送出去
		//...
		
		USART1_Tx_Len = USART1_Rx_Len;
		memcpy(USART1_TX_BUF,USART1_RX_BUF,USART1_Rx_Len); 
		//发送数据
		USART1_DMA_SendBuf(USART1_TX_BUF, USART1_Tx_Len);
	}
	//数据发送完成中断
    if(USART_GetITStatus(USART1, USART_IT_TC) != RESET)   
    {
		//清除数据发送完成中断
        USART_ClearITPendingBit(USART1, USART_IT_TC);  
		//关闭SART1 DMA Tx通道
        DMA_Cmd(USART1_TX_DMA_CHANNEL, DISABLE);    
		//初始化接收发送数组等
		USART1_Rx_Len = 0;
		USART1_Tx_Len = 0;
		memset(USART1_RX_BUF,0,UART_BUF_SIZE);
		memset(USART1_TX_BUF,0,UART_BUF_SIZE);
	}
}

(5)DMA发送数据

//开启一次DMA数据传输
void USART1_DMA_RX_CLC(DMA_Channel_TypeDef *DMA_CHx)
{ 
	DMA_Cmd(DMA_CHx, DISABLE );  //关闭SART1 TX DMA1所指示的通道      
 	DMA_SetCurrDataCounter(DMA_CHx,UART_BUF_SIZE);//设置DMA通道的DMA缓存大小
 	DMA_Cmd(DMA_CHx, ENABLE);  //使能USART1 TX DMA1所指示的通道
}

//USART1 DMA发送数据
void USART1_DMA_SendBuf(uint8_t *arr, uint8_t len)
{
	uint8_t sendLen= 0;
	if(len == 0)
	{		
		return;
	}
	
	sendLen = len > UART_BUF_SIZE ? UART_BUF_SIZE : len;	
    //判断DMA通道里是否还有数据,即上一帧数据是否发送完毕
    while(DMA_GetCurrDataCounter(USART1_TX_DMA_CHANNEL)); 
   
	if(arr) 
	{
		memcpy(USART1_TX_BUF, arr, sendLen);
	}
	//关闭USART1_DMA_Tx通道
    DMA_Cmd(USART1_TX_DMA_CHANNEL, DISABLE);
	//设置DMA_TX要传输的数据长度
    DMA_SetCurrDataCounter(USART1_TX_DMA_CHANNEL, sendLen); 
	//使能USART1 DMA Tx通道,发送数据
    DMA_Cmd(USART1_TX_DMA_CHANNEL, ENABLE);
}

-------------------------------------------------

代码下载:

(1)STM32F103ZET6 UART1_DMA收发不定长数据:

https://download.csdn.net/download/wangzhichunnihao/69328698

(2)STM32F103ZET6 UART2_DMA收发不定长数据:

https://download.csdn.net/download/wangzhichunnihao/69329351

(3)STM32F103ZET6 UART3_DMA收发不定长数据:

https://download.csdn.net/download/wangzhichunnihao/69330092

(4)STM32F103ZET6 UART4_DMA收发不定长数据:

STM32F103ZET6UART4_DMA收发不定长数据-嵌入式文档类资源-CSDN下载

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

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