stm32串口dma发送接收程序

stm32串口dma发送接收程序,第1张

  串口可以配置成用DMA的方式接收数据,不过DMA需要定长才能产生接收中断,如何接收可变长度的数据呢?

  方法有以下3种:

  1.将RX脚与一路时钟外部引脚相连,当串口一帧发完,即可利用此定时器产生超时中断。这个实时性较高,可以做到1个字节实时监测。

  2.不改变硬件,开启一个定时器监控DMA接收,如果超时则产生中断。这个实时性不高,因为超时时间必须要大于需要接收帧的时间,精度不好控制。

  3.STM32单片机有的串口可以监测总线是否处于空闲,如果空闲则产生中断。可以用它来监测DMA接收是否完毕。这种方式实时性很高。

  串口DMA发送:

  发送数据的流程:

  前台程序中有数据要发送,则需要做如下几件事

  1. 在数据发送缓冲区内放好要发送的数据,说明:此数据缓冲区的首地址必须要在DMA初始化的时候写入到DMA配置中去。

  2. 将数据缓冲区内要发送的数据字节数赋值给发送DMA通道,(串口发送DMA和串口接收DAM不是同一个DMA通道)

  3. 开启DMA,一旦开启,则DMA开始发送数据,说明一下:在KEIL调试好的时候,DMA和调试是不同步的,即不管Keil 是什么状态,DMA总是发送数据。

  4. 等待发送完成标志位,即下面的终端服务函数中的第3点设置的标志位。或者根据自己的实际情况来定,是否要一直等待这个标志位,也可以通过状态机的方式来循环查询也可以。或者其他方式。 判断数据发送完成:

  启动DMA并发送完后,产生DMA发送完成中断,在中断函数中做如下几件事:

  1. 清DMA发送完成中断标志位 2. 关闭串口发送DMA通道

  3. 给前台程序设置一个软件标志位,说明数据已经发送完毕

  串口DMA接收:

  接收数据的流程:

  串口接收DMA在初始化的时候就处于开启状态,一直等待数据的到来,在软件上无需做任何事情,只要在初始化配置的时候设置好配置就可以了。

  判断数据数据接收完成:

  这里判断接收完成是通过串口空闲中断的方式实现,即当串口数据流停止后,就会产生IDLE中断。这个中断里面做如下几件事:

  1.关闭串口接收DMA通道,2点原因:1.防止后面又有数据接收到,产生干扰。2.便于DMA的重新配置赋值,下面第4点。

  2. 清除DMA 所有标志位

  3. 从DMA寄存器中获取接收到的数据字节数

  4.重新设置DMA下次要接收的数据字节数,注意,这里是给DMA寄存器重新设置接收的计数值,这个数量只能大于或者等于可能接收的字节数,否则当DMA接收计数器递减到0的时候,又会重载这个计数值,重新循环递减计数,所以接收缓冲区的数据则会被覆盖丢失。

  5. 开启DMA通道,等待下一次的数据接收,注意,对DMA的相关寄存器配置写入,如第4条的写入计数值,必须要在关闭DMA的条件进行,否则 *** 作无效。

  说明一下,STM32的IDLE的中断在串口无数据接收的情况下,是不会一直产生的,产生的条件是这样的,当清除IDLE标志位后,必须有接收到第一个数据后,才开始触发,一断接收的数据断流,没有接收到数据,即产生IDLE中断。

  串口用DMA方式发送和接收,分以下几步:

  1)串口初始化

  2)DMA初始化

  3)发送数据

  4)接收数据

  我们按部就班:

  1) 串口初始化 — 使用串口一

  #define DMASIZE 1024

  // 配置串口一的发送和接收的GPIO口功能,以及中断

  staTIc void _uart1_gpio_init(void)

  {

  NVIC_InitTypeDef NVIC_InitStructure;

  GPIO_InitTypeDef GPIO_InitStructure;

  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA |

  RCC_APB2Periph_USART1 |

  RCC_APB2Periph_AFIO, ENABLE) ;

  GPIOA-》CRH&=0XFFFFF00F;

  GPIOA-》CRH|=0X000008B0;//IO状态设置 10pin_上拉输入 9pin_推挽输出

  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

  /* Configure USART1 Rx as input floaTIng */

  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;

  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;

  GPIO_Init(GPIOA, &GPIO_InitStructure);

  /* Configure USART1 Tx as alternate funcTIon push-pull */

  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;

  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;

  GPIO_Init(GPIOA, &GPIO_InitStructure);

  /* Enable the USART1 Interrupt */

  NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQChannel;

  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;

  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;

  NVIC_Init(&NVIC_InitStructure);

  USART_ClearFlag(USART1, USART_FLAG_TC); /* 清发送外城标志,Transmission Complete flag */

  USART_ITConfig(USART1, USART_IT_IDLE, ENABLE);// 采用空闲中断,目的是在产生空闲中断时,说明接收或者发送已经结束,此时可以读取DMA中的数据了。

  //USART_ITConfig(USART1, USART_IT_TC, ENABLE);

  //USART_ITConfig(USART1, USART_IT_FE, ENABLE);

  }

  // 设置对应串口的波特率

  staTIc void _uart_setbaudrate(USART_TypeDef* USARTx,u32 value)

  {

  USART_InitTypeDef USART_InitStructure;

  USART_InitStructure.USART_BaudRate =value;

  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(USARTx, &USART_InitStructure);

  USART_Cmd(USARTx, ENABLE);

  2)初始化DMA

  u8 sendbuf[1024];

  u8 receivebuf[1024];

  static void _uart1_dma_configuration()

  {

  DMA_InitTypeDef DMA_InitStructure;

  /* DMA1 Channel6 (triggered by USART1 Rx event) Config */

  RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1 ,

  ENABLE);

  /* DMA1 Channel5 (triggered by USART1 Rx event) Config */

  DMA_DeInit(DMA1_Channel5);

  DMA_InitStructure.DMA_PeripheralBaseAddr = USART1_DR_Base;// 初始化外设地址,相当于“哪家快递”

  DMA_InitStructure.DMA_MemoryBaseAddr =(u32)receivebuf;// 内存地址,相当于几号柜

  DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;//外设作为数据来源,即为收快递

  DMA_InitStructure.DMA_BufferSize = DMASIZE ;// 缓存容量,即柜子大小

  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_Normal;// 正常模式,即满了就不在接收了,而不是循环存储

  DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh;// 优先级很高,对应快递就是加急

  DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; // 内存与外设通信,而非内存到内存

  DMA_Init(DMA1_Channel5, &DMA_InitStructure);// 把参数初始化,即拟好与快递公司的协议

  DMA_Cmd(DMA1_Channel5, ENABLE);// 启动DMA,即与快递公司签订合同,正式生效

  /* DMA1 Channel4 (triggered by USART1 Tx event) Config */

  DMA_DeInit(DMA1_Channel4);

  DMA_InitStructure.DMA_PeripheralBaseAddr = USART1_DR_Base; // 外设地址,串口1, 即发件的快递

  DMA_InitStructure.DMA_MemoryBaseAddr =(u32)sendbuf;// 发送内存地址

  DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;// 外设为传送数据目的地,即发送数据,即快递是发件

  DMA_InitStructure.DMA_BufferSize = 0; //发送长度为0,即未有快递需要发送

  DMA_Init(DMA1_Channel4, &DMA_InitStructure);//初始化

  USART_ITConfig(USART1, USART_IT_TC, ENABLE);// 使能串口发送完成中断

  USART_DMACmd(USART1, USART_DMAReq_Tx|USART_DMAReq_Rx, ENABLE);// 使能DMA串口发送和接受请求

  }

  }

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/dianzi/2717455.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-08-17
下一篇 2022-08-17

发表评论

登录后才能评论

评论列表(0条)

保存