Files
stc32g128k/Docs/60_coding/mod-led.md

135 lines
4.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 编码实现 - WS2812B 可编程 RGB 灯效 (Docs/60_coding/mod-led.md)
本文件对应可编程幻彩 RGB 灯珠硬件 SPI 驱动与报警指示灯控的编码实现细节。
## 1. 对应代码源文件
* [App/main.c](file:///c:/workfile/105/stc32g12k128/App/main.c) (定义 SPI 配置、展宽查表及 1ms 定时中断中的闪烁控制)
## 2. 关键代码片段与逻辑实现
### 2.1 驱动初始化与管脚分配
WS2812B 输入脚接在单片机硬件 SPI 组管脚中的 MOSI (`P2.3`)
```c
sbit WS2812_DI = P2^3;
void WS2812_Init(void) {
// P2.3 (MOSI) 配置为推挽输出,默认输出低电平 0
P2M1 &= ~(1 << 3);
P2M0 |= (1 << 3);
WS2812_DI = 0;
}
```
### 2.2 硬件 SPI 防噪声极速发送 (WS2812_Write24Bit)
由于 SPI 时钟 SCLK 与马达引脚复用 `P2.5`,发送期间关闭总中断并将 `P2.5` 设为高阻输入以规避马达杂音,通过 SPDAT 展开 24bit 数据串行输出。
展宽 LUT 定义:
```c
const u16 code SPI_LUT[16] = {
0x924, 0x926, 0x934, 0x936, 0x9A4, 0x9A6, 0x9B4, 0x9B6,
0xD24, 0xD26, 0xD34, 0xD36, 0xDA4, 0xDA6, 0xDB4, 0xDB6
};
```
发送函数实现:
```c
void WS2812_Write24Bit(u8 g, u8 r, u8 b) {
u8 data buf[10];
u8 b0, b1, b2, b3, b4, b5, b6, b7, b8, b9;
buf[0] = 0x00; // 虚拟前导字节,吸收硬件启动瞬态抖动
WS2812_EncodeByte(g, &buf[1]);
WS2812_EncodeByte(r, &buf[4]);
WS2812_EncodeByte(b, &buf[7]);
b0 = buf[0]; b1 = buf[1]; b2 = buf[2]; b3 = buf[3];
b4 = buf[4]; b5 = buf[5]; b6 = buf[6]; b7 = buf[7];
b8 = buf[8]; b9 = buf[9];
EA = 0; // 关中断保证 SPI 传输的连续性
// 配置 P2.5 为高阻输入模式,屏蔽马达噪声
P2M1 |= (1 << 5);
P2M0 &= ~(1 << 5);
SPSTAT = 0xC0; // 清除 SPI 状态寄存器
SPDAT = b0; // 发送数据
SPCTL = 0xD0; // 开启 SPI 硬件传输
// 展开的非阻塞高速发送时序 - 发送第 1 个灯珠 (Top LED)
while (!(SPSTAT & 0x80)); SPSTAT = 0xC0; SPDAT = b1;
while (!(SPSTAT & 0x80)); SPSTAT = 0xC0; SPDAT = b2;
while (!(SPSTAT & 0x80)); SPSTAT = 0xC0; SPDAT = b3;
while (!(SPSTAT & 0x80)); SPSTAT = 0xC0; SPDAT = b4;
while (!(SPSTAT & 0x80)); SPSTAT = 0xC0; SPDAT = b5;
while (!(SPSTAT & 0x80)); SPSTAT = 0xC0; SPDAT = b6;
while (!(SPSTAT & 0x80)); SPSTAT = 0xC0; SPDAT = b7;
while (!(SPSTAT & 0x80)); SPSTAT = 0xC0; SPDAT = b8;
while (!(SPSTAT & 0x80)); SPSTAT = 0xC0; SPDAT = b9;
// 展开的非阻塞高速发送时序 - 发送第 2 个灯珠 (Bottom LED, 级联相同颜色)
while (!(SPSTAT & 0x80)); SPSTAT = 0xC0; SPDAT = b1;
while (!(SPSTAT & 0x80)); SPSTAT = 0xC0; SPDAT = b2;
while (!(SPSTAT & 0x80)); SPSTAT = 0xC0; SPDAT = b3;
while (!(SPSTAT & 0x80)); SPSTAT = 0xC0; SPDAT = b4;
while (!(SPSTAT & 0x80)); SPSTAT = 0xC0; SPDAT = b5;
while (!(SPSTAT & 0x80)); SPSTAT = 0xC0; SPDAT = b6;
while (!(SPSTAT & 0x80)); SPSTAT = 0xC0; SPDAT = b7;
while (!(SPSTAT & 0x80)); SPSTAT = 0xC0; SPDAT = b8;
while (!(SPSTAT & 0x80)); SPSTAT = 0xC0; SPDAT = b9;
while (!(SPSTAT & 0x80)); SPSTAT = 0xC0;
SPCTL = 0x90; // 关闭 SPI 硬件使能
WS2812_DI = 0;
// 恢复 P2.5 为推挽输出,控制马达常规功能
P2M1 &= ~(1 << 5);
P2M0 |= (1 << 5);
MOTOR = 0; // 确保马达断开
EA = 1; // 恢复中断
}
void WS2812_Reset(void) {
WS2812_DI = 0;
// 延时 > 80us 触发重置
{
u8 i;
for (i = 0; i < 100; i++) {
_nop_();
}
}
}
```
### 2.3 报警状态交替闪烁逻辑 (LED_Flash_Process)
`Timer1_Isr` (每 10ms 调用一次) 中,管理指示灯闪烁状态:
```c
u16 led_flash_time = 0;
bit led_flash_state = 0;
bit led_running_flag = 0;
u8 led_color_r = 0, led_color_g = 0, led_color_b = 0;
void LED_Flash_Process(void) {
if (!led_running_flag) {
WS2812_Write24Bit(0, 0, 0); // 关闭 LED
WS2812_Reset();
return;
}
led_flash_time += 10;
if (led_flash_time >= 500) { // 500ms 交替周期
led_flash_time = 0;
led_flash_state = ~led_flash_state;
if (led_flash_state) {
WS2812_Write24Bit(led_color_g, led_color_r, led_color_b);
} else {
WS2812_Write24Bit(0, 0, 0);
}
WS2812_Reset();
}
}
```
<!-- Checked and verified with SGM3833 boost/inverting PMIC removal and LCD_PWR_CTRL update changes -->