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){ }
}

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/62609.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【Flink-scala】DataStream编程模型之窗口计算-触发器-驱逐器

DataStream API编程模型 1.【Flink-Scala】DataStream编程模型之数据源、数据转换、数据输出 2.【Flink-scala】DataStream编程模型之 窗口的划分-时间概念-窗口计算程序 文章目录 DataStream API编程模型前言1.触发器1.1 代码示例 2.驱逐器2.1 代码示例 总结 前言 本小节我想…

vue3使用monaco编辑器(VSCode网页版)

vue3使用monaco编辑器&#xff08;VSCode网页版&#xff09; 文章说明参考文章核心代码效果展示实践说明源码下载 文章说明 一直在找网页版的编辑器&#xff0c;网页版的VSCode功能很强大&#xff0c;这个monaco就是VSCode样式的编辑器&#xff0c;功能很强大&#xff0c;可以直…

UWB数字钥匙安全测距和场景应用

1. CCC数字钥匙 2021年7月CCC将UWB定义为第三代数字钥匙的核心技术&#xff0c;并发布CCC R3&#xff08;第三代数字钥匙&#xff09;规范。 CCC R3是基于NFC/BLE/UWB作为基础的无线电技术的使用&#xff0c;该系统采用非对称密码技术对车辆和设备进行相互签名认证&#xff0…

SpringBoot小知识(2):日志

日志是开发项目中非常重要的一个环节&#xff0c;它是程序员在检查程序运行的手段之一。 1.日志的基础操作 1.1 日志的作用 编程期调试代码运营期记录信息&#xff1a; * 记录日常运营重要信息(峰值流量、平均响应时长……) * 记录应用报错信息(错误堆栈) * 记录运维过程数据(…

SAP Native SQL 的简单说明

Open SQL访问数据字典中声明的数据库表&#xff0c;不区分数据库类型&#xff0c;执行时会自动转换为对应的语句&#xff0c;且可以使用本地缓存。Native SQL使用特定于数据库的SQL语句,但是可以访问比Open SQL 更多的表&#xff0c;更多的操作&#xff0c;缺点也很明显&#x…

ARP欺骗-监控网络

kali: 使用arp-scan -l 查看同个局域网 windows arp -a 查看地址的物理地址 192.168.21.2 对应的是00-50-56-f5-d5-f0 攻击利用: 我们要让目标ip的流量经过我的网卡,从网关出去 使用的开启 echo 1 > /proc/sys/net/ipv4/ip_forward 当为0时&#xff0c;我们不转发&…

pycharm链接neo4j(导入文件)

1.新建csv文件 2.写入文件 3.运行代码 import csv from py2neo import Graph, Node# 连接到Neo4j数据库&#xff0c;使用Bolt协议 graph Graph("bolt://localhost:7687", auth("neo4j", "password"))# 读取CSV文件 with open(D:\\Users\\ran…

数据结构4——栈和队列

目录 1.栈 1.1.栈的概念及结构 1.2栈的实现 2.队列 2.1队列的概念及结构 2.2队列的实现 1.栈 1.1.栈的概念及结构 栈&#xff1a;一种特殊的线性表&#xff0c;其只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除操作的一段称为栈顶&#xff0c;另一端称为…

SSM搭建(1)——配置MyBatis

目录 一、框架概述 1.什么是JDBC&#xff1f; 2.JDBC基本流程 3.JDBC的缺点 二、MyBatis的入门程序 1. 创建数据库和表结构 2. MyBatis入门流程总结 3. MyBatis的入门步骤 &#xff08;1&#xff09; 创建maven的项目&#xff0c;创建Java工程即可。 &…

Zero to JupyterHub with Kubernetes上篇 - Kubernetes 离线二进制部署

前言&#xff1a; 纯个人记录使用。 搭建 Zero to JupyterHub with Kubernetes 上篇 - Kubernetes 离线二进制部署。搭建 Zero to JupyterHub with Kubernetes 中篇 - Kubernetes 常规使用记录。搭建 Zero to JupyterHub with Kubernetes 下篇 - Jupyterhub on k8s。 k8s二进…

阻塞式队列

目录 一、阻塞队列 阻塞队列的概念 生产者消费者模型 二、自定义实现阻塞队列 一、阻塞队列 阻塞队列的概念 队列我们并不默认&#xff0c;一提起队列&#xff0c;我们立马就能想到 "先进先出"的特性。 今天我们就来学习一下特殊的队列: 阻塞队列&#xff0c;它…

开发一套ERP 第八弹 RUst 插入数据

更全面的报错,方便检查错误在哪里,现代高级语言越来越智能 还是得看下原文档怎么操作的 src 目录为crate 的根目录 想在crate 中模块相互引入需要在 main 中声明,各个模块,然后才能在各个模块中相互引入和使用 原始工程引入,避免直接使用 lib.rs 回合cargo 中的一些 工程管理出…

剖析 SpringBoot 于夕阳红公寓管理系统架构搭建的核心作用

3 系统分析 本文作者在确定了研究的课题之后&#xff0c;从各大数字图书馆下载文献来阅读&#xff0c;并了解同类型的网站具备的大致功能&#xff0c;然后与本系统用户的实际需求结合进行分析&#xff0c;得出本系统要研究的具体功能与性能。虽然分析系统这一阶段性工作主要是确…

30分钟学会正则表达式

正则表达式是对字符串操作的一种逻辑公式&#xff0c;就是用事先定义好的一些特定字符、及这些特定字符的组合&#xff0c;组成一个“规则字符串”&#xff0c;这个“规则字符串”用来表达对字符串的一种过滤逻辑。 作用 匹配 查看一个字符串是否符合正则表达式的语法 搜索 正…

电子应用设计方案-33:智能AI投影仪系统方案设计

智能 AI 投影仪系统方案设计 一、引言 随着科技的不断进步&#xff0c;投影仪在家庭娱乐、商务办公和教育培训等领域的应用越来越广泛。智能 AI 投影仪作为一种创新的投影设备&#xff0c;结合了人工智能技术&#xff0c;为用户带来更便捷、智能和个性化的使用体验。 二、系统…

【微服务】SpringBoot 对接飞书多维表格事件回调监听流程详解

目录 一、前言 二、前置准备 2.1 创建一个应用 2.2 准备一张测试使用的多维表 2.3 获取对接文档 2.4 工程中添加SDK 三、对接过程 3.1 配置Encrypt Key 和 Verification Token 3.2 配置订阅方式 3.3 添加事件 3.4 申请权限 3.5 编写订阅代码 3.6 订阅文档事件 3.7…

【优选算法篇】两队接力跑:双指针协作解题的艺术(下篇)

文章目录 须知 &#x1f4ac; 欢迎讨论&#xff1a;如果你在学习过程中有任何问题或想法&#xff0c;欢迎在评论区留言&#xff0c;我们一起交流学习。你的支持是我继续创作的动力&#xff01; &#x1f44d; 点赞、收藏与分享&#xff1a;觉得这篇文章对你有帮助吗&#xff1…

Y20030018基于Java+Springboot+mysql+jsp+layui的家政服务系统的设计与实现 源代码 文档

家政服务系统的设计与实现 1.摘要2.开发目的和意义3.系统功能设计4.系统界面截图5.源码获取 1.摘要 随着人们生活水平的提高&#xff0c;老龄化、少子化等多重因素影响&#xff0c;我国对家政服务人群的需求与日俱增。家政服务行业对我国的就业和社会效益贡献也与日俱增&#…

南京仁品耳鼻喉专科医院:12月启动公益义诊月

专业医疗资源送至“家门口”&#xff01;南京仁品耳鼻喉专科医院启动公益义诊月 随着2024年即将步入尾声&#xff0c;南京仁品耳鼻喉医院为回馈社会&#xff0c;提升公众健康福祉&#xff0c;将于12月隆重推出“三甲专家公益义诊月”活动。此次活动旨在通过汇聚众多耳鼻喉领域…

ospf协议(动态路由协议)

ospf基本概念 定义 OSPF 是典型的链路状态路由协议&#xff0c;是目前业内使用非常广泛的 IGP 协议之一。 目前针对 IPv4 协议使用的是 OSPF Version 2 &#xff08; RFC2328 &#xff09;&#xff1b;针对 IPv6 协议使用 OSPF Version 3 &#xff08; RFC2740 &#xff09;。…