关于串口开启DMA进行收发的配置

之前在用STM32进行开发的时候,有用到485进行数据的采集。因为数据量相对较大,所以开启了DMA通道。这边就对485串口配置和DMA的配置以及后续相关的收发操作进行一点总结。首先我485接的是板子上的串口一。根据手册可以看出这边使用的是DMA1的通道4和通道5,接下来就是相关的配置。PS:用库函数进行的开发

//一些定义

#define RX_LEN 1024

u8 real_recv_len ; //串口实际接收的数据长度

OS_SEM tx_sem;  //发送的信号量


串口配置:

/*开启串口1 GPIO扣 DMA相关的时钟*/

RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO, ENABLE);//打开GPIOA的重映射功能
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);

/*配置RX TX的IO口功能*/

//PA10  RX
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA, &GPIO_InitStructure);

//PA9  TX
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_Init(GPIOA, &GPIO_InitStructure);

//UART1
  USART_InitStructure.USART_BaudRate = 9600;//9600;
  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_Tx;  //先不使能接收 到相应task中使能
  USART_Init(USART1, &USART_InitStructure);
  USART_ClearFlag(USART1, USART_FLAG_TC);
  USART_DMACmd(USART1, USART_DMAReq_Tx,ENABLE);
  USART_DMACmd(USART1, USART_DMAReq_Rx, ENABLE);
  USART_ITConfig(USART1,USART_IT_IDLE,ENABLE);
  //DMA1_CH4  USART1 TX
  DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)&USART1->DR; //目标地址
  DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST; //方向
  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_PeripheralDataSize_Byte; //内存字节为单位
  DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; //
  DMA_InitStructure.DMA_Priority = DMA_Priority_High;
  DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; //非内存到内存
  DMA_Init(DMA1_Channel4, &DMA_InitStructure);
  DMA_ITConfig(DMA1_Channel4, DMA_IT_TC, ENABLE);
  DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; //方向
  DMA_Init(DMA1_Channel5, &DMA_InitStructure);
  USART_Cmd(USART1, ENABLE);


接下来是中断函数的配置和进行数据的收发操作

首先定义DMA使能的宏定义

#define DMA1_CH4_EN()  DMA1_Channel4->CCR |= DMA_CCR1_EN  //开DMA
#define DMA1_CH5_EN()  DMA1_Channel5->CCR |= DMA_CCR1_EN;//开DMA
#define DMA1_CH4_DIS() DMA1_Channel4->CCR &= (u16)(~DMA_CCR1_EN)  //关DMA
#define DMA1_CH5_DIS() DMA1_Channel5->CCR &= (u16)(~DMA_CCR1_EN);  //关DMA

接下来是中断函数的完成

void USART1_IRQHandler()
{
u32 temp;
int len;
u16 crc , crc_sum; 

usart1_rx_dis();  //先关闭串口的接收

//清理中断标志位
temp = USART1->SR;
temp = USART1->DR;

real_recv_len = MODBUS_RX_LEN - DMA1_Channel5->CNDTR;  //本次收到数据长度

//可以做你想要进行的操作,不过不要在中断函数中做太复杂的操作 也不要做一些数据量大的运行和浮点型的运行

...

...

...

//操作完使能串口1的接收

usart1_rx_en();
}

//下面是DMA的中断函数

void DMA1_Channel4_IRQHandler()
{
DMA1->IFCR = DMA1_IT_TC4;  //清标志
DMA1_CH4_DIS();  //关发送DMA
isr_sem_send(&tx_sem); //设置信号量
}


//下面发送函数

static int usart1_send(u8* buf, u8 lenth)
{
//用信号量来判断DMA1是否发生中断
if(os_sem_wait(&tx_sem, 50) == OS_R_TMO)
{
DMA1_CH4_DIS();
}


  DMA1_Channel4->CMAR = (u32)buf;
  DMA1_Channel4->CNDTR = lenth;
usart1_rx_en(); 
  DMA1_CH4_EN();  //发送
return 0;
}


//下面是通道一的接收初始化和使能失效函数的封装


//使能接收
static void usart1_rx_en()
{
DMA1_Channel5->CNDTR = RX_LEN;
DMA1_CH5_EN();
USART1->CR1 |= USART_Mode_Rx;  //使能接收
}

//关闭接收
static void usart1_rx_dis()
{
USART1->CR1 &= ~USART_Mode_Rx;  //关闭接收
DMA1_CH5_DIS();  //关接收DMA
}

//接收初始化
void lcd_rx1_init()
{
DMA1_Channel5->CNDTR = RX_LEN;
DMA1_Channel5->CMAR = (u32)modebus_rx_buff;
}


经过测试是可以正常使用的,其中大部分参考的是零死角玩转STM32这本书,书写的很好,很多例子很受用。


    






猜你喜欢

转载自blog.csdn.net/jutun5887/article/details/78652367