环形队列+DMA空闲中断+接收串口数据

简介: 环形队列+DMA空闲中断+接收串口数据


一.序言

本次实验利用环形队列+DMA空闲中断+串口。。通过这个实验可以非常深入的理解队列,DMA,串口的知识。如果你能自己实现掌握这个实验,那么你应该基本掌握了队列,DMA,串口的知识。

二.实验原理

本次使用的是用环形队列当缓冲器区接收串口数据。我们可以先区了解DMA的空闲中断。本次实验就是使用DMA空闲中断。这里就简单介绍一下,当串口接收到一帧数据后就会产生中断,那么如何判断数据是一帧呢?这里的判断机制就是,如果收到数据后,大概接收一个字节的时间,都没有接收到数据的话,就判断已经接收的数据是一帧。接收一帧数据后,串口就会产生空闲中断。同时DMA会把串口DR移位寄存器的值搬运到环形队列缓冲区。我们只需要在环形队列缓冲器拿数据即可。

三.实战是检验真理的唯一标准

仅仅通过理论,只能说你知道有这个东西,但是你可能并不会。下面我通过代码讲解也帮助深入理解理论。

3.1 usart1.c

void Usart1_Init(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;
  USART_InitTypeDef USART_InitStructure;
  NVIC_InitTypeDef NVIC_InitStructure;
  DMA_InitTypeDef DMA_InitStructure;
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOA, ENABLE); 
  
  //USART1_TX   GPIOA.9
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //PA.9
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; 
    GPIO_Init(GPIOA, &GPIO_InitStructure);//³õʼ»¯GPIOA.9
   
  //USART1_RX   GPIOA.10³õʼ»¯
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;//PA10
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
    GPIO_Init(GPIOA, &GPIO_InitStructure);//
  //Usart1 NVIC ÅäÖÃ
  NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=5 ;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;  
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;     
  NVIC_Init(&NVIC_InitStructure); //¸ù¾ÝÖ¸¶¨µÄ²ÎÊý³õʼ»¯VIC¼Ä´æÆ÷
  
  
  USART_InitStructure.USART_BaudRate = 115200
  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(USART1, &USART_InitStructure); 
    //使能空闲中断
    USART_ITConfig(USART1, USART_IT_IDLE , ENABLE);
    //使能发送完成中断--通过串口发送数据
    USART_ITConfig(USART1, USART_IT_TC , ENABLE);
    USART_DMACmd(USART1, USART_DMAReq_Tx|USART_DMAReq_Rx, ENABLE);
    USART_Cmd(USART1, ENABLE);                    
    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);    
  DMA_DeInit(DMA1_Channel5);
  //外设地址--串口1 的DR寄存器
  DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)(&USART1->DR);
  DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)Uart1_Rx_Buffer; 
  DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; 
  DMA_InitStructure.DMA_BufferSize = BSP_UART1_RX_SIZE; 
  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_Circular;  
  DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;
  DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
  //串口1的接收引脚为DAM1的通道5
  DMA_Init(DMA1_Channel5, &DMA_InitStructure);
  DMA_Cmd (DMA1_Channel5,ENABLE); 
   //初始化环形队列
  Fifo_Init(&Uart1_Rx_Fifo,Uart1_Rx_Buffer,BSP_UART1_RX_SIZE);

3.2 串口中断

void USART1_IRQHandler(void)
{ 
 //加上volatile 关键字只是为了防止警告
  volatile uint32_t temp = 0;
  BaseType_t xHigherPriorityTaskWoken = pdFALSE;
  if(USART_GetITStatus(USART1,USART_IT_IDLE)!= RESET)//¿ÕÏÐÖжÏ
  {
      //根据数据量数据入队列
      //DMA_GetCurrDataCounter(DMA1_Channel5); 通道5还剩下多少个数据应该传输。
      //初始化的时候设置的通道5传输多少数据。
    Uart1_Rx_Fifo.in = BSP_UART1_RX_SIZE - DMA_GetCurrDataCounter(DMA1_Channel5);
   //先读SR 再读DR 只是为了消除空闲中断标志位。手册上有说明
    temp = USART1->SR; 
    temp = USART1->DR;
    USART_ClearITPendingBit(USART1,USART_IT_IDLE);
  }

三.队列代码

代码可能看起来简单,但是不是那么容易理解。得自己慢慢体会,才能真正掌握,

而不是一昧的copy,不然出了问题也解决不了,自己代码水平也不能提高。

4.1 fifo.c

#include "sys.h"
#include "app_fifo.h"
//初始化
void Fifo_Init(FIFO_Type* fifo, uint8_t* buffer, uint16_t size)
{
  fifo->buffer = buffer;
  fifo->in = 0 ;
  fifo->out = 0;
  fifo->size = size;
}
//从队列中拿数据
uint16_t Fifo_Get(FIFO_Type* fifo, uint8_t* buffer, uint16_t len)
{
  uint16_t lenght;
  uint16_t in = fifo->in; 
  uint16_t i;
  lenght = (in + fifo->size - fifo->out)%fifo->size;
  if(lenght > len)
    lenght = len;
  for(i = 0; i < lenght; i++)
  {
    buffer[i] = fifo->buffer[(fifo->out + i)%fifo->size];
  }
  fifo->out = (fifo->out + lenght)%fifo->size;
  return lenght;
}

4.2 fifo.h

#ifndef FIFO_H
#define FIFO_H
#include "stm32f10x.h"
typedef struct {
  uint8_t* buffer;  
  uint16_t in;      
  uint16_t out;     
  uint16_t size;    
}FIFO_Type;
void Fifo_Init(FIFO_Type* fifo, uint8_t* buffer, uint16_t size);
uint16_t Fifo_Get(FIFO_Type* fifo, uint8_t* buffer, uint16_t len);
#endif

五.结语

代码放出来的就是以上这些,都放上去也比较麻烦,同时也没什么意义。写这篇博客是想让大家有大致的思路以及参考代码,从而根据自己的项目或者需求区进行改动。最后,如果真的需要全部代码的可以私信博主!最好点点关注!!!

目录
相关文章
|
1月前
处理串口线程数据的函数
【8月更文挑战第4天】处理串口线程数据的函数。
20 4
|
传感器 存储 物联网
为什么定时器,串口这些东西被称之为外设
为什么定时器,串口这些东西被称之为外设
145 0
|
数据处理
STM32实现DMA接收串口数据
STM32实现DMA接收串口数据
271 0
|
安全 API
6-FreeRTOS流缓冲区
6-FreeRTOS流缓冲区
龙芯2K驱动开发——使用中断触发读取GPIO电平值上传给读取进程
龙芯2K驱动开发——使用中断触发读取GPIO电平值上传给读取进程
450 0
龙芯2K驱动开发——使用中断触发读取GPIO电平值上传给读取进程
|
Linux 芯片
stm32-HAL使用usart发送中断判断发送库的一个问题
stm32-HAL使用usart发送中断判断发送库的一个问题
198 0
stm32-HAL使用usart发送中断判断发送库的一个问题
|
安全 开发工具 Perl
ZYNQ-定时器中断使用
ZYNQ-定时器中断使用
280 0
ZYNQ-定时器中断使用
向PC端发送数据(中断方式)
向PC端发送数据(中断方式) 宏定义 初始化 延迟 数据 中断 主函数
136 0
|
程序员 数据处理 调度
单片机I/O控制方式(UART中断和DMA中断的区别)
单片机I/O控制方式(UART中断和DMA中断的区别)
单片机I/O控制方式(UART中断和DMA中断的区别)