【ST NUCLEO-C031C6开发板测评】使用定时器PWM输出控制RGB LED
<div class='showpostmsg'><p><strong>一、硬件了解</strong></p><p>STM32C031C6的MCU系统架构中,提供了多个定时器:</p>
<p> </p>
<p> </p>
<p>这些定时器的具体异同点如下:</p>
<p> </p>
<p>本篇分享使用定时器PWM输出控制RGB LED,选用了TIM3定时器来进行控制。</p>
<p>TIM3的具体介绍如下:</p>
<p> </p>
<p> </p>
<p>该定时器框图如下:</p>
<p> </p>
<p> </p>
<p>要单独控制RGB LED的R、G、B,需要3个通道。而TIM3有4个独立通道,所以用来控制没有问题。</p>
<p> </p>
<p> </p>
<p>二、RGB LED了解</p>
<p>我使用的RGB LED为5050灯珠的三色全彩LED:</p>
<p> </p>
<p> </p>
<p>注意这个上面的灯珠和WS2812B的灯珠看起来一样,但是实际使用不同。</p>
<p>WS2812B的自带IC,一个灯带上的每一颗都可以单独控制。而普通5050灯带需要统一行动。</p>
<p> </p>
<p><strong>三、zephyr对定时器的支持</strong></p>
<p>从zephyr/../modules/hal/stm32/dts/st/c0/stm32c031c(4-6)tx-pinctrl.dtsi中,可以了解到tim3定时器关联的pinctrl信息:</p>
<p> </p>
<p>因为PA5已经被 zephyr/boards/arm/nucleo_c031c6/nucleo_c031c6.dts 配置中默认的TIM1对应的PWM占用了,</p>
<p> </p>
<p> </p>
<p>所以我选择了TIM3中所对应的PA6、PA7、PB0通道来做为RGB的控制,对应开发板上的如下引脚:</p>
<p> </p>
<p> </p>
<p> </p>
<p>不过,zephyr/boards/arm/nucleo_c031c6/nucleo_c031c6.dts中没有TIM3的配置,所以需要自己添加一个配置文件:nucleo_c031c6.overlay</p>
<pre>
<code class="language-json">/ {
mypwmleds {
compatible = "pwm-leds";
my_red_pwm_led: my_led_pwm_0 {
pwms = <&pwm3 1 PWM_MSEC(20) PWM_POLARITY_NORMAL>;
label = "Red PWM LED";
};
my_green_pwm_led: my_led_pwm_1 {
pwms = <&pwm3 2 PWM_MSEC(20) PWM_POLARITY_NORMAL>;
label = "Green PWM LED";
};
my_blue_pwm_led: my_led_pwm_2 {
pwms = <&pwm3 3 PWM_MSEC(20) PWM_POLARITY_NORMAL>;
label = "Blue PWM LED";
};
};
aliases {
my-pwm-led0 = &my_green_pwm_led;
my-pwm-led1 = &my_blue_pwm_led;
my-pwm-led2 = &my_red_pwm_led;
my-green-pwm-led = &my_green_pwm_led;
my-blue-pwm-led = &my_blue_pwm_led;
my-red-pwm-led = &my_red_pwm_led;
};
};
&timers3 {
st,prescaler = <10000>;
status = "okay";
pwm3: pwm {
pinctrl-0 = <&tim3_ch1_pa6 &tim3_ch2_pa7 &tim3_ch3_pb0>;
pinctrl-names = "default";
status = "okay";
};
};</code></pre>
<p> </p>
<p><strong>四、代码编写</strong></p>
<p>在 zephyr/samples/basic/rgb_led,有单个RGB LED的控制代码:</p>
<pre>
<code class="language-cpp">/*
* Copyright (c) 2016 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @File Sample app to demonstrate PWM-based RGB LED control
*/
#include <zephyr/kernel.h>
#include <zephyr/sys/printk.h>
#include <zephyr/device.h>
#include <zephyr/drivers/pwm.h>
static const struct pwm_dt_spec red_pwm_led =
PWM_DT_SPEC_GET(DT_ALIAS(red_pwm_led));
static const struct pwm_dt_spec green_pwm_led =
PWM_DT_SPEC_GET(DT_ALIAS(green_pwm_led));
static const struct pwm_dt_spec blue_pwm_led =
PWM_DT_SPEC_GET(DT_ALIAS(blue_pwm_led));
#define STEP_SIZE PWM_USEC(2000)
int main(void)
{
uint32_t pulse_red, pulse_green, pulse_blue; /* pulse widths */
int ret;
printk("PWM-based RGB LED control\n");
if (!pwm_is_ready_dt(&red_pwm_led) ||
!pwm_is_ready_dt(&green_pwm_led) ||
!pwm_is_ready_dt(&blue_pwm_led)) {
printk("Error: one or more PWM devices not ready\n");
return 0;
}
while (1) {
for (pulse_red = 0U; pulse_red <= red_pwm_led.period;
pulse_red += STEP_SIZE) {
ret = pwm_set_pulse_dt(&red_pwm_led, pulse_red);
if (ret != 0) {
printk("Error %d: red write failed\n", ret);
return 0;
}
for (pulse_green = 0U;
pulse_green <= green_pwm_led.period;
pulse_green += STEP_SIZE) {
ret = pwm_set_pulse_dt(&green_pwm_led,
pulse_green);
if (ret != 0) {
printk("Error %d: green write failed\n",
ret);
return 0;
}
for (pulse_blue = 0U;
pulse_blue <= blue_pwm_led.period;
pulse_blue += STEP_SIZE) {
ret = pwm_set_pulse_dt(&blue_pwm_led,
pulse_blue);
if (ret != 0) {
printk("Error %d: "
"blue write failed\n",
ret);
return 0;
}
k_sleep(K_SECONDS(1));
}
}
}
}
return 0;
}
</code></pre>
<p> </p>
<p>参考上述代码,编写控制3个LED的代码:</p>
<pre>
<code class="language-cpp">#include <zephyr/kernel.h>
#include <zephyr/sys/printk.h>
#include <zephyr/device.h>
#include <zephyr/drivers/pwm.h>
static const struct pwm_dt_spec red_pwm_led =
PWM_DT_SPEC_GET(DT_ALIAS(my_red_pwm_led));
static const struct pwm_dt_spec green_pwm_led =
PWM_DT_SPEC_GET(DT_ALIAS(my_green_pwm_led));
static const struct pwm_dt_spec blue_pwm_led =
PWM_DT_SPEC_GET(DT_ALIAS(my_blue_pwm_led));
// 延时时间
#define DELAY_TIME_MS 500U
// pulse基础值
#define PULSE_BASE 0x80000
// 亮度最大值
#define BRIGHTNESS_MAX 32
int main(void)
{
uint32_t pulse_red, pulse_green, pulse_blue; /* pulse widths */
int ret;
printk("PWM-based RGB LED control\n");
if (!pwm_is_ready_dt(&red_pwm_led) ||
!pwm_is_ready_dt(&green_pwm_led) ||
!pwm_is_ready_dt(&blue_pwm_led)) {
printk("Error: one or more PWM devices not ready\n");
return 0;
}
printk("period(r,g,b)=(%d,%d,%d)\n", red_pwm_led.period, green_pwm_led.period, blue_pwm_led.period);
uint32_t color_pulse_list = {
{0, 0, 0},
{1, 0, 0},
{0, 1, 0},
{0, 0, 1},
{1, 1, 0},
{0, 1, 1},
{1, 0, 1},
{1, 1, 1}
};
uint32_t i = 0;
uint32_t brightness = 1;
while (1) {
pulse_red = color_pulse_list * PULSE_BASE * brightness;
pulse_green = color_pulse_list * PULSE_BASE * brightness;
pulse_blue = color_pulse_list * PULSE_BASE * brightness;
ret = pwm_set_pulse_dt(&red_pwm_led, pulse_red);
if (ret != 0) {
printk("Error %d: red write failed\n", ret);
return 0;
}
ret = pwm_set_pulse_dt(&green_pwm_led,
pulse_green);
if (ret != 0) {
printk("Error %d: green write failed\n",
ret);
return 0;
}
ret = pwm_set_pulse_dt(&blue_pwm_led,
pulse_blue);
if (ret != 0) {
printk("Error %d: "
"blue write failed\n",
ret);
return 0;
}
printk("pulse(r,g,b)=(%04X,%04X,%04X), brightness=%d\n", pulse_red, pulse_green, pulse_blue, brightness);
k_sleep(K_MSEC(DELAY_TIME_MS));
i++;
if (i == 8) {
i = 0;
brightness++;
if(brightness>BRIGHTNESS_MAX) {
brightness = 1;
}
}
#endif
}
return 0;
}
</code></pre>
<p>上述代码中,使用 my_red_pwm_led、my_green_pwm_led、my_blue_pwm_led来对应dts定义的R、G、B控制设备。</p>
<p>然后定义了 color_pulse_list ,用于设置R、G、B的点亮情况:</p>
<pre>
<code class="language-cpp"> uint32_t color_pulse_list = {
{0, 0, 0},
{1, 0, 0},
{0, 1, 0},
{0, 0, 1},
{1, 1, 0},
{0, 1, 1},
{1, 0, 1},
{1, 1, 1}
};</code></pre>
<p>然后在循环中,依次使用上述配置,点亮R、G、B中的1个或者多个,并使用brightness来控制亮度。</p>
<p> </p>
<p><strong>五、输出结果</strong></p>
<p>将之前的nucleo_c031c6.overlay保存到 zephyr/samples/basic/rgb_led/boards/下,然后编译烧录到开发板,就能输出结果:</p>
<p> </p>
<p>RGB LED也会随之跟着变换颜色:</p>
<p>8f8a3ab0d522f5561e7f2c9395f9324b<br />
</p>
<p><strong>六、参考资料</strong></p>
<ul>
<li><a href="https://blog.csdn.net/m0_49330686/article/details/129555465">STM32定时器详解_stm32中定时器1-5有啥区别-CSDN博客</a></li>
</ul>
</div><script> var loginstr = '<div class="locked">查看本帖全部内容,请<a href="javascript:;" style="color:#e60000" class="loginf">登录</a>或者<a href="https://bbs.eeworld.com.cn/member.php?mod=register_eeworld.php&action=wechat" style="color:#e60000" target="_blank">注册</a></div>';
if(parseInt(discuz_uid)==0){
(function($){
var postHeight = getTextHeight(400);
$(".showpostmsg").html($(".showpostmsg").html());
$(".showpostmsg").after(loginstr);
$(".showpostmsg").css({height:postHeight,overflow:"hidden"});
})(jQuery);
} </script><script type="text/javascript">(function(d,c){var a=d.createElement("script"),m=d.getElementsByTagName("script"),eewurl="//counter.eeworld.com.cn/pv/count/";a.src=eewurl+c;m.parentNode.insertBefore(a,m)})(document,523)</script> <p><span style="color: rgb(51, 51, 51); text-transform: none; text-indent: 0px; letter-spacing: normal; font-family: Tahoma, "Microsoft Yahei", Simsun; font-size: 14px; font-style: normal; font-weight: 400; word-spacing: 0px; float: none; display: inline !important; white-space: normal; orphans: 2; widows: 2; background-color: rgb(255, 255, 255); font-variant-ligatures: normal; font-variant-caps: normal; -webkit-text-stroke-width: 0px; text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;">注意这个上面的灯珠和WS2812B的灯珠看起来一样,但是实际使用不同,什么原因</span></p>
页:
[1]