docs: 建立马达和 RGB 灯效的模块拆分及编码实现设计文档,并整理 UI 画册路径
This commit is contained in:
123
Docs/60_coding/mod-led.md
Normal file
123
Docs/60_coding/mod-led.md
Normal file
@@ -0,0 +1,123 @@
|
||||
# 编码实现 - 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 硬件传输
|
||||
|
||||
// 展开的非阻塞高速发送时序 (300ns 传输间隔)
|
||||
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 always-on screen, sleep removal, screen replacement and battery/charge pins update changes -->
|
||||
119
Docs/60_coding/mod-motor.md
Normal file
119
Docs/60_coding/mod-motor.md
Normal file
@@ -0,0 +1,119 @@
|
||||
# 编码实现 - 振动马达驱动与反馈 (Docs/60_coding/mod-motor.md)
|
||||
|
||||
本文件对应振动马达异步时序控制的编码实现细节。
|
||||
|
||||
## 1. 对应代码源文件
|
||||
|
||||
* [App/main.c](file:///c:/workfile/105/stc32g12k128/App/main.c) (定义马达引脚控制及 1ms 中断中的异步脉冲状态机处理)
|
||||
|
||||
## 2. 关键代码片段与逻辑实现
|
||||
|
||||
### 2.1 引脚控制宏与初始化
|
||||
马达由引脚 `P2.5` 控制。配置模式为推挽输出:
|
||||
```c
|
||||
sbit MOTOR = P2^5;
|
||||
|
||||
void Motor_Init(void) {
|
||||
// 将 P2.5 配置为推挽输出模式,默认输出低电平 0
|
||||
P2M1 &= ~(1 << 5);
|
||||
P2M0 |= (1 << 5);
|
||||
MOTOR = 0;
|
||||
}
|
||||
```
|
||||
|
||||
### 2.2 异步定时脉冲时序控制 (Motor_Pulse_Process)
|
||||
为了避免采用阻塞式的 `Delay` 函数占用 CPU,我们在 1ms 定时中断中实现非阻塞状态机。
|
||||
定义全局控制变量:
|
||||
```c
|
||||
u16 motor_pattern_time = 0; // 阶段累计计数器
|
||||
u8 motor_phase = 0; // 振动阶段指示器
|
||||
u8 motor_total_pulses = 0; // 当前告警所需触发的总脉冲数
|
||||
u8 motor_pulse_count = 0; // 已振动次数
|
||||
u16 motor_on_ms = 0; // 单次振动持续时间
|
||||
u16 motor_off_ms = 0; // 振动间隔休眠时间
|
||||
bit motor_running_flag = 0; // 正在振动告警指示标志
|
||||
```
|
||||
|
||||
在 `Timer1_Isr` (每 10ms 调用一次) 中驱动该状态机:
|
||||
```c
|
||||
void Motor_Pulse_Process(void) {
|
||||
if (!motor_running_flag) {
|
||||
MOTOR = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
motor_pattern_time += 10;
|
||||
|
||||
if (motor_phase == 0) {
|
||||
// 振动阶段
|
||||
MOTOR = 1;
|
||||
if (motor_pattern_time >= motor_on_ms) {
|
||||
MOTOR = 0;
|
||||
motor_pattern_time = 0;
|
||||
motor_phase = 1; // 切换到休眠阶段
|
||||
}
|
||||
}
|
||||
else if (motor_phase == 1) {
|
||||
// 休眠间隔阶段
|
||||
MOTOR = 0;
|
||||
if (motor_pattern_time >= motor_off_ms) {
|
||||
motor_pattern_time = 0;
|
||||
motor_pulse_count++;
|
||||
|
||||
if (motor_pulse_count >= motor_total_pulses) {
|
||||
// 已达到指定次数,停止当前周期振动
|
||||
MOTOR = 0;
|
||||
motor_running_flag = 0;
|
||||
} else {
|
||||
motor_phase = 0; // 继续下一次振动
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 2.3 启动与重置接口
|
||||
```c
|
||||
void Motor_Start_Alarm_Pattern(u8 type) {
|
||||
motor_pattern_time = 0;
|
||||
motor_phase = 0;
|
||||
motor_pulse_count = 0;
|
||||
|
||||
switch (type) {
|
||||
case 0: // 🚪 门磁: 1 次短振 300ms
|
||||
motor_on_ms = 300; motor_off_ms = 5000; motor_total_pulses = 1;
|
||||
break;
|
||||
case 1: // 👤 PIR: 2 次短振 300ms
|
||||
motor_on_ms = 300; motor_off_ms = 200; motor_total_pulses = 2;
|
||||
break;
|
||||
case 2: // 🔥 烟感: 3 次短振 200ms
|
||||
motor_on_ms = 200; motor_off_ms = 150; motor_total_pulses = 3;
|
||||
break;
|
||||
case 3: // 🆘 紧急按钮: 1 次长振 800ms
|
||||
motor_on_ms = 800; motor_off_ms = 5000; motor_total_pulses = 1;
|
||||
break;
|
||||
case 4: // 💨 气体: 4 次短振 200ms
|
||||
motor_on_ms = 200; motor_off_ms = 100; motor_total_pulses = 4;
|
||||
break;
|
||||
case 5: // 💧 水浸: 2 次长振 600ms
|
||||
motor_on_ms = 600; motor_off_ms = 300; motor_total_pulses = 2;
|
||||
break;
|
||||
case 6: // 📳 振动: 3 次短振 150ms
|
||||
motor_on_ms = 150; motor_off_ms = 100; motor_total_pulses = 3;
|
||||
break;
|
||||
case 7: // 🚨 本地主动 SOS: 循环长振
|
||||
motor_on_ms = 1000; motor_off_ms = 200; motor_total_pulses = 0xFF; // 近似无限循环
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
motor_running_flag = 1;
|
||||
}
|
||||
|
||||
void Motor_Stop(void) {
|
||||
motor_running_flag = 0;
|
||||
MOTOR = 0;
|
||||
}
|
||||
```
|
||||
|
||||
<!-- Checked and verified with always-on screen, sleep removal, screen replacement and battery/charge pins update changes -->
|
||||
Reference in New Issue
Block a user