700字范文,内容丰富有趣,生活中的好帮手!
700字范文 > stm32的串口DMA空闲中断接收不等长数据 stm32F1的usart1-DMA-IDLE收发

stm32的串口DMA空闲中断接收不等长数据 stm32F1的usart1-DMA-IDLE收发

时间:2021-02-02 04:24:43

相关推荐

stm32的串口DMA空闲中断接收不等长数据 stm32F1的usart1-DMA-IDLE收发

stm32的DMA收发原理,和stm32F4 + USART2 +DMA +IDLE使用,见另一篇:/Mark_md/article/details/107243054

stm32F1的串口DMA和stm32F4的大同小异,使用时要区分通道和数据流区别。

stm32F1的usart1-DMA-IDLE收发

直接上代码

usart.c

#include "usart.h"uint8_t Uart1_Rx_Buff[DMA_UART1_RX_SIZE];uint8_t Uart1_Tx_Buff[DMA_UART1_TX_SIZE];uint16_t Uart1_RxLength;//Uart1 DMA 一次接收到的数据长度void uart1_init(u32 bound){/*定义串口初始化结构体*/GPIO_InitTypeDef GPIO_InitStructure;USART_InitTypeDef USART_InitStructure;NVIC_InitTypeDef NVIC_InitStructure;/*使能内部外设时钟*/ RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOA, ENABLE);//使能USART1,GPIOA时钟/*GPIO端口设置*//*USART1_TX GPIOA.9*/GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //PA.9GPIO_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;//PA.10//GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;//上拉输入GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.10 /*USART1 参数设置*/USART_InitStructure.USART_BaudRate = bound;//串口波特率USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字长为8位数据格式USART_InitStructure.USART_StopBits = USART_StopBits_1;//停止位 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); //初始化串口1/*Usart1 NVIC 配置*/NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;//串口1中断通道NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=6 ;//抢占优先级6NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;//子优先级0NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;//IRQ通道使能NVIC_Init(&NVIC_InitStructure);//根据指定的参数初始化VIC寄存器/*设置UART1 中断触发模式*/USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//RX NO Empty,RX非空,RX有数据中断。开启串口接受中断,使用DMA接收时要失能这个,使能空闲中断//USART_ITConfig(USART1, USART_IT_TC, ENABLE);// Transmit Complete,发送完成中断。开启串口发送完成中断,发送一个字节就会进入中断,只需要清除中断标志位,不需要关闭中断//USART_IT_TXE TX Empty,TX为空,发送寄存器DR清零。发送寄存器空闲中断,发送完一个字节后,必须关闭这个中断,否则只要寄存器为空值,就会反复进入中断//USART_ITConfig(USART1, USART_IT_IDLE, ENABLE);//开启串口空闲中断??发送会不会触发空闲中断/*开启UART1 */USART_Cmd(USART1, ENABLE);//使能串口1}void uart1_dma_rx_configuration(void){/*定义DMA初始化结构体*/DMA_InitTypeDef DMA_InitStructure;/*使能内部外设时钟*/ RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);//使能DMA时钟/*DMA 通道5 接收配置*/DMA_DeInit(DMA1_Channel5); DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)&USART1->DR;//DMA外设基地址DMA_InitStructure.DMA_MemoryBaseAddr = (u32)Uart1_Rx_Buff;//DMA内存基地址,把接收到的数据放到哪儿DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;//数据传输方向,从内存从外设读取,外设作为数据来源DMA_InitStructure.DMA_BufferSize = DMA_UART1_RX_SIZE;//DMA通道的缓存的大小,一次接收的最大字节数DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;//外设地址寄存器不递增DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;//内存地址寄存器递增DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; //外设数据宽度为8位DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; //内存数据宽度为8位DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; //工作在正常模式,即满了不再接收,而不是循环储存DMA_InitStructure.DMA_Priority = DMA_Priority_Medium; //DMA通道 中优先级//DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh; //DMA通道 优先级很高DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; //DMA通道为内存与内存通信,而非内存到内存DMA_Init(DMA1_Channel5, &DMA_InitStructure);//启动DMA/*设置UART1 中断触发模式*/USART_ITConfig(USART1, USART_IT_RXNE, DISABLE);//RX NO Empty,RX非空,RX有数据中断。开启串口接受中断,使用DMA接收时要失能这个,使能空闲中断//USART_ITConfig(USART1, USART_IT_TC, ENABLE);// Transmit Complete,发送完成中断。开启串口发送完成中断,发送一个字节就会进入中断,只需要清除中断标志位,不需要关闭中断//USART_IT_TXE TX Empty,TX为空,发送寄存器DR清零。发送寄存器空闲中断,发送完一个字节后,必须关闭这个中断,否则只要寄存器为空值,就会反复进入中断USART_ITConfig(USART1, USART_IT_IDLE, ENABLE);//开启串口空闲中断??发送会不会触发空闲中断/*开启DMA接收*/DMA_Cmd(DMA1_Channel5, ENABLE);//开启DMA 通道5传输,即接收传输USART_DMACmd(USART1,USART_DMAReq_Rx,ENABLE);//使能UART1的DMA接收}void uart1_dma_rxtx_configuration(void){/*定义DMA初始化结构体*/DMA_InitTypeDef DMA_InitStructure;/*使能内部外设时钟*/ RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);//使能DMA时钟/*DMA 通道5 接收配置*/DMA_DeInit(DMA1_Channel5); DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)&USART1->DR;//DMA外设基地址DMA_InitStructure.DMA_MemoryBaseAddr = (u32)Uart1_Rx_Buff;//DMA内存基地址,把接收到的数据放到哪儿DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;//数据传输方向,从内存读取发送到外设,外设作为数据来源DMA_InitStructure.DMA_BufferSize = DMA_UART1_RX_SIZE;//DMA通道的缓存的大小,一次接收的最大字节数DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;//外设地址寄存器不递增DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;//内存地址寄存器递增DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; //外设数据宽度为8位DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; //内存数据宽度为8位DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; //工作在正常模式,即满了不再接收,而不是循环储存DMA_InitStructure.DMA_Priority = DMA_Priority_Medium; //DMA通道 中优先级//DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh; //DMA通道 优先级很高DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; //DMA通道为内存与外设通信,而非内存到内存DMA_Init(DMA1_Channel5, &DMA_InitStructure);//配置DMA 通道5/*DMA 通道4 发送配置*/DMA_DeInit(DMA1_Channel4); DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)&USART1->DR;//DMA外设基地址DMA_InitStructure.DMA_MemoryBaseAddr = (u32)Uart1_Tx_Buff;//DMA发送的内存地址DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;//数据传输方向,从内存到外设发送,外设作为数据传输目的地//因为刚开始初始化时候不需要发送数据,所以发送长度为0DMA_InitStructure.DMA_BufferSize = 0;//发送长度为0DMA_Init(DMA1_Channel4, &DMA_InitStructure);//配置DMA 通道4/*设置UART1 中断触发模式*/USART_ITConfig(USART1, USART_IT_RXNE, DISABLE);//RX NO Empty,RX非空,RX有数据中断。开启串口接受中断,使用DMA接收时要失能这个,使能空闲中断//USART_ITConfig(USART1, USART_IT_TC, ENABLE);// Transmit Complete,发送完成中断。开启串口发送完成中断,发送一个字节就会进入中断,只需要清除中断标志位,不需要关闭中断//USART_IT_TXE TX Empty,TX为空,发送寄存器DR清零。发送寄存器空闲中断,发送完一个字节后,必须关闭这个中断,否则只要寄存器为空值,就会反复进入中断USART_ITConfig(USART1, USART_IT_IDLE, ENABLE);//开启串口空闲中断??发送会不会触发空闲中断/*开启DMA接收因为刚开始初始化时候不需要发送数据,所以 DMA发送通道4 不开启*/DMA_Cmd(DMA1_Channel5, ENABLE);//开启DMA 通道5传输,即接收传输USART_DMACmd(USART1,USART_DMAReq_Tx|USART_DMAReq_Rx,ENABLE);//使能UART1的DMA发送和接收}uint16_t Uart1_DMA_Send_Data(void * buffer, u16 size){if(!size) return 0;// 判断长度是否有效while (DMA_GetCurrDataCounter(DMA1_Channel4));// 检查DMA发送通道内是否还有数据if(buffer) memcpy(Uart1_Tx_Buff, buffer,(size > DMA_UART1_TX_SIZE?DMA_UART1_TX_SIZE:size));//判断发送长度是否大于DMA可传输长度//DMA发送数据-要先关DMA,再设置发送长度,最后开启DMADMA_Cmd(DMA1_Channel4, DISABLE);//开启DMA 通道4传输,即发送传输DMA1_Channel4->CNDTR = size;// 设置发送长度DMA_Cmd(DMA1_Channel4, ENABLE);// 启动DMA发送return size;}//验证uart1的DMA,在不清除接收队列的情况下,后来的数据会覆盖原来的数据,未覆盖的数据会保留。所以接收一次数据并使用完成后,想要接收下一次数据,必须将接收缓存区清零//验证清除uart1 IDLE中断,正确的方法是先读SR,再度DRvoid USART1_IRQHandler(void)//串口1中断服务程序{uint8_t temp;if(USART_GetITStatus(USART1, USART_IT_IDLE) != RESET){DMA_Cmd(DMA1_Channel5,DISABLE);//关闭DMA通道//没用,不过还是加上吧DMA_ClearFlag(DMA1_FLAG_TC5);//DMA 通道5 清中断标志,否则会一直中断USART_ClearITPendingBit(USART1, USART_IT_IDLE);//清除空闲中断标志//IDLE标志位清零的过程是:先读SR,再读DR寄存器//注意:这句必须要,否则不能够清除中断标志位。temp = USART1->SR;//先读SR,然后读DR才能清除temp = USART1->DR;//清除DRtemp = temp;/*在这里处理数据长度 及数据处理事件*/Uart1_RxLength = DMA_UART1_RX_SIZE - DMA_GetCurrDataCounter(DMA1_Channel5);//DMA接收完数据后,不会将Uart1_Rx_Buff任何数据清零,下一次数据会重新覆盖,没有覆盖的数据会保留,所以获取数据长度和清零接收缓冲区是必要的/*清零本次DMA接收缓冲区*///清零接收缓存区,可以不全部清空,提高运行效率;全部清空,确保长时间稳定性//memset(Uart1_Rx_Buff,0,Uart1_RxLength);memset(Uart1_Rx_Buff,0,DMA_UART1_RX_SIZE);//待uart接收缓存区项目处理完后,清除数据接收缓冲区USART_RX_BUF,用于下一次数据接/*重新开启下一次DMA接收*/DMA_SetCurrDataCounter(DMA1_Channel5,DMA_UART1_RX_SIZE);//DMA通道的DMA缓存的大小。重置传输数目,当再次达到这个数目就会进中断DMA_Cmd(DMA1_Channel5,ENABLE);//开启DMA通道}}

usart.h

#ifndef __USART_H#define __USART_H#include "stdio.h"#include "sys.h" /************************************************************************************************/#defineDMA_UART1_RX_SIZE20#defineDMA_UART1_TX_SIZE20extern uint8_t Uart1_Rx_Buff[DMA_UART1_RX_SIZE];extern uint8_t Uart1_Tx_Buff[DMA_UART1_TX_SIZE];extern uint16_t Uart1_RxLength;//Uart1 DMA 一次接收到的数据长度void uart1_init(u32 bound);void uart1_dma_rx_configuration(void);void uart1_dma_rxtx_configuration(void);uint16_t Uart1_DMA_Send_Data(void * buffer, u16 size);#endif

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。