18:(标准库)DMA二:DMA+串口收发数据
DMA+串口收发数据
- 1、DMA+串口发送数据
- 2、DMA中断+串口接收定长数据包
- 3、串口空闲中断+DMA接收不定长数据包
- 4、串口空闲中断+DMA接收不定长数据包+DMA发送数据包
1、DMA+串口发送数据
当串口的波特率大于115200时,可以通过DMA1进行数据搬运,以防止数据的丢失。如上图所示:UART1的Tx发送请求使用DMA1的通道4,UART1的Rx接收数据请求使用DMA1的通道5。
①串口发送时:当UART1的发送数据寄存器TDR中没有数据时,就会向DMA1的通道4申请数据搬运,DMA1将缓冲区的数据搬运到TDR数据寄存器中,然后串口将数据发送出去。
②串口接收时:当UART1的接收数据寄存器RDR中有数据时,就会向DMA1的通道5申请数据搬运,DMA1将数据从RDR寄存器中搬运到缓冲区中。
【注意】数据的搬运和数据的发送的过程都不需要CPU参与,CPU只参与串口UART1和DMA1通道1的配置。
①UART.c文件的代码如下:
#include "UART.h"uint8_t Buff[Buffer_Size];//定义数据缓冲区
/*** 串口1的初始化函数*/
void UART1_Init(void)
{/* 开启串口的UART1的时钟 */RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);/* 开启串口的GPIO的时钟 */RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);/* 配置串口1的引脚 */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_Init(GPIOA, &GPIO_InitStruct);/* 配置串口1的模式 */USART_InitTypeDef USART_InitStruct;USART_InitStruct.USART_BaudRate = 115200;USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None;// 不使用硬件流控制USART_InitStruct.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;// 收发模式USART_InitStruct.USART_Parity = USART_Parity_No;// 无奇偶校验位USART_InitStruct.USART_StopBits = USART_StopBits_1;// 1个停止位USART_InitStruct.USART_WordLength = USART_WordLength_8b;// 8个数据位USART_Init(USART1, &USART_InitStruct);/* 使能串口DMA发送请求 */USART_DMACmd(USART1, USART_DMAReq_Tx, ENABLE);/* 使能串口1 */USART_Cmd(USART1, ENABLE);
}
②UART.h文件的代码如下:
#ifndef __UART_H
#define __UART_H
#include "stm32f10x.h"
#include "stdio.h"#define Buffer_Size 256
extern uint8_t Buff[Buffer_Size];//定义数据缓冲区void UART1_Init(void);#endif
③MyDMA.c文件的代码如下:
#include "MyDMA.h"
#include "UART.h"
/*** DMA1的通道4的初始化 */
void DMA1_Init(void)
{/* 1、使能DMA1的时钟 */RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);/* 2、配置DMA1的通道1 */DMA_InitTypeDef DMA_InitStruct;DMA_InitStruct.DMA_PeripheralBaseAddr = (uint32_t)&(USART1->DR); //“外设站点”的起始地址DMA_InitStruct.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;//数据宽度,8位DMA_InitStruct.DMA_PeripheralInc = DMA_PeripheralInc_Disable; //外设站点地址是否自增,这里选择不自增,因为搬运到数据寄存器TDR中DMA_InitStruct.DMA_MemoryBaseAddr = (uint32_t)Buff; //“内存站点”起始地址DMA_InitStruct.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; //数据宽度,8位DMA_InitStruct.DMA_MemoryInc = DMA_MemoryInc_Enable; //目的站点地址是否自增,自增DMA_InitStruct.DMA_DIR = DMA_DIR_PeripheralDST; //搬运方向的选择(目的地选择),这里选择内存站点--->外设站点:DMA_DIR_PeripheralDSTDMA_InitStruct.DMA_BufferSize = 0; //传输计数器的大小,代表搬运数据的个数,先置为0DMA_InitStruct.DMA_Mode = DMA_Mode_Normal; //是否自动重装,这里选择不自动重装DMA_InitStruct.DMA_M2M = DMA_M2M_Disable; //是否软件触发,这里选择不是,由硬件触发DMA_InitStruct.DMA_Priority = DMA_Priority_Medium; //优先级,这里选择中等DMA_Init(DMA1_Channel4,&DMA_InitStruct); //配置DMA1的通道4// DMA_Cmd(DMA1_Channel4,ENABLE); //使能DMA1的通道4DMA_Cmd(DMA1_Channel4,DISABLE); //先失能DMA1的通道4
}/*** DMA1开启搬运函数*/
void UART1_DMA1_Transport(uint16_t DataNumber)
{/* 1、失能DMA1 */DMA_Cmd(DMA1_Channel4,DISABLE); /* 2、先设置传输计数器的计数值 */DMA_SetCurrDataCounter(DMA1_Channel4, DataNumber);/* 3、使能DMA1 */DMA_Cmd(DMA1_Channel4,ENABLE); /* 4、等待搬运完成 */while(!DMA_GetFlagStatus(DMA1_FLAG_TC4)); //等待DMA1通道4全部搬运完成DMA_ClearFlag(DMA1_FLAG_TC4); //手动清除标志位
}
④MyDMA.h文件的代码如下:
#ifndef __MyDMA_H
#define __MyDMA_H
#include "stm32f10x.h"void DMA1_Init(void);
void UART1_DMA1_Transport(uint16_t DataNumber);#endif
⑤主函数main.c文件的代码如下:
#include "stm32f10x.h"
#include "Delay.h"
#include "UART.h"
#include "MyDMA.h"#define DataNumber 10 //定义需要发送的数据个数int main(void)
{for(uint8_t i = 0; i<DataNumber; i++)//先向缓冲区里面填入数据{Buff[i] = i;}UART1_Init();DMA1_Init();UART1_DMA1_Transport(DataNumber); //开始搬运数据 while(1){ }
}
2、DMA中断+串口接收定长数据包
①UART.c文件的代码如下:
#include "UART.h"uint8_t Buff[Buffer_Size]; //定义数据缓冲区
uint16_t Length = 10; //定义定长数据包长度
uint8_t Flag = 0; //传输完成标志位
/*** 串口1的初始化函数*/
void UART1_Init(void)
{/* 开启串口的UART1的时钟 */RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);/* 开启串口的GPIO的时钟 */RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);/* 配置串口1的引脚 */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_Init(GPIOA, &GPIO_InitStruct);/* 配置串口1的模式 */USART_InitTypeDef USART_InitStruct;USART_InitStruct.USART_BaudRate = 115200;USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None;// 不使用硬件流控制USART_InitStruct.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; // 收发模式USART_InitStruct.USART_Parity = USART_Parity_No; // 无奇偶校验位USART_InitStruct.USART_StopBits = USART_StopBits_1; // 1个停止位USART_InitStruct.USART_WordLength = USART_WordLength_8b; // 8个数据位USART_Init(USART1, &USART_InitStruct);/* 使能串口DMARx接收请求 */USART_DMACmd(USART1, USART_DMAReq_Rx, ENABLE);/* 使能串口1 */USART_Cmd(USART1, ENABLE);
}/*** 串口发送多个字节的数据*/
void USART_SendArray(uint8_t *array, uint16_t len)
{/* 发送一组数据 */for (uint16_t i = 0; i < len; i++){USART_SendChar(array[i]);}
}
②UART.h文件的代码如下:
#ifndef __UART_H
#define __UART_H
#include "stm32f10x.h"
#include "stdio.h"#define Buffer_Size 256
extern uint8_t Buff[Buffer_Size];//定义数据缓冲区
extern uint16_t Length;
extern uint8_t Flag;void UART1_Init(void);
void USART_SendArray(uint8_t *array, uint16_t len);#endif
③MyDMA.c文件的代码如下:
#include "MyDMA.h"
#include "UART.h"
/*** DMA1通道5的初始化*/void DMA1_Init(void)
{/* 1、使能DMA1的时钟 */RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);/* 2、配置DMA1的通道1 */DMA_InitTypeDef DMA_InitStruct;DMA_InitStruct.DMA_PeripheralBaseAddr = (uint32_t)&(USART1->DR); //外设站点的起始地址DMA_InitStruct.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;//数据宽度,8位DMA_InitStruct.DMA_PeripheralInc = DMA_PeripheralInc_Disable; //外设站点地址是否自增,这里选择不自增,因为搬运到数据寄存器TDR中DMA_InitStruct.DMA_MemoryBaseAddr = (uint32_t)Buff; //内存站点起始地址DMA_InitStruct.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; //数据宽度,8位DMA_InitStruct.DMA_MemoryInc = DMA_MemoryInc_Enable; //目的站点地址是否自增,自增DMA_InitStruct.DMA_DIR = DMA_DIR_PeripheralSRC; //搬运方向的选择(目的地选择),这里选择外设站点--->内存站点:DMA_DIR_PeripheralSRCDMA_InitStruct.DMA_BufferSize = Length; //传输计数器的大小,代表搬运数据的个数DMA_InitStruct.DMA_Mode = DMA_Mode_Circular; //是否自动重装,这里选择自动重装DMA_InitStruct.DMA_M2M = DMA_M2M_Disable; //是否软件触发,这里选择不是,由硬件触发DMA_InitStruct.DMA_Priority = DMA_Priority_Medium; //优先级,这里选择中等DMA_Init(DMA1_Channel5,&DMA_InitStruct); //配置DMA1的通道5/* 3、使能DMA1通道5搬运完成中断和NVIC */DMA_ITConfig(DMA1_Channel5, DMA_IT_TC, ENABLE);NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);NVIC_InitTypeDef NVIC_InitStruct;NVIC_InitStruct.NVIC_IRQChannel = DMA1_Channel5_IRQn;NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0;NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0;NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;NVIC_Init(&NVIC_InitStruct);DMA_Cmd(DMA1_Channel5,ENABLE); //使能DMA1的通道5
}/*** DMA1开启搬运函数*/
//void UART1_DMA1_Transport(uint16_t DataNumber)
//{
// /* 1、失能DMA1 */
// DMA_Cmd(DMA1_Channel4,DISABLE);
//
// /* 2、先设置传输计数器的计数值 */
// DMA_SetCurrDataCounter(DMA1_Channel4, DataNumber);
//
// /* 3、使能DMA1 */
// DMA_Cmd(DMA1_Channel4,ENABLE);
//
// /* 4、等待搬运完成 */
// while(!DMA_GetFlagStatus(DMA1_FLAG_TC4)); //等待通道4搬运完成
// DMA_ClearFlag(DMA1_FLAG_TC4); //手动清除标志位
//}/*** DMA1通道5传输完成的中断服务函数*/
void DMA1_Channel5_IRQHandler(void)
{if(DMA_GetFlagStatus(DMA1_FLAG_TC5)){DMA_ClearFlag(DMA1_FLAG_TC5); //清除通道5的标志位Flag = 1;}
}
④主函数main.c文件的代码如下:
#include "stm32f10x.h"
#include "Delay.h"
#include "UART.h"
#include "MyDMA.h"int main(void)
{UART1_Init();DMA1_Init();while(1){ if(Flag){ Flag = 0;USART_SendArray(Buff, Length); } }
}
3、串口空闲中断+DMA接收不定长数据包
①UART.c文件的代码如下:
#include "UART.h"uint8_t Buff[Buffer_Size]; //定义数据缓冲区
uint8_t Flag = 0; //传输完成标志位
uint16_t Index = 0; //定义接收到的数据个数
/*** 串口1的初始化函数*/
void UART1_Init(void)
{/* 开启串口的UART1的时钟 */RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);/* 开启串口的GPIO的时钟 */RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);/* 配置串口1的引脚 */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_Init(GPIOA, &GPIO_InitStruct);/* 配置串口1的模式 */USART_InitTypeDef USART_InitStruct;USART_InitStruct.USART_BaudRate = 115200;USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None;// 不使用硬件流控制USART_InitStruct.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; // 收发模式USART_InitStruct.USART_Parity = USART_Parity_No; // 无奇偶校验位USART_InitStruct.USART_StopBits = USART_StopBits_1; // 1个停止位USART_InitStruct.USART_WordLength = USART_WordLength_8b; // 8个数据位USART_Init(USART1, &USART_InitStruct);/* 使能串口DMARx接收请求 */USART_DMACmd(USART1, USART_DMAReq_Rx, ENABLE);/* 使能串口IDLE空闲中断和NVIC */USART_ITConfig(USART1, USART_IT_IDLE, ENABLE);NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);NVIC_InitTypeDef NVIC_InitStruct;NVIC_InitStruct.NVIC_IRQChannel = USART1_IRQn;NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0;NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0;NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;NVIC_Init(&NVIC_InitStruct);/* 使能串口1 */USART_Cmd(USART1, ENABLE);
}/*** 串口发送一个字节的数据*/
void USART_SendChar(uint8_t ch)
{/* 发送一个字节的数据 */USART_SendData(USART1, ch);/* 等待发送数据寄存器为空 */while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
}/*** 串口发送一个字符串的数据*/
void USART_SendString(uint8_t *str)
{/* 发送多个字节的数据 */while (*str!= '\0'){USART_SendChar(*str++);}
}/*** 串口发送多个字节的数据*/
void USART_SendArray(uint8_t *array, uint16_t len)
{/* 发送一组数据 */for (uint16_t i = 0; i < len; i++){USART_SendChar(array[i]);}
}/*** 对printf函数进行重定向*/
int fputc(int ch, FILE *f)
{/* 等待发送数据寄存器为空 */while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);/* 发送一个字节的数据 */USART_SendData(USART1, (uint8_t)ch);return ch;
}/*** 串口1的空闲中断服务函数*/
void USART1_IRQHandler(void)
{uint8_t Receive_Data;if(USART_GetFlagStatus(USART1, USART_FLAG_IDLE)){ Receive_Data = USART1->SR;Receive_Data = USART1->DR; //清除中断标志位IDLE// Index = Buffer_Size - DMA_GetCurrDataCounter(DMA1_Channel5);//获取接收到的数据个数Index = Buffer_Size -(DMA1_Channel5->CNDTR); //获取接收到的数据个数Flag = 1;/* 重新给DMA传输计数器设置值:让第二个数据包从缓冲区第一位开始存储 */DMA_Cmd(DMA1_Channel5,DISABLE); DMA_SetCurrDataCounter(DMA1_Channel5, Buffer_Size); DMA_Cmd(DMA1_Channel5,ENABLE); //使能DMA1的通道5}
}
②UART.h文件的代码如下:
#ifndef __UART_H
#define __UART_H
#include "stm32f10x.h"
#include "stdio.h"#define Buffer_Size 256
extern uint8_t Buff[Buffer_Size];//定义数据缓冲区
extern uint8_t Flag;
extern uint16_t Index;void UART1_Init(void);
void USART_SendChar(uint8_t ch);
void USART_SendString(uint8_t *str);
void USART_SendArray(uint8_t *array, uint16_t len);#endif
③MyDMA.c文件的代码如下:
#include "MyDMA.h"
#include "UART.h"
/*** DMA1通道5的初始化*/void DMA1_Init(void)
{/* 1、使能DMA1的时钟 */RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);/* 2、配置DMA1的通道1 */DMA_InitTypeDef DMA_InitStruct;DMA_InitStruct.DMA_PeripheralBaseAddr = (uint32_t)&(USART1->DR); //外设站点的起始地址DMA_InitStruct.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;//数据宽度,8位DMA_InitStruct.DMA_PeripheralInc = DMA_PeripheralInc_Disable; //外设站点地址是否自增,这里选择不自增,因为搬运到数据寄存器TDR中DMA_InitStruct.DMA_MemoryBaseAddr = (uint32_t)Buff; //内存站点起始地址DMA_InitStruct.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; //数据宽度,8位DMA_InitStruct.DMA_MemoryInc = DMA_MemoryInc_Enable; //目的站点地址是否自增,自增DMA_InitStruct.DMA_DIR = DMA_DIR_PeripheralSRC; //搬运方向的选择(目的地选择),这里选择外设站点--->内存站点:DMA_DIR_PeripheralDSTDMA_InitStruct.DMA_BufferSize = Buffer_Size; //传输计数器的大小,代表搬运数据的个数DMA_InitStruct.DMA_Mode = DMA_Mode_Normal; //是否自动重装,这里选择不自动重装,接收一个数据包,在空闲中断里面重装DMA_InitStruct.DMA_M2M = DMA_M2M_Disable; //是否软件触发,这里选择不是,由硬件触发DMA_InitStruct.DMA_Priority = DMA_Priority_Medium; //优先级,这里选择中等DMA_Init(DMA1_Channel5,&DMA_InitStruct); //配置DMA1的通道5DMA_Cmd(DMA1_Channel5,ENABLE); //使能DMA1的通道5
}
④主函数main.c文件的代码如下:
#include "stm32f10x.h"
#include "Delay.h"
#include "UART.h"
#include "MyDMA.h"int main(void)
{UART1_Init();DMA1_Init();while(1){ if(Flag){ Flag = 0;USART_SendArray(Buff, Index); } }
}
4、串口空闲中断+DMA接收不定长数据包+DMA发送数据包
①MyDMA.c文件的代码如下:
#include "MyDMA.h"
#include "UART.h"
/*** DMA1通道5的初始化*/
void DMA1_Init(void)
{/* 1、使能DMA1的时钟 */RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);/* 2、配置DMA1的通道5,接收数据 */DMA_InitTypeDef DMA_InitStruct;DMA_InitStruct.DMA_PeripheralBaseAddr = (uint32_t)&(USART1->DR); //外设站点的起始地址DMA_InitStruct.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;//数据宽度,8位DMA_InitStruct.DMA_PeripheralInc = DMA_PeripheralInc_Disable; //外设站点地址是否自增,这里选择不自增,因为搬运到数据寄存器TDR中DMA_InitStruct.DMA_MemoryBaseAddr = (uint32_t)Buff; //内存站点起始地址DMA_InitStruct.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; //数据宽度,8位DMA_InitStruct.DMA_MemoryInc = DMA_MemoryInc_Enable; //目的站点地址是否自增,自增DMA_InitStruct.DMA_DIR = DMA_DIR_PeripheralSRC; //搬运方向的选择(目的地选择),这里选择外设站点--->内存站点:DMA_DIR_PeripheralSRCDMA_InitStruct.DMA_BufferSize = Buffer_Size; //传输计数器的大小,代表搬运数据的个数DMA_InitStruct.DMA_Mode = DMA_Mode_Normal; //是否自动重装,这里选择不自动重装DMA_InitStruct.DMA_M2M = DMA_M2M_Disable; //是否软件触发,这里选择不是,由硬件触发DMA_InitStruct.DMA_Priority = DMA_Priority_Medium; //优先级,这里选择中等DMA_Init(DMA1_Channel5,&DMA_InitStruct); //配置DMA1的通道5DMA_Cmd(DMA1_Channel5,ENABLE); //使能DMA1的通道5/* 2、配置DMA1的通道4,发送数据 */DMA_InitStruct.DMA_PeripheralBaseAddr = (uint32_t)&(USART1->DR); //外设站点的起始地址DMA_InitStruct.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;//数据宽度,8位DMA_InitStruct.DMA_PeripheralInc = DMA_PeripheralInc_Disable; //外设站点地址是否自增,这里选择不自增,因为搬运到数据寄存器TDR中DMA_InitStruct.DMA_MemoryBaseAddr = (uint32_t)Buff; //内存站点起始地址DMA_InitStruct.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; //数据宽度,8位DMA_InitStruct.DMA_MemoryInc = DMA_MemoryInc_Enable; //目的站点地址是否自增,自增DMA_InitStruct.DMA_DIR = DMA_DIR_PeripheralDST; //搬运方向的选择(目的地选择),这里选择内存站点--->外设站点:DMA_DIR_PeripheralDSTDMA_InitStruct.DMA_BufferSize = 0; //传输计数器的大小,代表搬运数据的个数DMA_InitStruct.DMA_Mode = DMA_Mode_Normal; //是否自动重装,这里选择不自动重装DMA_InitStruct.DMA_M2M = DMA_M2M_Disable; //是否软件触发,这里选择不是,由硬件触发DMA_InitStruct.DMA_Priority = DMA_Priority_Low; //优先级,这里选择低DMA_Init(DMA1_Channel4,&DMA_InitStruct); //配置DMA1的通道4DMA_Cmd(DMA1_Channel4,DISABLE); //失能DMA1的通道4
}/*** DMA1通道5的传输计数器重装设置*/
void DMA1_Chanael5_Count(uint16_t DataNumber)
{DMA_Cmd(DMA1_Channel5,DISABLE); DMA_SetCurrDataCounter(DMA1_Channel5, DataNumber); DMA_Cmd(DMA1_Channel5,ENABLE); //使能DMA1的通道5
}/*** DMA1通道4的传输计数器重装设置*/
void DMA1_Chanael4_Count(uint16_t DataNumber)
{DMA_Cmd(DMA1_Channel4,DISABLE); DMA_SetCurrDataCounter(DMA1_Channel4, DataNumber); DMA_Cmd(DMA1_Channel4,ENABLE); //使能DMA1的通道5
}
②MyDMA.h文件的代码如下:
#ifndef __MyDMA_H
#define __MyDMA_H
#include "stm32f10x.h"void DMA1_Init(void);
void DMA1_Chanael5_Count(uint16_t DataNumber);
void DMA1_Chanael4_Count(uint16_t DataNumber);#endif
③UART.c文件的代码如下:
#include "UART.h"
#include "MyDMA.h"uint8_t Buff[Buffer_Size]; //定义数据缓冲区
uint16_t Index = 0; //定义接收到的数据个数
/*** 串口1的初始化函数*/
void UART1_Init(void)
{/* 开启串口的UART1的时钟 */RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);/* 开启串口的GPIO的时钟 */RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);/* 配置串口1的引脚 */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_Init(GPIOA, &GPIO_InitStruct);/* 配置串口1的模式 */USART_InitTypeDef USART_InitStruct;USART_InitStruct.USART_BaudRate = 115200;USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None;// 不使用硬件流控制USART_InitStruct.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; // 收发模式USART_InitStruct.USART_Parity = USART_Parity_No; // 无奇偶校验位USART_InitStruct.USART_StopBits = USART_StopBits_1; // 1个停止位USART_InitStruct.USART_WordLength = USART_WordLength_8b; // 8个数据位USART_Init(USART1, &USART_InitStruct);/* 使能串口DMARx接收DMATx发送和请求 */USART_DMACmd(USART1, USART_DMAReq_Rx, ENABLE);USART_DMACmd(USART1, USART_DMAReq_Tx, ENABLE);/* 使能串口IDLE空闲中断和NVIC */USART_ITConfig(USART1, USART_IT_IDLE, ENABLE);NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);NVIC_InitTypeDef NVIC_InitStruct;NVIC_InitStruct.NVIC_IRQChannel = USART1_IRQn;NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0;NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0;NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;NVIC_Init(&NVIC_InitStruct);/* 使能串口1 */USART_Cmd(USART1, ENABLE);
}/*** 串口发送一个字节的数据*/
void USART_SendChar(uint8_t ch)
{/* 发送一个字节的数据 */USART_SendData(USART1, ch);/* 等待发送数据寄存器为空 */while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
}/*** 串口发送一个字符串的数据*/
void USART_SendString(uint8_t *str)
{/* 发送多个字节的数据 */while (*str!= '\0'){USART_SendChar(*str++);}
}/*** 串口发送多个字节的数据*/
void USART_SendArray(uint8_t *array, uint16_t len)
{/* 发送一组数据 */for (uint16_t i = 0; i < len; i++){USART_SendChar(array[i]);}
}/*** 对printf函数进行重定向*/
int fputc(int ch, FILE *f)
{/* 等待发送数据寄存器为空 */while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);/* 发送一个字节的数据 */USART_SendData(USART1, (uint8_t)ch);return ch;
}/*** 串口1的空闲中断服务函数*/
void USART1_IRQHandler(void)
{uint8_t Receive_Data;if(USART_GetFlagStatus(USART1, USART_FLAG_IDLE)){ Receive_Data = USART1->SR;Receive_Data = USART1->DR; //清除中断标志位IDLE// Index = Buffer_Size - DMA_GetCurrDataCounter(DMA1_Channel5);//获取接收到的数据个数Index = Buffer_Size -(DMA1_Channel5->CNDTR); //获取接收到的数据个数DMA1_Chanael4_Count(Index); //将数据发送出去DMA1_Chanael5_Count(Buffer_Size); //启动第二轮的数据接收搬运}
}
④主函数main.c文件的代码如下:
#include "stm32f10x.h"
#include "Delay.h"
#include "UART.h"
#include "MyDMA.h"int main(void)
{UART1_Init();DMA1_Init();while(1){ }
}
相关文章:

18:(标准库)DMA二:DMA+串口收发数据
DMA串口收发数据 1、DMA串口发送数据2、DMA中断串口接收定长数据包3、串口空闲中断DMA接收不定长数据包4、串口空闲中断DMA接收不定长数据包DMA发送数据包 1、DMA串口发送数据 当串口的波特率大于115200时,可以通过DMA1进行数据搬运,以防止数据的丢失。如…...

【C++】 算术操作符与数据类型溢出详解
博客主页: [小ᶻ☡꙳ᵃⁱᵍᶜ꙳] 本文专栏: C 文章目录 💯前言💯C 算术操作符详解基本算术操作符整数除法与取模行为类型转换在算术运算中的作用自增与自减操作符 💯数值溢出:当值超出类型范围时数据类型的取值范围…...

柔性芯片:实现万物互联的催化剂
物联网 (IoT) 市场已经非常成熟,麦肯锡预测,物联网将再创高峰,到 2030 年将达到 12.5 万亿美元的估值。然而,万物互联 (IoE) 的愿景尚未实现,即由数十亿台智能互联设备组成,提供大规模洞察和效率。 究竟是…...

FFmpeg 简介与编译
1. ffmpeg 简介: FFmpeg是一套可以用来记录、转换数字音频、视频,并能将其转化为流的开源计算机程序。采用LGPL或GPL许可证。它提供了录制、转换以及流化音视频的完整解决方案。它包含了非常先进的音频/视频编解码库libavcodec,为了保证高可移…...

低代码与微服务融合在医疗集团中的补充应用探究
摘要 本论文深入探讨了低代码与微服务融合在医疗系统集群中的应用。分析了其优势,包括提高开发效率、降低技术门槛、灵活适应需求变化和易于维护扩展等;阐述了面临的挑战,如数据安全与隐私保护、技术应用复杂性等;并展望了其在医…...
速盾:高防cdn的搜索引擎回源是什么?
高防CDN(Content Delivery Network)是一种用于加速网站访问速度和增加安全性的服务,它通过将静态和动态内容缓存在全球分布的服务器上,从而将用户请求的响应时间降至最低,并提供有效的防御攻击的能力。在实际使用过程中…...

减少电路和配电系统谐波的五种方法
K 级变压器 ANSI 标准 C57.110-1986 定义了 K 系数来评估电路消耗多少谐波电流并确定该谐波电流的热效应。根据电路 K 系数,变压器按 K 等级制造。值得注意的是,K 级变压器不会减少谐波。K 等级表示变压器承受谐波有害影响的相对能力。K级变压器增加了铁…...

基于Java Springboot Vue3图书管理系统
一、作品包含 源码数据库设计文档万字全套环境和工具资源部署教程 二、项目技术 前端技术:Html、Css、Js、Vue3、Element-ui 数据库:MySQL 后端技术:Java、Spring Boot、MyBatis 三、运行环境 开发工具:IDEA 数据库&#x…...

vue-cli项目质量约束配置
同步发布于我的网站 🚀 package.json scriptslint-stageddevDependencies git-hooksno-eslintdevDependencies - scssdevDependencies - lessengines pre-commit.eslintrc.js.stylelintrc scssless vue.config.jsREADME.md package.json scripts "scripts&…...

第七课 Unity编辑器创建的资源优化_UI篇(UGUI)
上期我们学习了简单的Scene优化,接下来我们继续编辑器创建资源的UGUI优化 UI篇(UGUI) 优化UGUI应从哪些方面入手? 可以从CPU和GPU两方面考虑,CPU方面,避免触发或减少Canvas的Rebuild和Rebatch,…...
【docker】docker build上下文
什么是 Docker Build 上下文? 在 Docker 中,构建上下文(Build Context) 是指在执行 docker build 命令时,Docker 会发送给 Docker 引擎的所有文件和目录的集合。构建上下文包含了 Dockerfile 和用于构建镜像的所有文件…...
ESLint 配置文件全解析:格式、层叠与扩展(3)
配置文件系统处于一个更新期,存在两套配置文件系统,旧的配置文件系统适用于 v9.0.0 之前的版本,而新的配置文件系统适用于 v9.0.0之后的版本,但是目前还处于 v8.x.x 的大版本。 配置文件格式 在 ESLint 中,支持如下格…...

org.apache.commons.lang3包下的StringUtils工具类的使用
前言 相信平时在写项目的时候,一定使用到StringUtils.isEmpty();StringUtils.isBlank();但是你真的了解他们吗? 也许你两个都不知道,也许你除了isEmpty/isNotEmpty/isNotBlank/isBlank外,并不知道还有isAnyEmpty/isNon…...

HarmonyOS4+NEXT星河版入门与项目实战(23)------组件转场动画
文章目录 1、控件图解2、案例实现1、代码实现2、代码解释3、实现效果4、总结1、控件图解 这里我们用一张完整的图来汇整 组件转场动画的用法格式、属性和事件,如下所示: 2、案例实现 这里我们对上一节小鱼游戏进行改造,让小鱼在游戏开始的时候增加一个转场动画,让小鱼自…...

十一、快速入门go语言之接口和反射
文章目录 接口:one: 接口基础:two: 接口类型断言和空接口:star2: 空接口实现存储不同数据类型的切片/数组:star2: 复制切片到空接口切片:star2: 类型断言 反射 📅 2024年5月9日 📦 使用版本为1.21.5 接口 十、Java类的封装和继承、多态 - 七点半的菜市…...

智能化图书馆导航系统方案之系统架构与核心功能设计
hello~这里是维小帮,点击文章最下方获取图书馆导航系统解决方案!如有项目需求和技术交流欢迎大家私聊我们~撒花! 针对传统图书馆在图书查找困难、座位紧张、空间导航不便方面的问题,本文深入剖析了基于高精度定位、3D建模、图书搜…...
学习嵩山版《Java 开发手册》:编程规约 - 命名风格(P13 ~ P14)
概述 《Java 开发手册》是阿里巴巴集团技术团队的集体智慧结晶和经验总结,他旨在提升开发效率和代码质量 《Java 开发手册》是一本极具价值的 Java 开发规范指南,对于提升开发者的综合素质和代码质量具有重要意义 学习《Java 开发手册》是一个提升 Jav…...

Qt关于padding设置不起作用的的解决办法
观察以下的代码: MyWidget::MyWidget(QWidget *parent): QWidget{parent},m_btn(new QToolButton(this)) {this->setFixedSize(500,500);m_btn->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);m_btn->setIcon(QIcon("F:tabIcon/person-white.s…...
Golang教程第10篇(语言循环语句-语言循环嵌套)
Go 语言循环嵌套 Go 语言循环语句Go 语言循环语句 Go 语言允许用户在循环内使用循环。接下来我们将为大家介绍嵌套循环的使用。 语法 以下为 Go 语言嵌套循环的格式: for [condition | ( init; condition; increment ) | Range] {for [condition | ( init; con…...
Python Web 开发:FastAPI 入门实战 —— HTTP 基础与 RESTful API 设计
Python Web 开发:FastAPI 入门实战 —— HTTP 基础与 RESTful API 设计 目录 🚀 HTTP 协议概述🌐 HTTP 请求与响应的工作原理🛠️ RESTful API 设计理念🗂️ JSON 格式数据的传输与解析 1. 🚀 HTTP 协议概…...
利用ngx_stream_return_module构建简易 TCP/UDP 响应网关
一、模块概述 ngx_stream_return_module 提供了一个极简的指令: return <value>;在收到客户端连接后,立即将 <value> 写回并关闭连接。<value> 支持内嵌文本和内置变量(如 $time_iso8601、$remote_addr 等)&a…...

阿里云ACP云计算备考笔记 (5)——弹性伸缩
目录 第一章 概述 第二章 弹性伸缩简介 1、弹性伸缩 2、垂直伸缩 3、优势 4、应用场景 ① 无规律的业务量波动 ② 有规律的业务量波动 ③ 无明显业务量波动 ④ 混合型业务 ⑤ 消息通知 ⑥ 生命周期挂钩 ⑦ 自定义方式 ⑧ 滚的升级 5、使用限制 第三章 主要定义 …...

Swift 协议扩展精进之路:解决 CoreData 托管实体子类的类型不匹配问题(下)
概述 在 Swift 开发语言中,各位秃头小码农们可以充分利用语法本身所带来的便利去劈荆斩棘。我们还可以恣意利用泛型、协议关联类型和协议扩展来进一步简化和优化我们复杂的代码需求。 不过,在涉及到多个子类派生于基类进行多态模拟的场景下,…...

【机器视觉】单目测距——运动结构恢复
ps:图是随便找的,为了凑个封面 前言 在前面对光流法进行进一步改进,希望将2D光流推广至3D场景流时,发现2D转3D过程中存在尺度歧义问题,需要补全摄像头拍摄图像中缺失的深度信息,否则解空间不收敛…...

2021-03-15 iview一些问题
1.iview 在使用tree组件时,发现没有set类的方法,只有get,那么要改变tree值,只能遍历treeData,递归修改treeData的checked,发现无法更改,原因在于check模式下,子元素的勾选状态跟父节…...
镜像里切换为普通用户
如果你登录远程虚拟机默认就是 root 用户,但你不希望用 root 权限运行 ns-3(这是对的,ns3 工具会拒绝 root),你可以按以下方法创建一个 非 root 用户账号 并切换到它运行 ns-3。 一次性解决方案:创建非 roo…...
spring:实例工厂方法获取bean
spring处理使用静态工厂方法获取bean实例,也可以通过实例工厂方法获取bean实例。 实例工厂方法步骤如下: 定义实例工厂类(Java代码),定义实例工厂(xml),定义调用实例工厂ÿ…...

有限自动机到正规文法转换器v1.0
1 项目简介 这是一个功能强大的有限自动机(Finite Automaton, FA)到正规文法(Regular Grammar)转换器,它配备了一个直观且完整的图形用户界面,使用户能够轻松地进行操作和观察。该程序基于编译原理中的经典…...

【7色560页】职场可视化逻辑图高级数据分析PPT模版
7种色调职场工作汇报PPT,橙蓝、黑红、红蓝、蓝橙灰、浅蓝、浅绿、深蓝七种色调模版 【7色560页】职场可视化逻辑图高级数据分析PPT模版:职场可视化逻辑图分析PPT模版https://pan.quark.cn/s/78aeabbd92d1...

关于easyexcel动态下拉选问题处理
前些日子突然碰到一个问题,说是客户的导入文件模版想支持部分导入内容的下拉选,于是我就找了easyexcel官网寻找解决方案,并没有找到合适的方案,没办法只能自己动手并分享出来,针对Java生成Excel下拉菜单时因选项过多导…...