[CW32F030系列]

【CW32F030CxTx StartKit测评】03点灯并不简单

[复制链接]
533|3
手机看帖
扫描二维码
随时随地手机跟帖
秦生0303|  楼主 | 2022-7-10 19:52 | 显示全部楼层 |阅读模式
ar, cw
本帖最后由 秦生0303 于 2022-7-10 20:00 编辑

#申请原创#            
      在上一贴,很多人留言说点灯被玩坏了,感觉大家对此都不满足,这里还是要再强调一下,那不是点灯,只是一个时钟配置后的一个验证,本人习惯通过操作IO口来验证一下程序正常运行,LED比较直观而已,在最开始是非常发生一些意想不到的错误的。
      言归正传,点灯在各位大神的手里已经已经玩出花样了,芯源的测试板板载可控的LED只有两个,想想都可以做什么呢?循环灯、同亮同灭、循环闪烁、再加上一个高级点的呼吸灯。
      接下来重点分析一下实现这些功能够需要什么?
      循环灯、同亮同灭、循环闪烁基本操作就是IO口的翻转,不过期间需要延时功能,一种是原地等待,一种是定时器定时,这里选择定时器定时,相对来说定时器定时精准;
      呼吸灯涉及到的就是定时器的PWM输出了,查阅数据手册发现:
IO口.jpg
      PB8/9可以连接通用定时器(GTIM) ,可以产生输出波形(输出比较和PWM)。
      接下来就是模式切换的功能分析,一种是自动模式切换,设计到的就是定时功能,一种是按键操作功能,设计到的就是按键采集,可以使用轮询的方法,也可以使用外部中断的方式,芯源的所有IO口都可以配置为外部中断。
      这里我们把灯操作可能设计到的资源需求都分析出来,接下来就让我们一起一步一步实现他们。

      对于IO口的数字输出功能不在进行赘述,主要讲一下外部中断功能,GPIO 在设置为数字输入模式时,可作为外部中断信号源,中断的信号源可以设置为高电平、低电平、上升沿、下降沿4 种,结合开发板的原理图,当按键按下时会产生一个下降沿,故选择下降沿方式作为外部中断的触发方式,同时中断数字滤波器可对引脚上的输入信号进行数字滤波,实现防抖功能,注意同一组引脚使用相同的滤波时钟。对于外部中断一般都是使用高优先级,芯片默认的优先级即为高优先级。
      初始化代码如下:
//******************************************************************************
// 函数名称  : port_EXIT_init                                            
// 函数描述  : 单片机的外部中断初始化                                       
// 输入参数  :                                                                 
// 参数描述  :                                                                 
// 输出参数  : 无                                                              
// 返回值    : 无                                                              
//******************************************************************************
void port_EXIT_init(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
  __RCC_GPIOA_CLK_ENABLE();
  
  GPIO_InitStruct.IT = GPIO_IT_FALLING;
  GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
  GPIO_InitStruct.Pins = GPIO_PIN_1|GPIO_PIN_2;
  GPIO_InitStruct.Speed = GPIO_SPEED_HIGH;
  GPIO_Init(CW_GPIOA,&GPIO_InitStruct);
  
  //配置中断滤波
  GPIO_ConfigFilter(CW_GPIOA,bv1,GPIO_FLTCLK_RC150K);
  
  //清除PA00中断标志并使能NVIC
  GPIOA_INTFLAG_CLR(bv1| bv2);
  NVIC_EnableIRQ(GPIOA_IRQn);

}

      接下来就是定时器的初始化配置,需要配置GTIM1的CH3和CH4为PWM输出,GTIM2实现10ms定时功能。
      GTIM2代码如下:
//******************************************************************************
//* 函数名称  : GTIM2PWM_init
//* 函数描述  : 定时器2的配置为ms级定时器
//* 输入参数  :     Period:ms
//* 参数描述  : 对应    定时器引脚初始化及配置
//* 输出参数  : 无
//* 返回值    : 无
//******************************************************************************
void GTIM2_init(uint16_t Period)
{
  GTIM_InitTypeDef GTIM_InitStruct;
  BTIM_TimeBaseInitTypeDef BTIM_InitStruct;;
  
  __RCC_BTIM_CLK_ENABLE();
  __RCC_GTIM2_CLK_ENABLE();
  
  __disable_irq();
  NVIC_EnableIRQ(GTIM2_IRQn);
  __enable_irq();
  
  GTIM_InitStruct.Mode = GTIM_MODE_COUNTER;
  GTIM_InitStruct.OneShotMode = GTIM_COUNT_CONTINUE;
  GTIM_InitStruct.Prescaler = GTIM_PRESCALER_DIV1;   
  GTIM_InitStruct.ReloadValue = Period-1;//定时ms  
  GTIM_InitStruct.ToggleOutState = DISABLE;
  GTIM_TimeBaseInit(CW_GTIM2, >IM_InitStruct);
  
  GTIM2_ITRConfig(ITR_SOURCE_BTIM1);
  
  BTIM_InitStruct.BTIM_Mode = BTIM_Mode_TIMER;
  BTIM_InitStruct.BTIM_OPMode = BTIM_OPMode_Repetitive;
  BTIM_InitStruct.BTIM_Period = 999;
  BTIM_InitStruct.BTIM_Prescaler = BTIM_PRS_DIV64;
  BTIM_TimeBaseInit(CW_BTIM1, &BTIM_InitStruct);
  
  GTIM_ITConfig(CW_GTIM2, GTIM_IT_OV, ENABLE);
  GTIM_Cmd(CW_GTIM2, ENABLE);
  BTIM_Cmd(CW_BTIM1, ENABLE);

}
      每Period ms会产生一个定时中断,首先通过BTIM1进行第一级分频,产生的输出作为GTIM2的输入,这样64M通过BTIM_PRS_DIV64分频后每1ms产生一个输出,同时GTIM2根据设置Period ms产生一个中断。
      GTIM1产生PWM初始化代码:
//******************************************************************************
//* 函数名称  : GTIM1PWM_init
//* 函数描述  : 定时器1的配置输出PWM
//* 输入参数  :
//* 参数描述  : 对应    定时器引脚初始化及配置
//* 输出参数  : 无
//* 返回值    : 无
//******************************************************************************
void GTIM1PWM_init(uint16_t Period)
{
  
  GPIO_InitTypeDef GPIO_InitStruct;
  GTIM_InitTypeDef GTIM_InitStruct;
  
  __RCC_GPIOB_CLK_ENABLE();
  __RCC_GTIM1_CLK_ENABLE();

  //set PB08 / PB09 as outupt with pur / int = none
  GPIO_InitStruct.Pins  = GPIO_PIN_8 | GPIO_PIN_9;
  GPIO_InitStruct.Mode  = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.IT    = GPIO_IT_NONE;
  GPIO_InitStruct.Speed = GPIO_SPEED_HIGH;
//  PB08_AFx_GTIM1CH3();
//  PB09_AFx_GTIM1CH4();
  GPIO_Init(CW_GPIOB,&GPIO_InitStruct);
  
  GTIM_InitStruct.Mode = GTIM_MODE_TIME;
  GTIM_InitStruct.OneShotMode = GTIM_COUNT_CONTINUE;
  GTIM_InitStruct.Prescaler = GTIM_PRESCALER_DIV64;    // DCLK = PCLK / 64 = 64MHz/64 = 1MHz
  GTIM_InitStruct.ReloadValue = 1000000/Period-1;//PWM为200Hz  (1/200)/(1/1M)
  GTIM_InitStruct.ToggleOutState = DISABLE;
  
  GTIM_TimeBaseInit(CW_GTIM1, >IM_InitStruct);
  GTIM_OCInit(CW_GTIM1, GTIM_CHANNEL3, GTIM_OC_OUTPUT_PWM_HIGH);
  GTIM_SetCompare3(CW_GTIM1, 0);
  GTIM_OCInit(CW_GTIM1, GTIM_CHANNEL4, GTIM_OC_OUTPUT_PWM_HIGH);
  GTIM_SetCompare4(CW_GTIM1, 0);
//  GTIM_ITConfig(CW_GTIM1, GTIM_IT_OV, ENABLE);

//  GTIM_Cmd(CW_GTIM1, ENABLE);

}
      配置时先不开启定时器及对应IO模式,主要是设置的模式前三种都是IO操作,是普通GPIO功能,而呼吸灯需要配置成复用功能。
      定义一个LED的结构体:
typedef struct 
{
uint8_t Mode_Dis; //LED显示模式
uint8_t Mode_OidDis; //LED上一次显示模式
uint8_t Mode_VIE; //LED控制模式
uint8_t state; //LED过程
uint8_t UpFlag; //更新标志
uint8_t Upcnt; //更新计时计数
}LED_states;
      然后通过中断处理函数对参数进行更改,在while中循环检测LED参数,对LED的实际状态进行操作:
      外部中断处理(模式切换):
if (CW_GPIOA->ISR_f.PIN1)
  {
    GPIOA_INTFLAG_CLR(bv1);
    LED.Mode_Dis++;
    LED.Mode_Dis %= 4;
  }
      定时中断处理:
if (GTIM_GetITStatus(CW_GTIM2, GTIM_IT_OV))
  {
  GTIM_ClearITPendingBit(CW_GTIM2, GTIM_IT_OV);
  if(LED.UpFlag == 0)
  {
    if(LED.Mode_Dis == 0 || LED.Mode_Dis == 1)
    {
      LED.Upcnt++;
      if(LED.Upcnt%100 == 0)
      {
        LED.Upcnt = 0;
        LED.UpFlag = 1;
       }
     }
  else if(LED.Mode_Dis == 2)
  {
     LED.Upcnt++;
     if(LED.Upcnt%100 == 0)
    {
       LED.Upcnt = 0;
       LED.UpFlag = 1;
       LED.state++;
       LED.state %= 3;
    }
  }
  else if(LED.Mode_Dis == 3)
  {
    LED.UpFlag = 1;
    if(LED.state == 0 && LED.Upcnt < 100)
    {
      LED.Upcnt++;
    }
    if(LED.state == 0 && LED.Upcnt == 100)
    {
      LED.Upcnt--;
      LED.state = 1;
    }
    if(LED.state == 1 && LED.Upcnt > 0)
    {
     LED.Upcnt--;
    }
   if(LED.state == 1 && LED.Upcnt == 0)
   {
      LED.Upcnt++;
      LED.state = 0;
   }
      }
    }
  }
      while中循环检测代码:
//******************************************************************************
// 函数名称  : App_LED                                                     *
// 函数描述  : LED模式操作                                                *
// 输入参数  :                                                                 *
// 参数描述  : 无                                                              *
// 输出参数  : 无                                                              *
// 返回值    : 无                                                              *
//******************************************************************************
void App_LED(void)
{
  if(LED.Mode_OidDis != LED.Mode_Dis)
  {
    LED1Off;
    LED2Off;
    LED.Upcnt = 0;
    LED.state = 0;
    LED.UpFlag = 1;
   
    if(LED.Mode_OidDis == 3)
    {
      GTIM_Cmd(CW_GTIM1, DISABLE);
      PB08_AFx_GPIO();
      PB09_AFx_GPIO();
      
    }
   
    switch(LED.Mode_Dis)
    {
      case 0:
        LED1On;
        LED2On;
        break;
        
      case 1:
        LED1On;
        break;
        
      case 3:
        PB08_AFx_GTIM1CH3();
        PB09_AFx_GTIM1CH4();
        GTIM_Cmd(CW_GTIM1, ENABLE);
        break;

      default:
        break;
    }
    LED.Mode_OidDis = LED.Mode_Dis;
  }
  
  if(LED.UpFlag == 1)
  {
    if(LED.Mode_Dis == 0 || LED.Mode_Dis == 1)
    {
      LED1Toggle;
      LED2Toggle;
    }
    else if(LED.Mode_Dis == 2)
    {
      switch(LED.state)
      {
        case 0:
          LED1On;
          break;
         
        case 1:
          LED1Off;
          LED2On;
          break;
         
        case 2:
          LED1Off;
          LED2Off;
          break;
         
        default:
          break;
      }
    }
    else if(LED.Mode_Dis == 3)
    {
      GTIM_SetCompare3(CW_GTIM1, 50*LED.Upcnt);
      GTIM_SetCompare4(CW_GTIM1, 50*(100-LED.Upcnt));//注意根据PWM频率修改系数
    }
   
    LED.UpFlag = 0;
  }

}
      就到这吧,二姨家这个编辑器真是不得不吐槽一下,人家是创作时间比较麻烦,这论坛发个贴确实编辑最费时间,不要怪我们不爱发贴,是真不好用。

操作演示





使用特权

评论回复
秦生0303|  楼主 | 2022-7-10 19:54 | 显示全部楼层
如何插入视频呢?求大神指教

使用特权

评论回复
guijial511| | 2022-7-11 08:14 | 显示全部楼层
二姨的编辑器确实有点不好用啊!

使用特权

评论回复
huquanz711| | 2022-7-15 07:50 | 显示全部楼层
确实不简单…………

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

4

主题

181

帖子

2

粉丝