使用Platformio平台的libopencm3开发框架来开发STM32G0,下面使用PWM来实现LED呼吸灯效果。

1 新建项目

  • 在PIO主页新建项目pwm,框架选择libopencm3,开发板选择 MonkeyPi_STM32_G070RB;
  • 新建完成后在src目录新建主程序文件main.c;
  • 然后更改项目文件platformio.ini的烧写和调试方式:
1
2
upload_protocol = cmsis-dap
debug_tool = cmsis-dap

2 PWM配置

  • GPIO设置为复用PWM输出
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/**
* @brief gpio config
*
*/
static void gpio_setup(void)
{
rcc_periph_clock_enable(RCC_GPIOC);

gpio_mode_setup(GPIOC,
GPIO_MODE_AF,
GPIO_PUPD_NONE,
GPIO12);

gpio_set_output_options(GPIOC,GPIO_OTYPE_PP,GPIO_OSPEED_50MHZ,GPIO12);

//TIM14_CH1 , AF2
gpio_set_af(GPIOC,GPIO_AF2,GPIO12);
}
  • PWM配置
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
/**
* @brief pwm channel setup
*
*/
static void pwm_setup(void)
{
rcc_periph_clock_enable(RCC_TIM14);

/* Timer global mode:
* - No divider
* - Alignment edge
* - Direction up
*/
timer_set_mode(TIM14, TIM_CR1_CKD_CK_INT, TIM_CR1_CMS_EDGE, TIM_CR1_DIR_UP);

/*
* APB1 PRE = 1, TIMPCLK = PCLK
* APB1 PRE != 1, TIMPCLK = PCLK * 2
*/
timer_set_prescaler(TIM14, (rcc_apb1_frequency/100000-1)); //100KHz

/* Disable preload. */
timer_disable_preload(TIM14);
timer_continuous_mode(TIM14);

/* Timer Period */
timer_set_period(TIM14, 20-1); /* 100kHz /20 = 5 KHz */

/* Set the initual output compare value for OC1. */
timer_set_oc_mode(TIM14, TIM_OC1, TIM_OCM_PWM1);
timer_set_oc_value(TIM14, TIM_OC1, 20*0.3); //duty = 0.3

/* Enable output */
timer_enable_oc_output(TIM14, TIM_OC1);
timer_enable_counter(TIM14);
}

先配置定时器的预分频和周期,这里设置到周期为5KHz,可以参考定时器章节的说明;

然后使用timer_set_oc_value 设置占空比,占空比根据定时器周期计算,比如这里设置为30%占空比;

  • 将程序烧写到开发板后可以测量引脚的输出PWM波形如下:

3 呼吸灯效果

实现呼吸灯效果就是更改占空比,让其从0-100变化在从100-0变化即可;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
int duty = 0;

while(1){

//from 0 - 100
for(duty=0; duty <= 100; duty++){
duty = duty + 1;
timer_set_oc_value(TIM14,TIM_OC1, 20*duty/100);

//delay some time
for(int i=0; i<600000; i++){
__asm__("nop");
}
}

//from 100-0
for(duty=100;duty>=0; duty--){
duty = duty - 1;
timer_set_oc_value(TIM14,TIM_OC1, 20*duty/100);

//delay some time
for(int i=0; i<600000; i++){
__asm__("nop");
}

}

}

通过 timer_set_oc_value 改变输出占空比,然后延时一定时间即可达到呼吸灯的效果;