#define SEG1_PIN GPIO_PIN_4 #define SEG2_PIN GPIO_PIN_5 #define SEG3_PIN GPIO_PIN_6 #define SEG4_PIN GPIO_PIN_7 #define SEG5_PIN GPIO_PIN_8 #define DISP_PORT GPIOA #define DISP_MASK (SEG1_PIN | SEG2_PIN | SEG3_PIN | SEG4_PIN | SEG5_PIN) /** * [url=/u/brief]@brief[/url] 原子刷新:仅将标记为输出的引脚从输入切换为推挽 * [url=/u/NOTE]@NOTE[/url] 前置条件:全部引脚已经处于浮空输入状态,ODR已提前预加载完成 * @param out_dir : bit=1 该引脚设推挽输出;bit=0 保持高阻输入 * [url=/u/Attention]@Attention[/url] 存在极低概率被休眠/初始化流程抢占,内部自带临界保护 */ void disp_refresh(uint32_t out_dir) { uint32_t dir = out_dir & DISP_MASK; if (dir == 0) return; GPIO_InitTypeDef gpio_pp = { .Pin = dir, .Mode = GPIO_MODE_OUTPUT_PP, .Pull = GPIO_NOPULL, .Speed = GPIO_SPEED_FREQ_LOW}; uint32_t primask = __get_PRIMASK(); __disable_irq(); HAL_GPIO_Init(DISP_PORT, &gpio_pp); __set_PRIMASK(primask); } /** * @brief 预设置引脚电平(兼容浮空输入状态下直接写入ODR锁存,底层逻辑同HAL_GPIO_WritePin) * @param mask : 需要操作的引脚掩码 * @param state: GPIO_PIN_SET / GPIO_PIN_RESET * @note 建议在disp_blank之后(IO浮空输入)调用,仅预存ODR,不会直接驱动引脚输出 */ void disp_set_pin(uint32_t mask, GPIO_PinState state) { mask &= DISP_MASK; if (mask == 0) return; if (state == GPIO_PIN_SET) DISP_PORT->BSRR = mask; else DISP_PORT->BSRR = (uint32_t)mask << 16U; } static inline void disp_set_high(uint32_t mask) { disp_set_pin(mask, GPIO_PIN_SET); } static inline void disp_set_low(uint32_t mask) { disp_set_pin(mask, GPIO_PIN_RESET); } /** * @brief 消隐Blank * @note 全部切高阻输入,同时将DISP_MASK内ODR统一清零作为基准 * 基准选全0,适合本扫描周期内大部分引脚为0、仅少量引脚需要置1的场景,后续仅需置1,无需清零; * 若大部分引脚为1、仅少量引脚需要置0,则改用基准全1,后续仅需置0 * @attention 5线查理复用理论最多支持20态,本例示范使用19态(0~18) */ void disp_blank(void) { GPIO_InitTypeDef gpio_conf = {0}; gpio_conf.Pin = DISP_MASK; gpio_conf.Mode = GPIO_MODE_INPUT; gpio_conf.Pull = GPIO_NOPULL; uint32_t primask = __get_PRIMASK(); __disable_irq(); HAL_GPIO_Init(DISP_PORT, &gpio_conf); // ODR基准:全部清零 DISP_PORT->BSRR = (uint32_t)DISP_MASK << 16U; __set_PRIMASK(primask); } /** * @brief 休眠配置:全部推挽输出固定电平 * @note 仅深度休眠场景有意义:高阻悬空引脚会引入额外漏电流,设置确定电平可降低深度休眠功耗; * 正常运行、浅休眠时该漏电流影响很小,可不处理。 */ void disp_sleep(void) { GPIO_InitTypeDef gpio_conf = {0}; gpio_conf.Pin = DISP_MASK; gpio_conf.Mode = GPIO_MODE_OUTPUT_PP; gpio_conf.Pull = GPIO_NOPULL; gpio_conf.Speed = GPIO_SPEED_FREQ_LOW; uint32_t primask = __get_PRIMASK(); __disable_irq(); DISP_PORT->BSRR = DISP_MASK; HAL_GPIO_Init(DISP_PORT, &gpio_conf); __set_PRIMASK(primask); } void disp_init(void) { __HAL_RCC_GPIOA_CLK_ENABLE(); disp_blank(); disp_sleep(); } void PS_ScanDisp(void) { static uint8_t seg = 0; disp_blank(); if (++seg > 18) // 0~18,合计19态;5线查理复用理论上限20态 seg = 0; uint32_t dir_val = 0; uint32_t port_val = 0; switch (seg) { case 0: // dig1为业务自定义位域变量,使用者根据实际显示定义 if (dig1.bits.B) { port_val = SEG3_PIN; dir_val = SEG3_PIN | SEG4_PIN; } break; // 其余18个case自行扩充 default: break; } disp_set_high(port_val); disp_refresh(dir_val); }
收藏0 举报
datouyuan 发表于 2026-8-27 17:05 我之前只在 51 以及更低端的 MCU 上实际使用过查理复用方案,对于楼主所用的芯片并不熟悉,这份示范代码就 ...
本版积分规则 发表回复 回帖并转播 回帖后跳转到最后一页
等级类勋章
发帖类勋章
时间类勋章
人才类勋章
本站内容禁止未经授权用于AI模型训练。如需商业数据合作,请联系我们。
扫码关注 21ic 官方微信
扫码关注嵌入式微处理器
扫码关注电源系统设计
扫码关注21ic项目外包
扫码浏览21ic手机版
本站介绍 | 申请友情链接 | 欢迎投稿 | 隐私声明 | 广告业务 | 网站地图 | 联系我们 | 诚聘英才
京公网安备 11010802024343号