找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 1810|回复: 20
打印 上一主题 下一主题
收起左侧

单片机程序一般用什么做延时

  [复制链接]
跳转到指定楼层
楼主
ID:959051 发表于 2022-7-20 09:21 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
是用定时器做延时还是直接在主程序里面做延时,都有什么弊端和优点?定时器数量有限,怎么只用一个定时器,完成其他时间的定时,比如100ms  10ms  1000ms,能用一个定时器吗?方法是什么?本人是新手,忘各位大佬多多指教,谢谢
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏4 分享淘帖 顶 踩
回复

使用道具 举报

沙发
ID:752974 发表于 2022-7-20 11:02 | 只看该作者
用一个定时器即可,将定时器设置成标准节拍,如1MS。需要多少定时时间,在定时器中断服务程序中计数就可以了。
回复

使用道具 举报

板凳
ID:332444 发表于 2022-7-20 11:03 | 只看该作者
不同变量获得不同时间
回复

使用道具 举报

地板
ID:161164 发表于 2022-7-20 11:26 | 只看该作者
100us以下用delay
100us~1ms看情况用delay或定时器
1ms以上用定时器

一个定时器产生不同时间心跳例子
  1. bit Flag10ms = 0;
  2. bit Flag20ms = 0;
  3. bit Flag50ms = 0;
  4. bit Flag100ms = 0;
  5. void 1ms中断函数() interrupt x
  6. {
  7.         static unsigned char SysDiv10ms=0;
  8.         static unsigned char SysDiv20ms=0;
  9.         static unsigned char SysDiv50ms=0;
  10.         static unsigned char SysDiv100ms=0;
  11.         if(++SysDiv10ms>=10)
  12.         {
  13.                 SysDiv10ms = 0;
  14.                 Flag10ms = 1;//10ms心跳
  15.         }
  16.         if(++SysDiv20ms>=20)
  17.         {
  18.                 SysDiv20ms = 0;
  19.                 Flag20ms = 1;//20ms心跳
  20.         }
  21.         if(++SysDiv50ms>=50)
  22.         {
  23.                 SysDiv50ms = 0;
  24.                 Flag50ms = 1;//50ms心跳
  25.         }
  26.         if(++SysDiv100ms>=100)
  27.         {
  28.                 SysDiv100ms = 0;
  29.                 Flag100ms = 1;//100ms心跳
  30.         }
  31. }
  32. void main()
  33. {
  34.         while(1)
  35.         {
  36.                 if(Flag10ms)
  37.                 {
  38.                                 Flag10ms = 0;
  39.                                 //your code
  40.                 }
  41.                 if(Flag20ms)
  42.                 {
  43.                                 Flag20ms = 0;
  44.                                 //your code
  45.                 }
  46.                 if(Flag50ms)
  47.                 {
  48.                                 Flag50ms = 0;
  49.                                 //your code
  50.                 }
  51.                 if(Flag100ms)
  52.                 {
  53.                                 Flag100ms = 0;
  54.                                 //your code
  55.                 }
  56.         }       
  57. }
复制代码




回复

使用道具 举报

5#
ID:883242 发表于 2022-7-20 11:28 | 只看该作者
ms级别的延迟用定时器就行了,100ms  10ms  1000ms就是加一个变量的问题,你觉得挺难,单片机在延迟的万分之一时间就能把变量算明白。
回复

使用道具 举报

6#
ID:86450 发表于 2022-7-20 11:39 | 只看该作者
你看是单任务还是多任务。 就是说你在延时的时候还要响应其他的事件吗?如果延时时候不干其他的时间,那用软件延时方便,还容易理解。
回复

使用道具 举报

7#
ID:401564 发表于 2022-7-20 11:54 | 只看该作者
超过1mS的,基本都是用定时器
像while这种等待的延时,一般是用在延时几个时钟或者精度并不高的延时中,像有的延时要求并不高,只要是超过一定的时间就行的
比如IIC延时,只要延时在10uS以上,对其它的就没有什么要求的,就用软件延时
回复

使用道具 举报

8#
ID:959051 发表于 2022-7-20 19:49 | 只看该作者
lkc8210 发表于 2022-7-20 11:26
100us以下用delay
100us~1ms看情况用delay或定时器
1ms以上用定时器

谢谢 大佬
回复

使用道具 举报

9#
ID:959051 发表于 2022-7-22 19:07 | 只看该作者
lkc8210 发表于 2022-7-20 11:26
100us以下用delay
100us~1ms看情况用delay或定时器
1ms以上用定时器

你好,大佬,可以用这种方法延时5秒到10秒吗?另外问下,我想获取一个ADC的值,但是想10秒获取一次,请问具体要怎么做,是延时10秒去获取一下数据吗?
回复

使用道具 举报

10#
ID:883242 发表于 2022-7-22 19:12 | 只看该作者
guoqiang881245 发表于 2022-7-22 19:07
你好,大佬,可以用这种方法延时5秒到10秒吗?另外问下,我想获取一个ADC的值,但是想10秒获取一次,请问 ...

就是一个变量的事儿,1ms中断一次,8位单片机unsigned int最大65535,可以控制65秒以内的延时,有必要问那么多吗?
回复

使用道具 举报

11#
ID:959051 发表于 2022-7-22 19:44 | 只看该作者
Hephaestus 发表于 2022-7-22 19:12
就是一个变量的事儿,1ms中断一次,8位单片机unsigned int最大65535,可以控制65秒以内的延时,有必要问 ...

谢谢指教!
回复

使用道具 举报

12#
ID:1040352 发表于 2022-7-23 18:51 | 只看该作者
guoqiang881245 发表于 2022-7-22 19:07
你好,大佬,可以用这种方法延时5秒到10秒吗?另外问下,我想获取一个ADC的值,但是想10秒获取一次,请问 ...

做一个时间触发器。
回复

使用道具 举报

13#
ID:161164 发表于 2022-7-23 22:56 | 只看该作者
guoqiang881245 发表于 2022-7-22 19:07
你好,大佬,可以用这种方法延时5秒到10秒吗?另外问下,我想获取一个ADC的值,但是想10秒获取一次,请问 ...

我给的例程展示了用1ms心跳产生10ms,20ms,50ms,100ms心跳的方法
10s的也是一样方法
回复

使用道具 举报

14#
ID:963677 发表于 2022-7-24 22:01 | 只看该作者
用systemtick用于粗略的定时,用定时器较为精准,要是延时用delay较为合适,用_nop()也可以,想要定时100ms 10ms这样子的话用定时器就可以了,在定时器里加上一个标志位,每10ms加1,判断标志位的数字即可扩大倍数,实现你提出的问题
回复

使用道具 举报

15#
ID:959051 发表于 2022-7-26 20:46 | 只看该作者
lkc8210 发表于 2022-7-23 22:56
我给的例程展示了用1ms心跳产生10ms,20ms,50ms,100ms心跳的方法
10s的也是一样方法

大佬,你这个函数我遇到了个问题,就是当其他函数调用这个延时的时候,有时不管用。比如延时3秒,定时器10ms中断一次,有时会错开这个延时,我不是放在main函数下执行的。
回复

使用道具 举报

16#
ID:161164 发表于 2022-7-26 21:04 | 只看该作者
guoqiang881245 发表于 2022-7-26 20:46
大佬,你这个函数我遇到了个问题,就是当其他函数调用这个延时的时候,有时不管用。比如延时3秒,定时器1 ...

上代码看看
回复

使用道具 举报

17#
ID:959051 发表于 2022-7-27 20:57 | 只看该作者

/*定时器1中断****************************************************************************************************/
void TIMER1_ISR (void) interrupt 3                  //每10ms产生中断
{
        static unsigned int SysDiv1000ms=0;

        static unsigned int SysDiv50ms=0;

        TH1 = TH_VAL;
        TL1 = TL_VAL;
        if(++SysDiv1000ms>=10)  //灯闪时间
        {
                        SysDiv1000ms = 0;
                        Flag1000ms = 1;//100ms心跳
        }
       
        if(++SysDiv50ms>=30)  //SOS闪灯时间
        {
                        SysDiv50ms = 0;
                        Flag50ms = 1;//100ms心跳
        }

        if(P35)   
        {
        if (fangdianCount < 20)
        {
                fangdianCount += 2;
        }               
        }
        else   
        {               
                if (fangdianCount>0)
                {
                        fangdianCount--;
                }               
        }

        Key2_Server_YDD (); //定时器刷新按键
        Key1_Server_SDT();
        FangdianDisp();  //放电指示灯
        Led_shan(); //闪灯

//        maichongCheck();
       
}
void Charge_lamp()
{
         
        if (P03 == 0)
        {               
                if (Flag1000ms == 1)
                {
                        Flag1000ms = 0;

                        if (Adc_celiang() >= 1.473)
                        {       
                                chongdian4 = 0;chongdian3 = 0;chongdian2 = 0;chongdian1 = 0;P10 = 1;P11 = 1;P12 = 1;P13 = 1;
                        }
                        else if (Adc_celiang() >= 1.423 && Adc_celiang() <= 1.471) //闪第四颗灯
                        {
                                chongdian4 = 1;chongdian3 = 0;chongdian2 = 0;chongdian1 = 0;                       
                        }
                        else if (Adc_celiang()>=1.360 && Adc_celiang()<=1.420)  //闪第三颗灯
                        {
                                chongdian4 = 0;chongdian3 = 1;chongdian2 = 0;chongdian1 = 0;
                        }
                        else if (Adc_celiang()>=1.283 && Adc_celiang()<=1.358)         //闪第二颗灯
                        {
                                chongdian4 = 0;chongdian3 = 0;chongdian2 = 1;chongdian1 = 0;
                        }
                        else if (Adc_celiang() <= 1.280)  //闪第一颗灯
                        {
                                chongdian4 = 0;chongdian3 = 0;chongdian2 = 0;chongdian1 = 1;
                        }
                }               
        }                       
               
}
/*主函数****************************************************************************************************/
void main(void)
{
#ifdef LVD_RST_ENABLE
        LVDCON = 0xE1;                                        //设置LVD复位电压为2V
#endif

#if (SYSCLK_SRC == PLL)
        Sys_Clk_Set_PLL(PLL_Multiple);        //设置系统时钟为PLL,PLL_Multiple为倍频倍数
#endif
       
#ifdef UART0_EN
        Uart0_Initial(UART0_BAUTRATE);        //初始化UART0
#endif
       
#ifdef UART1_EN
        Uart1_Initial(UART1_BAUTRATE);        //初始化UART1
#endif

        EA = 1;                                                        //开全局中断

#ifdef PRINT_EN
        uart_printf("INT2 to INT9 Demo Code\n");
#endif

CKCON |= IHCKE;                                //PWM打开IRCH时钟
frq = 0x00;
ADC_Init();     //ADC初始化
IO_Init();                //IO初始化
TIM0_Init();          //定时器初始化
TIM1_Init();          //定时器初始化
//INT2_Init();         //中断初始化
               
        while(1)
        {               
                Charge_lamp(); //充电检测
                ChongDSD();  //充电闪灯       
                Out_lamp();
                Meideng();//灭灯
                baojin();        //报警声               
                // uart_printf ("VDD Voltage = %f\n",Adc_celiang());        //打印VDD电压值               
        }

}
回复

使用道具 举报

18#
ID:959051 发表于 2022-7-27 21:00 | 只看该作者
飞熊入梦 发表于 2022-7-24 22:01
用systemtick用于粗略的定时,用定时器较为精准,要是延时用delay较为合适,用_nop()也可以,想要定时100ms ...

好的 谢谢大佬回答。
回复

使用道具 举报

19#
ID:382454 发表于 2022-7-28 17:42 | 只看该作者
精确的几十ms的,用STC官方软件计算出来,这样才是精确的,比如写一些单总线的驱动程序要求非常精确。长时间的比如几秒,几分钟的用定时器定好时间长数。最好做好时基,比如0.5秒,1秒,10秒 60秒 10分,20分 30分 1小时,这样你在写代码的时候就很灵活的调用了。
回复

使用道具 举报

20#
ID:398623 发表于 2022-7-28 18:42 | 只看该作者
定时器定一个最小单位时间,其他时间分频得到
回复

使用道具 举报

21#
ID:993066 发表于 2022-7-30 15:26 | 只看该作者
定时器,稳定精度度高
回复

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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