Type-C 长供电、上电即工作、无软关机,删除 app_boot/app_power 及 DP0 开关相关逻辑, 去掉空占位 app_fan_run 和无效的 usr_timer_pick_mode/rearm(数码管 4ms 扫描已 priority=1, 系统本来就不会进低功耗)。按键 5s 配对 / 12s OTA 改走 key.c 长按分级,去掉自计时与 1~5s 死区。 新增 app_defer,NVM/配对/OTA 只在 ISR 置位、在 500ms 任务上下文落地,避免再在 usr_timer 里写 flash。 规格书与注释同步精简。
149 lines
5.4 KiB
C
149 lines
5.4 KiB
C
/******************************************************************************
|
||
* @file bsp_ct1642.c
|
||
* @brief CBR3 CT1642 类数码管驱动实现(软件移位)
|
||
* @author cyWu <1917507415@qq.com>
|
||
* @date 2026.08.29
|
||
* @version V1.0.1,IO 分离:CT1642 独立 PG0=CLK/PG1=DATA,无总线共享机制
|
||
*
|
||
* @note 驱动协议严格参照 CT1642 手册(与 CSDN yitx 一致):
|
||
* 一帧 = 18bit,CLK 上升沿采样 DATA(DATA 只在 CLK=低时改变):
|
||
* [0:3] C1-C4 位选(低有效,入参 com 取反后发送,先发 C1)
|
||
* [4:9] 6 位保留位(固定填 1)
|
||
* [10:17] Q2-Q9 段码(LSB 先,seg 的 bit0 → Q2 引脚)
|
||
* 发完 18bit 后:CLK=高时 DATA 0→1 = 锁存;CLK=低时 DATA 0→1 = 输出。
|
||
* 段码/位选物理映射由 PCB 决定,SCAN_TEST 扫段/扫位已定型(见 board_pin.h)。
|
||
* 本驱动独立使用 PG0/PG1,与 AHT20 的 PC4/PC5 互不干扰。
|
||
******************************************************************************/
|
||
|
||
#include "bsp_ct1642.h"
|
||
#include "board_pin.h"
|
||
#include "asm/gpio.h"
|
||
|
||
/* 软件延时:1 次空循环(24MHz 下 ~0.1us 量级,gpio 调用本身开销另计)。
|
||
* ⚠ 提速历程:8→2(鬼影明显→一点点)→1(继续压残余微亮)。
|
||
* 若出现显示乱码/错位(低于 CT1642 最小脉宽),回调到 2。
|
||
* 软件压到极限后残余的微亮 = 硬件层(Q2-Q9 段线加 1~10k 下拉可根除)。 */
|
||
static void ct1642_delay(void)
|
||
{
|
||
volatile uint32_t i;
|
||
|
||
for (i = 0; i < 1; i++) {
|
||
/* nop */
|
||
}
|
||
}
|
||
|
||
/**
|
||
* @brief 初始化 PG0(CLK)/PG1(DATA) 为推挽输出,初始 0
|
||
* @note ⚠ 必须在第一次发帧前调用(app_disp_init 内)。
|
||
* CT1642 为纯输入从机,两根线全程推挽驱动即可,无需上拉/开漏。
|
||
* @return 无
|
||
*/
|
||
void bsp_ct1642_init(void)
|
||
{
|
||
gpio_set_pull_up(BOARD_DISP_CLK_PIN, 0);
|
||
gpio_set_pull_down(BOARD_DISP_CLK_PIN, 0);
|
||
gpio_set_die(BOARD_DISP_CLK_PIN, 1);
|
||
gpio_direction_output(BOARD_DISP_CLK_PIN, 0);
|
||
|
||
gpio_set_pull_up(BOARD_DISP_DATA_PIN, 0);
|
||
gpio_set_pull_down(BOARD_DISP_DATA_PIN, 0);
|
||
gpio_set_die(BOARD_DISP_DATA_PIN, 1);
|
||
gpio_direction_output(BOARD_DISP_DATA_PIN, 0);
|
||
}
|
||
|
||
static void ct1642_clk(uint8_t level)
|
||
{
|
||
gpio_direction_output(BOARD_DISP_CLK_PIN, level);
|
||
ct1642_delay();
|
||
}
|
||
|
||
static void ct1642_data(uint8_t level)
|
||
{
|
||
gpio_direction_output(BOARD_DISP_DATA_PIN, level);
|
||
ct1642_delay();
|
||
}
|
||
|
||
/**
|
||
* @brief 7 段数码管数字转段码(共阴,A=bit0 ... G=bit6,DP=bit7)
|
||
* @param digit 0~9;10='-'(G 段);11=全灭
|
||
* @return 段码
|
||
*/
|
||
uint8_t bsp_ct1642_seg(uint8_t digit)
|
||
{
|
||
static const uint8_t seg_tbl[12] = {
|
||
0x3F, /* 0: abcdef */
|
||
0x06, /* 1: bc */
|
||
0x5B, /* 2: abdeg */
|
||
0x4F, /* 3: abcdg */
|
||
0x66, /* 4: bcfg */
|
||
0x6D, /* 5: acdfg */
|
||
0x7D, /* 6: acdefg */
|
||
0x07, /* 7: abc */
|
||
0x7F, /* 8: abcdefg */
|
||
0x6F, /* 9: abcdfg */
|
||
0x40, /* '-': g */
|
||
0x00, /* 灭 */
|
||
};
|
||
|
||
if (digit > 11) {
|
||
digit = 11;
|
||
}
|
||
return seg_tbl[digit];
|
||
}
|
||
|
||
/**
|
||
* @brief 发一帧 18bit(不含消影):C1-C4 → 6保留 → Q2-Q9,再锁存+输出
|
||
* @note 内部函数;com/seg 的消影由 bsp_ct1642_send_frame 负责。
|
||
*/
|
||
static void ct1642_xfer(uint8_t seg, uint8_t com)
|
||
{
|
||
uint8_t i;
|
||
uint8_t posn = (uint8_t)(~com); /* C1-C4 低有效:位0=选中位 */
|
||
|
||
/* 起始空闲:CLK=低,DATA=高(规格“上电 CLK 低、DATA 高”) */
|
||
ct1642_data(1);
|
||
ct1642_clk(0);
|
||
|
||
/* 1. 移位 18bit:C1-C4(4) → 6位保留(填1) → Q2-Q9(8,LSB=Q2=seg bit0) */
|
||
for (i = 0; i < 4; i++) { /* C1-C4,先发 C1 */
|
||
ct1642_data((uint8_t)(posn & 0x01u));
|
||
ct1642_clk(0); ct1642_clk(1); /* 下降沿改完,上升沿采样 */
|
||
posn >>= 1;
|
||
}
|
||
for (i = 0; i < 6; i++) { /* 6 位保留,固定填 1 */
|
||
ct1642_data(1);
|
||
ct1642_clk(0); ct1642_clk(1);
|
||
}
|
||
for (i = 0; i < 8; i++) { /* Q2-Q9 段码,先发 Q2(=seg bit0) */
|
||
ct1642_data((uint8_t)(seg & 0x01u));
|
||
ct1642_clk(0); ct1642_clk(1);
|
||
seg >>= 1;
|
||
}
|
||
|
||
/* 2. 锁存:CLK 保持高,DATA 给 0→1 上升沿 */
|
||
ct1642_clk(1);
|
||
ct1642_data(0);
|
||
ct1642_data(1);
|
||
|
||
/* 3. 输出:CLK 拉低,DATA 给 0→1 上升沿(刷新该位显示) */
|
||
ct1642_clk(0);
|
||
ct1642_data(0);
|
||
ct1642_data(1);
|
||
}
|
||
|
||
/**
|
||
* @brief 发一帧刷新一位数码管(CT1642 18bit 协议)
|
||
* @param seg 段码(bit7=DP ... bit0=A,与 seg_tbl 一致;先发 bit0→Q2)
|
||
* @param com COM 位选掩码(bit3=C4 ... bit0=C1,仅 1 位置位;硬件低有效内部取反)
|
||
* @note ⚠ 不做任何消影预帧:CT1642 移位过程实时输出,“持续刷新”才是鬼影根因
|
||
* (切位瞬间杂段),预帧/全灭帧都无法根除,且每帧翻倍会饿死 ISR 喂狗导致
|
||
* 上电复位(实测)。鬼影的正确解法在应用层:数字没变就不刷新(值变化才
|
||
* 刷一次,其余时间锁存静止显示)。本函数保持单帧、极短,适配 ISR 上下文。
|
||
* @return 无
|
||
*/
|
||
void bsp_ct1642_send_frame(uint8_t seg, uint8_t com)
|
||
{
|
||
// ct1642_xfer(0, 0);
|
||
ct1642_xfer(seg, com); /* 单帧:18bit 移位 + 锁存 + 输出,无消影预帧 */
|
||
}
|