STM32F103C8T6通过PWM旋转编码器控制WS2812亮度,
今天我们来玩玩用旋转编码器来控制灯带亮度,老规矩:软件使用STM32CubeIDE,用的HAL库。
今天我们来玩玩用旋转编码器来控制灯带亮度,老规矩:软件使用STM32CubeIDE,用的HAL库
-
新建工程
-
设置 RCC 和 SYS


-
设置TIM1
开启旋转编码器
设置编码器反转

-
设置TIM2
Clock Source 选择 Internal Clock,开启 TIM2 的内部时钟源和通道 1,引脚使用 PA15,Prescaler 配置为 0,Counter Period配置为90-1

-
设置DMA

-
设置GPIO
我的旋转编码器按键引脚在PB15,所以设置引脚PB15

-
设置时钟树
将HCLK频率配置为 72 MHz

-
单独生成.c / .h 文件

-
按下Ctrl + S 生成工程
-
添加WS2812.c 文件
注意在 void ws2812_update(void)函数中的HAL_TIM_PWM_Start_DMA(&htim2, TIM_CHANNEL_1, 如果你不是TIM2,channel 1,在这里修改
#include "ws2812.h"
#include <math.h>
#include <stdlib.h>
#include <string.h>
// LED颜色
uint32_t ws2812_color[WS2812_NUM] = {0};
// 当前LED颜色
static uint32_t _ws2812_color_current[WS2812_NUM];
/**
* @brief 直接更新LED颜色
*/
void ws2812_update(void)
{
// 数据缓冲,每个LED占用24个字节,共10个LED,前100个字节用于复位信号
static uint16_t ws2812_data[RST_PERIOD_NUM + WS2812_NUM * 24];
for (uint8_t led_id = 0; led_id < WS2812_NUM; led_id++)
{
_ws2812_color_current[led_id] = ws2812_color[led_id];
static uint8_t r, g, b;
color_to_rgb(_ws2812_color_current[led_id], &r, &g, &b);
uint16_t *p = ws2812_data + RST_PERIOD_NUM + led_id * 24;
for (uint8_t i = 0; i < 8; i++)
{
p[i] = (r << i) & (0x80) ? CODE_ONE_DUTY : CODE_ZERO_DUTY;
p[i + 8] = (g << i) & (0x80) ? CODE_ONE_DUTY : CODE_ZERO_DUTY;
p[i + 16] = (b << i) & (0x80) ? CODE_ONE_DUTY : CODE_ZERO_DUTY;
}
}
HAL_TIM_PWM_Start_DMA(&htim2, TIM_CHANNEL_1, (uint32_t *)ws2812_data,
RST_PERIOD_NUM + WS2812_NUM * 24);
}
/**
* @brief 通过渐变方式更新LED颜色(线性插值)
* @param steps: 渐变步数
* @param delay_ms: 每步之间的延迟时间(毫秒)
*/
void ws2812_gradient(uint8_t steps, uint16_t delay_ms)
{
static uint8_t start_r[WS2812_NUM], start_g[WS2812_NUM], start_b[WS2812_NUM];
static float r_step[WS2812_NUM], g_step[WS2812_NUM], b_step[WS2812_NUM];
// 提取初始颜色,并计算每步的渐变步长
for (uint8_t i = 0; i < WS2812_NUM; i++)
{
color_to_rgb(_ws2812_color_current[i], &start_r[i], &start_g[i], &start_b[i]);
uint8_t target_r, target_g, target_b;
color_to_rgb(ws2812_color[i], &target_r, &target_g, &target_b);
r_step[i] = (float)(target_r - start_r[i]) / steps;
g_step[i] = (float)(target_g - start_g[i]) / steps;
b_step[i] = (float)(target_b - start_b[i]) / steps;
}
// 逐步渐变
for (uint8_t step = 1; step <= steps; step++)
{
for (uint8_t led_id = 0; led_id < WS2812_NUM; led_id++)
{
// 计算当前步的颜色
uint8_t r = (uint8_t)(start_r[led_id] + r_step[led_id] * step);
uint8_t g = (uint8_t)(start_g[led_id] + g_step[led_id] * step);
uint8_t b = (uint8_t)(start_b[led_id] + b_step[led_id] * step);
ws2812_set_rgb(led_id, r, g, b);
}
ws2812_update();
HAL_Delay(delay_ms);
}
}
/**
* @brief 设置LED颜色(RGB格式)
* @param led_id: LED编号(学习板一共有10个LED,编号范围0-9)
* @param r: 红色亮度(0-255)
* @param g: 绿色亮度(0-255)
* @param b: 蓝色亮度(0-255)
*/
void ws2812_set_rgb(uint8_t led_id, uint8_t r, uint8_t g, uint8_t b)
{
ws2812_color[led_id] = rgb_to_color(r, g, b);
}
/**
* @brief 设置LED颜色(24bit颜色格式)
* @param led_id: LED编号(学习板一共有10个LED,编号范围0-9)
* @param color: 24bit颜色
*/
void ws2812_set(uint8_t led_id, uint32_t color)
{
ws2812_color[led_id] = color;
}
/**
* @brief 设置所有LED颜色(24bit颜色格式)
* @param color: 24bit颜色
*/
void ws2812_set_all(uint32_t color)
{
for (uint8_t led_id = 0; led_id < WS2812_NUM; led_id++)
{
ws2812_color[led_id] = color;
}
}
/**
* @brief RGB转换为24bit颜色
* @param r: 红色亮度(0-255)
* @param g: 绿色亮度(0-255)
* @param b: 蓝色亮度(0-255)
* @retval 24bit颜色
*/
uint32_t rgb_to_color(uint8_t r, uint8_t g, uint8_t b)
{
return (r << 16) | (g << 8) | b;
}
/**
* @brief 24bit颜色转换为RGB
* @param color: 24bit颜色
* @param r: 红色亮度(0-255)
* @param g: 绿色亮度(0-255)
* @param b: 蓝色亮度(0-255)
*/
void color_to_rgb(uint32_t color, uint8_t *r, uint8_t *g, uint8_t *b)
{
*r = (color >> 16) & 0xFF;
*g = (color >> 8) & 0xFF;
*b = color & 0xFF;
}
注意 #define WS2812_NUM ,这是灯带LED的数量
#ifndef __WS2812_H__
#define __WS2812_H__
#include "main.h"
#include "gpio.h"
#include "tim.h"
#include "stdio.h"
#include "string.h"
#define CODE_ONE_DUTY 66
#define CODE_ZERO_DUTY 21
// #define CODE_ONE_DUTY 90
// #define CODE_ZERO_DUTY 32
#define RST_PERIOD_NUM 100
#define WS2812_NUM 60 //灯带LED灯数量
extern uint32_t ws2812_color[WS2812_NUM];
// 将颜色数组直接更新到 LED,不使用渐变过渡
void ws2812_update(void);
// 渐变的更新LED颜色
void ws2812_gradient(uint8_t steps, uint16_t delay_ms);
// 设置LED颜色(24bit颜色)
void ws2812_set(uint8_t led_id, uint32_t color);
// 设置LED颜色(RGB)
void ws2812_set_rgb(uint8_t led_id, uint8_t r, uint8_t g, uint8_t b);
// 设置所有LED颜色
void ws2812_set_all(uint32_t color);
// RGB转换为24bit颜色
uint32_t rgb_to_color(uint8_t r, uint8_t g, uint8_t b);
// 24bit颜色转换为RGB
void color_to_rgb(uint32_t color, uint8_t *r, uint8_t *g, uint8_t *b);
#endif
-
main.c
int main(void)
{
/* USER CODE BEGIN 1 */
uint8_t led_on_count = 0;// 当前点亮 LED 数量
int16_t last_encoder_value = 0; // 记录上一次编码器计数
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_DMA_Init();
MX_TIM1_Init();
MX_TIM2_Init();
/* USER CODE BEGIN 2 */
// 启动定时器TIM1编码器模式
HAL_TIM_Encoder_Start(&htim1, TIM_CHANNEL_1 | TIM_CHANNEL_2);
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
// 读取编码器计数
int16_t current_encoder_value = __HAL_TIM_GET_COUNTER(&htim1);
// 判断旋转方向
if (current_encoder_value > last_encoder_value)
{
// 顺时针旋转,增加点亮的LED数量
if (led_on_count < WS2812_NUM)
{
led_on_count++;
}
}
else if (current_encoder_value < last_encoder_value)
{
// 逆时针旋转,减少点亮的LED数量
if (led_on_count > 0)
{
led_on_count--;
}
}
// 更新灯带状�??
for (uint8_t i = 0; i < WS2812_NUM; i++)
{
if (i < led_on_count)
{
// 点亮LED
ws2812_set_rgb(i,255, 255, 255);
}
else
{
// 熄灭LED
ws2812_set_rgb(i, 0, 0, 0);
}
}
ws2812_update();
// 更新上一次编码器计数
last_encoder_value = current_encoder_value;
HAL_Delay(10);
}
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
/* USER CODE END 3 */
}
-
代码解释
uint8_t led_on_count = 0;// 当前点亮 LED 数量
int16_t last_encoder_value = 0; // 记录上一次编码器计数
// 启动定时器TIM1编码器模式
HAL_TIM_Encoder_Start(&htim1, TIM_CHANNEL_1 | TIM_CHANNEL_2);
// 读取编码器计数
int16_t current_encoder_value = __HAL_TIM_GET_COUNTER(&htim1);
// 判断旋转方向
if (current_encoder_value > last_encoder_value)
{
// 顺时针旋转,增加点亮的LED数量
if (led_on_count < WS2812_NUM)
{
led_on_count++;
}
}
else if (current_encoder_value < last_encoder_value)
{
// 逆时针旋转,减少点亮的LED数量
if (led_on_count > 0)
{
led_on_count--;
}
}
// 更新灯带状态
for (uint8_t i = 0; i < WS2812_NUM; i++)
{
if (i < led_on_count)
{
// 点亮LED
ws2812_set_rgb(i,255, 255, 255);//暖色
}
else
{
// 熄灭LED
ws2812_set_rgb(i, 0, 0, 0);
}
}
ws2812_update();
// 更新上一次编码器计数
last_encoder_value = current_encoder_value;
HAL_Delay(10);
-
来个好玩的
// 更新灯带状态
for (uint8_t i = 0; i < WS2812_NUM; i++)
{
if (i < led_on_count)
{
// 点亮LED
ws2812_set_rgb(i-50,255, 255, 255);
ws2812_set_rgb(i-40,153, 255, 102);
ws2812_set_rgb(i-30,0, 51, 102);
ws2812_set_rgb(i-20,102, 51, 0);
ws2812_set_rgb(i-10,102, 0, 102);
ws2812_set_rgb(i,51, 102, 204);
}
else
{
// 熄灭LED
ws2812_set_rgb(i, 0, 0, 0);
}
}
更多推荐



所有评论(0)