历史上的今天
返回首页

历史上的今天

今天是:2025年06月08日(星期日)

正在发生

2018年06月08日 | STM32 串口采用DMA方式接收数据

2018-06-08 来源:eefocus

环境:

主机:WINXP

开发环境:MDK4.23

MCU:STM32F103CBT6


说明:

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

方法有以下3种:

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

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

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

本文采用第3种方式.在波特率576000下大数据包冲击证明可行.


源代码:


  1. //串口接收DMA缓存  

  2. #define UART_RX_LEN     128  

  3. extern uint8_t Uart_Rx[UART_RX_LEN];  



  1. //串口接收DMA缓存  

  2. uint8_t Uart_Rx[UART_RX_LEN] = {0};  



  1. //---------------------串口功能配置---------------------  

  2.     //打开串口对应的外设时钟    

  3.     RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 , ENABLE);   

  4.     //串口发DMA配置    

  5.     //启动DMA时钟  

  6.     RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);  

  7.     //DMA发送中断设置  

  8.     NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel4_IRQn;  

  9.     NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3;  

  10.     NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;  

  11.     NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;  

  12.     NVIC_Init(&NVIC_InitStructure);  

  13.     //DMA1通道4配置  

  14.     DMA_DeInit(DMA1_Channel4);  

  15.     //外设地址  

  16.     DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)(&USART1->DR);  

  17.     //内存地址  

  18.     DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)Uart_Send_Buffer;  

  19.     //dma传输方向单向  

  20.     DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;  

  21.     //设置DMA在传输时缓冲区的长度  

  22.     DMA_InitStructure.DMA_BufferSize = 100;  

  23.     //设置DMA的外设递增模式,一个外设  

  24.     DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;  

  25.     //设置DMA的内存递增模式  

  26.     DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;  

  27.     //外设数据字长  

  28.     DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;  

  29.     //内存数据字长  

  30.     DMA_InitStructure.DMA_MemoryDataSize = DMA_PeripheralDataSize_Byte;  

  31.     //设置DMA的传输模式  

  32.     DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;  

  33.     //设置DMA的优先级别  

  34.     DMA_InitStructure.DMA_Priority = DMA_Priority_High;  

  35.     //设置DMA的2个memory中的变量互相访问  

  36.     DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;  

  37.     DMA_Init(DMA1_Channel4,&DMA_InitStructure);  

  38.     DMA_ITConfig(DMA1_Channel4,DMA_IT_TC,ENABLE);  

  39.       

  40.     //使能通道4  

  41.     //DMA_Cmd(DMA1_Channel4, ENABLE);  

  42.   

  43.     //串口收DMA配置    

  44.     //启动DMA时钟  

  45.     RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);  

  46.     //DMA1通道5配置  

  47.     DMA_DeInit(DMA1_Channel5);  

  48.     //外设地址  

  49.     DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)(&USART1->DR);  

  50.     //内存地址  

  51.     DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)Uart_Rx;  

  52.     //dma传输方向单向  

  53.     DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;  

  54.     //设置DMA在传输时缓冲区的长度  

  55.     DMA_InitStructure.DMA_BufferSize = UART_RX_LEN;  

  56.     //设置DMA的外设递增模式,一个外设  

  57.     DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;  

  58.     //设置DMA的内存递增模式  

  59.     DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;  

  60.     //外设数据字长  

  61.     DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;  

  62.     //内存数据字长  

  63.     DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;  

  64.     //设置DMA的传输模式  

  65.     DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;  

  66.     //设置DMA的优先级别  

  67.     DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh;  

  68.     //设置DMA的2个memory中的变量互相访问  

  69.     DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;  

  70.     DMA_Init(DMA1_Channel5,&DMA_InitStructure);  

  71.   

  72.     //使能通道5  

  73.     DMA_Cmd(DMA1_Channel5,ENABLE);  

  74.       

  75.         

  76.     //初始化参数    

  77.     //USART_InitStructure.USART_BaudRate = DEFAULT_BAUD;    

  78.     USART_InitStructure.USART_WordLength = USART_WordLength_8b;    

  79.     USART_InitStructure.USART_StopBits = USART_StopBits_1;    

  80.     USART_InitStructure.USART_Parity = USART_Parity_No;    

  81.     USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;    

  82.     USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;      

  83.     USART_InitStructure.USART_BaudRate = DEFAULT_BAUD;   

  84.     //初始化串口   

  85.     USART_Init(USART1,&USART_InitStructure);    

  86.     //TXE发送中断,TC传输完成中断,RXNE接收中断,PE奇偶错误中断,可以是多个     

  87.     //USART_ITConfig(USART1,USART_IT_RXNE,ENABLE);  

  88.       

  89.     //中断配置  

  90.     USART_ITConfig(USART1,USART_IT_TC,DISABLE);  

  91.     USART_ITConfig(USART1,USART_IT_RXNE,DISABLE);  

  92.     USART_ITConfig(USART1,USART_IT_IDLE,ENABLE);    

  93.   

  94.     //配置UART1中断    

  95.     NVIC_PriorityGroupConfig(NVIC_PriorityGroup_3);  

  96.     NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;               //通道设置为串口1中断    

  97.     NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;       //中断占先等级0    

  98.     NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;              //中断响应优先级0    

  99.     NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;                 //打开中断    

  100.     NVIC_Init(&NVIC_InitStructure);     

  101.           

  102.     //采用DMA方式发送  

  103.     USART_DMACmd(USART1,USART_DMAReq_Tx,ENABLE);  

  104.     //采用DMA方式接收  

  105.     USART_DMACmd(USART1,USART_DMAReq_Rx,ENABLE);  

  106.     //启动串口    

  107.     USART_Cmd(USART1, ENABLE);   



  1. //串口1接收中断     

  2. void USART1_IRQHandler(void)                                 

  3. {     

  4.     uint32_t temp = 0;  

  5.     uint16_t i = 0;  

  6.       

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

  8.     {  

  9.         //USART_ClearFlag(USART1,USART_IT_IDLE);  

  10.         temp = USART1->SR;  

  11.         temp = USART1->DR; //清USART_IT_IDLE标志  

  12.         DMA_Cmd(DMA1_Channel5,DISABLE);  

  13.   

  14.         temp = UART_RX_LEN - DMA_GetCurrDataCounter(DMA1_Channel5);  

  15.         for (i = 0;i < temp;i++)  

  16.         {  

  17.             Data_Receive_Usart = Uart_Rx[i];  

  18.             //启动串口状态机  

  19.             usart_state_run();   

  20.         }  

  21.   

  22.         //设置传输数据长度  

  23.         DMA_SetCurrDataCounter(DMA1_Channel5,UART_RX_LEN);  

  24.         //打开DMA  

  25.         DMA_Cmd(DMA1_Channel5,ENABLE);  

  26.     }   

  27.       

  28.     __nop();   

  29. }   


测试结果:

条件:单片机运行于72M,与PC通信速率为460800.PC每隔100ms发送一个9个字节的包:c5 5c 6 0 6F 10 5 4e f7.

测试:单片机每次收到此包,一个IO作电平跳转,然后处理返回一包.

示波器显示:


放大显示:


推荐阅读

史海拾趣

C-TON Industries公司的发展小趣事

在电子行业中,产品质量的稳定性是企业生存的关键。C-TON深知这一点,因此从公司成立之初就高度重视品质管理。公司建立了一套严格的质量检测体系,确保每一件产品都符合高标准的质量要求。此外,C-TON还不断引进先进的生产设备和技术,提升生产效率和产品质量。这些努力使得C-TON的产品在市场上获得了良好的口碑,也为其赢得了众多忠实客户。

Able Systems公司的发展小趣事

随着电子行业的不断变革,Able Systems公司也面临着新的挑战。例如,新技术的出现、市场需求的变化等都对公司的发展提出了新的要求。然而,Able Systems始终保持着敏锐的市场洞察力,不断调整战略,积极应对挑战。通过不断创新和改进,公司成功克服了各种困难,保持了稳健的发展态势。

台湾三礼(3L)公司的发展小趣事

1991年,三礼公司正式成立了美国分公司(3LU),此举标志着公司开始进军北美市场,将其作为货物管理中心,并与G-TEP合作组建了3L Global Co.(3LG),共同开拓和发展所有北美业务。这一战略决策为三礼公司打开了新的增长通道,使得公司能够更好地服务全球客户,提升品牌影响力。

成都成电硅海公司的发展小趣事

在电子行业中,知识产权的保护尤为重要。成都成电硅海公司非常重视知识产权的申请和保护工作。公司成立了专门的知识产权部门,负责专利、商标等知识产权的申请和管理。同时,公司还积极参与各种知识产权的维权行动,维护自身的合法权益。这种对知识产权的重视和保护,不仅提升了公司的核心竞争力,也为公司在电子行业的发展提供了有力的法律保障。

ATP [ATP Electronics]公司的发展小趣事

面对工业应用领域的特殊需求,ATP敏锐地捕捉到了市场机遇。公司成功推出了业界首款工业级SLC e.MMC产品E800Pi,这款产品以其高达6万次的单元擦写耐久性和出色的耐高温、交叉温度能力,受到了工业领域的广泛认可。E800Pi的推出,不仅拓宽了ATP的产品线,也进一步提升了公司在工业存储解决方案领域的市场地位。

雅特力(Artery)公司的发展小趣事

雅特力公司自成立以来,始终致力于技术创新和产品升级。在早期的发展阶段,公司便推出了一系列具有竞争力的电子产品,通过不断的技术突破,逐渐在市场中占据了一席之地。特别是在集成电路设计领域,雅特力凭借其高效能、低能耗的产品特性,赢得了众多客户的青睐。随着技术的不断进步,雅特力逐渐成为了电子行业的佼佼者,引领着市场的发展方向。

问答坊 | AI 解惑

关于dvb-mhp标准的问题?

本帖最后由 jameswangsynnex 于 2015-3-3 19:59 编辑 最近mhp发布了它的专利费收取情况,除了设备提供上的每台$2\\运营商的每台$1.5/用户的25美分外,是否还需要交其他的费用?例如交给sun公司关于java方面的专利费? 哪位大侠知情,告知一下,谢 ...…

查看全部问答>

模拟厂商如何应对手机产品提出的挑战?

整个手机产业目前的状况似乎已经陷入一种以价格竞争的阶段,有点像电视机市场。手机好像已经不属于我们印象中的高科技产品,几百块钱的手机就已经具备很丰富的功能,如音乐、拍照、摄像、手写输入、超大的触摸屏,真令人不可思议。用Intersil公司中 ...…

查看全部问答>

TSB11

老师,我还少一个MC14433…

查看全部问答>

汇编的基础问题

在51单片机中,汇编程序出现如下: Org 0000h; Ljmp main; Org 0100h; Main:------- 然而:有人写成这样: Org 0100h; Ljmp main; Main:------ 两者相同吗? 为什么? 为什么要从100h开始? 老师讲过最少从30h开始,原 ...…

查看全部问答>

??怎样屏蔽外部中断??

我用的是2450,要在某些时刻屏蔽外部中断0,5~13一共10个外部中断中的部分中断。 我想可能有两种方法吧(不知道是不是): 1.对中断寄存器操作;  2.调用API 对于第一种方法,我参考了一下三星的使用手册,知道关键是操作INTMASK寄存 ...…

查看全部问答>

怎样获得spy在shell中打印的某个数据呢?

各位高手,在shell中用spy可以查看各个任务以及总的cpu利用率,并用一个表列出结果,现在我只想取出空闲率这个数据,请问该怎样实现呢?…

查看全部问答>

在Linux中安装turbo c

我现在刚开始学嵌入式开发,要用到c语言开发,我想请问一下怎么样在Linux虚拟机中安装turbo c,我用的Linux是 RedHat 9.0版本…

查看全部问答>

LM3开发笔记_5.ADC采集

       由于项目需要监测一些模拟量所以要用到ADC,这两天试了试LM3S8962的ADC功能,有一些收获,不敢独享和拿出来和大家分享。          ADC用于将连续变化的模拟电压转换成 ...…

查看全部问答>

自己做的LM3S9B96的板子,HJTAG无法识别

有没有兄弟遇到过相同的问题啊,jtag电路是和开发板上的一样,加了27欧电阻,TMS加了上拉电阻,其他信号线没上拉,h-jtag可以识别开发板的内核ID,但是无法识别自己做的板子的。后来在其他信号线上也加了上拉,还是无法识别。外部16M晶振起振,引脚 ...…

查看全部问答>

9B96的EPI模块能用于并行接口的AD吗?

如题,9B96的EPI模块能用于访问并行接口的AD吗? EPI模块为什么要强调地址总线,还有EPI时钟,这些好像不是为AD这样的东西准备的吧,那是不是说EPI模块就不能用于访问并行接口的AD呢? 完全不懂,请大家不要见笑,多多指教我哦………

查看全部问答>