51单片机自定义毫秒级延时函数时遇到定时不准确的问题

51单片机自定义毫秒级延时函数时遇到定时不准确的问题

编程环境keil5,语言C

不明白具体原因

1.问题描述
刚接触51单片机编程,使用C语言想实现延迟,通过官方STC-ISP软件只能自动生成指定时间的延迟函数。非常不方便每次需要修改延迟时间都要重新生产延迟函数。于是想自己设计一个可以在编程时自己控制的毫秒级延迟程序。
自动生成的一毫秒延迟函数为:

void Delay1ms()        //@11.0592MHz
{
    unsigned char i, j;

    _nop_();
    _nop_();
    _nop_();
    i = 11;
    j = 190;
    do
    {
        while (--j);
    } while (--i);
}

这个时候是没有形式参数,和返回值。于是想修改成需要一个参数的函数,参数既为具体需要延迟的毫秒数的函数:

void Delayms(unsigned int count)        //@11.0592MHz
{
    unsigned int i, j;

    _nop_();
    _nop_();
    _nop_();
    i = 11 * count;
    j = 190;
    do
    {
        while (--j);
    } while (--i);
}

将数据类型unsigned char 修改成unsigned int是因为unsigned char 最大只能存储500+的数值容易溢出于是修改为unsign int类型。结果发现实际延迟效果远远大于于其的延迟效果。

2.可能原因
51延迟是通过多次计算来实现延迟,因为每次计算的机器周期数量是固定的,调用能实现精确的延迟。所以我觉得可能是因为修改类型后每次计算所需要的机器周期数量增大,所以实际延迟效果远远大于预期效果。

3.一种解决办法,改变嵌套循环i、j的类型,将count用于外层的while循环此时延迟效果与预期效果相近。

void Delayms(unsigned int count)        //@11.0592MHz
{
    unsigned char i, j;

  while(count)
{
  count-=1;

      _nop_();
      _nop_();
      _nop_();
      i = 11 ;
      j = 190;
      do
      {
          while (--j);
      } while (--i);
}
}

4.所以到底是为什么呢

可以看下 c参考手册中的 c语言--函数

每次函数调用会出现出栈,入栈操作,增加时间开销,这个值应该大体可推断,延迟时把这个时间减掉,应该精确度会提高

这种延时方法不好,不同的编译环境,不同优化级别都会导致不同时间
最好用定时器延时

前边几个nop也占用时间的,你应该单独做个函数调用这个函数

你这里误差的主要原因是因为i和j之前在while中生成,作用域为单次循环,因此每次循环需要重新创建以及销毁i和j变量,误差主要源于这里