首页 > 其他分享 >三、STM32F103标准库DMA+USART接收不定长数据

三、STM32F103标准库DMA+USART接收不定长数据

时间:2024-09-02 23:22:13浏览次数:15  
标签:STM32F103 DMA USART NVIC InitStructure GPIO USART1

项目中常用到串口通信,当需要使用串口中断接不定长数据时,可以参考以下示例:

本实例使用DMA+USART空闲中断来进行不定长数据接受,在数据接收完成后将数据透传。

结果将通过另一个串口信息显示。

1、主函数配置

#include "stm32f10x.h"
#include "printfsupport.h"
#include "usart1.h"

int main(void)
{
	//打印信息接口
	Printf_Init(115200);

	//DMA+USART1接口初始化
	USART1_Init(115200);

	printf("This is a Usart Test Project\n");
	while(1)
	{
		
	}
}

主函数中初始化了打印信息串口以及用于数据接收的串口。

2、打印接口配置

C文件如下: 

#include "printfsupport.h"
/************************************
*说明:Printf默认重定向为USART3
************************************
*/
/*****************Printf重定向*****************/
#pragma import(__use_no_semihosting)    
         
//标准库需要的支持函数                 
struct __FILE 
{ 
	int handle; 
}; 

FILE __stdout;       
//定义_sys_exit()以避免使用半主机模式    
void _sys_exit(int x) 
{ 
	x = x; 
} 
//重定义fputc函数 
int fputc(int ch, FILE *f)
{      
	while((USART3->SR&0X40)==0){}//循环发送,直到发送完毕   
    USART3->DR = (u8) ch;      
	return ch;
}
/*****************Printf输出串口配置*****************/
/*
    配置内容
    波特率:BaudRate
    数据位:8bit
    校验位:无
    停止位:1
    硬件流控制:无
    输出输入模式:发送
*/
void Printf_Init(u32 BaudRate)
{
	GPIO_InitTypeDef  GPIO_InitStructure;
	USART_InitTypeDef USART_InitStructure;

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB|RCC_APB2Periph_AFIO,ENABLE);
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE);		

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; 
    GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;
    GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
    GPIO_Init(GPIOB, &GPIO_InitStructure);

    USART_InitStructure.USART_BaudRate = 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_Tx;

    USART_Init(USART3, &USART_InitStructure); 
    USART_Cmd(USART3, ENABLE);   
}

对应的h文件

#ifndef  _PRINTF_SUPPORT_H__
#define  _PRINTF_SUPPORT_H__

#include "stm32f10x.h"
#include "stdio.h"

void Printf_Init(u32 BaudRate);

#endif

3、DMA+USART配置(以USART1为例)

 C原文件如下:

#include "usart1.h"
uint8_t UART1_TX_DATA[USART1_REC_LEN];      //dma源地址     发送
uint8_t UART1_RX_DATA[USART1_REC_LEN];      //缓存地址
uint8_t USART1_RECV_BUFF[USART1_REC_LEN];   //dma目标地址   接收
uint8_t Usart1_Recv_len = 0;                //接收数据长度  
uint8_t USART1_DMA_TX_Finish = 1;           //DMA发送完成

//Usart1初始化
void USART1_Init(uint32_t baud)
{
    //结构体
	GPIO_InitTypeDef  GPIO_InitStructure;
	USART_InitTypeDef USART_InitStructure;
    NVIC_InitTypeDef NVIC_InitStructure;
    DMA_InitTypeDef     DMA_InitStructure;
    //时钟初始化
    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_AFIO,ENABLE);	
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);	
    //USART1_TX  
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;                  
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;             //复用推挽输出
    GPIO_Init(GPIOA, &GPIO_InitStructure);                      //初始化
    //USART1_RX	 
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;                   
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;               //上拉输入
    GPIO_Init(GPIOA, &GPIO_InitStructure);                      //初始化  
    //串口中断
    NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;           //IRQ通道:串口1
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;   //抢占优先级3
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;			    //IRQ通道使能
    NVIC_Init(&NVIC_InitStructure);	                            //初始化NVIC寄存器
    //USART1 DMA TX
    NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel4_IRQn;    //IRQ通道:DMA1通道4
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;   //抢占优先级3
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;             //IRQ通道使能
    NVIC_Init(&NVIC_InitStructure);                             //初始化NVIC寄存器
    //USART1 DMA RX
    NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel5_IRQn;    //IRQ通道:DMA1通道5
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;   //抢占优先级3
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;             //IRQ通道使能
    NVIC_Init(&NVIC_InitStructure);                             //初始化NVIC寄存器

    USART_InitStructure.USART_BaudRate = baud;
    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_Tx|USART_Mode_Rx;
    //初始化USART端口
    USART_Init(USART1, &USART_InitStructure);
    //开启USART1中断
    USART_ITConfig(USART1,USART_IT_TC,ENABLE); 
    USART_ITConfig(USART1,USART_IT_IDLE,ENABLE); 
    //使能USART1
    USART_Cmd(USART1, ENABLE);  
    //清中断
    USART1->SR;  
    USART1->DR;

    //使能DMA传输
    USART_DMACmd(USART1, USART_DMAReq_Tx | USART_DMAReq_Rx, ENABLE); 
    //DMA 串口发送配置 
    DMA_DeInit(DMA1_Channel4);
    DMA_InitStructure.DMA_PeripheralBaseAddr=(uint32_t)(&USART1->DR);
    DMA_InitStructure.DMA_MemoryBaseAddr=(uint32_t)UART1_TX_DATA;
    DMA_InitStructure.DMA_DIR=DMA_DIR_PeripheralDST;
    DMA_InitStructure.DMA_BufferSize=USART1_REC_LEN;
    DMA_InitStructure.DMA_MemoryDataSize=DMA_MemoryDataSize_Byte;
    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_InitStructure.DMA_Mode=DMA_Mode_Normal;
    DMA_InitStructure.DMA_Priority=DMA_Priority_VeryHigh;
    DMA_InitStructure.DMA_M2M=DMA_M2M_Disable;
    DMA_Init(DMA1_Channel4,&DMA_InitStructure);    

    DMA_Cmd(DMA1_Channel4,DISABLE);
    DMA_ITConfig(DMA1_Channel4,DMA_IT_TC,ENABLE);
    
    //DMA 串口接收配置
    DMA_DeInit(DMA1_Channel5);
    DMA_InitStructure.DMA_PeripheralBaseAddr=(uint32_t)(&USART1->DR);
    DMA_InitStructure.DMA_MemoryBaseAddr=(uint32_t)USART1_RECV_BUFF;
    DMA_InitStructure.DMA_DIR=DMA_DIR_PeripheralSRC;
    DMA_InitStructure.DMA_BufferSize=USART1_REC_LEN;
    DMA_InitStructure.DMA_MemoryDataSize=DMA_MemoryDataSize_Byte;
    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_InitStructure.DMA_Mode=DMA_Mode_Normal;
    DMA_InitStructure.DMA_Priority=DMA_Priority_VeryHigh;
    DMA_InitStructure.DMA_M2M=DMA_M2M_Disable;
    DMA_Init(DMA1_Channel5,&DMA_InitStructure);
    
    DMA_Cmd(DMA1_Channel5,DISABLE);   
    DMA_ITConfig(DMA1_Channel5,DMA_IT_TC,ENABLE);
    DMA_Cmd(DMA1_Channel5,ENABLE); 
}
//Usart1中断
void USART1_IRQHandler(void)                	
{
    //发送字节完成中断
    if(USART_GetITStatus(USART1,USART_IT_TC) != RESET)
    {
        USART_ClearITPendingBit(USART1,USART_IT_TC); //清除标志位
        USART1_DMA_TX_Finish = 1;
    }
    else if(USART_GetITStatus(USART1,USART_IT_IDLE) != RESET)
    {
        //清除IDLE中断
        USART1->SR;
        USART1->DR;
        USART_ClearITPendingBit(USART1,USART_IT_IDLE);
        //读取接收数量
        Usart1_Recv_len = USART1_REC_LEN-DMA_GetCurrDataCounter(DMA1_Channel5);	

        //打印数据
        printf("Data:");
        for(uint8_t i=0;i<Usart1_Recv_len;i++)
        {
            UART1_RX_DATA[i]=USART1_RECV_BUFF[i];
            printf("%x ",UART1_RX_DATA[i]);
        }
        printf("\n");

        //此时可以透传数据测试
        Usart1_DMA_Send(UART1_RX_DATA,Usart1_Recv_len);

        //清除DMA接收中断
        DMA_ClearITPendingBit(DMA1_IT_TC5);      
        //重新配置DMA接收数据
        DMA_Cmd(DMA1_Channel5,DISABLE);
        DMA_SetCurrDataCounter(DMA1_Channel5,USART1_REC_LEN);
        DMA_Cmd(DMA1_Channel5,ENABLE);          
    }
}

//RX中断
void DMA1_Channel5_IRQHandler(void)
{
	//接收完成DMA中断处理
	if(DMA_GetITStatus(DMA1_IT_TC5)==SET)
	{
		DMA_ClearITPendingBit(DMA1_IT_TC5);          //清除中断标志位 (通道5传输完成中断)        
	} 
}
//TX中断
void DMA1_Channel4_IRQHandler(void)
{
    //发送完成DMA中断处理
    //DMA1_Channel4向USART1数据传输完成 注意USART1并没有实际发送完成,需等待usart1发送完成中断
	if(DMA_GetITStatus(DMA1_IT_TC4)==SET)
	{
		DMA_ClearITPendingBit(DMA1_IT_TC4);           //清除中断标志位 (通道4传输完成中断)   
        DMA_Cmd(DMA1_Channel4, DISABLE);              //关闭DMA通道4    
	} 
}

/*****************  发送数组  **********************/
void Usart1_DMA_Send(uint8_t Buffer[],uint16_t len)
{
    //发送完成标志检测
    if(USART1_DMA_TX_Finish)
    {
        //发送状态
        USART1_DMA_TX_Finish = 0;
        //使能DMA将缓冲区数据给串口DR
        DMA_Cmd(DMA1_Channel4, DISABLE);             //关闭DMA_CHx所指示的通道   
        DMA1_Channel4 -> CMAR = (u32)Buffer;         //设置源地址内存地址切换发给外面的BUFF    
        DMA_SetCurrDataCounter(DMA1_Channel4,len);   //DMA通道的DMA缓存的大小
        DMA_Cmd(DMA1_Channel4, ENABLE);   
    }
}




h文件如下:

#ifndef _USART1_H_
#define _USART1_H_

#include "stm32f10x.h"
#include "stdio.h"


#define  USART1_REC_LEN  256


void USART1_Init(uint32_t baud);
void Usart1_DMA_Send(uint8_t Buffer[],uint16_t len);


#endif

4、测试结果

 上电:

发送测试:

代码实测完毕,可直接使用。

标签:STM32F103,DMA,USART,NVIC,InitStructure,GPIO,USART1
From: https://blog.csdn.net/qq_44597640/article/details/141829375

相关文章

  • 八、2 DMA数据转运 DMA函数介绍
    把数组定义在Flash中,可以节省SRAM的空间去掉const不会影响程序运行,但会占用SRAM的空间1、步骤(1)RCC开启DMAD的时钟(2)调用DMA_Init,初始化参数(3)调用DMA_Cmd,通道使能若使用硬件触发,要调用×××_DMACmd开启对应外设的触发信号的输出;若需要DMA的中断,就调用DMA_ITConfig,开......
  • 【STM32 Blue Pill编程】-UART数据发送与接收(DMA模式)
    UART数据发送与接收(DMA模式)文章目录UART数据发送与接收(DMA模式)1、DMA介绍2、STM32的UART端口3、硬件准备及接线4、UART配置5、代码实现在本文中,我们将展示如何使用STM32BluePillUART通过直接内存访问(DMA)来发送和接收数据。这一过程而无需涉及CPU。......
  • STM32笔记(10)——USART
    USART(UniversalSynchronous/AsynchronousReceiver/Transmitter)通用同步/异步收发器USART是STM32内部集成的硬件外设,可根据数据寄存器的一个字节数据自动生成数据帧时序,从TX引脚发送出去,也可自动接收RX引脚的数据帧时序,拼接为一个字节数据,存放在数据寄存器里自带波特率发生......
  • 手把手在STM32F103C8T6上构建可扩展可移植的DHT11驱动
    前言如何驱动一个你陌生的传感器呢?别看我,也别在网上死马当活马医!你需要做的,首先是明确你的传感器的名称,在这里,我们想要使用的是DHT11温湿度传感器可能需要的前置知识简单的OLED驱动原理简单的IIC通信知识基础的查手册能力相对稳固的C语言基础不会没关系,我会详细......
  • 关于关于STM32F103芯片RTC模块的一些注意事项
    1、首先是晶振的问题,只有外部低速晶振LSE支持VBAT供电时持续运行,LSI或者HSE均不行,所以若要求设备断电后,RTC时钟可以继续运行,一定要使用LSE晶振。2、关于LSE晶振的干扰问题,本次调试设备的过程中发现,LSE虽然正常起振,RTC也正常走时,但刚开机的时候会走的比较慢,之后逐渐稳定,通过抓取LS......
  • 探索未来家居,3DMAX室内设计实战精英班
    ✨【空间魔术师,等你来变身!】✨你是否渴望用设计改变世界,让冰冷的房间焕发生机?3DMAX室内设计实战研修班,是你通往梦想设计殿堂的钥匙。......
  • STM32F4 timer定时器触发ADC采集,DMA转运数据 (标准库)
    硬件平台:STM32F401RCT6项目需求:需要实现100hzADC采集用于FFT频谱分析,同时要支持切换采集通道,每次采集之前改变数据存储地址与buff长度直接说配置过程的重点在DMA和ADC初始化之后,要处于disable状态,每次采集之前enable。如果一开始处于enable状态,没有采集,执行了disable再enabl......
  • 基于stm32f103c8t6的智能蓝牙遥控小车(有代码)
    智能小车对于初学者而言还是有点挑战性的,由于本人一直以来都在专注于学业绩点,很少有时间来学习stm32,但这学期开始课慢慢的变少,所以又开始学习32顺便做一些小项目,本文将以stm32为核心制作蓝牙遥控小车。之后我也会继续发一些其他的小项目资料和经验总结。所需材料:12v的电源3......
  • STM32学习记录-08-USART串口
    1通信接口        通信的目的:将一个设备的数据传送到另一个设备,扩展硬件系统        通信协议:制定通信的规则,通信双方按照协议规则进行数据收发                USART:TX数据发送、RX数据接收        I2C:SCL时钟、SDA数据  ......
  • stm32f103c8t6 程序编译后的 Program Size: Code=xxx RO-data=xxx RW-data=xxx ZI-dat
            之前在裸机跑一些简单的项目内存完全够用,就不会涉及到内存方面的问题。最近在学FreeRTOS时,将大容量的stm32f103rct6代码移植到小容量的stm32f103c8t6上时,就遇到了内存不足的问题,所以才注意到这些东西。    那么在我们编译后看到的这些东西到底......