STM32F4 UART1 DMA发送和接收不定长度数据

发布者:Quail最新更新时间:2017-09-25 来源: eefocus关键字:STM32F4  UART1  DMA  发送和接收  数据 手机看文章 扫描二维码
随时随地手机看文章

STM32F4 串口收发使用DMA还是很方便的。但是配置DMA时需要配置数据长度,这一点对于发送来说可以预估计自己发送的长度来配置DMA发送数据长度,但是对于接收不是很好解决,因为如果使用DMA接收中断是要配置的数据长度减到0才能出发中断。但是我们无法判断接受数据的长度,导致无法判断数据接收完成。网上有提出的解决方法是用定时器固定周期的读DMA接收的长度来判断是否接收完成,也有使用UART的空闲中断来处理的。在这里我使用UART的空闲中断来处理接收不定长数据。当然也要打开DMA接收完成中断,处理数据接收超过DMA配置的长度导致的DMA接收中断。

1.使用DMA发送时每次发送数据前需要配置发送的数据长度,此时要注意应先关闭DMA,然后配置数据长度,最后开启DMA发送,同时在DMA发送中断里面不要忘记清除相应的中断标志位。

2.DMA接收长度达到配置长度后会导致接收中断,此时在中断处理函数内要先关闭DMA,然后读出数据长度,清掉相应的中断标志位,最后重新配置DMA接收长度并打开DMA接收。在这里的DMA中断指示为了防护一次性接收数据超过DMA配置长度。

3.UART空闲中断,利用空闲中断可以很好地判断DMA接收不定长度的数据是否完成。初始化UART时打开空闲中断。当数据接收完成后会触发UART空闲中断。在中断内首先关闭DMA,读出DMA接收到的数据长度,清除DMA标志,重新配置DMA接收长度,清除空闲中断标志IDLE。这里要注意清除IDLE要由软件序列清除即依次读取USART1->SR;和USART1->DR;

下面贴出代码方便以后查看


  1. u8  ReceiveBuff[RECEIVE_BUF_SIZE];   //接收缓冲  

  2. u8  SendBuff[SEND_BUF_SIZE];    //发送数据缓冲区  

  3.   

  4. u16 UART1_ReceiveSize = 0;  

  5.   

  6. //初始化IO 串口1   

  7. //bound:波特率  

  8. void uart_init(u32 bound)  

  9. {  

  10.     //GPIO端口设置  

  11.     GPIO_InitTypeDef GPIO_InitStructure;  

  12.     USART_InitTypeDef USART_InitStructure;  

  13.     NVIC_InitTypeDef NVIC_InitStructure;  

  14.     DMA_InitTypeDef  DMA_InitStructure;  

  15.   

  16.     RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE); //使能GPIOA时钟  

  17.     RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);//使能USART1时钟  

  18.     RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2,ENABLE);//DMA2时钟使能   

  19.   

  20.     //串口1对应引脚复用映射  

  21.     GPIO_PinAFConfig(GPIOA,GPIO_PinSource9,GPIO_AF_USART1); //GPIOA9复用为USART1  

  22.     GPIO_PinAFConfig(GPIOA,GPIO_PinSource10,GPIO_AF_USART1); //GPIOA10复用为USART1  

  23.   

  24.     //USART1端口配置  

  25.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9 | GPIO_Pin_10; //GPIOA9与GPIOA10  

  26.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;//复用功能  

  27.     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;   //速度50MHz  

  28.     GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; //推挽复用输出  

  29.     GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; //上拉  

  30.     GPIO_Init(GPIOA,&GPIO_InitStructure); //初始化PA9,PA10  

  31.   

  32.     //USART1 初始化设置  

  33.     USART_InitStructure.USART_BaudRate = bound;//波特率设置  

  34.     USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字长为8位数据格式  

  35.     USART_InitStructure.USART_StopBits = USART_StopBits_1;//一个停止位  

  36.     USART_InitStructure.USART_Parity = USART_Parity_No;//无奇偶校验位  

  37.     USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//无硬件数据流控制  

  38.     USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; //收发模式  

  39.     USART_Init(USART1, &USART_InitStructure); //初始化串口1  

  40.   

  41.     USART_Cmd(USART1, ENABLE);  //使能串口1   

  42.   

  43.     //USART_ClearFlag(USART1, USART_FLAG_TC);  

  44.       

  45.     USART_ITConfig(USART1, USART_IT_IDLE, ENABLE);//开启相关中断  

  46.   

  47.     //Usart1 NVIC 配置  

  48.     NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;//串口1中断通道  

  49.     NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3;//抢占优先级3  

  50.     NVIC_InitStructure.NVIC_IRQChannelSubPriority =3;       //子优先级3  

  51.     NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;         //IRQ通道使能  

  52.     NVIC_Init(&NVIC_InitStructure); //根据指定的参数初始化VIC寄存器、  

  53.   

  54.     USART_DMACmd(USART1,USART_DMAReq_Tx,ENABLE);  //使能串口1的DMA发送     

  55.     USART_DMACmd(USART1,USART_DMAReq_Rx,ENABLE);  //使能串口1的DMA接收  

  56.   

  57.   

  58.     //****************************配置UART1发送  

  59.     DMA_DeInit(DMA2_Stream7);  

  60.     while (DMA_GetCmdStatus(DMA2_Stream7) != DISABLE);//等待DMA可配置   

  61.     /* 配置 DMA Stream */  

  62.     DMA_InitStructure.DMA_Channel = DMA_Channel_4;  //通道选择  

  63.     DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)&USART1->DR;//DMA外设地址  

  64.     DMA_InitStructure.DMA_Memory0BaseAddr = (u32)SendBuff;//DMA 存储器0地址  

  65.     DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral;//存储器到外设模式  

  66.     DMA_InitStructure.DMA_BufferSize = SEND_BUF_SIZE;//数据传输量   

  67.     DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;//外设非增量模式  

  68.     DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;//存储器增量模式  

  69.     DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;//外设数据长度:8位  

  70.     DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;//存储器数据长度:8位  

  71.     DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;// 使用普通模式   

  72.     DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;//中等优先级  

  73.     DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;           

  74.     DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;  

  75.     DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;//存储器突发单次传输  

  76.     DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;//外设突发单次传输  

  77.     DMA_Init(DMA2_Stream7, &DMA_InitStructure);//初始化DMA Stream  

  78.     //DMA NVIC    

  79.     NVIC_InitStructure.NVIC_IRQChannel = DMA2_Stream7_IRQn;    

  80.     NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;    

  81.     NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;    

  82.     NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;    

  83.     NVIC_Init(&NVIC_InitStructure);    

  84.     DMA_ITConfig(DMA2_Stream7,DMA_IT_TC,ENABLE);  

  85.   

  86.     //****************************配置UART1接收  

  87.     DMA_DeInit(DMA2_Stream5);  

  88.     while (DMA_GetCmdStatus(DMA2_Stream5) != DISABLE);//等待DMA可配置   

  89.     /* 配置 DMA Stream */  

  90.     DMA_InitStructure.DMA_Channel = DMA_Channel_4;  //通道选择  

  91.     DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)&USART1->DR;//DMA外设地址  

  92.     DMA_InitStructure.DMA_Memory0BaseAddr = (u32)ReceiveBuff;//DMA 存储器0地址  

  93.     DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory ;//外设到存储器模式  

  94.     DMA_InitStructure.DMA_BufferSize = RECEIVE_BUF_SIZE;//数据传输量   

  95.     DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;//外设非增量模式  

  96.     DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;//存储器增量模式  

  97.     DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;//外设数据长度:8位  

  98.     DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;//存储器数据长度:8位  

  99.     DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;// 使用普通模式   

  100.     DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;//中等优先级  

  101.     DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;           

  102.     DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;  

  103.     DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;//存储器突发单次传输  

  104.     DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;//外设突发单次传输  

  105.     DMA_Init(DMA2_Stream5, &DMA_InitStructure);//初始化DMA Stream  

  106.     //DMA NVIC    

  107.     NVIC_InitStructure.NVIC_IRQChannel = DMA2_Stream5_IRQn;    

  108.     NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;    

  109.     NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;    

  110.     NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;    

  111.     NVIC_Init(&NVIC_InitStructure);    

  112.     DMA_Cmd(DMA2_Stream5, ENABLE);  //开启DMA传输   

  113.       

  114.     DMA_ITConfig(DMA2_Stream5,DMA_IT_TC,ENABLE);  

  115.       

  116. }  

  117.   

  118. //开启一次DMA传输  

  119. //DMA_Streamx:DMA数据流,DMA1_Stream0~7/DMA2_Stream0~7   

  120. //ndtr:数据传输量    

  121. void DmaSendDataProc(DMA_Stream_TypeDef *DMA_Streamx,u16 ndtr)  

  122. {  

  123.    

  124.     DMA_Cmd(DMA_Streamx, DISABLE);                      //关闭DMA传输   

  125.       

  126.     while (DMA_GetCmdStatus(DMA_Streamx) != DISABLE){}  //确保DMA可以被设置    

  127.           

  128.     DMA_SetCurrDataCounter(DMA_Streamx,ndtr);          //数据传输量    

  129.    

  130.     DMA_Cmd(DMA_Streamx, ENABLE);                      //开启DMA传输   

  131. }       

  132.   

  133. ///////////////////////////////////////////////////////////////////////////  

  134. //串口1  

  135. //发送单字节  

  136.  void SendByteInfoProc(u8 nSendInfo)  

  137. {  

  138.     u8 *pBuf = NULL;  

  139.     //指向发送缓冲区  

  140.     pBuf = SendBuff;  

  141.     *pBuf++ = nSendInfo;  

  142.   

  143.     DmaSendDataProc(DMA2_Stream7,1); //开始一次DMA传输!       

  144. }  

  145. //发送多字节  

  146. void SendBytesInfoProc(u8* pSendInfo, u16 nSendCount)  

  147. {  

  148.     u16 i = 0;  

  149.     u8 *pBuf = NULL;  

  150.     //指向发送缓冲区  

  151.     pBuf = SendBuff;  

  152.   

  153.     for (i=0; i

  154.     {  

  155.         *pBuf++ = pSendInfo[i];  

  156.     }  

  157.     //DMA发送方式  

  158.     DmaSendDataProc(DMA2_Stream7,nSendCount); //开始一次DMA传输!      

  159. }  

  160.   

  161. //发送完成中断  

  162. void DMA2_Stream7_IRQHandler(void)  

  163. {  

  164.     //清除标志  

  165.     if(DMA_GetFlagStatus(DMA2_Stream7,DMA_FLAG_TCIF7)!=RESET)//等待DMA2_Steam7传输完成  

  166.     {   

  167.         DMA_ClearFlag(DMA2_Stream7,DMA_FLAG_TCIF7);//清除DMA2_Steam7传输完成标志  

  168.     }  

  169. }  

  170. //接收完成中断  

  171. void DMA2_Stream5_IRQHandler(void)  

  172. {  

  173.     //清除标志  

  174.     if(DMA_GetFlagStatus(DMA2_Stream5,DMA_FLAG_TCIF5)!=RESET)//等待DMA2_Steam7传输完成  

  175.     {   

  176.         DMA_Cmd(DMA2_Stream5, DISABLE); //关闭DMA,防止处理其间有数据  

  177.   

  178.         UART1_ReceiveSize =RECEIVE_BUF_SIZE - DMA_GetCurrDataCounter(DMA2_Stream5);  

  179.         if(UART1_ReceiveSize !=0)  

  180.         {  

  181.             OSSemPost(DMAReceiveSize_Sem);  

  182.         }  

  183.           

  184.         DMA_ClearFlag(DMA2_Stream5,DMA_FLAG_TCIF5 | DMA_FLAG_FEIF5 | DMA_FLAG_DMEIF5 | DMA_FLAG_TEIF5 | DMA_FLAG_HTIF5);//清除DMA2_Steam7传输完成标志  

  185.         DMA_SetCurrDataCounter(DMA2_Stream5, RECEIVE_BUF_SIZE);  

  186.         DMA_Cmd(DMA2_Stream5, ENABLE);     //打开DMA,  

  187.     }  

  188. }  

  189.   

  190. //空闲中断  

  191. void USART1_IRQHandler(void)  

  192. {  

  193.     u16 data;  

  194.     if(USART_GetITStatus(USART1,USART_IT_IDLE) != RESET)  

  195.     {  

  196.         DMA_Cmd(DMA2_Stream5, DISABLE); //关闭DMA,防止处理其间有数据  

  197.   

  198.         data = USART1->SR;  

  199.         data = USART1->DR;  

  200.           

  201.         UART1_ReceiveSize =RECEIVE_BUF_SIZE - DMA_GetCurrDataCounter(DMA2_Stream5);  

  202.         if(UART1_ReceiveSize !=0)  

  203.         {  

  204.             OSSemPost(DMAReceiveSize_Sem);  

  205.         }  

  206.         DMA_ClearFlag(DMA2_Stream5,DMA_FLAG_TCIF5 | DMA_FLAG_FEIF5 | DMA_FLAG_DMEIF5 | DMA_FLAG_TEIF5 | DMA_FLAG_HTIF5);//清除DMA2_Steam7传输完成标志  

  207.         DMA_SetCurrDataCounter(DMA2_Stream5, RECEIVE_BUF_SIZE);  

  208.         DMA_Cmd(DMA2_Stream5, ENABLE);     //打开DMA,  

  209.   

  210.     }  

  211. }   



关键字:STM32F4  UART1  DMA  发送和接收  数据 引用地址:STM32F4 UART1 DMA发送和接收不定长度数据

上一篇:STM32F407时钟树
下一篇:STM32关闭全局中断时需要注意的问题

推荐阅读最新更新时间:2024-03-16 15:38

电动汽车和数据中心的热管理的未来
在电动车(EV)技术发展中,电池的角色至关重要。然而,为了实现整车性能的最优化,动力系统的综合考量和对乘客舱温度调节系统的协同作用不容忽视。其中,电机和电力电子设备的热管理同电池的重要性不相上下。 过往,电动车市场主要采用被动冷却或强迫空气冷却电池技术,如今这一趋势已转向利用冷板和冷却通道的液体冷却。据研究,95%的电动汽车市场已采纳该技术。进一步来看,以单体直接组装(cell-to-pack)和单体直接车身(cell-to-body)为代表的电池集成设计,由于倾向于使用大型单体,减少了冷板设计的复杂度。比如,比亚迪的刀片电池组只需单一大型冷板即可。特斯拉的4680电池包因单体数量减少,降低了对冷却通道的需求。 与此同
[嵌入式]
电动汽车和<font color='red'>数据</font>中心的热管理的未来
Keil MDK STM32系列(七) STM32F4基于HAL的PWM定时器
配置 PWM 输出 选择芯片 System Core - SYS- Debug: Serial Wire 防止下次无法烧录 System Core - RCC- High Speed Clock (HSE): Crystal/Ceramic Resonator 启用外接高速晶振 Clock Configuration: (配置为最高84MHz)选择外部晶振, 把HSE和PLLCLK连上, 在HCLK上输入84回车, 软件会自动调节各节点倍数 Timers - TIM2 Clock Source: Internel Clock, 使用系统的时钟源 Channelx: PWM Generation CHx PWM输出 Counter
[单片机]
行走的“数据库”,Crucial英睿达 X6 4TB系列问市
美光的电脑内存和存储全球消费品牌 Crucial® 英睿达™今天推出了备受认可的移动固态硬盘 (SSD) 产品组合的扩展产品,以丰富的价位为消费者提供更多的外部存储性能、容量和价值选择。即将上市的新产品包括高性能 4TB 移动固态硬盘,预计售价约为人民币3,999元;以及新推出的 500GB 移动固态硬盘,预计售价约为人民币579元。希望存储大型游戏库或为长途旅行存储更多电影的消费者将在 Crucial 英睿达 X6 中找到理想的解决方案。 美光消费产品事业部副总裁兼总经理 Teresa Kelley 表示:“我们的客户正在寻找价格合理、便捷、快速、可靠的存储方法,X6 移动固态硬盘产品线新增的两个容量选择进一步证明了
[嵌入式]
行走的“<font color='red'>数据</font>库”,Crucial英睿达 X6 4TB系列问市
USB总线数据采集设备驱动程序的设计
  0 引言   随着计算机应用技术的发展,虚拟仪器、自动测试系统、自动控制等领域,均越来越多的应用计算机来进行数据处理。USB总线标准的提出,解决了计算机传统I/O接口通用性差、不易扩展、易受计算机插槽数量、地址和中断资源的限制等缺点,使计算机在测控领域的重要性与日俱增,也使USB总线在数采测控业界备受关注,并在各种测控设备中迅速发展,但专用的USB设备不能像鼠标、键盘等HID类设备一样使用Windows系统提供的标准驱动程序,而是需要开发专用的驱动程序。开发驱动程序与开发Windows应用程序完全不同,驱动程序以系统的内核模式运行,任何细小的错误都可能引起操作系统的崩溃。因此,专用设备驱动程序开发的复杂性,成为了USB总线
[嵌入式]
三星电子挑战6G数据传输纪录
为评估下一代网络蜂窝设备,韩国三星电子表示将在美国得克萨斯州普莱诺周边1公里距离内,进行12.7GHz—13.25GHz频段的6G测试。三星电子美国分部日前已向美国联邦通信委员会(FCC)申请无线电频率使用许可。 2021年底,三星电子曾在得克萨斯州针对500米距离申请无线电频率使用许可,并进行了6G测试。此次申请的测试距离再次增加,若测试成功,将刷新6G数据的传输距离纪录。 值得关注的是,三星电子此次计划在12.7GHz—13.25GHz频段进行测试,由于此前测试多使用100GHz以上频段,此次与之前测试相比频段大幅下降,三星在申请中明确阐明了将该频段范围用于6G的计划。目前业界正在讨论6G频段划分标准,三星电子在向FCC提交的
[网络通信]
LabVIEW在暖通空调数据采集控制系统的应用
   引言   LabVIEW 大量应用在自动控制领域,对于HVAC系统中采用LabVIEW作为上位端软件还不多见,但随着LabVIEW 7 Express的发布,LabVIEW已经开始逐渐渗透到各个领域。在笔者所在专业HVAC自动控制领域使用LabVIEW后发现,其功能十分强大,节省系统开发时间,非常适合工程开发人员使用。笔者结合近来开发的一套HVAC系统,对LabVIEW在HVAC数据采集控制系统的应用做个介绍。    1 系统总体结构   HVAC中有大量数据需要采集,通过对数据的采集,来对各项系统参数进行调整。本系统主要由水系统、风系统、控制系统组成。   ● 水系统包括:水冷式冷水机组,冷却塔,膨胀水箱,冷冻水泵
[测试测量]
LabVIEW在暖通空调<font color='red'>数据</font>采集控制系统的应用
您的数据策略达到高可用性了吗?
据Gartner估算,服务宕机一分钟带来的损失可超过5600美元,并且这个数字正在不断攀升。目前,大部分企业缺乏适合自身情况同时具有高可用性的数据策略,以应对不断增加的风险,保证业务的连续性。 造成企业宕机的主要原因是什么? 多产品、多供应商的数据备份方式会限制企业备份和恢复架构的敏捷性和可用性,从而加剧意外宕机发生的风险。然而,企业可以通过单个供应商部署一个全面的数据管理平台,来消除多种产品同时使用带来的宕机风险。 IDC机构的《量化Commvault软件的商业价值——全球客户调查分析》报告中指出,相比使用多个产品和供应商的企业,采用单一平台进行数据备份和恢复的企业可使宕机时间减少55%。 随着基础设施简化、IT
[网络通信]
移动医疗浪潮来袭 数据加密备受关注
    随着现代医疗技术的进步和人们对健康状况的重视,医疗领域迎来了繁荣发展期,各大医疗机构如雨后春笋般纷纷涌现。医疗作为与人们的身体健康息息相关的一部分,也关系着国民经济的命脉。随着信息化的全面发展,医疗行业也纳入到了移动互联网的触及范围之中,推动着医疗业的快速发展。移动医疗有着十分可观的发展前景,据市场调查显示,到2018年移动医疗行业将产生118亿美元的市场营收。 移动医疗浪潮来袭,发展前景可观     与传统的纸笔记录病历、纸张保存病人资料和数据信息相比,互联网的介入大大提高了工作效率,带来的效益不仅体现在医疗成本的减少,还有医疗质量的提升、信息管理效率的提高,移动医疗为我们带来的巨大价值体验在:     1、
[医疗电子]
小广播
添点儿料...
无论热点新闻、行业分析、技术干货……
热门活动
换一批
更多
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

更多精选电路图
换一换 更多 相关热搜器件
更多每日新闻
随便看看
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved