找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 4937|回复: 24
收起左侧

一个关于单片机延时的困惑,想和大家请教

  [复制链接]
ID:518902 发表于 2020-10-9 21:49 | 显示全部楼层 |阅读模式
本帖最后由 laopihappy123 于 2020-10-10 12:06 编辑

学习单片机到现在 总共看到了3种方法进行延时软延时。
1.定义一个变量 然后while(变量--)
2.用软件,比如stc-isp或者单片机小精灵生成的一个延时函数
大概是delay1ms()
{
...........
}的样子
3.最后一种就是用定时器中断来算了,这个属于硬件计时了。
平常见大家用的都是第一种比较多,偶尔有第二种的。

问题1 :除了这几种 不知道还有没有别的好用的定时方式呢?我有个想法 能不能写个函数delayms(uint ms)
然后在里面包一个1ms的子函数,用for(i=0;i<ms;i++) 来调用 要多少毫秒来几次循环不就行了?!

这样岂不是更加轻松吗? 我再一想 调用这个1ms子函数应该应该也要耗费时钟周期的吧?!

问题2 :上述的方式会不会误差很大呢?我不太懂51单片机的汇编 这个在汇编里应该是JUMP指令吧(?)
但是我又没有示波器看不到,想到这里,我懊恼起来,就上论坛发了这个帖子,希望能向大家取取经。



回复

使用道具 举报

ID:685842 发表于 2020-10-10 08:35 | 显示全部楼层
单片机运行延时函数的时候进入函数也需要时间,如果要写一个通过while和for递增或者递减变量的延时函数,进入函数需要的时间也需要考虑一下。 而且这种延时不是很准确,如果对延时精度要求不是很高可以用,对精度要求高的情况下,还是使用定时器比较好。
这种通过耗费CPU运行速度的延时,在主时钟频率为一个固定值时可以用,但如果主时钟频率被更改,CPU的执行速度也会改变,使用这种方法的延时时间也会被改变
回复

使用道具 举报

ID:401564 发表于 2020-10-10 09:46 | 显示全部楼层
C是做不到一两个时钟精度的延时的,除非你在编译之后再通过汇编来更改,但这并不重要,1mS的延时肯定是不会有太大误差的
不需要去管汇编的,也不要用小精灵什么的,STC下载器有专门的延时代码生成,你设定好直接复制就可以用了
STC的8051指令执行时间是很乱的,你只能在STC的下载器那复制
不同单片机型号延时函数是不同的,换了单片机就要更改 51hei截图20201010094544.jpg
回复

使用道具 举报

ID:827584 发表于 2020-10-10 09:59 | 显示全部楼层
复制来的一些
51单片机的指令有单字节、双字节和三字节的,它们的指令周期不尽相同,一个单周期指令包含一个机器周期,即12个时钟周期,所以一条单周期指令被执行所占时间为12*(1/ 晶振频率)= x μs。常用单片机的晶振为11.0592MHz,12MHz,24MHz。其中11.0592MHz的晶振更容易产生各种标准的波特率,后两种的一个机器周期分别为1 μs和2 μs,便于精确延时。

接下来列出这三种不同的晶振的延时函数

1、 11.0592MHz

//N ms延时
void delay_ms(uint n)
{
uint i,j;
for(i=n;i>0;i–)
for(y=114;y>0;y–);
}

2、12MHz晶振


//延时n毫秒
void delay_ms(unsigned int n)
{
    unsigned int i=0,j=0;
    for(i=0;i<n;i++)
        for(j=0;j<123;j++);
}
1
2
3
4
5
6
7
8

//延时n秒
void delay_m(unsigned int n)
{
    unsigned int i=0,j=0;
    for(i=0;i<n;i++)
        for(j=0;j<21738;j++);
}
1
2
3
4
5
6
7
8
//延时10*n微秒
void delay_10um(unsigned int n)
{
    while(n--);
}
1
2
3
4
5
3、24MHz晶振

//延时n毫秒
void delay_ms(unsigned int n)
{
unsigned int i=0,j=0;
for(i=0;i

//延时n秒  
void delay_s(unsigned int n)  
{  
    unsigned int i=0,j=0;  
    for(i=0;i<n;i++)  
        for(j=0;j<54053;j++);   
}  
1
2
3
4
5
6
7
//延时10*n微秒  
void delay_10us(unsigned int n)  
{  
    unsigned int i=0;  
    char j=0;  
    for(i=0;i<n;i++)  
        for(j=0;j<2;j++);  
}  
1
2
3
4
5
6
7
8
建议大家封装为头文件,可以方便的调用。

接下来介绍几个自动适应主时钟的延时函数

//参数:ms,要延时的ms数,自动适应主时钟  
#define MAIN_Fosc        11059200UL    //定义主时钟HZ  
typedef unsigned int INT16U;  

void delay_ms(INT16U ms)    //INT16U 等价于 unsigned int  
{  
    INT16U i;  
    do{  
        i=MAIN_Fosc/9600;  
        while(--i);     //96T per loop  
    }while(--ms);       //--ms  ms=ms-1  
}  
1
2
3
4
5
6
7
8
9
10
11
12
//5us 延时函数,自动适应主时钟  
#define MAIN_Fosc        11059200UL    //定义主时钟HZ  

void delay5us()  
{  
    #if MAIN_Fosc == 11059200  
        _nop_();  
    #elif MAIN_Fosc == 12000000  
        _nop_();  
    #elif MAIN_Fosc == 22118400  
        _nop_(); _nop_(); _nop_();  
    #elif  
}  
1
2
3
4
5
6
7
8
9
10
11
12
13
单片机中还可自动生成

//11.0592MHZ延时100微秒

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

    _nop_();
    _nop_();
    i = 2;
    j = 15;
    do
    {
        while (--j);
    } while (--i);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
//100US

void Delay100us()       //@12.000MHz
{
    unsigned char i, j;

    i = 2;
    j = 39;
    do
    {
        while (--j);
    } while (--i);
}
1
2
3
4
5
6
7
8
9
10
11
12
//100US

void Delay100us()       //@24.000MHz
{
    unsigned char i, j;

    i = 3;
    j = 82;
    do
    {
        while (--j);
    } while (--i);
}
回复

使用道具 举报

ID:822755 发表于 2020-10-10 10:09 | 显示全部楼层
软件延时,在多事件要处理的情况下,影响响应速度。尽量少用。
当然,如果用操作系统,在任务中,是可以调用系统的延时函数的。
回复

使用道具 举报

ID:739545 发表于 2020-10-10 10:49 | 显示全部楼层
函数的延时和硬件有很大关系,如果对时间要求比较精确的话,这种函数延时是不可靠的
回复

使用道具 举报

ID:298952 发表于 2020-10-10 16:15 | 显示全部楼层
你的这种延时可以使用,不过只能是使用在延时时间不需要很精确的情况下。
因为for循环中还需要判断和跳转之类的操作,所以延时函数执行起来的时间会比预想的时间长,所以你这种方式只能实现大概的延时,而且肯定比预想的时间长,如果碰巧在延时函数执行中遇见了中断那么延时时间还要另加执行中断的时间。
时间要求较高的话还是放在中断里面操作比较稳妥
回复

使用道具 举报

ID:518902 发表于 2020-10-10 18:18 | 显示全部楼层

感谢您的回复
回复

使用道具 举报

ID:518902 发表于 2020-10-10 18:18 | 显示全部楼层
渐入寒冬 发表于 2020-10-10 08:35
单片机运行延时函数的时候进入函数也需要时间,如果要写一个通过while和for递增或者递减变量的延时函数,进 ...

是这样的 所以还是定时器比较精准
回复

使用道具 举报

ID:518902 发表于 2020-10-10 18:19 | 显示全部楼层
Y_G_G 发表于 2020-10-10 09:46
C是做不到一两个时钟精度的延时的,除非你在编译之后再通过汇编来更改,但这并不重要,1mS的延时肯定是不会有 ...

这个软件的确不错
回复

使用道具 举报

ID:827413 发表于 2020-10-10 18:19 | 显示全部楼层
函数的延时一般要改变硬件系统,所以精确的调整函数的延时是比较难的,容易造成别的软件也延时
回复

使用道具 举报

ID:462827 发表于 2020-10-10 18:25 | 显示全部楼层
能,但不精确
回复

使用道具 举报

ID:420836 发表于 2020-10-11 04:57 | 显示全部楼层
还有一种方法可以通过运行NOP指令一定次数来获得所需的延迟,从而在单片机程序中产生延迟。
回复

使用道具 举报

ID:828091 发表于 2020-10-11 08:05 | 显示全部楼层

软件延时,在多事件要处理的情况下,影响响应速度。尽量少用。
当然,如果用操作系统,在任务中,是可以调用系统的延时函数的。
回复

使用道具 举报

ID:828160 发表于 2020-10-11 09:43 | 显示全部楼层
精确定时用硬件定时器,不精确的定时用指令延时
回复

使用道具 举报

ID:822598 发表于 2020-10-11 12:11 | 显示全部楼层
使用定时器延时会更好,比指令延时更加准确,建议使用定时器延时
回复

使用道具 举报

ID:687694 发表于 2020-10-12 23:06 | 显示全部楼层
真心提示,少用延时,因为单片机本身就是资源匮乏。
回复

使用道具 举报

ID:518902 发表于 2020-10-13 15:27 | 显示全部楼层
lovexulu 发表于 2020-10-12 23:06
真心提示,少用延时,因为单片机本身就是资源匮乏。

那么用硬件定时器吗...感觉硬件中断有点麻烦啊
回复

使用道具 举报

ID:548551 发表于 2020-10-13 17:56 | 显示全部楼层
laopihappy123 发表于 2020-10-13 15:27
那么用硬件定时器吗...感觉硬件中断有点麻烦啊

请问中断麻烦吗? 你这边使用主定时的时候怎么定时的? 还有就时一个案子需要很多定时的时候你怎么用? 还时用延时? 那为什么不用基准的中断来定时呢,?把所有的定时都在这上面进行计算.这样多方便啊. 还有就时你们跑主程序while(1)里面的时候都不需要定时?让它一直不停的指令周期跑?
回复

使用道具 举报

ID:829423 发表于 2020-10-13 18:05 | 显示全部楼层
我也有此问题,希望解决
回复

使用道具 举报

ID:829453 发表于 2020-10-13 19:07 | 显示全部楼层
而且肯定比预想的时间长,如果碰巧在延时函数执行中遇见了中断那么延时时间还要另
回复

使用道具 举报

ID:687694 发表于 2020-10-13 19:17 | 显示全部楼层
laopihappy123 发表于 2020-10-13 15:27
那么用硬件定时器吗...感觉硬件中断有点麻烦啊

不,我说的是延时程序,利用for。while空循环之类的定时,少用,可以用内部定时器,配置好之后,使用时填装装载值,溢出内部中断。这种方式单片机可以在计时期间去做其他的事情,长计时可以中断中自动填装启动计时,设置全局变量累计中断次数,以取得较长时间的定时效果,如果要求精度非常高,请用外部硬件定时器外部中断。如果只是为了定时,没有其他的任务处理,那么单片机本身也可以做高精度定时器,请使用外部晶振,另外晶振负载电容一定要匹配。晶振PBC走线外包地过孔。线尽量短。定时精度还是有保证的。
回复

使用道具 举报

ID:518902 发表于 2020-10-13 20:25 | 显示全部楼层
lovexulu 发表于 2020-10-13 19:17
不,我说的是延时程序,利用for。while空循环之类的定时,少用,可以用内部定时器,配置好之后,使用时填 ...

懂了,谢谢您
回复

使用道具 举报

ID:807680 发表于 2020-10-13 23:38 | 显示全部楼层
你的方法可行,确实是有用这个方法的,那个τ 宝STM32战舰等系列卖家给的延迟函数里就有
回复

使用道具 举报

ID:414556 发表于 2020-10-15 22:22 | 显示全部楼层
看要求,一般程序延时受程序影响,要求准的还是用中断靠谱
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表