STM32 DMA 串口透传

发布者:黑白之间最新更新时间:2016-06-13 来源: eefocus关键字:STM32  DMA  串口透传 手机看文章 扫描二维码
随时随地手机看文章
一直没有好好的捣鼓过DMA,在调BLE项目的时候,遇到了DMA串口传输的问题,伤心流涕甚长时间!!! 

DMA 网上的解释一大堆,简单总结一下:

 

DMA 处理过程全部是由硬件来实现的,速度很快!

DMA 在专门的DMA控制下,实现高速外设与主存储期之间自动成批量的数据交换。

通常有两种交换方式:1 独占总线方式  2 周期挪用方式

 

 

DMA 传送过程

  DMA 预处理

  DMA 数据传送

  DMA 结束处理 将总线控制权交换给CPU

 

 

DMA 内部寄存器

  地址寄存器 : 存放DMA传输是储存单元地址

  字节寄存器 : 存放DMA 传输字节数

  控制寄存器 : 存放CPU  设定的DMA传输方式

  状态寄存器 : 存放DMAC当前的状态

 

 

DMA 外设地址 : 基地址 + 偏移地址

两种方法设定地址:

#define USART1_DR_Base  0x40013804

#define USART1_DR_Base   (&(USART1->DR))  觉得还是第二种方法比较直接

 

DMA 两种中断触发方式 :

DMA_IT_TC1  传输完成中断  :每次更新发生在计数>= 设定值

DMA_IT_HT1  传输过半中断  :每次更新发生在计数> (设定值 / 2)

DMA_IT_GL1  全局中断      :(实验了几次和过半中断传输情况一致)

 

编程的时候根据DMA请求映像来判断通道号,然后找到目的地址和原地址基本上就算完事儿了。当然得分清是传输是外设和内存,内存和外设,内存和内存三种情况,会有 (DMA_InitTypeDef 结构体).DMA_M2M 进行设置。

 

 

下面是DMA串口收发简单例子,并没有用到FIFO精确收发,有时间再好好写写~

DMA_Configuration()是DMA5通道     串口1接收通道配置函数

DMA_Configuration2()是DMA4通道    串口1发送通道配置函数

 

对于发送 可以每当发送的时候 都执行DMA_Configuration2(),进行发送操作

对于接收 理应采用FIFO,对于接收数组进行处理,这里只是简单的接收,没有进一步处理

 

 

/* Includes ------------------------------------------------------------------*/
#include "stm32f10x.h"
#include "stm32f10x_tim.h" 
#include "stm32f10x_rcc.h"
#include "stm32f10x_map.h"	
#include "stm32f10x_it.h"	  
#include "misc.h" 
#include "bsp_timer.h"

#include "stm32f10x_usart.h"
#include "stm32f10x_dma.h"

#include "stdio.h"

#define SENDBUFF_SIZE   10
vu8 SendBuff[SENDBUFF_SIZE]={0};


vu8 TxBuffer[] = "hello xiao lei !!! ";
vu8 NbrOfDataToTransfer = sizeof(TxBuffer)-1;


GPIO_InitTypeDef GPIO_InitStructure;
#define LED1_ON GPIO_SetBits(GPIOB, GPIO_Pin_5);  
#define LED1_OFF GPIO_ResetBits(GPIOB, GPIO_Pin_5); 

#define LED2_ON GPIO_SetBits(GPIOD, GPIO_Pin_6);  
#define LED2_OFF GPIO_ResetBits(GPIOD, GPIO_Pin_6); 

#define LED3_ON GPIO_SetBits(GPIOD, GPIO_Pin_3);  
#define LED3_OFF GPIO_ResetBits(GPIOD, GPIO_Pin_3);  

void RCC_Configuration(void);
void LED_Config(void);
void Delay(__IO uint32_t nCount);

int fputc(int ch, FILE *f)
{
    USART_SendData(USART1, (u8) ch);

    while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET)
    {
    }

    return ch;
}


/
* 名    称:void LED_Config(void)
* 功    能:LED 控制初始化函数
* 入口参数:无
* 出口参数:无
* 说    明:
* 调用方法:无 
/ 
void LED_Config(void){
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOD , ENABLE);	
	
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;				     //LED1  V6	   //将V6,V7,V8 配置为通用推挽输出  
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;			 //口线翻转速度为50MHz
  GPIO_Init(GPIOB, &GPIO_InitStructure);					 

  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6|GPIO_Pin_3;		 //LED2, LED3	 V7 V8
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
  GPIO_Init(GPIOD, &GPIO_InitStructure);
  GPIO_Init(GPIOD, &GPIO_InitStructure);

  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13; 			      //LCD背光控制
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
  GPIO_Init(GPIOD, &GPIO_InitStructure);
  GPIO_ResetBits(GPIOD, GPIO_Pin_13);			              //LCD背光关闭	

}


void USART1_Configration()
{
   USART_InitTypeDef USART_InitStructure;  
   GPIO_InitTypeDef GPIO_InitStructure;

   RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | 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_IN_FLOATING;
    GPIO_Init(GPIOA, &GPIO_InitStructure);

	 USART_InitStructure.USART_BaudRate = 9600;
    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_Init(USART1, &USART_InitStructure);

	USART_Cmd(USART1, ENABLE);

}


void DMA_Configuration(void)
{
	DMA_InitTypeDef DMA_InitStructure;
	NVIC_InitTypeDef NVIC_InitStructure;
	RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE); //使能DMA传输
	DMA_DeInit(DMA1_Channel5);

    DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)(&(USART1->DR));
    DMA_InitStructure.DMA_MemoryBaseAddr = (u32)SendBuff;
    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;                              //外设作源头//外设是作为数据传输的目的地还是来源
    DMA_InitStructure.DMA_BufferSize = 5;                                           //DMA缓存的大小 单位在下边设定
    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_PeripheralDataSize_Byte;             //内存字节为单位
    DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;                                 //工作在循环缓存模式
    DMA_InitStructure.DMA_Priority = DMA_Priority_High;                             //4优先级之一的(高优先) VeryHigh/High/Medium/Low
    DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;                                    //非内存到内存
    DMA_Init(DMA1_Channel5, &DMA_InitStructure);                                    //根据DMA_InitStruct中指定的参数初始化DMA的通道1寄存器
    DMA_ITConfig(DMA1_Channel5, DMA_IT_HT, ENABLE);                                 //DMA5半传输完成中断
    USART_DMACmd(USART1,USART_DMAReq_Rx,ENABLE);                                    //使能USART1的接收DMA请求
    DMA_Cmd(DMA1_Channel5, ENABLE);          
    DMA_ClearFlag(DMA1_FLAG_TC5); 


     NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); 
     NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel5_IRQn;  
     NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; 
     NVIC_InitStructure.NVIC_IRQChannelSubPriority =  0; 
     NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; 
     NVIC_Init(&NVIC_InitStructure);
}
void DMA_Configuration2(void)
{
	DMA_InitTypeDef DMA_InitStructure;
	NVIC_InitTypeDef NVIC_InitStructure;
	RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE); //使能DMA传输
    DMA_DeInit(DMA1_Channel4);

    DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)(&(USART1->DR));
    DMA_InitStructure.DMA_MemoryBaseAddr = (u32)TxBuffer;
    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST ;                             //外设作源头//外设是作为数据传输的目的地还是来源
    DMA_InitStructure.DMA_BufferSize = NbrOfDataToTransfer;                         //DMA缓存的大小 单位在下边设定
    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_PeripheralDataSize_Byte;             //内存字节为单位
    DMA_InitStructure.DMA_Mode = DMA_Mode_Normal ;                                  //工作在循环缓存模式
    DMA_InitStructure.DMA_Priority = DMA_Priority_High;                             //4优先级之一的(高优先) VeryHigh/High/Medium/Low
    DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;                                    //内存到非内存
    DMA_Init(DMA1_Channel4, &DMA_InitStructure);                                    //根据DMA_InitStruct中指定的参数初始化DMA的通道1寄存器
    DMA_ITConfig(DMA1_Channel4, DMA_IT_TC , ENABLE);                                //DMA4传输完成中断
    
	
	USART_DMACmd(USART1,USART_DMAReq_Tx,ENABLE);                                    //使能USART1的发送DMA请求
    DMA_Cmd(DMA1_Channel4, ENABLE);          
    DMA_ClearFlag(DMA1_FLAG_TC4); 


     NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); 
     NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel4_IRQn;  
     NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2; 
     NVIC_InitStructure.NVIC_IRQChannelSubPriority =  1; 
     NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; 
     NVIC_Init(&NVIC_InitStructure);
}


/
* 名    称:int main(void)
* 功    能:主函数
* 入口参数:无
* 出口参数:无
* 说    明:
* 调用方法:无 
/ 
int main(void)
{
   int i,j;
  RCC_Configuration();   				//系统时钟配置
  //
  
  TIM3_Configuration();
  NVIC_Configuration();			
  LED_Config();	
  USART1_Configration();
  DMA_Configuration();	
  //DMA_Configuration2();
  						//LED控制配置
  // printf("Start DMA transmission!\r\n");
  //LED1_ON ;
 	 for(i=0;i<1000000;i++);
	 // for(j=0;j<20;j++);	
	 DMA_Configuration2();
  while (1)
  {
  	 	
  }
}

/
* 名    称:void RCC_Configuration(void)
* 功    能:系统时钟配置为72MHZ
* 入口参数:无
* 出口参数:无
* 说    明:
* 调用方法:无 
/ 
void RCC_Configuration(void)
{   
  SystemInit();
}
void DMA1_Channel5_IRQHandler(void)
{
 u8 end;
 int i;	  

    printf("Start DMA transmission!\r\n");

/ 全传输完成*/
//   if(DMA_GetITStatus(DMA1_IT_TC5))
//    {  
//  end = DMA_GetCurrDataCounter(DMA1_Channel5);
//  DMA_ClearITPendingBit(DMA1_IT_GL5);///* 清中断源
//  DMA_ClearFlag(DMA1_FLAG_TC5);   
// 
//       printf("AA%dAA:", end);
//       printf("%s\r\n", SendBuff);
//	  for(i=0;i<100000;i++); 
//   }
 //
	 
/ 半传输完成*/
   if(DMA_GetITStatus(DMA1_FLAG_HT5))
    {  
  end = DMA_GetCurrDataCounter(DMA1_Channel5);
  DMA_ClearITPendingBit(DMA1_IT_GL5);///* 清中断源
  DMA_ClearFlag(DMA1_IT_TC5);   
 
       printf("AA%dAA:", end);
       printf("%s\r\n", SendBuff);
	  for(i=0;i<100000;i++); 
   }
//

}
void DMA1_Channel4_IRQHandler(void)
{
	if(DMA_GetITStatus(DMA1_IT_TC4)==SET)
	{
	    DMA_ClearFlag(DMA1_IT_TC4);//TCIE,TE,RE			
		 printf("AAAA!");
	}
}

关键字:STM32  DMA  串口透传 引用地址:STM32 DMA 串口透传

上一篇:Mini2440 NRF24L01无线模块驱动
下一篇:STM32关于USART的问题集锦

推荐阅读最新更新时间:2024-03-16 14:56

STM32 上电后的启动过程
微控制器(单片机)上电后,是如何寻找到并执行main函数的呢?很显然微控制器无法从硬件上定位main函数的入口地址,因为使用C语言作为开发语言后,变量/函数的地址便由编译器在编译时自行分配,这样一来main函数的入口地址在微控制器的内部存储空间中不再是绝对不变的。相信读者都可以回答这个问题,答案也许大同小异,但肯定都有个关键词,叫“启动文件”,用英文单词来描述是“Bootloader”。 无论性能高下,结构简繁,价格贵贱,每一种微控制器(处理器)都必须有启动文件,启动文件的作用便是负责执行微控制器从“复位”到“开始执行main函数”中间这段时间(称为启动过程)所必须进行的工作。最为常见的51,AVR或MSP430等微控制器当然
[单片机]
基于STM32设计的蓝牙健康管理设备
1. 前言 随着移动通信技术的发展,移动互联网日益普及,传统互联网已经在向移动互联网迁移,智能穿戴设备近年来发展的非常迅速,成为一个热点行业,它通过借助传感器,与人体进行信息交互,是一种在新理念下诞生的智能设备,具有广泛的应用领域,并能够根据用户需求不断升级。智能穿戴设备在提高人们生活品质、促进生活方式智能化方面将会起到很重要的作用。 按照主要功能的不同,智能穿戴设备产品可以划分为以下几类:运动健康类、体感交互类、信息资讯类、医疗健康类和综合功能类等,每类设备针对不同的细分市场和消费人群。运动和医疗健康类的设备有运动、体侧腕带及智能手环,主要消费人群为大众消费者;体感控制和综合功能类的设备有智能眼镜等,消费人群以年轻人为主;信
[单片机]
基于<font color='red'>STM32</font>设计的蓝牙健康管理设备
基于STM32的单通道示波器制作成功
终于把基于STM32的示波器做出来啦!本来想用外部高速AD做一个1Mhz采样率的示波器,由于自己没有制作示波器经验,手头上也没现成的IC,于是就先利用STM32内部的12位AD做了一个简易示波器,小练一下示波器的制作,以后有时间再继续做一个实用性较强的便携式示波器吧。 该示波器的硬件配置为:3.7V锂电池供电,显示屏为带触摸的16位3.2寸TFT液晶,主控芯片为STM32F103VC。为了省事,信号触发采用软件触发,幅值、周期、XY轴偏移都是通过触控屏来设置。(由于宿舍没有函数发生器,下面演示图片中的波形是由LM358搭出来的简易信号发生器,波形非常不规则) 下为示波器的实物图(后面那块小小的东西为简陋的波形发生器):
[测试测量]
基于<font color='red'>STM32</font>的单通道示波器制作成功
STM32笔记之八:来跟PC打个招呼,基本串口通讯
a) 目的:在基础实验成功的基础上,对串口的调试方法进行实践。硬件代码顺利完成之后,对日后调试需要用到的printf重定义进行调试,固定在自己的库函数中。 b) 初始化函数定义: void USART_Configuration(void); //定义串口初始化函数 c) 初始化函数调用: void UART_Configuration(void); //串口初始化函数调用 初始化代码: void USART_Configuration(void) //串口初始化函数 { //串口参数初始化
[单片机]
STM32—数组作为被调用函数的入口参数时定义成指针
STM32—数组作为被调用函数的入口参数时,要两个条件, 1:数组首地址 2:数组长度 在被调用函数中,比如把数据保存到数组pbuffer 中,那么在入口参数定义时要定义成指针u8 *pbuffer, 1 而在调用时,比如要保存到tab 中,要在入口参数处强制转换成(u8 *)tab,
[单片机]
<font color='red'>STM32</font>—数组作为被调用函数的入口参数时定义成指针
STM32之GPIO操作(库函数版)
1.在stm32f10x_gpio.h文件中 首先GPIOD定义: #define IS_GPIO_ALL_PERIPH(PERIPH) (((PERIPH) == GPIOA) || ((PERIPH) == GPIOB) || ((PERIPH) == GPIOC) || ((PERIPH) == GPIOD) || ((PERIPH) == GPIOE) || ((PERIPH) == GPIOF) ||
[单片机]
STM32配置DAC输出固定电压和方波
STM32F103VCT6 自带两个 12 位 DAC , DAC 的转换速度一直没有查到,网上有人说是 1MHZ 的频率,那就是 1us 了。 ADC 的转换时间在 56MHZ 工作频率下为 1us ,在 72MHZ 工作频率下为 1.17us 。如果 AD 和 DA 有对称关系的话,那么很可能跟 ADC 的时间相同。 ( 仅作分析用! ) DAC 于我,有两个用途: 输出波形 和 输出固定电压 。先来说说前者的配置。 第一个参数:触发方式, DAC_InitStructure.DAC_Trigger 。可选的外部触发源一共有八个。六个是定时器触发: TIM2 , TIM4 , TIM5 , TIM6
[单片机]
采用STM32 单片机的太阳能LED街灯解决方案
  随着化石类能源的日益减少,以及温室气体的过度排放导致全球变暖问题越来越受到重视,人们一方面在积极开发各类可再生新能源,另一方面也在倡导节能减排的绿色环保技术。太阳能作为取之不尽、用之不竭的清洁能源,成为众多可再生能源的重要代表;而在照明领域,寿命长、节能、安全、绿色环保、色彩丰富、微型化的LED固态照明也已被公认为世界一种节能环保的重要途径。太阳能-LED街灯同时整合了这两者的优势,利用清洁能源以及高效率的LED实现绿色照明。   本文介绍的太阳能-LED街灯方案,能自动检测环境光以控制路灯的工作状态,最大功率点追踪(MPPT)保证最大太阳能电池板效率,恒电流控制LED,并带有蓄电池状态输出以及用户可设定LED工作时间等功
[电源管理]
采用<font color='red'>STM32</font> 单片机的太阳能LED街灯解决方案
小广播
添点儿料...
无论热点新闻、行业分析、技术干货……
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved