STC8H单片机delay_ms函数闪烁不准?原因是参数溢出!

STC8H单片机delay_ms函数闪烁不准?原因是参数溢出!

问题背景

在基于STC8H单片机编写LED闪烁程序时,期望实现1秒(1000ms)的亮灭间隔,但实际闪烁速度远快于1秒。核心代码如下:

c 复制代码
while(1)
{
    P53 = 1;
    delay_ms(1000);  // 期望延时1秒,实际速度异常
    P53 = 0;
    delay_ms(1000);
}
问题根因

排查发现delay_ms函数的形参类型为unsigned char(U8/uint8_t),而U8类型的取值范围是0~255

  • 当传入1000时,数值超出U8的最大值255,发生数值溢出
  • 溢出后实际参与运算的数值为 1000 % 256 = 232(即仅延时232ms),导致闪烁间隔远小于1秒,视觉上闪烁变快。
解决方案
方案1:拆分延时(快速适配)

不修改原delay_ms函数,将1000ms拆分为4次250ms延时(250≤255,无溢出):

c 复制代码
#include <STC8H.H>
#include "gpio.h"
#include "delay.h"

#define mode_0

void gpio_config()
{
    GPIO_InitTypeDef gpio_init;
#ifdef mode_0
    gpio_init.Mode = GPIO_PullUp;
#endif
    gpio_init.Pin  = GPIO_Pin_3;
    GPIO_Inilize(GPIO_P5, &gpio_init);
}

// 封装1秒延时函数(避免重复写4次)
void delay_1s()
{
    delay_ms(250);
    delay_ms(250);
    delay_ms(250);
    delay_ms(250);
}

void main()
{
    gpio_config();
    P53 = 0;  // 灯灭
    
    while(1)
    {
        P53 = 1;  // 灯亮
        delay_1s();  // 精准延时1秒
        P53 = 0;  // 灯灭
        delay_1s();  // 精准延时1秒
    }
}
方案2:修改delay_ms形参类型(根治)

若想直接传入1000,需将delay_ms的形参改为unsigned int(U16/uint16_t,取值范围0~65535),适配STC8H的delay函数示例:

c 复制代码
// delay.h 头文件修改
#ifndef __DELAY_H
#define __DELAY_H

#include <STC8H.H>
#define FOSC 12  // 匹配单片机实际主频(如12MHz)

// 形参改为unsigned int(U16)
void delay_ms(unsigned int ms);  
void delay_us(unsigned char us);

#endif

// delay.c 实现修改
#include "delay.h"

void delay_us(unsigned char us)
{
    unsigned char i;
    while(us--)
    {
        for(i=0; i<FOSC/3; i++);  // STC8H单周期指令校准
    }
}

// 支持0~65535ms延时,无溢出
void delay_ms(unsigned int ms)
{
    unsigned int i;
    for(i=0; i<ms; i++)
    {
        delay_us(1000);
    }
}

修改后即可直接使用delay_ms(1000),无需拆分。

关键注意事项
  1. 数据类型取值范围

    • U8(unsigned char):0~255
    • U16(unsigned int):0~65535
    • U32(unsigned long):0~4294967295
      延时参数需匹配函数形参的类型范围,避免溢出。
  2. 主频校准
    delay函数内的FOSC需与单片机实际主频(如11.0592MHz、24MHz)一致,否则延时仍会有误差。

  3. 代码健壮性
    建议在封装延时函数时,增加参数范围检查(可选):

    c 复制代码
    void delay_ms(unsigned int ms)
    {
        // 防止传入超大值导致延时异常
        if(ms > 60000) ms = 60000; 
        unsigned int i;
        for(i=0; i<ms; i++)
        {
            delay_us(1000);
        }
    }
总结
  1. 核心问题:delay_ms形参为U8类型时,传入1000会溢出,实际仅延时232ms,导致LED闪烁变快;
  2. 快速解决 :将1000ms拆分为4次250ms延时(delay_ms(250)×4);
  3. 根治方案:将delay_ms的形参改为U16(unsigned int),支持直接传入1000;
  4. 避坑要点:编写延时函数时,务必匹配形参数据类型的取值范围,同时校准单片机主频。
相关推荐
天空'之城8 小时前
单片机基础核心知识点汇总(三十五)
单片机·嵌入式硬件
secondyoung8 小时前
I2C通信协议详解
arm开发·驱动开发·stm32·单片机·嵌入式硬件·mcu·51单片机
anew___9 小时前
蜂鸣器播放音乐——让 Arduino 唱出旋律
c++·stm32·单片机·嵌入式硬件·c
派葛穆9 小时前
Lerobot -飞特舵机ST-3215双舵机联动(ESP_NOW)
c语言
jianqiang.xue10 小时前
ESP-IDF保姆级入门40|量产烧录与产线测试全解:批量烧录方案/校准流程/功能测试/不良分拣/产线追溯,掌握工业级量产交付全流程
单片机·物联网·esp32
零依赖极客10 小时前
Day 6·1 ARMv8.2 dotprod——vdotq_s32 一条指令做 4 个点积
c语言·开发语言·人工智能·矩阵·arm·vllm
幼儿园蛋小黑13 小时前
单片机数码管LED灯独立按键中断定时器综合实战
单片机·嵌入式硬件
老王爱玩车13 小时前
深入理解指针2
c语言·开发语言·学习
自小吃多14 小时前
PCB Editor软件复制、改变、删除操作笔记
笔记·嵌入式硬件
数字新视界14 小时前
数据中心基础设施管理系统发布新版本,助力企业云化转型
嵌入式硬件·物联网·数据中心·数据中心基础设施管理·dcim管理系统