本帖最后由 是木科技 于 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进一次中断,
void bsp_InitSysTick(void)
  • {
  • /* SystemFrequency / 1000 1ms 进一次中断
  • * SystemFrequency / 100000 10us 进一次中断
  • * SystemFrequency / 1000000 1us 进一次中断
  • */
  •           if (SysTick_Config(SystemCoreClock / 1000))
  •   {
  •     /* Capture error */
  •     while (1);
  •   }                  
  • }
  • 复制代码
    2.写一个延时函数,定义一个静态的外部变量,每进一次中断就-1,意思就是我初始化的1ms进一次中断,那么减10次就是延时10ms
    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
    void RGB_Init(void)
  • {
  •         TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
  •         TIM_OCInitTypeDef          TIM_OCInitStructure;
  •         GPIO_InitTypeDef GPIO_InitStructure;                        
  •         //TIM2 clock enable
  •   RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
  •         RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO,ENABLE);
  •         
  •         GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2;
  •         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;         
  •         GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  •         GPIO_Init(GPIOA, &GPIO_InitStructure);         
  •         
  •         
  •         TIM_TimeBaseStructure.TIM_Period                         = 1000;        //1ms
  •         TIM_TimeBaseStructure.TIM_Prescaler         = 72 - 1;        
  •         TIM_TimeBaseStructure.TIM_CounterMode       = TIM_CounterMode_Up;
  •         TIM_TimeBaseStructure.TIM_ClockDivision           = 0;  
  •         TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;
  •         TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
  •         TIM_OCInitStructure.TIM_OCMode                     = TIM_OCMode_PWM2;
  •         TIM_OCInitStructure.TIM_OutputState         = TIM_OutputState_Enable;
  •         TIM_OCInitStructure.TIM_OutputNState         = TIM_OutputNState_Enable;
  •         TIM_OCInitStructure.TIM_OCPolarity           = TIM_OCPolarity_High;  //TIM_OCPolarity_High
  •         TIM_OCInitStructure.TIM_OCNPolarity         = TIM_OCPolarity_Low;  
  •         TIM_OCInitStructure.TIM_OCIdleState         = TIM_OCIdleState_Set;
  •         TIM_OCInitStructure.TIM_OCNIdleState         = TIM_OCIdleState_Reset;
  •         TIM_OCInitStructure.TIM_Pulse = 0;
  •         TIM_OC1Init(TIM2, &TIM_OCInitStructure);
  •         TIM_OC1PreloadConfig(TIM2, TIM_OCPreload_Enable);  
  •         
  •         TIM_OCInitStructure.TIM_Pulse = 0;
  •         TIM_OC2Init(TIM2, &TIM_OCInitStructure);
  •         TIM_OC2PreloadConfig(TIM2, TIM_OCPreload_Enable);  
  •         
  •         
  •         TIM_OCInitStructure.TIM_Pulse = 0;
  •         TIM_OC3Init(TIM2, &TIM_OCInitStructure);
  •         TIM_OC3PreloadConfig(TIM2, TIM_OCPreload_Enable);  
  •         
  •         
  •         TIM_ARRPreloadConfig(TIM2, ENABLE);
  •         TIM_Cmd(TIM2, ENABLE);
  •         TIM_CtrlPWMOutputs(TIM2, ENABLE);
  •         
  • }
  • 复制代码
    然后我们写一个函数,可以实时改变PWM占空比,通过红色(R),绿色(G),蓝色(B)显示的色温来显示不同的颜色,在需要改变颜色的时候调用即可。
    void RGB_Control(unsigned int r_pwm, unsigned int g_pwm, unsigned int b_pwm)
  • {
  •          if (r_pwm >= 1000)
  •                  r_pwm = 1000;
  •          if (g_pwm >= 1000)
  •                  g_pwm = 1000;
  •          if (b_pwm >= 1000)
  •                  b_pwm = 1000;
  •          
  •          TIM2->CCR1 = g_pwm;  //b_pwm
  •          TIM2->CCR2 = r_pwm;
  •         
  •          TIM2->CCR3 = b_pwm;  //g_pwm
  • }
  • 复制代码
    看下最终效果哟~~~
    2.gif 最后附上最终工程代码(这些代码都是uFun自带测试功能里面单独拿出稍作修改功能demo哟): Zcore_RGB.rar (19.76 MB, 下载次数: 16)
    全部回复 4
    • 122 主题
    • 342 帖子
    • 4781 积分
    身份:LV5 资深技术员
    E币:774
    沙发自己坐
    • 69 主题
    • 144 帖子
    • 2275 积分
    身份:版主
    E币:2335
    哈哈,写的不错嘛!systick能再详细介绍一下就更好了,一直搞不懂这个定时器到底是怎么定时的?公众号关注了,我看还没发什么文章,加油!
    • 122 主题
    • 342 帖子
    • 4781 积分
    身份:LV5 资深技术员
    E币:774
    whik 发表于 2019-3-25 20:29
    哈哈,写的不错嘛!systick能再详细介绍一下就更好了,一直搞不懂这个定时器到底是怎么定时的?公众号关注 ...

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