欢迎入群共同学习交流
时间记录:2024/5/23
一、概念介绍
(1)DMA:直接存储器存取(DMA)(Direct Memory Access)也是一个挂载在AHB总线上的外设,用来提供在外设和存储器之间或者存储器和存储器之间的高速数据传输。无须CPU干预,数据可以通过DMA快速地移动,这就节省了CPU的资源来做其他操作。两个DMA控制器有12个通道(DMA1有7个通道,DMA2(只存在于大容量和互联网产品中)有5个通道),每个通道专门用来管理来自于一个或多个外设对存储器访问的请求。还有一个仲裁器来协调各个DMA请求的优先权
(2)STM32F103C8T6单片机通道介绍
二、串口接收数据代码示例
(1)头文件
#ifndef __UART_H__
#define __UART_H__
#include "stm32f10x.h"
/**
* DMA+空闲中断实现UART接收数据
*/
void vUart1Init(int baudrate);
void vUart1Send(u8 *data,int dataLen);
extern void (*vUart1Callback)(u8 *data,int dataLen);
#endif
(2)源文件
#include "uart.h"
#include "string.h"
#define RX_BUF_SIZE 64
static u8 rx_buf[RX_BUF_SIZE];
void (*vUart1Callback)(u8 *data,int dataLen);
void vUart1Init(int baudrate)
{
//1.初始化串口1GPIO口
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_InitStruct);
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_10;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_InitStruct);
//2.初始化串口1
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);
USART_InitTypeDef USART_InitStruct;
USART_InitStruct.USART_BaudRate = baudrate;
USART_InitStruct.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
USART_InitStruct.USART_WordLength = USART_WordLength_8b;
USART_InitStruct.USART_StopBits = USART_StopBits_1;
USART_InitStruct.USART_Parity = USART_Parity_No;
USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_Init(USART1,&USART_InitStruct);
//3.初始化接收DMA通道
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE);
DMA_InitTypeDef DMA_InitStruct;
DMA_InitStruct.DMA_PeripheralBaseAddr = (uint32_t)&(USART1->DR); //外设地址
DMA_InitStruct.DMA_MemoryBaseAddr = (uint32_t)rx_buf; //接收数据的内存地址
DMA_InitStruct.DMA_DIR = DMA_DIR_PeripheralSRC; //DMA方向,外设到内存
DMA_InitStruct.DMA_BufferSize = RX_BUF_SIZE; //缓冲区大小
DMA_InitStruct.DMA_PeripheralInc = DMA_PeripheralInc_Disable; //外设地址不自增
DMA_InitStruct.DMA_MemoryInc = DMA_MemoryInc_Enable; //内存地址自增
DMA_InitStruct.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; // 移动数据的大小
DMA_InitStruct.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
DMA_InitStruct.DMA_Mode = DMA_Mode_Circular; //模式,循环模式
DMA_InitStruct.DMA_Priority = DMA_Priority_Medium; //DMA优先级
DMA_InitStruct.DMA_M2M = DMA_M2M_Disable; // 禁用内存到内存
DMA_Init(DMA1_Channel5,&DMA_InitStruct);
//4.初始化NVIC
NVIC_InitTypeDef NVIC_InitStruct;
NVIC_InitStruct.NVIC_IRQChannel = USART1_IRQn;
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStruct.NVIC_IRQChannelSubPriority = 3;
NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStruct);
//5.使能串口、空闲中断、DMA接收
USART_Cmd(USART1,ENABLE);
USART_ITConfig(USART1,USART_IT_IDLE,ENABLE);
USART_DMACmd(USART1,USART_DMAReq_Rx,ENABLE);
DMA_Cmd(DMA1_Channel5,ENABLE);
}
void vUart1Send(u8 *data,int dataLen)
{
for(int i=0;i<dataLen;i++)
{
while(USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET);
USART_SendData(USART1,data[i]);
while(USART_GetFlagStatus(USART1,USART_FLAG_TC)==RESET);
}
}
//中断服务函数
void USART1_IRQHandler(void)
{
if(USART_GetITStatus(USART1,USART_IT_IDLE)!=RESET)
{
USART_ClearITPendingBit(USART1,USART_IT_IDLE);
u8 temp = (u8)USART_ReceiveData(USART1);
//处理接收数据
DMA_Cmd(DMA1_Channel5,DISABLE);
int recvLen = RX_BUF_SIZE - DMA_GetCurrDataCounter(DMA1_Channel5);
vUart1Callback(rx_buf,recvLen);
memset(rx_buf,0,sizeof(rx_buf));
DMA_SetCurrDataCounter(DMA1_Channel5,RX_BUF_SIZE);
DMA_Cmd(DMA1_Channel5,ENABLE);
}
}