当前位置: 首页 > news >正文

STM32F407VET6开发板标准库实现DMA空闲接收和发送

使用STM32F407VET6开发板的标准库实现DMA空闲接收和收发,

此开发板有两个485接口和一个232接口,实现了三个串口的DMA收发数据。

代码下载地址:

https://gitee.com/stm_3/stm32-f407-vet6-dma.git

232接口:USART1,针脚PA9和PA10

第一路485接口:USART2,复用针脚PD5和PD6,485切换方向针脚PB10

第二路485接口:UART4,复用针脚PC10和PC11,485切换方向针脚PE15

main.c

//main.c
#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "led.h"
#include "rs485_1.h"
#include "rs485_2.h"
#include <string.h>
int main(void)
{NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置系统中断优先级分组2LED_Init();delay_init(168);   //初始化延时函数uart_init(115200); //初始化串口波特率为115200USART2_DMA_Init(115200);USART4_DMA_Init(115200);while(1){process_uart();Process_USART2();//Rs485 1Process_USART4();//Rs485 2      LED0=!LED0;LED1=!LED1;//如果需要加快速度,可以注释掉下面这句delay_ms(50);}
}

232接口的实现:文件名usart.c

//usart.c
#include "sys.h"
#include "usart.h"
#include <string.h>  
//////////////////////////////////////////////////////////////////////////////////    
//如果使用ucos,则包括下面的头文件即可.
#if SYSTEM_SUPPORT_UCOS
#include "includes.h"          //ucos 使用    
#endif//////////////////////////////////////////////////////////////////
//加入以下代码,支持printf函数,而不需要选择use MicroLIB    
#if 1
#pragma import(__use_no_semihosting)             
//标准库需要的支持函数                 
struct __FILE 
{ int handle; 
}; FILE __stdout;       
//定义_sys_exit()以避免使用半主机模式    
void _sys_exit(int x) 
{ x = x; 
} 
//重定义fputc函数 
int fputc(int ch, FILE *f)
{   while((USART1->SR&0X40)==0);//循环发送,直到发送完毕   USART1->DR = (u8) ch;      return ch;
}
#endif#define BUFFER_SIZE 8uint8_t rxBuffer[BUFFER_SIZE];
uint8_t txBuffer[BUFFER_SIZE];volatile uint8_t dmaTxComplete = 1;
volatile uint16_t usart1RecvLen = 0;void USART1_DMA_Send() {while(!dmaTxComplete); // 等待上次传输完成   dmaTxComplete = 0;DMA_Cmd(DMA2_Stream7, DISABLE);DMA_SetCurrDataCounter(DMA2_Stream7, usart1RecvLen);DMA_Cmd(DMA2_Stream7, ENABLE);
}void DMA_Config(void) {DMA_InitTypeDef DMA_InitStruct;RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE);// DMA2 Stream2 Channel4 for USART1_RXDMA_InitStruct.DMA_Channel = DMA_Channel_4;DMA_InitStruct.DMA_PeripheralBaseAddr = (uint32_t)&USART1->DR;DMA_InitStruct.DMA_Memory0BaseAddr = (uint32_t)rxBuffer;DMA_InitStruct.DMA_DIR = DMA_DIR_PeripheralToMemory;DMA_InitStruct.DMA_BufferSize = BUFFER_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_Normal;DMA_InitStruct.DMA_Priority = DMA_Priority_High;DMA_InitStruct.DMA_FIFOMode = DMA_FIFOMode_Disable;DMA_InitStruct.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;DMA_InitStruct.DMA_MemoryBurst = DMA_MemoryBurst_Single;DMA_InitStruct.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;DMA_Init(DMA2_Stream2, &DMA_InitStruct);DMA_Cmd(DMA2_Stream2, ENABLE);USART_DMACmd(USART1, USART_DMAReq_Rx, ENABLE);// DMA2 Stream7 Channel4 for USART1_TXDMA_InitStruct.DMA_Channel = DMA_Channel_4;DMA_InitStruct.DMA_PeripheralBaseAddr = (uint32_t)&USART1->DR;DMA_InitStruct.DMA_Memory0BaseAddr = (uint32_t)txBuffer;DMA_InitStruct.DMA_DIR = DMA_DIR_MemoryToPeripheral;DMA_InitStruct.DMA_BufferSize = BUFFER_SIZE;DMA_InitStruct.DMA_Mode = DMA_Mode_Normal;DMA_Init(DMA2_Stream7, &DMA_InitStruct);USART_DMACmd(USART1, USART_DMAReq_Tx, ENABLE);}/*
void NVIC_Config(void) {// 统一使用快捷函数时显式设置优先级(需配合NVIC_SetPriority)NVIC_SetPriority(DMA2_Stream2_IRQn, 0);  // 设置优先级NVIC_EnableIRQ(DMA2_Stream2_IRQn);DMA_ITConfig(DMA2_Stream2, DMA_IT_TC, ENABLE);NVIC_SetPriority(DMA2_Stream7_IRQn, 0);NVIC_EnableIRQ(DMA2_Stream7_IRQn);DMA_ITConfig(DMA2_Stream7, DMA_IT_TC, ENABLE);
}*/
void NVIC_Config(void) {NVIC_InitTypeDef NVIC_InitStruct;    NVIC_InitStruct.NVIC_IRQChannel = DMA2_Stream2_IRQn;NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0;NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0;NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;NVIC_Init(&NVIC_InitStruct);//enable receive interruptDMA_ITConfig(DMA2_Stream2, DMA_IT_TC, ENABLE);//enable transfer interruptDMA_ITConfig(DMA2_Stream7, DMA_IT_TC, ENABLE);NVIC_EnableIRQ(DMA2_Stream7_IRQn);
}void DMA2_Stream2_IRQHandler(void) {if(DMA_GetITStatus(DMA2_Stream2, DMA_IT_TCIF2)) {        int i = 0;uint16_t recvLen = 0;// 必须按顺序操作:先停止DMA再读取计数器DMA_Cmd(DMA2_Stream2, DISABLE);recvLen = sizeof(rxBuffer) -  DMA_GetCurrDataCounter(DMA2_Stream2);DMA_ClearITPendingBit(DMA2_Stream2, DMA_IT_TCIF2);// 数据处理for(i = 0; i < recvLen; i++) {txBuffer[i] = rxBuffer[i];}// 重置DMA配置DMA_SetCurrDataCounter(DMA2_Stream2, sizeof(rxBuffer));DMA_Cmd(DMA2_Stream2, ENABLE);usart1RecvLen = recvLen;}
}//发送
void DMA2_Stream7_IRQHandler(void) {if(DMA_GetITStatus(DMA2_Stream7, DMA_IT_TCIF7)) {DMA_ClearITPendingBit(DMA2_Stream7, DMA_IT_TCIF7);//由于不需要485的方向切换,可以直接在这里标志传输完成dmaTxComplete = 1;}
}//初始化IO 串口1 
//bound:波特率
void uart_init(u32 bound){//GPIO端口设置GPIO_InitTypeDef GPIO_InitStructure;USART_InitTypeDef USART_InitStructure;//NVIC_InitTypeDef NVIC_InitStructure;RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE); //使能GPIOA时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);//使能USART1时钟//串口1对应引脚复用映射GPIO_PinAFConfig(GPIOA,GPIO_PinSource9,GPIO_AF_USART1); //GPIOA9复用为USART1GPIO_PinAFConfig(GPIOA,GPIO_PinSource10,GPIO_AF_USART1); //GPIOA10复用为USART1//USART1端口配置GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9 | GPIO_Pin_10; //GPIOA9与GPIOA10GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;//复用功能GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;  //速度50MHzGPIO_InitStructure.GPIO_OType = GPIO_OType_PP; //推挽复用输出GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; //上拉GPIO_Init(GPIOA,&GPIO_InitStructure); //初始化PA9,PA10//USART1 初始化设置USART_InitStructure.USART_BaudRate = bound;//波特率设置USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字长为8位数据格式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(USART1, &USART_InitStructure); //初始化串口1USART_Cmd(USART1, ENABLE);  //使能串口1 /*USART_ClearFlag(USART1, USART_FLAG_TC);#if EN_USART1_RX  USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//开启相关中断//Usart1 NVIC 配置NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;//串口1中断通道NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3;//抢占优先级3NVIC_InitStructure.NVIC_IRQChannelSubPriority =3;    //子优先级3NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;      //IRQ通道使能NVIC_Init(&NVIC_InitStructure);  //根据指定的参数初始化VIC寄存器、#endif*/DMA_Config();NVIC_Config();
}void process_uart(void)
{if(usart1RecvLen>0){USART1_DMA_Send();usart1RecvLen = 0;}
}

第一路485接口:USART2,复用针脚PD5和PD6,485切换方向针脚PB10

文件名称:rs485_1.c

//rs485_1.c
#include <stdio.h>
#include <string.h>
#include "sys.h"
#include "rs485_1.h"
#include "delay.h"//485模式控制.0,接收;1,发送.
#define RS485_1_TX_EN PBout(10)#define USART2_RX_BUF_SIZE 256
#define USART2_TX_BUF_SIZE 256uint8_t usart2RxBuffer[USART2_RX_BUF_SIZE];
uint8_t usart2TxBuffer[USART2_TX_BUF_SIZE];
volatile uint16_t usart2RxLength = 0;/* GPIO初始化 */
static void USART2_GPIO_Init(void) {GPIO_InitTypeDef GPIO_InitStruct;//启用时钟RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE);GPIO_InitStruct.GPIO_Pin   = GPIO_Pin_5 | GPIO_Pin_6;GPIO_InitStruct.GPIO_Mode  = GPIO_Mode_AF;GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;GPIO_InitStruct.GPIO_PuPd  = GPIO_PuPd_UP;GPIO_Init(GPIOD, &GPIO_InitStruct);//复用针脚PD5和PD6GPIO_PinAFConfig(GPIOD, GPIO_PinSource5, GPIO_AF_USART2);GPIO_PinAFConfig(GPIOD, GPIO_PinSource6, GPIO_AF_USART2);//RS485 RE DE set,485方向切换针脚PB10,低电平接收,高电平发送RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB,ENABLE);GPIO_InitStruct.GPIO_Pin = GPIO_Pin_10;         //GPIOB10GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT; GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;  //速度50MHzGPIO_InitStruct.GPIO_OType = GPIO_OType_PP;     //推挽复用输出GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_UP;       //上拉GPIO_Init(GPIOB,&GPIO_InitStruct);              //初始化PB10//默认接收状态RS485_1_TX_EN = 0;
}/* USART2初始化 */
static void USART2_Init(uint32_t baudrate) {USART_InitTypeDef USART_InitStruct;NVIC_InitTypeDef NVIC_InitStruct;RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);USART_InitStruct.USART_BaudRate = baudrate;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_InitStruct.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;USART_Init(USART2, &USART_InitStruct);/* ** 配置串口接收空闲中断,这样可以接收变长数据** 但接收的最长数据的长度必须小于接收缓存,否则不会触发空闲中断*/USART_ITConfig(USART2, USART_IT_IDLE, ENABLE);//使能传输完成中断,用于判断完成后使能485USART_ITConfig(USART2, USART_IT_TC, ENABLE);USART_ClearFlag(USART2, USART_IT_TC);NVIC_InitStruct.NVIC_IRQChannel = USART2_IRQn;NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0;NVIC_InitStruct.NVIC_IRQChannelSubPriority = 1;NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;NVIC_Init(&NVIC_InitStruct);USART_Cmd(USART2, ENABLE);
}/* DMA接收初始化 DMA1_Stream5 通道4, 普通模式*/
static void USART2_DMA_Rx_Init(void) {DMA_InitTypeDef DMA_InitStruct;RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1, ENABLE);DMA_DeInit(DMA1_Stream5);while(DMA_GetCmdStatus(DMA1_Stream5) != DISABLE);DMA_InitStruct.DMA_Channel = DMA_Channel_4;DMA_InitStruct.DMA_PeripheralBaseAddr = (uint32_t)&USART2->DR;DMA_InitStruct.DMA_Memory0BaseAddr = (uint32_t)usart2RxBuffer;DMA_InitStruct.DMA_DIR = DMA_DIR_PeripheralToMemory;DMA_InitStruct.DMA_BufferSize = sizeof(usart2RxBuffer);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_Normal;DMA_InitStruct.DMA_Priority = DMA_Priority_High;DMA_InitStruct.DMA_FIFOMode = DMA_FIFOMode_Disable;DMA_InitStruct.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;DMA_InitStruct.DMA_MemoryBurst = DMA_MemoryBurst_Single;DMA_InitStruct.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;DMA_Init(DMA1_Stream5, &DMA_InitStruct);    USART_DMACmd(USART2, USART_DMAReq_Rx, ENABLE);DMA_Cmd(DMA1_Stream5, ENABLE);
}/* DMA发送初始化 DMA1_Stream6, 通道4,普通模式*/
static void USART2_DMA_Tx_Init(void) {DMA_InitTypeDef DMA_InitStruct;NVIC_InitTypeDef NVIC_InitStruct;DMA_DeInit(DMA1_Stream6);while(DMA_GetCmdStatus(DMA1_Stream6) != DISABLE);DMA_InitStruct.DMA_Channel = DMA_Channel_4;DMA_InitStruct.DMA_PeripheralBaseAddr = (uint32_t)&USART2->DR;DMA_InitStruct.DMA_Memory0BaseAddr = (uint32_t)usart2TxBuffer;DMA_InitStruct.DMA_DIR = DMA_DIR_MemoryToPeripheral;DMA_InitStruct.DMA_BufferSize = 0;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_Normal;DMA_InitStruct.DMA_Priority = DMA_Priority_Medium;DMA_InitStruct.DMA_FIFOMode = DMA_FIFOMode_Disable;DMA_InitStruct.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;DMA_InitStruct.DMA_MemoryBurst = DMA_MemoryBurst_Single;DMA_InitStruct.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;DMA_Init(DMA1_Stream6, &DMA_InitStruct);// 配置DMA发送完成中断DMA_ITConfig(DMA1_Stream6, DMA_IT_TC, ENABLE);    NVIC_InitStruct.NVIC_IRQChannel = DMA1_Stream6_IRQn;NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 1;NVIC_InitStruct.NVIC_IRQChannelSubPriority = 1;NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;NVIC_Init(&NVIC_InitStruct);USART_DMACmd(USART2, USART_DMAReq_Tx, ENABLE);
}/* 初始化函数 */
void USART2_DMA_Init(uint32_t baudrate) {USART2_GPIO_Init();USART2_Init(baudrate);USART2_DMA_Rx_Init();USART2_DMA_Tx_Init();
}/* 发送数据 */
void USART2_SendData(uint8_t *data, uint16_t length) {while(DMA_GetCmdStatus(DMA1_Stream6) == ENABLE);if(length > sizeof(usart2TxBuffer)){length = sizeof(usart2TxBuffer);}memcpy(usart2TxBuffer, data, length);//485高电平,准备发送RS485_1_TX_EN = 1;DMA_SetCurrDataCounter(DMA1_Stream6, length);DMA_Cmd(DMA1_Stream6, ENABLE);
}/* USART2中断服务函数 */
void USART2_IRQHandler(void) {if(USART_GetITStatus(USART2, USART_IT_IDLE) != RESET) {uint16_t recvLen = 0;// 清除空闲中断标志USART_ReceiveData(USART2);DMA_Cmd(DMA1_Stream5, DISABLE);recvLen = sizeof(usart2RxBuffer) - DMA_GetCurrDataCounter(DMA1_Stream5);/* 关键改进点 */if(recvLen > 0) {// 重置DMA前必须清除所有状态标志DMA_ClearFlag(DMA1_Stream5, DMA_FLAG_TCIF5 | DMA_FLAG_HTIF5 | DMA_FLAG_TEIF5);            // 重新配置DMA(必须包含以下步骤)DMA_SetCurrDataCounter(DMA1_Stream5, sizeof(usart2RxBuffer));}DMA_Cmd(DMA1_Stream5, ENABLE);usart2RxLength = recvLen;}if(USART_GetITStatus(USART2, USART_IT_TC) != RESET){USART_ClearITPendingBit(USART2, USART_IT_TC);//物理发送完成后,485必须处于低电平准备接收状态RS485_1_TX_EN = 0;}
}/* DMA发送完成中断 */
void DMA1_Stream6_IRQHandler(void) {if(DMA_GetITStatus(DMA1_Stream6, DMA_IT_TCIF6) != RESET) {DMA_ClearITPendingBit(DMA1_Stream6, DMA_IT_TCIF6);//这里发送完成仅仅是DMA计数为0,不代码物理发送完成。}
}void Process_USART2(void)
{if(usart2RxLength > 0){//printf("rs4851:%u\n", usart2RxLength);USART2_SendData(usart2RxBuffer, usart2RxLength);usart2RxLength = 0;}}

头文件名称:rs485_1.h

//rs485_1.h
#ifndef __RS485_1_H
#define __RS485_1_H 
#include "sys.h"
#include "stm32f4xx.h"void USART2_DMA_Init(uint32_t baudrate);
void USART2_SendData(uint8_t *data, uint16_t length);
void Process_USART2(void);#endif	   

第二路485接口:UART4,复用针脚PC10和PC11,485切换方向针脚PE15

文件名称:rs485_2.c

/*  rs485_2.c
代码特点:完整实现USART4的DMA收发功能,使用PC10(TX)和PC11(RX)引脚接收采用DMA1_Stream2通道4循环模式,发送采用DMA1_Stream4通道4普通模式通过空闲中断检测数据帧接收完成,避免频繁中断发送完成通过DMA中断通知,提高传输效率提供数据长度获取和拷贝接口,避免直接操作缓冲区模块化设计,头文件提供清晰接口,便于复用
*/#include <string.h>
#include <stdio.h>
#include "sys.h"
#include "rs485_2.h"
#include "delay.h"//485模式控制.0,接收;1,发送.
#define RS485_2_TX_EN PEout(15)#define USART4_RX_BUF_SIZE 256
#define USART4_TX_BUF_SIZE 256uint8_t usart4RxBuffer[USART4_RX_BUF_SIZE];
uint8_t usart4TxBuffer[USART4_TX_BUF_SIZE];
volatile uint16_t usart4RxLength = 0;static void USART4_GPIO_Init(void) {GPIO_InitTypeDef GPIO_InitStruct;RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE);GPIO_InitStruct.GPIO_Pin = GPIO_Pin_10 | GPIO_Pin_11;GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF;GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_UP;GPIO_Init(GPIOC, &GPIO_InitStruct);GPIO_PinAFConfig(GPIOC, GPIO_PinSource10, GPIO_AF_UART4);GPIO_PinAFConfig(GPIOC, GPIO_PinSource11, GPIO_AF_UART4);//RE DE setGPIO_InitStruct.GPIO_Pin = GPIO_Pin_15; //GPIOE15GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT;//GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;  //速度50MHzGPIO_InitStruct.GPIO_OType = GPIO_OType_PP; //推挽复用输出GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_UP; //上拉GPIO_Init(GPIOE,&GPIO_InitStruct); //初始化PE15//default, enable receive stateRS485_2_TX_EN = 0;
}static void USART4_Init(uint32_t baudrate) {USART_InitTypeDef USART_InitStruct;NVIC_InitTypeDef NVIC_InitStruct;RCC_APB1PeriphClockCmd(RCC_APB1Periph_UART4, ENABLE);USART_InitStruct.USART_BaudRate = baudrate;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_InitStruct.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;USART_Init(UART4, &USART_InitStruct);//使能空闲中断,接收的数据必须小于缓存才会触发USART_ITConfig(UART4, USART_IT_IDLE, ENABLE);//使能传输完成中断,用于判断完成后使能485USART_ITConfig(UART4, USART_IT_TC, ENABLE);USART_ClearFlag(UART4, USART_IT_TC);NVIC_InitStruct.NVIC_IRQChannel = UART4_IRQn;NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0;NVIC_InitStruct.NVIC_IRQChannelSubPriority = 1;NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;NVIC_Init(&NVIC_InitStruct);USART_Cmd(UART4, ENABLE);
}static void USART4_DMA_Rx_Init(void) {DMA_InitTypeDef DMA_InitStruct;NVIC_InitTypeDef NVIC_InitStruct;RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1, ENABLE);DMA_DeInit(DMA1_Stream2);while(DMA_GetCmdStatus(DMA1_Stream2) != DISABLE);DMA_InitStruct.DMA_Channel = DMA_Channel_4;DMA_InitStruct.DMA_PeripheralBaseAddr = (uint32_t)&UART4->DR;DMA_InitStruct.DMA_Memory0BaseAddr = (uint32_t)usart4RxBuffer;DMA_InitStruct.DMA_DIR = DMA_DIR_PeripheralToMemory;DMA_InitStruct.DMA_BufferSize = USART4_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_Normal;DMA_InitStruct.DMA_Priority = DMA_Priority_High;DMA_InitStruct.DMA_FIFOMode = DMA_FIFOMode_Disable;DMA_InitStruct.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;DMA_InitStruct.DMA_MemoryBurst = DMA_MemoryBurst_Single;DMA_InitStruct.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;DMA_Init(DMA1_Stream2, &DMA_InitStruct);DMA_ITConfig(DMA1_Stream2, DMA_IT_TC, ENABLE);    //same as NVIC_EnableIRQ(DMA1_Stream2_IRQn); default priorityNVIC_InitStruct.NVIC_IRQChannel = DMA1_Stream2_IRQn;NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0;NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0;NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;NVIC_Init(&NVIC_InitStruct);USART_DMACmd(UART4, USART_DMAReq_Rx, ENABLE);DMA_Cmd(DMA1_Stream2, ENABLE);
}static void USART4_DMA_Tx_Init(void) {DMA_InitTypeDef DMA_InitStruct;NVIC_InitTypeDef NVIC_InitStruct;DMA_DeInit(DMA1_Stream4);while(DMA_GetCmdStatus(DMA1_Stream4) != DISABLE);DMA_InitStruct.DMA_Channel = DMA_Channel_4;DMA_InitStruct.DMA_PeripheralBaseAddr = (uint32_t)&UART4->DR;DMA_InitStruct.DMA_Memory0BaseAddr = (uint32_t)usart4TxBuffer;DMA_InitStruct.DMA_DIR = DMA_DIR_MemoryToPeripheral;DMA_InitStruct.DMA_BufferSize = 0;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_Normal;DMA_InitStruct.DMA_Priority = DMA_Priority_Medium;DMA_InitStruct.DMA_FIFOMode = DMA_FIFOMode_Disable;DMA_InitStruct.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;DMA_InitStruct.DMA_MemoryBurst = DMA_MemoryBurst_Single;DMA_InitStruct.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;DMA_Init(DMA1_Stream4, &DMA_InitStruct);DMA_ITConfig(DMA1_Stream4, DMA_IT_TC, ENABLE);//same as NVIC_EnableIRQ(DMA1_Stream4_IRQn);NVIC_InitStruct.NVIC_IRQChannel = DMA1_Stream4_IRQn;NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 1;NVIC_InitStruct.NVIC_IRQChannelSubPriority = 1;NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;NVIC_Init(&NVIC_InitStruct);USART_DMACmd(UART4, USART_DMAReq_Tx, ENABLE);}void USART4_DMA_Init(uint32_t baudrate) {USART4_GPIO_Init();USART4_Init(baudrate);USART4_DMA_Rx_Init();USART4_DMA_Tx_Init();
}uint16_t USART4_SendData(uint8_t *data, uint16_t length) {while(DMA_GetCmdStatus(DMA1_Stream4) == ENABLE);if(length > USART4_TX_BUF_SIZE) length = USART4_TX_BUF_SIZE;memcpy(usart4TxBuffer, data, length);RS485_2_TX_EN = 1;DMA_SetCurrDataCounter(DMA1_Stream4, length);DMA_Cmd(DMA1_Stream4, ENABLE);return length;
}void UART4_IRQHandler(void) {if(USART_GetITStatus(UART4, USART_IT_IDLE) != RESET) {uint16_t recvLen = 0;// 清除空闲中断标志USART_ReceiveData(UART4);;DMA_Cmd(DMA1_Stream2, DISABLE);recvLen = sizeof(usart4RxBuffer) - DMA_GetCurrDataCounter(DMA1_Stream2);/* 关键改进点 */if(recvLen > 0) {// 重置DMA前必须清除所有状态标志DMA_ClearFlag(DMA1_Stream2, DMA_FLAG_TCIF2 | DMA_FLAG_HTIF2 | DMA_FLAG_TEIF2);            // 重新配置DMA(必须包含以下步骤)DMA_SetCurrDataCounter(DMA1_Stream2, sizeof(usart4RxBuffer));}DMA_Cmd(DMA1_Stream2, ENABLE);usart4RxLength = recvLen;}if(USART_GetITStatus(UART4, USART_IT_TC) != RESET){USART_ClearITPendingBit(UART4, USART_IT_TC);//物理发送完成后,485必须处于低电平准备接收状态RS485_2_TX_EN = 0;}/* 扩展错误处理(可选)*/if(DMA_GetITStatus(DMA1_Stream2, DMA_IT_TEIF2)) {DMA_ClearITPendingBit(DMA1_Stream2, DMA_IT_TEIF2);//Error_Handler();}
}// transfer data
void DMA1_Stream4_IRQHandler(void) {if(DMA_GetITStatus(DMA1_Stream4, DMA_IT_TCIF4) != RESET) {DMA_ClearITPendingBit(DMA1_Stream4, DMA_IT_TCIF4);}
}// receive data
void DMA1_Stream2_IRQHandler(void) 
{    if(DMA_GetITStatus(DMA1_Stream2, DMA_IT_TCIF2) != RESET) {DMA_ClearITPendingBit(DMA1_Stream2, DMA_IT_TCIF2);}if(DMA_GetITStatus(DMA1_Stream2, DMA_FLAG_HTIF2) != RESET) {DMA_ClearITPendingBit(DMA1_Stream2, DMA_FLAG_HTIF2);}if(DMA_GetITStatus(DMA1_Stream2, DMA_FLAG_TEIF2) != RESET) {DMA_ClearITPendingBit(DMA1_Stream2, DMA_FLAG_TEIF2);}if(DMA_GetITStatus(DMA1_Stream2, DMA_FLAG_DMEIF2) != RESET) {DMA_ClearITPendingBit(DMA1_Stream2, DMA_FLAG_DMEIF2);        }
}void Process_USART4(void)
{if(usart4RxLength > 0){//printf("rs4852:%u\n", usart4RxLength);USART4_SendData(usart4RxBuffer, usart4RxLength);usart4RxLength = 0;}}

头文件 rs485_2.h

// rs485_2.h
#ifndef __RS485_2_H
#define __RS485_2_H 
#include "sys.h"  
#include "stm32f4xx.h"void USART4_DMA_Init(uint32_t baudrate);
uint16_t USART4_SendData(uint8_t *data, uint16_t length);
void Process_USART4(void);#endif

http://www.dtcms.com/a/334990.html

相关文章:

  • 同创物流学习记录2·电车光电
  • 行为型设计模式:对象协作的舞蹈家(中)
  • Rust 入门 KV存储HashMap (十七)
  • 如何得知是Counter.razor通过HTTP回调处理的还是WASM处理的,怎么检测?
  • LeetCode 55.跳跃游戏:贪心策略下的可达性判断
  • 2025年睿抗国赛本科组题解
  • JavaScript 数组方法汇总
  • 第四章 数字特征
  • 数智管理学(四十七)
  • 【论文笔记】Multi-Agent Based Character Simulation for Story Writing
  • Kafka 面试题及详细答案100道(11-22)-- 核心机制1
  • 算法题打卡力扣第42题接雨水(hard)
  • 【图像算法 - 15】智能行李识别新高度:基于YOLO12实例分割与OpenCV的精准检测(附完整代码)
  • 一次性能排查引发的Spring MVC深度思考
  • Netty 的 Select/Poll 机制核心实现主要在 NioEventLoop 的事件循环
  • 院校机试刷题第二十三天|大精度整数运算、约瑟夫环
  • 二叉树应用实践
  • Dify 从入门到精通(第 38/100 篇):Dify 的实时协作功能
  • Python---异常链(Exception Chaining)
  • PowerShell 第11章:过滤和比较(上)
  • 深入分析MVCC机制
  • 16.CNN——猫狗二分类识别
  • Git使用和理解上的一些问题
  • ADHD时间感知组件
  • Java 9 新特性及具体应用
  • Flowith-节点式GPT-4 驱动的AI生产力工具
  • PS插件整合包!内置数百款PS插件,支持PS2017-PS2025所有版本!
  • 后量子密码算法SLH-DSA介绍及开源代码实现
  • 【学习嵌入式day-26-线程间通信】
  • Python脚本开发-统计Rte中未连接的Port