收集整理了一份《2024年最新物联网嵌入式全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升的朋友。
需要这些体系化资料的朋友,可以加我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行业感兴趣的新人**
**都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**