STM32 串口采用DMA方式收发_if(buffer) memcpy((1)

收集整理了一份《2024年最新物联网嵌入式全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升的朋友。
img
img

如果你需要这些资料,可以戳这里获取

需要这些体系化资料的朋友,可以加我V获取:vip1024c (备注嵌入式)

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人

都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

DMA1: 
这里写图片描述

DMA2: 
这里写图片描述

2、DMA配置 
1)数据传输的目的地和来源 
这里写图片描述 
对应我的例子,就是送快递还是取快递。

2)定义DMA通道的DMA缓存的大小 
ps: 即货柜大小,能存多少个快件

3)外设地址寄存器递增与否 
这里写图片描述

4)内存地址寄存器递增与否 
这里写图片描述

5)设定了外设数据宽度 
这里写图片描述

6)设定了内存数据宽度 
这里写图片描述

7)设置了DMA的工作模式 
这里写图片描述

8)DMA通道的软件优先级 
这里写图片描述

9)使能或关闭DMA通道的内存到内存传输 
这里写图片描述

三、 编程 
串口用DMA方式发送和接收,分以下几步: 
1)串口初始化 
2)DMA初始化 
3)发送数据 
4)接收数据

我们按部就班: 
1) 串口初始化 — 使用串口一

#define  DMASIZE 1024

// 配置串口一的发送和接收的GPIO口功能,以及中断
static void _uart1_gpio_init(void)
{
  NVIC_InitTypeDef NVIC_InitStructure;
  GPIO_InitTypeDef GPIO_InitStructure;

  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA   |
                     RCC_APB2Periph_USART1  |
                         RCC_APB2Periph_AFIO, ENABLE) ;

  GPIOA->CRH&=0XFFFFF00F; 
  GPIOA->CRH|=0X000008B0;//IO状态设置 10pin_上拉输入  9pin_推挽输出

  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    /* Configure USART1 Rx as input floating */
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
  GPIO_Init(GPIOA, &GPIO_InitStructure);

  /* Configure USART1 Tx as alternate function push-pull */
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
  GPIO_Init(GPIOA, &GPIO_InitStructure);


  /* Enable the USART1 Interrupt */
  NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQChannel;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStructure);

  USART_ClearFlag(USART1, USART_FLAG_TC); /* 清发送外城标志,Transmission Complete flag */

  USART_ITConfig(USART1, USART_IT_IDLE, ENABLE);// 采用空闲中断,目的是在产生空闲中断时,说明接收或者发送已经结束,此时可以读取DMA中的数据了。
  //USART_ITConfig(USART1, USART_IT_TC, ENABLE);
  //USART_ITConfig(USART1, USART_IT_FE, ENABLE);
}
// 设置对应串口的波特率
static void _uart_setbaudrate(USART_TypeDef* USARTx,u32 value)
{
  USART_InitTypeDef USART_InitStructure;
  USART_InitStructure.USART_BaudRate =value;
  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(USARTx, &USART_InitStructure);
  USART_Cmd(USARTx, ENABLE);
}

2)初始化DMA

u8 sendbuf[1024];
u8 receivebuf[1024];
static void _uart1_dma_configuration()
{
  DMA_InitTypeDef DMA_InitStructure;

  /* DMA1 Channel6 (triggered by USART1 Rx event) Config */
  RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1 ,
                        ENABLE);

  /* DMA1 Channel5 (triggered by USART1 Rx event) Config */
  DMA_DeInit(DMA1_Channel5);
  DMA_InitStructure.DMA_PeripheralBaseAddr = USART1_DR_Base;// 初始化外设地址,相当于“哪家快递”  
  DMA_InitStructure.DMA_MemoryBaseAddr =(u32)receivebuf;// 内存地址,相当于几号柜
  DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;//外设作为数据来源,即为收快递
  DMA_InitStructure.DMA_BufferSize = DMASIZE ;// 缓存容量,即柜子大小
  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, ENABLE);// 启动DMA,即与快递公司签订合同,正式生效

  /* DMA1 Channel4 (triggered by USART1 Tx event) Config */
  DMA_DeInit(DMA1_Channel4);
  DMA_InitStructure.DMA_PeripheralBaseAddr = USART1_DR_Base;  // 外设地址,串口1, 即发件的快递
  DMA_InitStructure.DMA_MemoryBaseAddr =(u32)sendbuf;// 发送内存地址
  DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;// 外设为传送数据目的地,即发送数据,即快递是发件
  DMA_InitStructure.DMA_BufferSize = 0;  //发送长度为0,即未有快递需要发送
  DMA_Init(DMA1_Channel4, &DMA_InitStructure);//初始化

  USART_ITConfig(USART1, USART_IT_TC, ENABLE);// 使能串口发送完成中断
  USART_DMACmd(USART1, USART_DMAReq_Tx|USART_DMAReq_Rx, ENABLE);// 使能DMA串口发送和接受请求
}

3、数据发送 
流程:串口发送数据,全部数据发送完毕后,会产生一个发送中断,所以 
发送数据分为两部分, 
A、发送数据 
B、中断处理

A、发送数据
u16 Uart_Send_Data(void* buffer, u16 size)
{
  if(!size) return 0;// 判断长度是否有效
  while (DMA_GetCurrDataCounter(DMA1_Channel4));// 检查DMA发送通道内是否还有数据
  if(buffer) memcpy(sendbuf, buffer,(size > 1024?1024:size));
  //DMA发送数据-要先关 设置发送长度 开启DMA
  DMA_Cmd(DMA1_Channel4, DISABLE);
  DMA1_Channel4->CNDTR = size;// 设置发送长度
  DMA_Cmd(DMA1_Channel4, ENABLE);  // 启动DMA发送
  return size;
}

B、中断处理
1)中断处理相关准备工作
typedef enum _UartEvent_
{
   E_uart_0 = 0,// 没有事件
   E_uart_tc=0x40,                  //发送完成
   E_uart_idle=0x80,               //接收完成
}UartEvent;
u16 receivelen = 0;// 声明接收数据长度
UartEvent event;//申明一个事件参数

//清除DMA 缓存,并终止DMA
void Uart_Dma_Clr(void)
{
    DMA_Cmd(DMA1_Channel4, DISABLE);
    DMA1_Channel4->CNDTR=0;
    DMA_Cmd(DMA1_Channel5, DISABLE);
    DMA1_Channel5->CNDTR=DMASIZE ;
    DMA_Cmd(DMA1_Channel5, ENABLE);
}
// 获取一个事件,事件分为发送完成事件和接收完成事件,可以根据事件进行进行处理
UartEvent Uart_Get_Event(void)
{
  UartEvent e;
  if(!DMA1_Channel5->CNDTR) Uart_Dma_Clr();// 如果产生一个事件后,接收数据通道已经没有了缓存空间,进行清除DMA清空
  return event;
}
// 清除对应的事件
void Uart_Clr_Event(UartEvent event_in)
{
    event&=~event_in;
}


2) 中断处理,当所有数据发送完毕,串口1产生一个发送完成中断
void Uatr1_Back_IRQHandler()
{


**收集整理了一份《2024年最新物联网嵌入式全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升的朋友。**
![img](https://img-blog.csdnimg.cn/img_convert/8848a4fbc7905bc26509e9017dcc823a.png)
![img](https://img-blog.csdnimg.cn/img_convert/890787fb57b0a9e8c713207235e61bde.png)

**[如果你需要这些资料,可以戳这里获取](https://bbs.csdn.net/topics/618679757)**

**需要这些体系化资料的朋友,可以加我V获取:vip1024c (备注嵌入式)**

**一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人**

**都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**

GB6N-1715907238865)]

**[如果你需要这些资料,可以戳这里获取](https://bbs.csdn.net/topics/618679757)**

**需要这些体系化资料的朋友,可以加我V获取:vip1024c (备注嵌入式)**

**一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人**

**都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**

  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值