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

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

本实例使用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、测试结果

 上电:

发送测试:

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值