本帖最后由 是木科技 于 2019-3-24 21:01 编辑

uFun.jpg
上期为大家介绍串口这个重要工具,这期为大家介绍一下Coretx-M3的滴答时钟,
也就是大家常说的Systemtick,此外还用TIM2的PWM控制RGB做个简单的demo。
问题一,什么是滴答时钟?
所有的 Coretx-M3以下简称CM3 芯片都带有这个定时器,软件在不同芯片生产厂商的 CM3 器件间的移植工作就得以化简。 该定时器的时钟源可以是内部时钟( FCLK, CM3 上的自由运行时钟),或者是外部时钟(CM3 处理器上的 STCLK 信号)。不过, STCLK 的具体来源则由芯片设计者决定,因此不同产品之间的时钟频率可能会大不相同。因此,需要阅读芯片的使用手册来确定选择什么作为时钟源。下图就是STM32F10xx系列的时钟树图,了解下
1.jpg
问题二,为啥要使用滴答时钟?
操作系统和有所有使用了时基的系统,都必须要一个硬件定时器来产生需要的“滴答”中断,作为整个系统的时基。滴答中断对操作系统尤其重要。例如,操作系统可以为多个任务许以不同数目的时间片,确保没有一个任务能霸占系统;或者把每个定时器周期的某个时间范围赐予特定的任务等,还有操作系统提供的各种定时功能,都与这个滴答定时器有关。因此,需要一个定时器来产生周期性的中断,而且最好还让用户程序不能随意访问它的寄存器,以维持操作系统“心跳”的节律。Cortex-M3 在内核部分 包含了一个简单的定时器——SysTick timer。说了这么多,同学们如果想深入了解systicktimer,可以参阅《 CortexM3 权威指南》,里面有深入讲解。

****************************************完美分割线**********************************************************************
1.初始化systick,我这边是1ms进一次中断,
  1. void bsp_InitSysTick(void)
  2. {
  3. /* SystemFrequency / 1000 1ms 进一次中断
  4. * SystemFrequency / 100000 10us 进一次中断
  5. * SystemFrequency / 1000000 1us 进一次中断
  6. */
  7.           if (SysTick_Config(SystemCoreClock / 1000))
  8.   {
  9.     /* Capture error */
  10.     while (1);
  11.   }                  
  12. }
2.写一个延时函数,定义一个静态的外部变量,每进一次中断就-1,意思就是我初始化的1ms进一次中断,那么减10次就是延时10ms
  1. static __IO uint32_t TimingDelay;
OK至此,精确定时的函数就写好了,只要在需要的地方调用就行啦。
************************************完美分割线**********************************************************************
下面说下RGB三色灯的驱动原理,实现让LED模块呈现不同的颜色,主要依靠人的视觉间歇惰性原理,利用对R、G、B三原色的LED的占空比实现颜色的混合。PWM Dimming (脉宽调制),是LED最佳的灰度调节方式。PWM说的容易理解些,就是控制LED开和关的时间比例,将开和关的时间比例划分为若干等级,LED就会显示出相应数量的灰阶。
4.jpg
uFun硬件上面控制RGB3个PIN是PA0,PA1,PA2也就是TIM2的CH1,CH2,CH3通道,
3.png
所以我们先初始化TIM2的PWM三个通道,频率定位1KHz
  1. void RGB_Init(void)
  2. {
  3.         TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
  4.         TIM_OCInitTypeDef          TIM_OCInitStructure;
  5.         GPIO_InitTypeDef GPIO_InitStructure;                        
  6.         //TIM2 clock enable
  7.   RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
  8.         RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO,ENABLE);
  9.         
  10.         GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2;
  11.         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;         
  12.         GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  13.         GPIO_Init(GPIOA, &GPIO_InitStructure);         
  14.         
  15.         
  16.         TIM_TimeBaseStructure.TIM_Period                         = 1000;        //1ms
  17.         TIM_TimeBaseStructure.TIM_Prescaler         = 72 - 1;        
  18.         TIM_TimeBaseStructure.TIM_CounterMode       = TIM_CounterMode_Up;
  19.         TIM_TimeBaseStructure.TIM_ClockDivision           = 0;  
  20.         TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;
  21.         TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
  22.         TIM_OCInitStructure.TIM_OCMode                     = TIM_OCMode_PWM2;
  23.         TIM_OCInitStructure.TIM_OutputState         = TIM_OutputState_Enable;
  24.         TIM_OCInitStructure.TIM_OutputNState         = TIM_OutputNState_Enable;
  25.         TIM_OCInitStructure.TIM_OCPolarity           = TIM_OCPolarity_High;  //TIM_OCPolarity_High
  26.         TIM_OCInitStructure.TIM_OCNPolarity         = TIM_OCPolarity_Low;  
  27.         TIM_OCInitStructure.TIM_OCIdleState         = TIM_OCIdleState_Set;
  28.         TIM_OCInitStructure.TIM_OCNIdleState         = TIM_OCIdleState_Reset;
  29.         TIM_OCInitStructure.TIM_Pulse = 0;
  30.         TIM_OC1Init(TIM2, &TIM_OCInitStructure);
  31.         TIM_OC1PreloadConfig(TIM2, TIM_OCPreload_Enable);  
  32.         
  33.         TIM_OCInitStructure.TIM_Pulse = 0;
  34.         TIM_OC2Init(TIM2, &TIM_OCInitStructure);
  35.         TIM_OC2PreloadConfig(TIM2, TIM_OCPreload_Enable);  
  36.         
  37.         
  38.         TIM_OCInitStructure.TIM_Pulse = 0;
  39.         TIM_OC3Init(TIM2, &TIM_OCInitStructure);
  40.         TIM_OC3PreloadConfig(TIM2, TIM_OCPreload_Enable);  
  41.         
  42.         
  43.         TIM_ARRPreloadConfig(TIM2, ENABLE);
  44.         TIM_Cmd(TIM2, ENABLE);
  45.         TIM_CtrlPWMOutputs(TIM2, ENABLE);
  46.         
  47. }
然后我们写一个函数,可以实时改变PWM占空比,通过红色(R),绿色(G),蓝色(B)显示的色温来显示不同的颜色,在需要改变颜色的时候调用即可。
  1. void RGB_Control(unsigned int r_pwm, unsigned int g_pwm, unsigned int b_pwm)
  2. {
  3.          if (r_pwm >= 1000)
  4.                  r_pwm = 1000;
  5.          if (g_pwm >= 1000)
  6.                  g_pwm = 1000;
  7.          if (b_pwm >= 1000)
  8.                  b_pwm = 1000;
  9.          
  10.          TIM2->CCR1 = g_pwm;  //b_pwm
  11.          TIM2->CCR2 = r_pwm;
  12.         
  13.          TIM2->CCR3 = b_pwm;  //g_pwm
  14. }
看下最终效果哟~~~
2.gif 最后附上最终工程代码(这些代码都是uFun自带测试功能里面单独拿出稍作修改功能demo哟): Zcore_RGB.rar (19.76 MB, 下载次数: 16)
全部回复 4
  • 122 主题
  • 342 帖子
  • 4759 积分
身份:LV5 资深技术员
E币:744
沙发自己坐
  • 69 主题
  • 144 帖子
  • 2275 积分
身份:版主
E币:2335
哈哈,写的不错嘛!systick能再详细介绍一下就更好了,一直搞不懂这个定时器到底是怎么定时的?公众号关注了,我看还没发什么文章,加油!
  • 122 主题
  • 342 帖子
  • 4759 积分
身份:LV5 资深技术员
E币:744
whik 发表于 2019-3-25 20:29
哈哈,写的不错嘛!systick能再详细介绍一下就更好了,一直搞不懂这个定时器到底是怎么定时的?公众号关注 ...

最近公司项目比较忙,公众号也是最近才有的想法,慢慢会丰富起来的,你的公众号我也关注了,一起学习交流。
  • 1044 主题
  • 4600 帖子
  • 20024 积分
身份:LV8 高级工程师
E币:5251
系统精确延时+RGB呼吸灯
回复楼主
您需要登录后才可以评论 登录 立即注册