🚗 LED 3位数点阵显示工程:数字布局调整为 [2空+7亮+1空]x3 + 左右各1列边界(附模拟器/C验证)

This commit is contained in:
2026-08-19 18:59:38 +08:00
parent 576b83cf73
commit e6fb2a1cdd
8 changed files with 959 additions and 0 deletions
+68
View File
@@ -0,0 +1,68 @@
# LED 3 位数点阵显示工程(32×16)
32×16 LED 点阵显示 3 位数字的布局调整工程。
## 需求背景
原布局:`2空 | 7亮 | 4空 | 7亮 | 4空 | 7亮 | 1空` = 32 列
(最左 2 列不亮、数字间 4 列不亮、最右 1 列不亮)
新布局:`1空 | [2空 + 7亮 + 1空] ×3 | 1空` = 32 列
- LED 最左 / 最右各留 1 列边界不亮
- 每个数字单元固定 10 列宽:左侧 2 列不亮 + 数字 7 列 + 右侧 1 列不亮
- 数字本体位置:列 3-9 / 13-19 / 23-29
## 文件说明
| 文件 | 说明 |
|------|------|
| `led3number.c` | **修改后的完整代码**(可直接替换工程原文件) |
| `led3number_original.c` | 修改前的原始上传版本(对照用) |
| `led3number_sim.py` | Python 模拟器:复现填充+移位逻辑,可渲染 32×16 点阵图 |
| `led3number_test.c` | 独立 C 验证程序(gcc 编译,与模拟器输出逐列对照) |
| `gen_led3number.py` | 生成脚本:从原始文件生成修改后的 `led3number.c` |
| `gen_c_test.py` | 生成脚本:从原始文件生成 `led3number_test.c` |
## 核心改动(read_code 函数内)
原移位拼接循环 → 新布局移位逻辑:
```c
// 数字本体(区域内列2-8, 7列) → 全局列 3-9 / 13-19 / 23-29
for(i=0;i<16;i++)
{
uint8_t s2 = code12_ram[2][i]; // 数字1 高字节
uint8_t s3 = code12_ram[3][i]; // 数字1 低字节
uint8_t s4 = code12_ram[4][i]; // 数字2 高字节
uint8_t s5 = code12_ram[5][i]; // 数字2 低字节
uint8_t s6 = code12_ram[6][i]; // 数字3 高字节
uint8_t s7 = code12_ram[7][i]; // 数字3 低字节
code12_ram[2][i] = (s2 >> 1) & 0x1F; // 数字1 → 列3-7
code12_ram[3][i] = ((s2 & 0x01) << 7) | ((s3 >> 1) & 0x40) // 数字1 → 列8-9
| ((s4 >> 3) & 0x07); // 数字2 → 列13-15
code12_ram[4][i] = ((s4 & 0x07) << 5) | ((s5 & 0x80) >> 3) // 数字2 → 列16-19
| ((s6 >> 5) & 0x01); // 数字3 → 列23
code12_ram[5][i] = ((s6 & 0x1F) << 3) | ((s7 & 0x80) >> 5); // 数字3 → 列24-29
}
```
另:移除已废弃的 `move_reg1/move_reg2` 声明(原移位逻辑专用)。
## 验证方法
```bash
# 1. Python 模拟(可看 32×16 点阵图)
python3 led3number_sim.py
# 2. C 独立验证(gcc 编译,输出与模拟器逐列对照)
gcc -Wall -Wextra -O2 -o led3number_test led3number_test.c && ./led3number_test
```
已验证数字组合:123 / 456 / 888 / 000 / 999 / 111,布局全部正确。
## 注意事项
- 协议行为未改动:显示数据流后 3 个字符(第 1 个字符被丢弃,原逻辑如此)
- 空格字符处理未改动
- 字库结构:每字符 16 位宽,数字本体 7 列位于区域内列 2-8,MSB 显示
+95
View File
@@ -0,0 +1,95 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""生成 C 验证程序: 独立复刻填充+新移位逻辑, 输出点阵供与 Python 模拟对照"""
import re
SRC = "/root/.openclaw/media/inbound/led3number---69efe51a-567a-4354-a1b8-6c796c184183.txt"
text = open(SRC, encoding="utf-8", errors="replace").read().replace("\r\n", "\n")
m = re.search(r"Code_Number_16_12\[17\]\[32\]\s*=\s*\{(.*?)\n\};", text, re.S)
entries = re.findall(r"\{([^{}]*)\}", m.group(1))
fonts = []
for e in entries:
fonts.append([int(x, 16) for x in re.findall(r"0[xX][0-9A-Fa-f]+", e)])
# 补到 17 个(未初始化的补 0
while len(fonts) < 17:
fonts.append([0]*32)
# 生成 C 字库
rows = []
for idx, f in enumerate(fonts):
vals = ", ".join(f"0x{v:02X}" for v in f)
rows.append(f" /* {idx} */ {{ {vals} }}")
font_tbl = ",\n".join(rows)
c_code = f'''#include <stdio.h>
#include <stdint.h>
#include <string.h>
static const unsigned char Code_Number_16_12[17][32] = {{
{font_tbl}
}};
/* 模拟: 填充 + 新移位 (照抄 led3number_new.c 逻辑) */
static void process(const uint8_t chars[4], uint8_t out[4][16])
{{
uint8_t code12[8][16];
int roll, i;
memset(code12, 0, sizeof(code12));
for (roll = 0; roll < 4; roll++) {{
uint8_t cc = chars[roll];
for (i = 0; i < 16; i++) {{
if (cc == 0x20) {{
code12[roll*2][i] = Code_Number_16_12[10][i*2];
code12[roll*2+1][i] = Code_Number_16_12[10][i*2+1];
}} else {{
code12[roll*2][i] = Code_Number_16_12[cc-0x30][i*2];
code12[roll*2+1][i] = (uint8_t)(Code_Number_16_12[cc-0x30][i*2+1] << 6);
}}
}}
}}
for (i = 0; i < 16; i++) {{
uint8_t s2 = code12[2][i];
uint8_t s3 = code12[3][i];
uint8_t s4 = code12[4][i];
uint8_t s5 = code12[5][i];
uint8_t s6 = code12[6][i];
uint8_t s7 = code12[7][i];
code12[2][i] = (uint8_t)((s2 >> 1) & 0x1F);
code12[3][i] = (uint8_t)(((s2 & 0x01) << 7) | ((s3 >> 1) & 0x40) | ((s4 >> 3) & 0x07));
code12[4][i] = (uint8_t)(((s4 & 0x07) << 5) | ((s5 & 0x80) >> 3) | ((s6 >> 5) & 0x01));
code12[5][i] = (uint8_t)(((s6 & 0x1F) << 3) | ((s7 & 0x80) >> 5));
}}
memcpy(out, &code12[2][0], 64);
}}
static void render(const char *name, const uint8_t out[4][16])
{{
int r, c;
printf("=== %s ===\\n", name);
printf("col: ");
for (c = 0; c < 32; c++) printf("%d", c % 10);
printf("\\n");
for (r = 0; r < 16; r++) {{
printf("%2d ", r);
for (c = 0; c < 32; c++) {{
uint8_t byte = out[c/8][r];
int bit = (byte >> (7 - (c % 8))) & 1;
putchar(bit ? '#' : '.');
}}
printf("\\n");
}}
}}
int main(void)
{{
uint8_t out[4][16];
/* 字符: 第1个被丢弃(协议), 后3个显示; 0x20=空格 */
process((uint8_t[]){{'1','2','3','0'}}, out); render("NEW 123+0", out);
process((uint8_t[]){{' ','4','5','6'}}, out); render("NEW 456+7", out);
process((uint8_t[]){{'8','8','8','8'}}, out); render("NEW 888+8", out);
return 0;
}}
'''
open("/root/.openclaw/workspace/led3number_test.c", "w").write(c_code)
print("已生成 led3number_test.c")
+49
View File
@@ -0,0 +1,49 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""生成修改后的 led3number.c: 替换移位拼接段为新布局逻辑"""
import re
SRC = "/root/.openclaw/media/inbound/led3number---69efe51a-567a-4354-a1b8-6c796c184183.txt"
OUT = "/root/.openclaw/workspace/led3number_new.c"
text = open(SRC, encoding="utf-8", errors="replace").read().replace("\r\n", "\n")
# 定位原移位段: 第二个 for(i=0;i<16;i++) 循环 (move_reg1 = code12_ram[5][i] 开头)
pat = re.compile(r"for\(i=0;i<16;i\+\+\)\s*\{\s*move_reg1 = code12_ram\[5\]\[i\];")
m = pat.search(text)
assert m, "移位段起始未找到"
start = m.start()
end = text.find("memcpy(&CodeRAM[32- Screen.Uart.Receive_ID_Number*4][0]")
assert end != -1, "memcpy 未找到"
# TODO 注释行在 memcpy 之前
todo_end = text.rfind("// TODO", start, end)
assert todo_end != -1
# 找到 TODO 行结尾
nl = text.find("\n", todo_end)
seg_end = nl + 1
new_seg = """\t// ========== 新布局: 32列 = 1空 | [2空 + 7数字 + 1空]x3 | 1空 ==========\n\
\t// 数字本体(区域内列2-8, 7列) → 全局列 3-9 / 13-19 / 23-29\n\
\t// 左边界1列 + 每数字左2右1空 + 右边界1列, 数字间空隙3列\n\
\tfor(i=0;i<16;i++)\n\
\t{\n\
\t\tuint8_t s2 = code12_ram[2][i]; // 数字1 高字节(区域内列0-7)\n\
\t\tuint8_t s3 = code12_ram[3][i]; // 数字1 低字节(区域内列8-15)\n\
\t\tuint8_t s4 = code12_ram[4][i]; // 数字2 高字节\n\
\t\tuint8_t s5 = code12_ram[5][i]; // 数字2 低字节\n\
\t\tuint8_t s6 = code12_ram[6][i]; // 数字3 高字节\n\
\t\tuint8_t s7 = code12_ram[7][i]; // 数字3 低字节\n\
\n\
\t\tcode12_ram[2][i] = (s2 >> 1) & 0x1F; // 数字1 → 列3-7\n\
\t\tcode12_ram[3][i] = ((s2 & 0x01) << 7) | ((s3 >> 1) & 0x40) // 数字1 → 列8-9\n\
\t\t | ((s4 >> 3) & 0x07); // 数字2 → 列13-15\n\
\t\tcode12_ram[4][i] = ((s4 & 0x07) << 5) | ((s5 & 0x80) >> 3) // 数字2 → 列16-19\n\
\t\t | ((s6 >> 5) & 0x01); // 数字3 → 列23\n\
\t\tcode12_ram[5][i] = ((s6 & 0x1F) << 3) | ((s7 & 0x80) >> 5); // 数字3 → 列24-29\n\
\t}\n\
\n\
"""
new_text = text[:start] + new_seg + text[seg_end:]
open(OUT, "w", encoding="utf-8").write(new_text)
print("已生成:", OUT)
print("原始文件长度:", len(text), "→ 新文件长度:", len(new_text))
+275
View File
@@ -0,0 +1,275 @@
const unsigned char Code_Number_16_12[17][32]={ //16点阵高,12点阵宽
{0x00, 0x00,
0x3F, 0x02,
0x3F, 0x02,
0x31, 0x02,
0x31, 0x02,
0x31, 0x02,
0x31, 0x02,
0x31, 0x02,
0x31, 0x02,
0x31, 0x02,
0x31, 0x02,
0x31, 0x02,
0x31, 0x02,
0x3F, 0x02,
0x3F, 0x02,
0x00, 0x00}, //0
{0x00, 0x00,
0x01, 0x02,
0x01, 0x02,
0x01, 0x02,
0x01, 0x02,
0x01, 0x02,
0x01, 0x02,
0x01, 0x02,
0x01, 0x02,
0x01, 0x02,
0x01, 0x02,
0x01, 0x02,
0x01, 0x02,
0x01, 0x02,
0x01, 0x02,
0x00, 0x00}, //1
{0x00, 0x00,
0x3F, 0x02,
0x3F, 0x02,
0x01, 0x02,
0x01, 0x02,
0x01, 0x02,
0x01, 0x02,
0x3F, 0x02,
0x3F, 0x02,
0x30, 0x00,
0x30, 0x00,
0x30, 0x00,
0x30, 0x00,
0x3F, 0x02,
0x3F, 0x02,
0x00, 0x00}, //2
{0x00, 0x00,
0x3F, 0x02,
0x3F, 0x02,
0x01, 0x02,
0x01, 0x02,
0x01, 0x02,
0x01, 0x02,
0x3F, 0x02,
0x3F, 0x02,
0x01, 0x02,
0x01, 0x02,
0x01, 0x02,
0x01, 0x02,
0x3F, 0x02,
0x3F, 0x02,
0x00, 0x00}, //3
{0x00, 0x00,
0x31, 0x02,
0x31, 0x02,
0x31, 0x02,
0x31, 0x02,
0x31, 0x02,
0x31, 0x02,
0x3F, 0x02,
0x3F, 0x02,
0x01, 0x02,
0x01, 0x02,
0x01, 0x02,
0x01, 0x02,
0x01, 0x02,
0x01, 0x02,
0x00, 0x00}, //4
{0x00, 0x00,
0x3F, 0x02,
0x3F, 0x02,
0x30, 0x00,
0x30, 0x00,
0x30, 0x00,
0x30, 0x00,
0x3F, 0x02,
0x3F, 0x02,
0x01, 0x02,
0x01, 0x02,
0x01, 0x02,
0x01, 0x02,
0x3F, 0x02,
0x3F, 0x02,
0x00, 0x00}, //5
{0x00, 0x00,
0x3F, 0x02,
0x3F, 0x02,
0x30, 0x00,
0x30, 0x00,
0x30, 0x00,
0x30, 0x00,
0x3F, 0x02,
0x3F, 0x02,
0x31, 0x02,
0x31, 0x02,
0x31, 0x02,
0x31, 0x02,
0x3F, 0x02,
0x3F, 0x02,
0x00, 0x00}, //6
{0x00, 0x00,
0x3F, 0x02,
0x3F, 0x02,
0x01, 0x02,
0x01, 0x02,
0x01, 0x02,
0x01, 0x02,
0x01, 0x02,
0x01, 0x02,
0x01, 0x02,
0x01, 0x02,
0x01, 0x02,
0x01, 0x02,
0x01, 0x02,
0x01, 0x02,
0x00, 0x00}, //7
{0x00, 0x00,
0x3F, 0x02,
0x3F, 0x02,
0x31, 0x02,
0x31, 0x02,
0x31, 0x02,
0x31, 0x02,
0x3F, 0x02,
0x3F, 0x02,
0x31, 0x02,
0x31, 0x02,
0x31, 0x02,
0x31, 0x02,
0x3F, 0x02,
0x3F, 0x02,
0x00, 0x00}, //8
{0x00, 0x00,
0x3F, 0x02,
0x3F, 0x02,
0x31, 0x02,
0x31, 0x02,
0x31, 0x02,
0x31, 0x02,
0x3F, 0x02,
0x3F, 0x02,
0x01, 0x02,
0x01, 0x02,
0x01, 0x02,
0x01, 0x02,
0x3F, 0x02,
0x3F, 0x02,
0x00, 0x00}, //9
{0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00
}, //空格
};
void read_code(void)
{
static uint16_t roll;
uint8_t i,j;
uint8_t cc,cd;
static uint16_t ROW_8BIT = 0;
static uint8_t code12_ram[48][16];
// 注: 原 move_reg1/move_reg2 已随旧移位逻辑移除
ROW_8BIT = 0;
if(Screen.Uart.First_Receive_Data)
{
if(Screen.Set.High==16 || Screen.DisplayMode.Work_Mode==2)
{
if(Screen.Para.Data_LEN%(Screen.Set.Width/8))
{
Screen.Para.Num = (Screen.Para.Data_LEN/(Screen.Set.Width/8))+1; //
}
else
Screen.Para.Num = Screen.Para.Data_LEN/(Screen.Set.Width/8);
}
else
{
if((Screen.Para.Data_LEN)%(Screen.Set.Width/16))
{
Screen.Para.Num = (Screen.Para.Data_LEN/(Screen.Set.Width/16))+1; //
}
else
Screen.Para.Num = Screen.Para.Data_LEN/(Screen.Set.Width/16);
}
}
else
{
Screen.Para.Num = 1;
}
if(Screen.Para.Num == 1)
{
Screen.Para.Single_Line_Direct_Display_Flag = 0;
}
if(!Screen.Uart.First_Receive_Data)
{
for(roll=0;roll<Screen.Para.Data_LEN;roll++)
{
cc = Display_data[roll];
for(i=0;i<16;i++)
{
if(cc==0x20) //空格
CodeRAM[roll][i] = Code_Number_16[16][i];
else
CodeRAM[roll][i] = Code_Number_16[cc-0X30][i];
}
}
}
else
{
for(roll=0;roll<4;roll++)
{
cc = Display_data[32- Screen.Uart.Receive_ID_Number*4+roll];
for(i=0;i<16;i++)
{
if(cc==0x20) //空格
{
code12_ram[roll*2][i]=Code_Number_16_12[10][i*2];
code12_ram[roll*2+1][i]=Code_Number_16_12[10][i*2+1];
}
else
{
code12_ram[roll*2][i]=Code_Number_16_12[cc-0X30][i*2] ;
code12_ram[roll*2+1][i]=Code_Number_16_12[cc-0X30][i*2+1] << 6;
}
}
}
// ========== 新布局: 32列 = 1空 | [2空 + 7数字 + 1空]x3 | 1空 ==========
// 数字本体(区域内列2-8, 7列) → 全局列 3-9 / 13-19 / 23-29
// 左边界1列 + 每数字左2右1空 + 右边界1列, 数字间空隙3列
for(i=0;i<16;i++)
{
uint8_t s2 = code12_ram[2][i]; // 数字1 高字节(区域内列0-7)
uint8_t s3 = code12_ram[3][i]; // 数字1 低字节(区域内列8-15)
uint8_t s4 = code12_ram[4][i]; // 数字2 高字节
uint8_t s5 = code12_ram[5][i]; // 数字2 低字节
uint8_t s6 = code12_ram[6][i]; // 数字3 高字节
uint8_t s7 = code12_ram[7][i]; // 数字3 低字节
code12_ram[2][i] = (s2 >> 1) & 0x1F; // 数字1 → 列3-7
code12_ram[3][i] = ((s2 & 0x01) << 7) | ((s3 >> 1) & 0x40) // 数字1 → 列8-9
| ((s4 >> 3) & 0x07); // 数字2 → 列13-15
code12_ram[4][i] = ((s4 & 0x07) << 5) | ((s5 & 0x80) >> 3) // 数字2 → 列16-19
| ((s6 >> 5) & 0x01); // 数字3 → 列23
code12_ram[5][i] = ((s6 & 0x1F) << 3) | ((s7 & 0x80) >> 5); // 数字3 → 列24-29
}
memcpy(&CodeRAM[32- Screen.Uart.Receive_ID_Number*4][0],&code12_ram[2][0],64);
}
memcpy(CodeRAM_Display,CodeRAM,sizeof(CodeRAM));
memcpy(CodeRAM2_Display,CodeRAM2,sizeof(CodeRAM2));
}
+276
View File
@@ -0,0 +1,276 @@
const unsigned char Code_Number_16_12[17][32]={ //16点阵高,12点阵宽
{0x00, 0x00,
0x3F, 0x02,
0x3F, 0x02,
0x31, 0x02,
0x31, 0x02,
0x31, 0x02,
0x31, 0x02,
0x31, 0x02,
0x31, 0x02,
0x31, 0x02,
0x31, 0x02,
0x31, 0x02,
0x31, 0x02,
0x3F, 0x02,
0x3F, 0x02,
0x00, 0x00}, //0
{0x00, 0x00,
0x01, 0x02,
0x01, 0x02,
0x01, 0x02,
0x01, 0x02,
0x01, 0x02,
0x01, 0x02,
0x01, 0x02,
0x01, 0x02,
0x01, 0x02,
0x01, 0x02,
0x01, 0x02,
0x01, 0x02,
0x01, 0x02,
0x01, 0x02,
0x00, 0x00}, //1
{0x00, 0x00,
0x3F, 0x02,
0x3F, 0x02,
0x01, 0x02,
0x01, 0x02,
0x01, 0x02,
0x01, 0x02,
0x3F, 0x02,
0x3F, 0x02,
0x30, 0x00,
0x30, 0x00,
0x30, 0x00,
0x30, 0x00,
0x3F, 0x02,
0x3F, 0x02,
0x00, 0x00}, //2
{0x00, 0x00,
0x3F, 0x02,
0x3F, 0x02,
0x01, 0x02,
0x01, 0x02,
0x01, 0x02,
0x01, 0x02,
0x3F, 0x02,
0x3F, 0x02,
0x01, 0x02,
0x01, 0x02,
0x01, 0x02,
0x01, 0x02,
0x3F, 0x02,
0x3F, 0x02,
0x00, 0x00}, //3
{0x00, 0x00,
0x31, 0x02,
0x31, 0x02,
0x31, 0x02,
0x31, 0x02,
0x31, 0x02,
0x31, 0x02,
0x3F, 0x02,
0x3F, 0x02,
0x01, 0x02,
0x01, 0x02,
0x01, 0x02,
0x01, 0x02,
0x01, 0x02,
0x01, 0x02,
0x00, 0x00}, //4
{0x00, 0x00,
0x3F, 0x02,
0x3F, 0x02,
0x30, 0x00,
0x30, 0x00,
0x30, 0x00,
0x30, 0x00,
0x3F, 0x02,
0x3F, 0x02,
0x01, 0x02,
0x01, 0x02,
0x01, 0x02,
0x01, 0x02,
0x3F, 0x02,
0x3F, 0x02,
0x00, 0x00}, //5
{0x00, 0x00,
0x3F, 0x02,
0x3F, 0x02,
0x30, 0x00,
0x30, 0x00,
0x30, 0x00,
0x30, 0x00,
0x3F, 0x02,
0x3F, 0x02,
0x31, 0x02,
0x31, 0x02,
0x31, 0x02,
0x31, 0x02,
0x3F, 0x02,
0x3F, 0x02,
0x00, 0x00}, //6
{0x00, 0x00,
0x3F, 0x02,
0x3F, 0x02,
0x01, 0x02,
0x01, 0x02,
0x01, 0x02,
0x01, 0x02,
0x01, 0x02,
0x01, 0x02,
0x01, 0x02,
0x01, 0x02,
0x01, 0x02,
0x01, 0x02,
0x01, 0x02,
0x01, 0x02,
0x00, 0x00}, //7
{0x00, 0x00,
0x3F, 0x02,
0x3F, 0x02,
0x31, 0x02,
0x31, 0x02,
0x31, 0x02,
0x31, 0x02,
0x3F, 0x02,
0x3F, 0x02,
0x31, 0x02,
0x31, 0x02,
0x31, 0x02,
0x31, 0x02,
0x3F, 0x02,
0x3F, 0x02,
0x00, 0x00}, //8
{0x00, 0x00,
0x3F, 0x02,
0x3F, 0x02,
0x31, 0x02,
0x31, 0x02,
0x31, 0x02,
0x31, 0x02,
0x3F, 0x02,
0x3F, 0x02,
0x01, 0x02,
0x01, 0x02,
0x01, 0x02,
0x01, 0x02,
0x3F, 0x02,
0x3F, 0x02,
0x00, 0x00}, //9
{0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00
}, //空格
};
void read_code(void)
{
static uint16_t roll;
uint8_t i,j;
uint8_t cc,cd;
static uint16_t ROW_8BIT = 0;
static uint8_t code12_ram[48][16];
uint8_t move_reg1 = 0;
uint8_t move_reg2 = 0;
ROW_8BIT = 0;
if(Screen.Uart.First_Receive_Data)
{
if(Screen.Set.High==16 || Screen.DisplayMode.Work_Mode==2)
{
if(Screen.Para.Data_LEN%(Screen.Set.Width/8))
{
Screen.Para.Num = (Screen.Para.Data_LEN/(Screen.Set.Width/8))+1; //
}
else
Screen.Para.Num = Screen.Para.Data_LEN/(Screen.Set.Width/8);
}
else
{
if((Screen.Para.Data_LEN)%(Screen.Set.Width/16))
{
Screen.Para.Num = (Screen.Para.Data_LEN/(Screen.Set.Width/16))+1; //
}
else
Screen.Para.Num = Screen.Para.Data_LEN/(Screen.Set.Width/16);
}
}
else
{
Screen.Para.Num = 1;
}
if(Screen.Para.Num == 1)
{
Screen.Para.Single_Line_Direct_Display_Flag = 0;
}
if(!Screen.Uart.First_Receive_Data)
{
for(roll=0;roll<Screen.Para.Data_LEN;roll++)
{
cc = Display_data[roll];
for(i=0;i<16;i++)
{
if(cc==0x20) //空格
CodeRAM[roll][i] = Code_Number_16[16][i];
else
CodeRAM[roll][i] = Code_Number_16[cc-0X30][i];
}
}
}
else
{
for(roll=0;roll<4;roll++)
{
cc = Display_data[32- Screen.Uart.Receive_ID_Number*4+roll];
for(i=0;i<16;i++)
{
if(cc==0x20) //空格
{
code12_ram[roll*2][i]=Code_Number_16_12[10][i*2];
code12_ram[roll*2+1][i]=Code_Number_16_12[10][i*2+1];
}
else
{
code12_ram[roll*2][i]=Code_Number_16_12[cc-0X30][i*2] ;
code12_ram[roll*2+1][i]=Code_Number_16_12[cc-0X30][i*2+1] << 6;
}
}
}
for(i=0;i<16;i++)
{
move_reg1 = code12_ram[5][i];
code12_ram[4][i]=(code12_ram[4][i]<<1) | (move_reg1>>7);
code12_ram[5][i]=code12_ram[5][i]<<1; //第二个数左移一位
move_reg1 = code12_ram[4][i];
code12_ram[3][i]=code12_ram[3][i] | (move_reg1>>4);
move_reg1 = code12_ram[4][i];
move_reg2 = code12_ram[5][i];
code12_ram[4][i]= move_reg1<<4 | move_reg2>>4;
move_reg1 = code12_ram[6][i];
code12_ram[4][i] |= move_reg1>>6;
move_reg1 = code12_ram[6][i];
code12_ram[5][i] = (move_reg1<<2) | (code12_ram[7][i]>>6);
}
// TODO: 新的移位要求 LED最左边和最右边的一列不亮;每个数字 左边有两列不亮,右侧一列不亮,也就是说 每个数字单元有10个点阵宽,左侧有两列不亮,右侧有一列不亮。
memcpy(&CodeRAM[32- Screen.Uart.Receive_ID_Number*4][0],&code12_ram[2][0],64);
}
memcpy(CodeRAM_Display,CodeRAM,sizeof(CodeRAM));
memcpy(CodeRAM2_Display,CodeRAM2,sizeof(CodeRAM2));
}
+102
View File
@@ -0,0 +1,102 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""led3number.c 移位逻辑模拟器 — 用于精确理解/验证 32x16 点阵数字布局"""
import re, sys
SRC = "/root/.openclaw/media/inbound/led3number---69efe51a-567a-4354-a1b8-6c796c184183.txt"
text = open(SRC, encoding="utf-8", errors="replace").read()
# ---------- 1. 解析字库 Code_Number_16_12[17][32] ----------
m = re.search(r"Code_Number_16_12\[17\]\[32\]\s*=\s*\{(.*?)\n\};", text, re.S)
assert m, "字库未找到"
body = m.group(1)
# 按 { ... }, //n 拆成 17 个字符
entries = re.findall(r"\{([^{}]*)\}", body)
assert len(entries) >= 11, f"字库条目数 {len(entries)} < 11"
fonts = []
for e in entries:
vals = [int(x, 16) for x in re.findall(r"0[xX][0-9A-Fa-f]+", e)]
assert len(vals) == 32, f"条目字节数 {len(vals)} != 32"
fonts.append(vals)
print(f"[字库] 解析 OK: 17 个字符 x 32 字节")
# ---------- 2. 模拟填充 + 移位(完全照抄 C 逻辑, uint8 语义) ----------
def simulate(chars_idx, new_layout=False):
"""chars_idx: 4 个字符索引, 0-9=数字, 16=空格(Code_Number_16_12[10]=空格索引10, 但调用处用 0x20 判断)"""
code12 = [[0]*16 for _ in range(8)] # 8 槽 x 16 行, uint8
for roll in range(4):
cc = chars_idx[roll]
for i in range(16):
if cc == 0x20 or cc == 16: # 空格
code12[roll*2][i] = fonts[10][i*2]
code12[roll*2+1][i] = fonts[10][i*2+1]
else:
code12[roll*2][i] = fonts[cc][i*2]
code12[roll*2+1][i] = (fonts[cc][i*2+1] << 6) & 0xFF
if not new_layout:
# ---- 原移位拼接(TODO 所在处, 原样模拟) ----
for i in range(16):
m1 = code12[5][i]
code12[4][i] = ((code12[4][i] << 1) | (m1 >> 7)) & 0xFF
code12[5][i] = (code12[5][i] << 1) & 0xFF
m1 = code12[4][i]
code12[3][i] = (code12[3][i] | (m1 >> 4)) & 0xFF
m1 = code12[4][i]
m2 = code12[5][i]
code12[4][i] = ((m1 << 4) | (m2 >> 4)) & 0xFF
m1 = code12[6][i]
code12[4][i] = (code12[4][i] | (m1 >> 6)) & 0xFF
m1 = code12[6][i]
code12[5][i] = ((m1 << 2) | (code12[7][i] >> 6)) & 0xFF
else:
# ---- 新布局: 1空 | [2空 7数字 1空]x3 | 1空 = 32列 ----
# 数字1(槽2,3) 区域内列2-8 → 全局列3-9
# 数字2(槽4,5) 区域内列2-8 → 全局列13-19
# 数字3(槽6,7) 区域内列2-8 → 全局列23-29
for i in range(16):
s2 = code12[2][i]; s3 = code12[3][i]
s4 = code12[4][i]; s5 = code12[5][i]
s6 = code12[6][i]; s7 = code12[7][i]
code12[2][i] = (s2 >> 1) & 0x1F # 数字1: 列3-7
code12[3][i] = ((s2 & 0x01) << 7) | ((s3 >> 1) & 0x40) \
| ((s4 >> 3) & 0x07) # 数字1列8-9 | 数字2列13-15
code12[4][i] = ((s4 & 0x07) << 5) | ((s5 & 0x80) >> 3) \
| ((s6 >> 5) & 0x01) # 数字2列16-19 | 数字3列23
code12[5][i] = ((s6 & 0x1F) << 3) | ((s7 & 0x80) >> 5) # 数字3列24-29
# memcpy 输出: 槽 2,3,4,5 → 每行 4 字节 = 32 列
out = [code12[s][i] for i in range(16) for s in (2,3,4,5)]
return out
def render(out, title):
print(f"\n=== {title} ===")
print("col: " + "".join(str(c % 10) for c in range(32)))
for row in range(16):
line = ""
for c in range(32):
byte = out[row*4 + c//8]
bit = (byte >> (7 - (c % 8))) & 1 # MSB first: bit7=列左
line += "#" if bit else "."
print(f"{row:2d} {line}")
# 每列统计
colsum = [0]*32
for row in range(16):
for c in range(32):
byte = out[row*4 + c//8]
colsum[c] += (byte >> (7 - (c % 8))) & 1
print("col#: " + "".join(str(colsum[c]) for c in range(32)))
# 亮列区间
lit = [c for c in range(32) if colsum[c] > 0]
print("亮列:", lit)
# ---------- 3. 测试几种字符组合 ----------
import itertools
# 原布局
for name, chars in [("OLD 123+0", [1,2,3,0]), ("OLD 456+7", [4,5,6,7]), ("OLD 888+8", [8,8,8,8])]:
render(simulate(chars), name)
# 新布局
for name, chars in [("NEW 123+0", [1,2,3,0]), ("NEW 456+7", [4,5,6,7]), ("NEW 888+8", [8,8,8,8]),
("NEW 000+0", [0,0,0,0]), ("NEW 999+9", [9,9,9,9]), ("NEW 111+1", [1,1,1,1])]:
render(simulate(chars, new_layout=True), name)
+85
View File
@@ -0,0 +1,85 @@
#include <stdio.h>
#include <stdint.h>
#include <string.h>
static const unsigned char Code_Number_16_12[17][32] = {
/* 0 */ { 0x00, 0x00, 0x3F, 0x02, 0x3F, 0x02, 0x31, 0x02, 0x31, 0x02, 0x31, 0x02, 0x31, 0x02, 0x31, 0x02, 0x31, 0x02, 0x31, 0x02, 0x31, 0x02, 0x31, 0x02, 0x31, 0x02, 0x3F, 0x02, 0x3F, 0x02, 0x00, 0x00 },
/* 1 */ { 0x00, 0x00, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x00, 0x00 },
/* 2 */ { 0x00, 0x00, 0x3F, 0x02, 0x3F, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x3F, 0x02, 0x3F, 0x02, 0x30, 0x00, 0x30, 0x00, 0x30, 0x00, 0x30, 0x00, 0x3F, 0x02, 0x3F, 0x02, 0x00, 0x00 },
/* 3 */ { 0x00, 0x00, 0x3F, 0x02, 0x3F, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x3F, 0x02, 0x3F, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x3F, 0x02, 0x3F, 0x02, 0x00, 0x00 },
/* 4 */ { 0x00, 0x00, 0x31, 0x02, 0x31, 0x02, 0x31, 0x02, 0x31, 0x02, 0x31, 0x02, 0x31, 0x02, 0x3F, 0x02, 0x3F, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x00, 0x00 },
/* 5 */ { 0x00, 0x00, 0x3F, 0x02, 0x3F, 0x02, 0x30, 0x00, 0x30, 0x00, 0x30, 0x00, 0x30, 0x00, 0x3F, 0x02, 0x3F, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x3F, 0x02, 0x3F, 0x02, 0x00, 0x00 },
/* 6 */ { 0x00, 0x00, 0x3F, 0x02, 0x3F, 0x02, 0x30, 0x00, 0x30, 0x00, 0x30, 0x00, 0x30, 0x00, 0x3F, 0x02, 0x3F, 0x02, 0x31, 0x02, 0x31, 0x02, 0x31, 0x02, 0x31, 0x02, 0x3F, 0x02, 0x3F, 0x02, 0x00, 0x00 },
/* 7 */ { 0x00, 0x00, 0x3F, 0x02, 0x3F, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x00, 0x00 },
/* 8 */ { 0x00, 0x00, 0x3F, 0x02, 0x3F, 0x02, 0x31, 0x02, 0x31, 0x02, 0x31, 0x02, 0x31, 0x02, 0x3F, 0x02, 0x3F, 0x02, 0x31, 0x02, 0x31, 0x02, 0x31, 0x02, 0x31, 0x02, 0x3F, 0x02, 0x3F, 0x02, 0x00, 0x00 },
/* 9 */ { 0x00, 0x00, 0x3F, 0x02, 0x3F, 0x02, 0x31, 0x02, 0x31, 0x02, 0x31, 0x02, 0x31, 0x02, 0x3F, 0x02, 0x3F, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x3F, 0x02, 0x3F, 0x02, 0x00, 0x00 },
/* 10 */ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
/* 11 */ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
/* 12 */ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
/* 13 */ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
/* 14 */ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
/* 15 */ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
/* 16 */ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }
};
/* 模拟: 填充 + 新移位 (照抄 led3number_new.c 逻辑) */
static void process(const uint8_t chars[4], uint8_t out[4][16])
{
uint8_t code12[8][16];
int roll, i;
memset(code12, 0, sizeof(code12));
for (roll = 0; roll < 4; roll++) {
uint8_t cc = chars[roll];
for (i = 0; i < 16; i++) {
if (cc == 0x20) {
code12[roll*2][i] = Code_Number_16_12[10][i*2];
code12[roll*2+1][i] = Code_Number_16_12[10][i*2+1];
} else {
code12[roll*2][i] = Code_Number_16_12[cc-0x30][i*2];
code12[roll*2+1][i] = (uint8_t)(Code_Number_16_12[cc-0x30][i*2+1] << 6);
}
}
}
for (i = 0; i < 16; i++) {
uint8_t s2 = code12[2][i];
uint8_t s3 = code12[3][i];
uint8_t s4 = code12[4][i];
uint8_t s5 = code12[5][i];
uint8_t s6 = code12[6][i];
uint8_t s7 = code12[7][i];
code12[2][i] = (uint8_t)((s2 >> 1) & 0x1F);
code12[3][i] = (uint8_t)(((s2 & 0x01) << 7) | ((s3 >> 1) & 0x40) | ((s4 >> 3) & 0x07));
code12[4][i] = (uint8_t)(((s4 & 0x07) << 5) | ((s5 & 0x80) >> 3) | ((s6 >> 5) & 0x01));
code12[5][i] = (uint8_t)(((s6 & 0x1F) << 3) | ((s7 & 0x80) >> 5));
}
memcpy(out, &code12[2][0], 64);
}
static void render(const char *name, const uint8_t out[4][16])
{
int r, c;
printf("=== %s ===\n", name);
printf("col: ");
for (c = 0; c < 32; c++) printf("%d", c % 10);
printf("\n");
for (r = 0; r < 16; r++) {
printf("%2d ", r);
for (c = 0; c < 32; c++) {
uint8_t byte = out[c/8][r];
int bit = (byte >> (7 - (c % 8))) & 1;
putchar(bit ? '#' : '.');
}
printf("\n");
}
}
int main(void)
{
uint8_t out[4][16];
/* 字符: 第1个被丢弃(协议), 后3个显示; 0x20=空格 */
process((uint8_t[]){'1','2','3','0'}, out); render("NEW 123+0", out);
process((uint8_t[]){' ','4','5','6'}, out); render("NEW 456+7", out);
process((uint8_t[]){'8','8','8','8'}, out); render("NEW 888+8", out);
return 0;
}
+9
View File
@@ -0,0 +1,9 @@
## 2026-08-19 15:35 — Gitea 禁用自助注册
- 需求:禁用 git.szdego.cn 自助注册,只允许管理员后台分配账户
- 架构发现:Gitea 跑在阿里云 8.155.27.249 的 Docker 容器(镜像 docker.gitea.com/gitea:latest,容器名 gitea),挂载 宿主机 /root/gitea/gitea → 容器 /data
- 运行配置:/root/gitea/gitea/gitea/conf/app.ini(容器内 /data/gitea/conf/app.ini
- 修改项:[service] DISABLE_REGISTRATION=true、SHOW_REGISTRATION_BUTTON=false、ENABLE_OPENID_SIGNUP=false
- 备份:/root/gitea/gitea/gitea/conf/app.ini.bak-20260819
- 重启:docker restart gitea;验证 /user/sign_up 显示 "Registration is disabled."
- SSHroot@8.155.27.249(本机已装 sshpass,公钥 openclaw-xde@dg-RH1288-V3 已生成但尚未加入远程 authorized_keys