你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

(已公布)狂欢节答题(附加题)  关闭

[复制链接]
zero99 提问时间:2017-11-28 10:05 /
附加题
自行选型一个STM32的单片机,要求输出4路可控制脉冲数的高速脉冲,必须要尽可能的节省CPU时间,而且不能频繁的进入中断(只需提供解决方案,不用代码)



虽然是附加题,还是希望大家能参与进来。或者,你最认同哪三位的答案呢?



答案如下
利用主从定时器协助的方式来进行对STM32外设的极致使用,答DMA是要扣分的。(采用DMA方式,在高速的时候会过多的占用总线时间,不符合题目中的尽可能的节省CPU时间的目地
1、自行选型一款STM32单片机,考得选型能力,根据项目要求选出一款比较合适的芯片
2、输出4路高速脉冲并且脉冲数可控,节省CPU,并且少进入中断,考的是对STM32的外设理解能力以及主从定时器协助能力



本题最佳答案为:@nyszx,其次是:@dsjsif @landeng1986

@dsjsif 虽然也指出了定时器的协助,但是并没有实际指出定时器如何具体的搭配和解决思路
@landeng1986 虽然指出了主从搭配,然而并没有从实际上进行设计题目所问道的实际解决方案
@wolfgang2015的回复有待商榷,@zeropandragon 回答不对







本帖为 #狂欢节第二波# 活动的附加题,也是最后一题,决定前3的最终排名DISC归属

本题为开放性题目,届时会根据答题结果,进行点评&排名


答题时间:2017年11月28日 10:00  -  11月30日 10:00 (两天)


本题由@nyszx、@landeng1986、@Zeyo_Pendragon、@wolfgang2015、@dsjsjf 5位大佬参加,其他网友也可以参加(但不计分)


另外,
请在第二波活动中答对3题及以上(即积分榜蓝色区域)的小伙伴,请速速把STM32中文官网注册邮箱私信给我(通过第一波活动的无需再次提供~)
查看答题积分榜>>(帖末)












收藏 评论35 发布时间:2017-11-28 10:05

举报

35个回答
nyszx 回答时间:2017-11-29 21:46:51
题目分析:
自行选择一个STM32,为啥不来点干脆的,直接指定型号,毕竟STM32产品线上有11个系列,将近800个型号,从中选择还是难度的,还好,ST提供了很多工具,比如:STMCUFinder、STM32CubeMX可以大大简化选型难度。要求4路可控脉冲数的高速脉冲,节省CPU时间,而且不能频繁的进入中断。重点来了,4路(独立?)、可控脉冲数、高速脉冲(有多高?),节省CPU,中断少。第一反应就想到了STM32强大的外设:定时器/HRTIM,通过外设自己工作才能不耽误CPU。因此通过工具搜索初步定下来在速度快常用的F3/F4以及F7/H7系列,F7/H7对于我这个菜鸟来说太高大上,就在F3/F4中选择,发现F3在电机控制上非常厉害,有强大的HRTIM,但是此题要求的是可控高速脉冲,发现F3在此处似乎并不太合适,F3适合在高精度“花样”控制中,也许是自己低估它了,反正放弃了,最终选择了F4系列。以上废话可忽略,以下才是重点。
解决方案:使用多个定时器,工作在主从模式,
主定时器负责高速脉冲输出,工作在主模式,设定为PWM 模式1,CH1输出脉冲,脉宽设定为50%占空比,频率可调,开启自动装载功能,设定MMS用作从定时器的预分频器。
从定时器负责计数,工作在从模式,选择内部触发,并开启UIE, 在中断中控制主定时器的启停。
从来没这么用过,第一次,也算是为了学习,为了简单,选择4个主定时器、4个从定时器,这样一算就要8个定时器,还好,STM32最多的定时器有18个之多,看F4系列的参考手册,可以这样组合:
3主、2从;4主5从;10主、9从;13主12从;这样组合出4路独立的组合,而且都使用ITR2触发。除了F411有11个定时器外F4其他系列都有17个定时器,且APB1 Timer 时钟高达84MHz  APB2Timer 时钟高达168MHz 主频达到168MHz完全胜任,因便宜的F407系列就能满足。
方案验证:
手头有一块F411RE的NUCLEO板,因此就拿他进行验证。查看数据手册F411有1、2、3、4、5、9、10、11,除了9以为都支持主模,除了10、11都支持从模式,遗憾的是只能有三组满足,不过用于验证还是可以的,一组能实现,其他的也类似,输出100KHz高速脉冲,题目没要求多少算高速,按PLC常规的脉冲输出有20Khz\100Khz\200Khz\400Khz,所以就按100KHz做应该满足题目要求吧。
部分测试代码(HCLK=APB1 Timer =[url=]APB2 Timer=100MHz [/url]):
TIM3主、TIM2从
  1. void TIM2_IRQHandler(void)
  2. {
  3.        
  4.         if (TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET)
  5.   {
  6.                 TIM3->CR1 &= (uint16_t)~TIM_CR1_CEN;
  7.                 TIM3->CCER &= (uint16_t)~0x001;
  8.                 TIM2->CNT=0;
  9.                 TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
  10.                 TIM_Cmd(TIM2, DISABLE);
  11.         }
  12.        
  13. }

  14. void OutputPulseOne(u32 Cycle,u32 PulseNum)
  15. {
  16.     GPIO_InitTypeDef GPIO_InitStructure;
  17.     TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
  18.     TIM_OCInitTypeDef  TIM_OCInitStructure;
  19.                 NVIC_InitTypeDef NVIC_InitStructure;
  20.        
  21.                 //脉冲管脚配置
  22.                 RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
  23.                
  24.                 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 ;             //TIM3_CH1输出脉冲
  25.                 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
  26.                 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
  27.                 GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
  28.                 GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
  29.                 GPIO_Init(GPIOA, &GPIO_InitStructure);

  30.                 GPIO_PinAFConfig(GPIOA, GPIO_PinSource6, GPIO_AF_TIM3);
  31.        
  32.                 //主定时器配置TIM3
  33.                 RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
  34.        
  35.                 TIM_TimeBaseStructure.TIM_Period = Cycle-1;                                                                 //脉冲频率
  36.                 TIM_TimeBaseStructure.TIM_Prescaler = 0;                   //不分频
  37.                 TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;//TIM向上计数模式
  38.                 TIM_TimeBaseStructure.TIM_ClockDivision = 0;               //设置时钟不分割
  39.                 TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;
  40.        
  41.     TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);                                       

  42.     TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;             //选择定时器模式:TIM脉冲宽度调制模式1      
  43.     TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //比较输出使能
  44.     TIM_OCInitStructure.TIM_Pulse = Cycle/2;                       //设置待装入捕获寄存器的脉冲值                                   
  45.     TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low;      //输出极性   
  46.                 TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Reset;   //空闲为低
  47.                 TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCIdleState_Reset;
  48.                
  49.     TIM_OC1Init(TIM3, &TIM_OCInitStructure);                                                         

  50.     TIM_SelectMasterSlaveMode(TIM3, TIM_MasterSlaveMode_Enable);        //启用主从模式
  51.     TIM_SelectOutputTrigger(TIM3, TIM_TRGOSource_Update);                                        //主定时器可用作从定时器的预分频器

  52.     TIM_OC1PreloadConfig(TIM3, TIM_OCPreload_Enable);                                                 //输出比较2预装载使能                           
  53.     TIM_ARRPreloadConfig(TIM3, ENABLE);                           //自动重载预装载使能  
  54.                
  55.                 //从定时器配置 TIM2               
  56.     RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);

  57.     TIM_TimeBaseStructure.TIM_Period = PulseNum;   
  58.     TIM_TimeBaseStructure.TIM_Prescaler =0;   
  59.     TIM_TimeBaseStructure.TIM_ClockDivision = 0;     
  60.     TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  
  61.     TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);  

  62.     TIM_SelectInputTrigger(TIM2, TIM_TS_ITR2);
  63.                 TIM_SelectSlaveMode(TIM2,TIM_SlaveMode_External1 );//为外部时钟模式SMCR 寄存器中的 SMS=111
  64.        

  65.        
  66.     TIM_ITConfig(TIM2,TIM_IT_Update,DISABLE);

  67.     NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
  68.     NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;        
  69.     NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
  70.     NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;     
  71.     NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  72.     NVIC_Init(&NVIC_InitStructure);
  73.                
  74.                 //启动工作
  75.     TIM_ClearITPendingBit(TIM2,TIM_IT_Update);
  76.     TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);
  77. TIM_Cmd(TIM2, ENABLE);
  78.     TIM_Cmd(TIM3, ENABLE);
  79. }
复制代码
OutputPulseOne(160,10)代表100KHz,10个脉冲
另外一组类似,使用的是TIM4主、TIM5从
效果如图:
两组同时输出15个脉冲、和10个脉冲
微信图片_20171129213051.jpg
两组同时输出10个脉冲、和6个脉冲
微信图片_20171129213103.jpg
两组同时输出8个脉冲、和8个脉冲
微信图片_20171129213119.jpg
两组尝试150KHz 输出10个脉冲、和10个脉冲
微信图片_20171129213136.jpg
最后附上已经摧残过很多次的F411板子
微信图片_20171129213125.jpg
此方案没有处理计数超过定时器定时溢出时的方法,可以通过中断来循环计数实现,扩展可实现4组输出,应该实现了题目要求,自己水平有限,就不在此班门弄斧了,期待学习高手更好的方案。

wolfgang 回答时间:2017-12-4 12:27:07
本帖最后由 wolfgang2015 于 2017-12-4 13:34 编辑
自行选型一个STM32的单片机,要求输出4路可控制脉冲数的高速脉冲,必须要尽可能的节省CPU时间,而且不能频繁的进入中断(只需提供解决方案,不用代码)

说到脉冲可控,控制的方法很种类很多,频率、数量、脉宽等等,从脉冲控制方式诞生的开始就有多种技术来实现,从无集成电路方案的晶体管、电子管、555、8051、再到各种ARM,应用领域不可说不广从单路再到多路控制,特别是多路互补PWM在步进电机领域有很重要的使用。

个人认为本地题的关键词
第一层为:
    4路、可控制、脉冲数、高速脉冲
第二层为:
   节省CPU时间
第三层为:
   不能频繁的进入中断

至于是否需要“多路正交“"用脉冲来代替正弦波" 等都不是该题目明确表达的内容及含义,因此应排除指定用途,因此这题目的答案就不能按某特定用途的解决方式来解决。

输出脉冲,最简单的就是控制PIN脚的电平高低,再计数获得电平高低输出时间长短 和 这种波形的电平周期性来获得一定数量的脉冲信号。

高速脉冲信号:那么这就需要涉及到高速脉冲的测量,拿示波器是一个方法。达到一定频度的持续脉冲就是高速脉冲。另外的一个就是用MCU自身的定时器来测量高速脉冲。

如果要测量4路就需要4个定时器来测量(这是做产品时要考虑的,现在题目没有要求测量可不考虑这项内容,但做产品时需要考虑的更多)。

可控制、脉冲数:这里要求的是脉冲数量有要求。
利用外设手段来控制脉冲数量是重点
可控的因素有,MCU计数、计数器、数组等方法。都是计数的方法,这就是一些控制数量的方法;
利用定时器来计数,那么要在判断定时器数量要求。
数组来计数,利用数组的长度来计数。
从数量感知来说,可以在脉冲输出后感知计数,另外需要在脉冲源侧进行计数输出。


接着第二层说了:节省CPU时间
这里就排除用MCU来计数的方法,需要利用外设计数,这里就有几种方法 计数器、DMA等方法节省CPU时间。


第三层不能频繁的进入中断
这里提到了中断,不能频繁进入,不是不能进入,而是计数时进入中断的频率不能太频繁。
1、利用输出后的感知来计数时,每次计数都是一次中断,占用大量的MCU中断所以不可取;

2、利用输出源的计数,用一个计数器来计算次数、用一个计数器来控制脉冲,这里有一种技术可以利用,就是溢出,出现了溢出中断,就停止发送脉冲。好方法。。。。

3、利用DMA数组+1的方法来发送,发送的次数限制,受数组的大小,这也是好方法。。。

当需要对2和3比较二者优劣时,就要分析两者边界问题上的影响:
1、中断与数组控制范围?
2、中断与数组控制触发的时间长短,是否对脉冲数量产生影响?
3、定时器与DMA的中断是否会被拦截屏蔽,拦截屏蔽后对脉冲数量输出是否有影响?
4、在中断相同优先级下,是否能准确控制脉冲数量?

wolfgang 回答时间:2017-11-28 11:21:12
本帖最后由 wolfgang2015 于 2017-11-28 18:02 编辑

自行选型一个STM32的单片机,要求输出4路可控制脉冲数的高速脉冲,必须要尽可能的节省CPU时间,而且不能频繁的进入中断(只需提供思路&方法,不用代码)

题目思路分析:
   1、“输出4路可控脉冲“, 需要用到的MCU定时器资源进行脉宽调制(PWM,所以,高级定时器 T1、T8,及普通定时器T2~T5就能满足;
   2、"必须要尽可能的节省CPU时间,而且不能频繁的进入中断",              需要降低控制MCU控制寄存器频度和数量,将MCU的工作量释放出来,这里选用DMA进行数据传递;选择DMA就需要MCU的参考对定时器进行选型,要选择具备4通道DMA输出的定时器方可使用,比如Timer1、Timer3。其他某些DMA通道缺失或者通道不够的定时器需加以排除;
             另外,不能频繁的进入中断,而且是满足"高速"最先可以使用DMA数组的方式进行,将发送脉冲数组+1的数量(数组最后一个字为0,表示停发脉冲)作为DMA数组;如果发送高速脉冲数超过65535个,则可以使用DMA传输完成中断中切换DMA传输的数据起始地址及发送数量,继续发送。

   3、使用CubeMx将芯片选择、定时器选择、DMA选择好,使用HAL方式输出代码,让代码具备
以下功能关键点:
     以选用的MCU是STM32F401RE(84MHz主频设置)为例:
     1)在CubeMx界面中,选中Tim3定时器中Channel1()、Channel2()、Channel3()、Channel4() 的下拉框,分别配置 PWM Generation CH1PWM Generation CH2PWM Generation CH3PWM Generation CH4

     2)在TIM3配置界面里,将Prescaler设置为84-1,Counter Period设置为1000-1, 脉宽调制的波形频率为1KHz。如果高速,可以调节分频系数,增加DMA队列中需发送脉冲数量,以达到高速脉冲频率的发送要求。

     3)占空比默认为0,极性为低电平;

     4)DMA设置中,分别将TIM3_CH1、TIM3_CH2、TIM3_CH3、TIM3_CH4 对应的DMA数据流(DMAx Stream);

     5)生成代码后,观察stm32f4xx_hal_msp.c 文件中中 HAL_TIM_PWM_MspInit(......)函数中具备 DMA和Timer的相关配置函数;

     6) PWM输出的数量通过DMA数组的方式来定义,能降低对中断的调用次数。         启动DMA命令 HAL_TIM_PWM_Start_DMA(......)
         或者用 HAL_TIM_PWM_Start() 配合 HAL_TIM_DMABurst_WriteStart()函数来实现脉冲数的发送。









zero99 回答时间:2017-11-28 10:05:47
MARK MARK MARK
Zeyo_Pendragon 回答时间:2017-11-28 12:11:35
STM32L432KC
采用TIM2的4个比较/捕获通道加DMA可以产生出4路不同频率和占空比的方波
1)脉冲宽度一致,DMA地址不增加;
2)脉冲频率不同,设置不同的装载值,PWM使用单次触发。
3)发送的脉冲数超过65535个,使用DMA传输完成中断切换DMA传输的数据起始地址及发送数量,继续发送
ddllxxrr 回答时间:2017-11-28 13:56:03
用DMA就行,不占用CPU时间
landeng 回答时间:2017-11-29 01:07:29
选择STM32F302R8T6,前面电机控制培训刚用过的。
主要参考应用笔记AN4776,利用STM32定时器输出指定脉冲个数。
STM32定时器的单脉冲输出功能,让定时器在某个事件触发后的一段时间产生指定脉宽的单脉冲信号。
计数器的启动可由从模式控制器控制,可由比较输出模式或PWM输出模式来产生波形。

例:通过使用STM32定时器的主从模式实现周期性地输出指定数目的脉冲:
TIMER2与TIMER1主从连接,实现周期性的输出5个脉冲。
TIMER2 配置为主触发模式,触发TIMER1的计数;
TIMER1 配置为从单脉冲输出模式;TIM1_RCR=4;
捕获.JPG 捕获1.JPG
利用这个方法经过改造可实现输出多路可控制脉冲数的高速脉冲。


我刚入门不久,边参与边学习,班门弄斧了

点评

虽然指出了主从搭配,然而并没有从实际上进行设计题目所问道的实际解决方案  发表于 2017-12-1 12:23
zero99 回答时间:2017-11-29 12:55:07
顶一下
nyszx 回答时间:2017-11-29 21:52:34
期间还测了测F411高达4Mhz PWM输出,很强大, 但已经失真很严重,2M还好。有机会拿刚换到的F7测测.
埃斯提爱慕 回答时间:2017-11-29 22:15:59
提示: 作者被禁止或删除 内容自动屏蔽
anywill 回答时间:2017-11-30 07:36:35
方法1,用定时器级联,开启一路pwm的同时,再开启一路定时器,如用tim1作为pwM,开启TIM1作为计数器中断

方法2,采用DMA的方式,DMA中断了就可以关闭PWM了

主要用作电机控制
feixiang20 回答时间:2017-11-30 21:58:41
厉害了啊
nyszx 回答时间:2017-12-1 15:45:40
学习了~
wolfgang 回答时间:2017-12-1 17:12:06
本帖最后由 wolfgang2015 于 2017-12-1 17:20 编辑

“应用笔记AN4776”不是万能的,我也考虑过,经过思索我选择不用该方法是有原因的

虽然TIMER级联方式是解决题目之一,但考虑到这种模式下太占用Timer数量,对于通道数低的尚可,如果面对4个及以上,6个、8个的通道不是最有的选项,对MCU的TIMER资源有着要求。

用DMA虽然浪费内存资源,在内存/Flash易扩展的今天,是一个低成本的解决方案,应该是优于Timer级联,4通道已经需要8个Timer,对那些天生Timer不够用的MCU来说,就无法实现,使用DAM方式应该是最容易普及的方式(外扩SPI Flash等方法)

而且脉冲数量不受65535的限制。

用DMA方式,不会造成脉冲丢失的情况。
具体的可以参看  http://www.stmcu.com.cn   "首页 / 设计资源 / 本地化资源"板块的相关文档

STM32L053可控PWM脉冲方法之DMA
文档说明:目标要求:系统时钟8Mhz,6个PWM脉冲。实现上述目标的方法有很多种,比如两个定时器级连,定时器定时中断翻转IO口,等等,这里使用DMA的方式去实现。
STM32L053可控PWM脉冲方法之DMA.pdf





Inc_brza 回答时间:2017-12-2 10:03:35
wolfgang2015 发表于 2017-12-1 17:12
“应用笔记AN4776”不是万能的,我也考虑过,经过思索我选择不用该方法是有原因的

虽然TIMER级联方式是解 ...

DMA本来是个很好的方法,但是这个方式只能用于低细分或者低速场合,因为加速过程的脉冲数不能太多,否则存储空间够呛。固定加速模式还能放在flash,如果是动态加速模式(加速曲线每次运行可以变化)必须放在ram中就受到很大限制了。
你可以计算一下16细分下用1s加速到2000转(梯形加速)用的总脉冲数
而且,你这个数组还要设计成“0  脉冲数 0 脉冲数 0”的结构,否则你用DMA传输完成中断的方式来断开就太慢了,你必须直接硬件关闭定时器!必须以最快的速度关闭,也就是说不能用软件去操作。一个中断响应的过程就会多发几个脉冲,最可怕的是,多发多少个你还没法统计。
同时,DMA通道时很珍贵的,因为外设之间的DMA是复用的。4路高速脉冲你得用4个DMA+4个定时器通道。你这里使用了,其他更需要大数据的外设就没得用了!所以选型很关键!
不过定时器就不同了,可以看到现在STM32里存在有很多很多的定时器。
123下一页

所属标签

相似问题

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32Cube扩展软件包
意法半导体边缘AI套件
ST - 理想汽车豪华SUV案例
ST意法半导体智能家居案例
STM32 ARM Cortex 32位微控制器
关注我们
st-img 微信公众号
st-img 手机版