数码管手动管脚控制: dispauto 开关 + dispset 命令 (APP V1.00.33)

- dispauto [on|off]: 关掉自动显示扫描, 7 脚置高阻, 供手动控制
- dispset <pin1-7> [0|1|z]: 手工驱动数码管 pin1~7 (pin1=PB0..pin7=PA6)
- app_display.c: g_disp_auto + display_auto_set/get + display_pin_map,
  display_task 自动关时释放管脚并让出
- 仅 APP 改动, Boot 不动 (仍 V1.00.07)
- docs/开发日志.md: 新增 §61
This commit is contained in:
evan.liu 2026-09-13 09:12:02 +08:00
parent 10531c2fa8
commit fb681a4b69
16 changed files with 6752 additions and 6363 deletions

View File

@ -1525,3 +1525,26 @@ APP2 链接的镜像发向 APP1 区。设备端 END 校验(向量表 Reset PC
- 命令表注册:`disp <value> [f] [hex]: set 7-seg display value`。
- 版本:APP `V1.00.31` → `V1.00.32`(`APP_FW_VERSION_NUM` 0x0001001F →
0x00010020)。Boot 不动(仍 V1.00.07)。
## 61. 数码管手动管脚控制:`dispauto` 开关 + `dispset` 命令(2026-09-06,APP V1.00.33,仅 APP)
- 需求:① 加开关可关掉自动显示扫描,用户手工控制数码管 1~7 管脚;② 加
`dispset pin1-7 0/1`,pin1~7 直接映射到数码管对应的 CPU IO。
- 管脚映射(同 §58,权威表在 `app_display.c` 的 `s_disp_pin[]`):
`pin1=PB0 pin2=PB1 pin3=PA0 pin4=PA1 pin5=PB11 pin6=PB13 pin7=PA6`。
- 实现:
- `app_display.c/h`:
- 新增 `g_disp_auto`(默认 1=自动)+ `display_auto_set/get()`;
- `display_task`:自动关(`g_disp_auto==0`)时把 7 脚一次性置高阻
(`all_pins_input()`,用 `last_auto` 沿检测只做一次),随后仅喂狗+
20ms 让出,不碰管脚;自动开时恢复正常扫描;
- `display_pin_map(pin_no 1..7, &port, &pin)`:管脚号→GPIO 端口+掩码。
- `cli_core.c`:
- `dispauto [on|off]`:开关自动显示并回显状态;
- `dispset <pin1-7> [0|1]`:手工驱动管脚——`0` 拉低 / `1` 拉高
(输出推挽),`z` 置高阻(Charlieplexing 手工驱动必需),不带值读电平;
自动扫描未关时打印 warning 提示先 `dispauto off`;回显带 CPU IO 名
(如 `pin1 (PB0) = 1`),用 `cli_pin_str()` 由 port+pin 生成;
- `cli_parse_disp_pin()`:解析 `pin1`~`pin7`(或裸 `1`~`7`)。
- 版本:APP `V1.00.32` → `V1.00.33`(`APP_FW_VERSION_NUM` 0x00010020 →
0x00010021)。Boot 不动(仍 V1.00.07)。

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -18,6 +18,7 @@ extern "C" {
#endif
#include <stdint.h>
#include "n32wb03x.h"
/* Display type / unit (controls the DIG6 "deg F" indicator A6) */
#define DISP_TYPE_CELSIUS 0u /* degree C: A6 off */
@ -41,6 +42,27 @@ void display_set(float value, uint8_t type, uint8_t base);
*/
void display_task(void *pvParameters);
/**
* @brief Enable (1) / disable (0) the automatic Charlieplexing scan.
* When disabled the scan task releases all 7 pins to high-impedance
* so another task (e.g. the "dispset" CLI) can drive them manually.
*/
void display_auto_set(uint8_t on);
/**
* @brief @return 1 when the automatic scan is enabled.
*/
uint8_t display_auto_get(void);
/**
* @brief Map a display pin number (1..7) to its GPIO port + pin mask.
* @param pin_no display pin number 1..7 (pin1=PB0 ... pin7=PA6)
* @param port out: GPIO port
* @param pin out: GPIO pin mask
* @return 1 on success, 0 when pin_no is out of range.
*/
int display_pin_map(uint8_t pin_no, GPIO_Module** port, uint16_t* pin);
#ifdef __cplusplus
}
#endif

View File

@ -9,12 +9,12 @@
#define __APP_VERSION_H__
#ifndef APP_FW_VERSION
#define APP_FW_VERSION "V1.00.32"
#define APP_FW_VERSION "V1.00.33"
#endif
/* Numeric form used by the BLE info query / OTA records: 0x00MMmmpp */
#ifndef APP_FW_VERSION_NUM
#define APP_FW_VERSION_NUM 0x00010020u
#define APP_FW_VERSION_NUM 0x00010021u
#endif
#endif /* __APP_VERSION_H__ */

View File

@ -106,6 +106,8 @@ static volatile float g_disp_value = 0.0f;
static volatile uint8_t g_disp_type = DISP_TYPE_CELSIUS;
/** Number base: DISP_BASE_DECIMAL / DISP_BASE_HEX. */
static volatile uint8_t g_disp_base = DISP_BASE_DECIMAL;
/** Automatic scan enable: 1 = auto scan, 0 = manual pin control. */
static volatile uint8_t g_disp_auto = 1u;
/* Private function prototypes -----------------------------------------------*/
/* Private functions ----------------------------------------------------------*/
@ -334,30 +336,80 @@ void display_set(float value, uint8_t type, uint8_t base)
g_disp_base = base;
}
/**
* @brief Enable (1) / disable (0) the automatic scan.
*/
void display_auto_set(uint8_t on)
{
g_disp_auto = (on != 0u) ? 1u : 0u;
}
/**
* @brief @return 1 when the automatic scan is enabled.
*/
uint8_t display_auto_get(void)
{
return g_disp_auto;
}
/**
* @brief Map a display pin number (1..7) to its GPIO port + pin mask.
*/
int display_pin_map(uint8_t pin_no, GPIO_Module** port, uint16_t* pin)
{
if (pin_no < 1u || pin_no > 7u)
{
return 0;
}
*port = s_disp_pin[pin_no - 1u].port;
*pin = s_disp_pin[pin_no - 1u].pin;
return 1;
}
/**
* @brief Display driver task: decode the global value and scan every lit
* segment, one at a time, forever.
*/
void display_task(void *pvParameters)
{
uint8_t last_auto = 1u; /* auto scan is on at boot */
(void)pvParameters;
all_pins_input();
for (;;)
{
float value = g_disp_value;
uint8_t type = g_disp_type;
uint8_t base = g_disp_base;
float value;
uint8_t type;
uint8_t base;
uint8_t digits[DISP_DIGITS];
uint8_t dp_flag;
uint8_t d, s;
uint8_t segmask;
display_decode(value, base, digits, &dp_flag);
app_wdt_heartbeat();
/* Manual mode (auto disabled): release every pin once, then keep the
* task alive and leave the pins for the caller to drive. */
if (g_disp_auto == 0u)
{
if (last_auto)
{
all_pins_input();
last_auto = 0u;
}
vTaskDelay(pdMS_TO_TICKS(20));
continue;
}
last_auto = 1u;
value = g_disp_value;
type = g_disp_type;
base = g_disp_base;
display_decode(value, base, digits, &dp_flag);
/* DIG1..DIG5 */
for (d = 1u; d <= DISP_DIGITS; d++)
{

View File

@ -622,6 +622,158 @@ static void CmdDisp(int argc, char* argv[])
}
}
/**
* @brief Parse a display pin selector "pin1".."pin7" (or bare "1".."7").
* @return 1 on success, 0 on bad input.
*/
static int cli_parse_disp_pin(const char* s, uint8_t* pin_no)
{
if (s[0] == 'p' || s[0] == 'P')
{
if ((s[1] != 'i' && s[1] != 'I') || (s[2] != 'n' && s[2] != 'N'))
{
return 0;
}
s += 3;
}
if (s[0] < '1' || s[0] > '7' || s[1] != '\0')
{
return 0;
}
*pin_no = (uint8_t)(s[0] - '0');
return 1;
}
/**
* @brief Format a GPIO port + pin mask as a pin name ("PA6"/"PB0"/"PB11").
*/
static void cli_pin_str(GPIO_Module* port, uint16_t pin, char* out)
{
char pc = (port == GPIOA) ? 'A' : 'B';
uint8_t n = 0u;
while ((pin & 1u) == 0u)
{
pin >>= 1;
n++;
}
if (n >= 10u)
{
out[0] = 'P';
out[1] = pc;
out[2] = '1';
out[3] = (char)('0' + (n - 10u));
out[4] = '\0';
}
else
{
out[0] = 'P';
out[1] = pc;
out[2] = (char)('0' + n);
out[3] = '\0';
}
}
/**
* @brief "dispauto [on|off]": enable/disable the automatic display scan.
* Turning it off releases all 7 display pins to high-impedance so
* "dispset" can drive them manually.
*/
static void CmdDispAuto(int argc, char* argv[])
{
if (argc >= 2)
{
if (strcmp(argv[1], "on") == 0)
{
display_auto_set(1u);
}
else if (strcmp(argv[1], "off") == 0)
{
display_auto_set(0u);
}
else
{
cli_write("usage: dispauto [on|off]\r\n");
return;
}
}
cli_printf("auto display: %s\r\n", display_auto_get() ? "on" : "off");
}
/**
* @brief "dispset <pin1-7> [0|1]": drive a display pin low/high manually.
* pin1..pin7 map to PB0/PB1/PA0/PA1/PB11/PB13/PA6. "z" = high-Z.
* No value reads the current level. Use after "dispauto off".
*/
static void CmdDispSet(int argc, char* argv[])
{
GPIO_Module* port;
uint16_t pin;
uint8_t pin_no;
GPIO_InitType s;
char name[8];
if (argc < 2)
{
cli_write("usage: dispset <pin1-7> [0|1] (e.g. dispset pin1 1)\r\n");
return;
}
if (!cli_parse_disp_pin(argv[1], &pin_no) ||
!display_pin_map(pin_no, &port, &pin))
{
cli_printf("bad pin: %s (use pin1..pin7)\r\n", argv[1]);
return;
}
cli_pin_str(port, pin, name);
if (argc >= 3)
{
if (display_auto_get())
{
cli_write("warning: auto display is ON - use 'dispauto off' first\r\n");
}
if (argv[2][0] == '1' && argv[2][1] == '\0')
{
GPIO_InitStruct(&s);
s.Pin = pin;
s.GPIO_Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitPeripheral(port, &s);
GPIO_SetBits(port, pin);
cli_printf("pin%u (%s) = 1\r\n", (unsigned)pin_no, name);
}
else if (argv[2][0] == '0' && argv[2][1] == '\0')
{
GPIO_InitStruct(&s);
s.Pin = pin;
s.GPIO_Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitPeripheral(port, &s);
GPIO_ResetBits(port, pin);
cli_printf("pin%u (%s) = 0\r\n", (unsigned)pin_no, name);
}
else if (argv[2][0] == 'z' || argv[2][0] == 'Z')
{
/* high-impedance (release the pin) */
GPIO_InitStruct(&s);
s.Pin = pin;
s.GPIO_Mode = GPIO_MODE_INPUT;
s.GPIO_Pull = GPIO_NO_PULL;
GPIO_InitPeripheral(port, &s);
cli_printf("pin%u (%s) = high-Z\r\n", (unsigned)pin_no, name);
}
else
{
cli_write("usage: dispset <pin1-7> [0|1] (0=low, 1=high, z=hi-Z)\r\n");
}
}
else
{
cli_printf("pin%u (%s) = %u\r\n", (unsigned)pin_no, name,
(unsigned)(GPIO_ReadInputDataBit(port, pin) ? 1u : 0u));
}
}
/* Command table; add new commands here */
static const CliCmd_t s_cmds[] = {
{"help", "help [cmd]: list commands / show one command's help", CmdHelp},
@ -639,6 +791,8 @@ static const CliCmd_t s_cmds[] = {
{"reset", "reset: system reset (reboot)", CmdReset},
{"pinset", "pinset <pxN> [0|1]: set/read GPIO level (pa0-6/pb0-13)", CmdPinSet},
{"disp", "disp <value> [f] [hex]: set 7-seg display value", CmdDisp},
{"dispauto", "dispauto [on|off]: enable/disable auto display scan", CmdDispAuto},
{"dispset", "dispset <pin1-7> [0|1]: drive display pin (pin1=PB0..pin7=PA6)", CmdDispSet},
{"factory", "factory: restore params to defaults and reboot", CmdFactory},
{"uartrst", "uartrst: re-init USART1 (460800 8N1), flush rx queue", CmdUartRst},
{"uartinfo", "uartinfo: show USART1 pins/baud/format", CmdUartInfo},

Binary file not shown.

Binary file not shown.

File diff suppressed because it is too large Load Diff

Binary file not shown.

View File

@ -1,7 +1,7 @@
{
"file": "mothercup_ble_prod_ota.bin",
"target_bank": 1,
"size": 58060,
"crc32": "0x71068ACD",
"version": 65568
"size": 59184,
"crc32": "0xCE4E676C",
"version": 65569
}

View File

@ -1,7 +1,7 @@
{
"file": "mothercup_ble_prod_ota_app2.bin",
"target_bank": 2,
"size": 58364,
"crc32": "0x6DC77249",
"version": 65568
"size": 59484,
"crc32": "0x3A51266C",
"version": 65569
}