精华内容
参与话题
问答
  • 这个原因还是蛮多的,分同的情况,单片机的处理速度是很快的,有的时候为了让我们便于观察需要加入延时,例如一个指示灯的亮灭,如果不加入延时是看不出来的,再有就是键盘去抖动,一般按键都有20ms左右的抖动,为了...
    这个原因还是蛮多的,分同的情况,单片机的处理速度是很快的,有的时候为了让我们便于观察需要加入延时,例如一个指示灯的亮灭,如果不加入延时是看不出来的,再有就是键盘去抖动,一般按键都有20ms左右的抖动,为了更好的检测防止干扰,也需要延时一段时间在进行判断,总之延时的作用在不同的情况下也不同。
    具体的使用例程将在之后学习中不断补充。

    摘自 http://zhidao.baidu.com/question/171796304.html百度回答,谢谢答主

    转载于:https://www.cnblogs.com/caolinsummer/p/5538130.html

    展开全文
  • 例如,要产生200Hz的音频信号,按图1接入喇叭(若属临时实验,也可喇叭直接接在P1口线上),实验程序为:其中子程序DEL为延时程序,当R3为1时,延时时间约为20us,R3中存放延时常数,对200HZ音频,其周期为1/200...
  • 前言说明 ...如要求每 500ms 上报一次 ADC 检测的值,通过判断这个全局变量是否大于 5000 (500*10),如果大于的话就 ADC 值通过串口发出去,实现间隔 500ms 上报一次。 其实这个思想是很不错的,但

    前言说明

    在我所接触到的很多MCU源代码(不跑RTOS),无论是我们的同事还是其它方案的源代码,为了实现某些不需要太精确固定周期的工作,常见的做法都会是启动一个定时器,按照比较小的间隔来产生中断,如 0.1 毫秒一次,在定时器中断函数里面进行计数,根据计数值来给多个全局变量置1,在需要的源文件里面导出这些全局变量。如要求每 500ms 上报一次 ADC 检测的值,通过判断 500ms 的全局变量是否被置1,如果置位的话就将 ADC 值通过串口发出去,并且将这个全局变量设置为0,实现间隔 500ms 上报一次。

    其实这个思想是很不错的,但是经常看到这些全局变量满天飞,真心有些受不了,即使有些源码将所有需要判断这些全局变量的地方集中在一个源文件,N多的 IF 语句,也会让人看的眼花缭乱,特别是与上下文的变量名相似时,特别容易出错,实在是不好维护。碰到这种源码,在项目时间容许的情况下,我大概率会选择重写,不然真的是太痛苦了。(通常这种全局变量满天飞的源代码,其它的功能实现的代码都好不到哪去)

    因为这种方法很常用,也很好用,所以我将其作为基础接口进行封装,实测效果不错,核心思想并未改变。

    封装源码

    time_base.h

    /**
    ******************************************************************************
    * @文件		time_base.h
    * @版本		V1.0.0
    * @日期
    * @概要		计时功能接口
    * @作者		lmx
    * @邮箱		lovemengx@qq.com
    ******************************************************************************
    * @注意
    *
    ******************************************************************************
    */
    
    #ifndef TIME_BASE_H
    #define TIME_BASE_H
    
    // 可选的时间点
    typedef enum
    {
    	TIME_BASE_FLAGS_01MS	= 1 << 0,
    	TIME_BASE_FLAGS_1MS		= 1 << 1,
    	TIME_BASE_FLAGS_10MS	= 1 << 2,
    	TIME_BASE_FLAGS_100MS	= 1 << 3,
    	TIME_BASE_FLAGS_500MS	= 1 << 4,
    	TIME_BASE_FLAGS_1000MS	= 1 << 5,
    	TIME_BASE_FLAGS_2000MS	= 1 << 6,
    	TIME_BASE_FLAGS_3000MS	= 1 << 7,
    	TIME_BASE_FLAGS_ALL		= 0xFF,
    }timer_base_flags_e;
    
    // 初始化和释放
    void time_base_init();
    void time_base_release();
    
    // 主循环里面每完成一个循环都需要调用一次
    void time_base_update_flags(); 
    
    // 各个功能模块需要在某个时间点执行的时候调用, 传入对应的标志即可判断时间点是否达到
    unsigned char time_base_is_flags(timer_base_flags_e flags);
    
    #endif 

    time_base.c

    /**
    ******************************************************************************
    * @文件		time_base.h
    * @版本		V1.0.0
    * @日期
    * @概要		计时功能接口
    * @作者		lmx
    * @邮箱		lovemengx@qq.com
    ******************************************************************************
    * @注意
    *
    ******************************************************************************
    */
    
    #include "gd32e23x.h"
    #include "configuration.h"
    #include "time_base.h"
    
    // 定义定时器基准结构
    typedef struct
    {
        unsigned int bitmap;       // 使用位来记录各个时间点是否到位
        unsigned int time[8];      // 每一个数据位置位所需要的计数值
    }timer_base_flags_t;
    
    // 这里的值与 timer_base_flags_e 一一对应, 并且与定时器中断时间相关
    // 定时器每 0.1ms 会产生一次中断, 这里的值必须是从小到大
    static volatile timer_base_flags_t timer_base_flags = {
        .bitmap = 0x00, 
        .time[0] = 1,               // 0.1ms
        .time[1] = 10,              // 1ms
        .time[2] = 100,             // 10ms
        .time[3] = 1000,            // 100ms
        .time[4] = 5000,            // 500ms
        .time[5] = 10000,           // 1000ms
        .time[6] = 20000,           // 2000ms
        .time[7] = 30000,           // 3000ms
    };
    #define TIMER_BASE_TIME_ARRAR_MAX   (sizeof(timer_base_flags.time) / sizeof(timer_base_flags.time[0]))
    
    // 用于被外部接口判断指定时间点是否到达
    static volatile unsigned int timer_bitmap = 0x00;
    
    // 定时器中断服务程序
    void CFG_TIME_BASE_IRQ_FUNCTION(void)
    {         
        static unsigned int time_01ms_count = 0; 
        static unsigned int i = 0;
        
    	if(RESET != timer_interrupt_flag_get (CFG_TIME_BASE_TIMER, TIMER_INT_FLAG_UP))
    	{
    		timer_interrupt_flag_clear(CFG_TIME_BASE_TIMER, TIMER_INT_UP);
    		
            // 计数器计数, 当达到最大值时会自动复位为 1 
    		time_01ms_count = time_01ms_count % timer_base_flags.time[TIMER_BASE_TIME_ARRAR_MAX - 1] + 1;
            timer_base_flags.bitmap |= 1 << 0;
            
            // 依次各个时间点是否到达
            for(i = 1; i < TIMER_BASE_TIME_ARRAR_MAX; i++){
                if(0 == time_01ms_count % timer_base_flags.time[i]){
                    timer_base_flags.bitmap |= 1 << i;
                }
            }
    	}
    }
    
    // 更新标志位
    void time_base_update_flags()
    {
        static unsigned int i = 0;
       
        // 拷贝当前时间标志位, 便于其他模块判断指定的时间点是否抵达
    	timer_interrupt_disable(CFG_TIME_BASE_TIMER, TIMER_INT_UP);
        timer_bitmap = timer_base_flags.bitmap;
        timer_base_flags.bitmap &= ~timer_base_flags.bitmap;
    	timer_interrupt_enable(CFG_TIME_BASE_TIMER, TIMER_INT_UP);
        
        return ;
    }
    
    // 判断标志位
    unsigned char time_base_is_flags(timer_base_flags_e flags)
    {
    	return timer_bitmap & flags ? 1 : 0;
    }
    
    // 初始化
    void time_base_init()
    {
    	timer_parameter_struct para;
    	rcu_periph_clock_enable(CFG_TIME_BASE_RCU_CLOCK);
    	
    	timer_deinit(CFG_TIME_BASE_TIMER);
    	para.prescaler         = 720 - 1;				// 72M720分频100khz
    	para.alignedmode       = TIMER_COUNTER_EDGE;
    	para.counterdirection  = TIMER_COUNTER_UP;		//向上计数
    	para.period            = 10 - 1;				// 0.1  ms
    	para.clockdivision     = 0;						//不分频
    	para.repetitioncounter = 0;						//计数重复值0
    	timer_init(CFG_TIME_BASE_TIMER, &para);
    	
    	nvic_irq_enable(CFG_TIME_BASE_IRQ_NUMBER, 0U);
    	timer_interrupt_enable(CFG_TIME_BASE_TIMER, TIMER_INT_UP);
    	timer_auto_reload_shadow_enable(CFG_TIME_BASE_TIMER);
    	timer_enable(CFG_TIME_BASE_TIMER);
    	
    	return ;
    }
    
    // 释放
    void time_base_release()
    {
    	timer_interrupt_disable(CFG_TIME_BASE_TIMER, TIMER_INT_UP);
    	nvic_irq_disable(CFG_TIME_BASE_IRQ_NUMBER);
    	timer_disable(CFG_TIME_BASE_TIMER);
    	rcu_periph_clock_disable(CFG_TIME_BASE_RCU_CLOCK);
    	
    	return ;
    }
    
    

    configuration.h

    /**
    ******************************************************************************
    * @文件		configuration.h
    * @版本		V1.0.0
    * @日期
    * @概要		配置信息文件
    * @作者		lmx
    * @邮箱		lovemengx@qq.com
    ******************************************************************************
    * @注意
    *
    ******************************************************************************
    */
    
    #ifndef CONFIGURATION_H
    #define CONFIGURATION_H
    
    #include "gd32e23x.h"
    #include "gd32e230c_eval.h"
    #include "systick.h"
    
    // 时基定时器
    #define CFG_TIME_BASE_TIMER							TIMER2
    #define CFG_TIME_BASE_RCU_CLOCK						RCU_TIMER2
    #define CFG_TIME_BASE_IRQ_NUMBER					TIMER2_IRQn
    #define CFG_TIME_BASE_IRQ_FUNCTION					TIMER2_IRQHandler
    
    #endif 
    

    使用方法

    /**
    ******************************************************************************
    * @文件		main.c
    * @版本		V1.0.0
    * @日期
    * @概要		主程序文件
    * @作者		lmx
    ******************************************************************************
    * @注意
    *
    * 版权归深圳市智汇创科技有限公司所有,未经允许不得使用或修改
    *
    ******************************************************************************
    */
    
    #include <stdlib.h>
    #include <stdio.h>
    #include <string.h>
    #include "time_base.h"
    #include "xxx.h"
    #include "ccc.h"
    #include "aaa.h"
    
    int main(void)
    {
        time_base_init();
        
    	// 主循环
    	while(1)
    	{
    		time_base_update_flags();	// 更新时间标志
            
            xxx_process();
            ccc_process();
            aaa_process();
    	}
    	
        time_base_release();
        
    	return 0;
    }
    
    
    // xxx.c 里面的实现
    void xxx_process()
    {
        if(time_base_is_flags(TIME_BASE_FLAGS_100MS) == 0){
           return ;
        }  
        
         // 100 ms 做的事情
    }
    
    // ccc.c 里面的实现
    void ccc_process()
    {
        if(time_base_is_flags(TIME_BASE_FLAGS_3000MS) == 0){
           return ;
        }  
        
        // 3000 ms 做的事情
    }
    
    // aaa.c 里面的实现
    void aaa_process()
    {
        if(time_base_is_flags(TIME_BASE_FLAGS_500MS) == 0){
           return ;
        }  
        
        // 500 ms 做的事情
    }
    

     

    展开全文
  • 参考了51单片机 Keil C 延时程序...参考了51单片机 Keil C 延时程序的简单研究后,我们可知道, 在Keil C中获得最为准确的延时函数是 voiddelay(unsignedchart){while(--t);} 反汇编代码如下:执行DJNZ指令需要...
    参考了51单片机 Keil C 延时程序的简单研究,自己也亲身测试和计算了一些已有的延时函数。

    这里假定单片机是时钟频率为12MHz,则一个机器周期为:1us.
    参考了51单片机 Keil C 延时程序的简单研究后,我们可知道, 在Keil C中获得最为准确的延时函数将是
    None.gifvoid delay(unsigned char t)
    ExpandedBlockStart.gifContractedBlock.gif
    dot.gif{
    InBlock.gif    
    while(--t);
    ExpandedBlockEnd.gif}
    反汇编代码如下:

    执行DJNZ指令需要2个机器周期,RET指令同样需要2个机器周期,根据输入t,在不计算调用delay()所需时间的情况下,具体时间延时如下:
    t Delay Time (us)
    1 2×1+2 =4
    2 2×2+2=6
    N 2×N+2=2(N+1)


    当在main函数中调用delay(1)时, 进行反汇编如下:

    调用delay()时,多执行了两条指令,其中MOV R, #data需要1个机器周期,LJMP需要2个机器周期,即调用delay()需要3us.

    Keil C仿真截图与计算过程:



    加上调用时间,准确的计算时间延时与Keil C仿真对比如下:(可见,仿真结果和计算结果是很接近的)
    t Delay Time (us) 仿真11.0592Mhz时钟(us)
    1 3+2×1+2 =7 | 7.7(实际) 7.60
    2 3+2×2+2=9 | 9.9 9.76
    N 3+2×N+2=2N+5 | (2N+5)*1.1 /
    3 11 | 12.1 11.94
    15 35 | 38.5  37.98
    100 205 | 225.5 222.44
    255 515 | 566.5 558.81

    也就是说,这个延时函数的精度为2us,最小的时间延时为7us,最大的时间延时为3+255×2+2=515us.  
    实际中使用11.0592MHz的时钟,这个延时函数的精度将为2.2us,最小时间延时为7.7us, 最大时间延时为566.5us.
    这个时间延时函数,对于与DS18B20进行单总线通信,已经足够准确了。

    现在,我们将时钟换成11.0592MHz这个实际用到的频率,每个机器周期约为1.1us.
    现在让我们来分析一下这个之前用过的延时函数:
    None.gif//延时函数, 对于11.0592MHz时钟, 例i=10,则大概延时10ms.
    None.gif
    void delayMs(unsigned int i)
    ExpandedBlockStart.gifContractedBlock.gif
    dot.gif{
    InBlock.gif    unsigned 
    int j;
    InBlock.gif    
    while(i--)
    ExpandedSubBlockStart.gifContractedSubBlock.gif    
    dot.gif{
    InBlock.gif        
    for(j = 0; j < 125; j++);
    ExpandedSubBlockEnd.gif    }

    ExpandedBlockEnd.gif}

    它的反汇编代码如下:

    分析: T表示一个机器周期(调用时间相对于这个ms级的延时来说,可忽略不计)
     1  C:0000      MOV   A,    R7       ;1T 
     2                   DEC   R7                ;1T   低8位字节减1
     3                   MOV   R2,   0x06   ;2T
     4                   JNZ   C:0007          ;2T   若低8位字节不为0, 则跳到C:0007
     5                   DEC   R6                ;1T   低8位字节为0, 则高8位字节减1
     6 C:0007      ORL   A,   R2         ;1T
     7                   JZ      C:001D         ;2T   若高8位也减为0, 则RET
     8                   CLR   A                  ;1T   A清零
     9                   MOV   R4,   A        ;1T   R4放高位
    10                   MOV   R5,   A        ;1T   R5放低位
    11 C:000D      CLR   C                  ;1T   C清零
    12                   MOV   A,   R5        ;1T   
    13                   SUBB   A, #0x7d    ;1T   A = A-125
    14                   MOV   A,   R4        ;1T   
    15                   SUBB   A,  #0x00   ;1T   A 
    16                   JNC  C:0000           ;2T   A为零则跳到C:0000
    17                   INC   R5                 ;1T   R5增1
    18                   CJNE R5,#0x00, C:001B ;2T   R5>0, 跳转到C:000D
    19                   INC   R4                 ;1T
    20 C:001B      SJMP      C:000D    ;2T
    21 C:001D      RET

    对于delayMs(1), 执行到第7行就跳到21行, 共需时12T, 即13.2us
    对于delayMs(2), 需时9T+13T+124×10T+7T+12T = 9T+13T+1240T+7T+12T =1281T =1409.1us.
    对于delayMs(3), 需时9T×(3-1)+(13T+124×10T+7T)×(3-1)+12T 
                                    =1269T×(3-1)+12T=2550T=2805us.
    对于delayMs(N),N>1, 需时1269T×(N-1)+12T = 1269NT-1257T=(1395.9N-1382.7)us.

    利用Keil C仿真delayMs(1) = 0.00166558s = 1.67ms 截图如下:




    由分析可知具体的计算延时时间与Keil C仿真延时对比如下:
    i Time Delay 仿真延时
    1 13.2us 1.67ms
    2 1409.1us 3.31ms
    3 2805us 4.96ms
    N (1395.9N-1382.7)us
    10 12.6ms 16.50ms
    20 26.5ms 32.98ms
    30 40.5ms 49.46ms
    50 68.4ms 82.43ms
    100 138.2ms 164.84ms
    200 277.8ms 329.56ms
    500 696.6ms 824.13ms
    1000 1394.5ms 1648.54ms
    1500 2092.5ms 2472.34ms
    2000 2790.4ms 3296.47ms
    5 5.6ms 8.26ms
    73 100.5ms 120.34ms
    720 1003.7ms = 1s 1186.74ms


    计算delayMs(10)得到延时时间为:12576.3us约等于12.6ms,接近我们认为的10ms。

    计算结果和仿真结果只要delayMs(1)有很大出入, 其它都接近, 在接受范围内. 

    经过以上分析,可见用C语言来做延时并不是不太准确,只是不容易做到非常准确而已,若有一句语句变了,延时时间很可能会不同,因为编译程序生成的汇编指令很可能不同。


    PS:
    对于每条51单片机汇编指令的字长和所需机器周期汇总如下:转自:http://bbs.mcustudy.com/printpage.asp?BoardID=2&ID=1454
    Appendix E - 8051 Instruction Set

    Arithmetic Operations

    Mnemonic Description Size Cycles
    ADD A,Rn  Add register to Accumulator (ACC). 1 1
    ADD A,direct  Add direct byte to ACC. 2 1
    ADD A,@Ri  Add indirect RAM to ACC. 1 1
    ADD A,#data  Add immediate data to ACC. 2 1
    ADDC A,Rn  Add register to ACC with carry. 1 1
    ADDC A,direct  Add direct byte to ACC with carry. 2 1
    ADDC A,@Ri  Add indirect RAM to ACC with carry. 1 1
    ADDC A,#data  Add immediate data to ACC with carry. 2 1
    SUBB A,Rn  Subtract register from ACC with borrow. 1 1
    SUBB A,direct  Subtract direct byte from ACC with borrow 2 1
    SUBB A,@Ri  Subtract indirect RAM from ACC with borrow. 1 1
    SUBB A,#data  Subtract immediate data from ACC with borrow. 2 1
    INC A  Increment ACC. 1 1
    INC Rn  Increment register. 1 1
    INC direct  Increment direct byte. 2 1
    INC @Ri  Increment indirect RAM. 1 1
    DEC A  Decrement ACC. 1 1
    DEC Rn  Decrement register. 1 1
    DEC direct  Decrement direct byte. 2 1
    DEC @Ri  Decrement indirect RAM. 1 1
    INC DPTR  Increment data pointer. 1 2
    MUL AB  Multiply A and B Result: A <- low byte, B <- high byte. 1 4
    DIV AB  Divide A by B Result: A <- whole part, B <- remainder.  1 4
    DA A  Decimal adjust ACC. 1 1
    Logical Operations

    Mnemonic Description Size Cycles
    ANL A,Rn  AND Register to ACC. 1 1
    ANL A,direct  AND direct byte to ACC. 2 1
    ANL A,@Ri  AND indirect RAM to ACC. 1 1
    ANL A,#data  AND immediate data to ACC. 2 1
    ANL direct,A  AND ACC to direct byte. 2 1
    ANL direct,#data  AND immediate data to direct byte. 3 2
    ORL A,Rn  OR Register to ACC. 1 1
    ORL A,direct  OR direct byte to ACC. 2 1
    ORL A,@Ri  OR indirect RAM to ACC. 1 1
    ORL A,#data  OR immediate data to ACC. 2 1
    ORL direct,A  OR ACC to direct byte. 2 1
    ORL direct,#data  OR immediate data to direct byte. 3 2
    XRL A,Rn  Exclusive OR Register to ACC. 1 1
    XRL A,direct  Exclusive OR direct byte to ACC. 2 1
    XRL A,@Ri  Exclusive OR indirect RAM to ACC. 1 1
    XRL A,#data  Exclusive OR immediate data to ACC. 2 1
    XRL direct,A  Exclusive OR ACC to direct byte. 2 1
    XRL direct,#data  XOR immediate data to direct byte. 3 2
    CLR A  Clear ACC (set all bits to zero). 1 1
    CPL A  Compliment ACC. 1 1
    RL A  Rotate ACC left. 1 1
    RLC A  Rotate ACC left through carry. 1 1
    RR A  Rotate ACC right. 1 1
    RRC A  Rotate ACC right through carry. 1 1
    SWAP A  Swap nibbles within ACC. 1 1
    Data Transfer

    Mnemonic Description Size Cycles
    MOV A,Rn  Move register to ACC. 1 1
    MOV A,direct  Move direct byte to ACC. 2 1
    MOV A,@Ri  Move indirect RAM to ACC. 1 1
    MOV A,#data  Move immediate data to ACC. 2 1
    MOV Rn,A  Move ACC to register. 1 1
    MOV Rn,direct  Move direct byte to register. 2 2
    MOV Rn,#data  Move immediate data to register. 2 1
    MOV direct,A  Move ACC to direct byte. 2 1
    MOV direct,Rn  Move register to direct byte. 2 2
    MOV direct,direct  Move direct byte to direct byte. 3 2
    MOV direct,@Ri  Move indirect RAM to direct byte. 2 2
    MOV direct,#data  Move immediate data to direct byte. 3 2
    MOV @Ri,A  Move ACC to indirect RAM. 1 1
    MOV @Ri,direct  Move direct byte to indirect RAM. 2 2
    MOV @Ri,#data  Move immediate data to indirect RAM. 2 1
    MOV DPTR,#data16  Move immediate 16 bit data to data pointer register. 3 2
    MOVC A,@A+DPTR  Move code byte relative to DPTR to ACC (16 bit address). 1 2
    MOVC A,@A+PC  Move code byte relative to PC to ACC (16 bit address). 1 2
    MOVX A,@Ri  Move external RAM to ACC (8 bit address). 1 2
    MOVX A,@DPTR  Move external RAM to ACC (16 bit address). 1 2
    MOVX @Ri,A  Move ACC to external RAM (8 bit address). 1 2
    MOVX @DPTR,A  Move ACC to external RAM (16 bit address). 1 2
    PUSH direct  Push direct byte onto stack. 2 2
    POP direct  Pop direct byte from stack. 2 2
    XCH A,Rn  Exchange register with ACC. 1 1
    XCH A,direct  Exchange direct byte with ACC. 2 1
    XCH A,@Ri  Exchange indirect RAM with ACC. 1 1
    XCHD A,@Ri  Exchange low order nibble of indirect RAM with low order nibble of ACC. 1 1
    Boolean Variable Manipulation

    Mnemonic Description Size Cycles
    CLR C  Clear carry flag. 1 1
    CLR bit  Clear direct bit. 2 1
    SETB C  Set carry flag. 1 1
    SETB bit  Set direct bit. 2 1
    CPL C  Compliment carry flag. 1 1
    CPL bit  Compliment direct bit. 2 1
    ANL C,bit  AND direct bit to carry flag. 2 2
    ANL C,/bit  AND compliment of direct bit to carry. 2 2
    ORL C,bit  OR direct bit to carry flag. 2 2
    ORL C,/bit  OR compliment of direct bit to carry. 2 2
    MOV C,bit  Move direct bit to carry flag. 2 1
    MOV bit,C  Move carry to direct bit. 2 2
    JC rel  Jump if carry is set. 2 2
    JNC rel  Jump if carry is not set. 2 2
    JB bit,rel  Jump if direct bit is set. 3 2
    JNB bit,rel  Jump if direct bit is not set. 3 2
    JBC bit,rel  Jump if direct bit is set & clear bit. 3 2
    Program Branching

    Mnemonic Description Size Cycles
    ACALL addr11  Absolute subroutine call. 2 2
    LCALL addr16  Long subroutine call. 3 2
    RET  Return from subroutine. 1 2
    RETI  Return from interrupt. 1 2
    AJMP addr11  Absolute jump. 2 2
    LJMP addr16  Long jump. 3 2
    SJMP rel  Short jump (relative address). 2 2
    JMP @A+DPTR  Jump indirect relative to the DPTR. 1 2
    JZ rel  Jump relative if ACC is zero. 2 2
    JNZ rel  Jump relative if ACC is not zero. 2 2
    CJNE A,direct,rel  Compare direct byte to ACC and jump if not equal. 3 2
    CJNE A,#data,rel  Compare immediate byte to ACC and jump if not equal. 3 2
    CJNE Rn,#data,rel  Compare immediate byte to register and jump if not equal. 3 2
    CJNE @Ri,#data,rel  Compare immediate byte to indirect and jump if not equal. 3 2
    DJNZ Rn,rel  Decrement register and jump if not zero. 2 2
    DJNZ direct,rel  Decrement direct byte and jump if not zero. 3 2
    Other Instructions

    Mnemonic Description Size Cycles
    NOP  No operation. 1 1
    其它可查看《单片机基础》-李广弟等编著,P70 “MCS-51单片机指令汇总”

    转载于:https://www.cnblogs.com/fengmk2/archive/2007/03/12/672477.html

    展开全文
  • STC单片机精确延时参数测定方法

    千次阅读 2011-10-27 23:53:28
    在使用STC单片机的时候,大家是不是会遇见一个问题:延时往往很难把握。当然可以使用延时函数产生波形输出到示波器观察来修改延时参数,但是没有示波器时有没有方法来...具体代码如下://程序说明:测试stc单片机延时
        在使用STC单片机的时候,大家是不是会遇见一个问题:延时往往很难把握。当然可以使用延时函数产生波形输出到示波器观察来修改延时参数,但是没有示波器时有没有方法来确定延时参数呢。我这里自创了个办法,发到这与大家分享一下。

       其方法是这样,首先设置好定时器的定时时间,在调用延时函数前打开定时器,定时器中断函数中读取出延时参数,然后通过串口将延时参数输出。具体代码如下:

    //程序说明:测试stc单片机延时常数,串口输出
    //作者:mjx
    //注:程序测量精度高,适用stc这种指令不固定的单片机
    #include "STC12C5A60S2.h"
    #include <intrins.h>
    int i,j,ii,jj;//ii,jj作为定时器定时结束时暂存数,用于延时结束后串口输出
    
    
    void Uart1_Send(unsigned char Data)	  //向控制器发送数据	
    {
       ES=0;
       TI=0;
       SBUF=Data;
       while(TI==0);
       TI=0;
       ES=1;
    }
    //延时函数
    void delay(int k)
    {		
    	for(i = 0; i < k; i++)
    	{
    		for(j = 0; j < 30000; j++)
    		{
    			_nop_();_nop_();_nop_();_nop_();_nop_();
    		}
    	}
    }
    
    void Uart1_init(void)		// 使用定时器1作为波特率发生器
    {
    	PCON=0x00; 				//SMOD=0
     	SCON=0x50;   			//0101,0000 8位可变波特率,无奇偶校验位
    	TMOD|=0x20;   			//0011,0001 设置顶时器1为8位自动重装计数器
    	AUXR=0x00; 				//设置定时器1工作在1T模式下
    
    	TH1=0xfd; 		//设置定时器1自动重装数
    	TL1=0xfd;
    	TR1=1;    				//开定时器1
      //  ES=1;    				//允许串口1中断
        EA=1;    				//开总中断
    }
    void main()
    {
    	TMOD=0x01;//T0定时器
        TH0 = 0xdC;	 //11.0592MHz--10ms	设置不同的时间,可以测试stc单片机内部延时参数				
        TL0 = 0x00;
        ET0 = 1;			
    	EA=1;
    	Uart1_init();//初始化uart1,波特率9600,其他默认
    
    	TR0 = 1;//开启定时
    	delay(100);//延时
        Uart1_Send(0x30+jj/10000);
    	Uart1_Send(0x30+(jj%10000)/1000);
    	Uart1_Send(0x30+(jj%1000)/100);
    	Uart1_Send(0x30+(jj%100)/10);
    	Uart1_Send(0x30+jj%10);
    
    	Uart1_Send(0x2e);
    	Uart1_Send(0x30+ii/10000);
    	Uart1_Send(0x30+(ii%10000)/1000);
    	Uart1_Send(0x30+(ii%1000)/100);
    	Uart1_Send(0x30+(ii%100)/10);
    	Uart1_Send(0x30+ii%10);
    	while(1);
    }
    
    void Timer0(void) interrupt 1 using 3
    {
    	 ii=i; //  暂存延时函数的i和j 
    	 jj=j; //
    	 TR0=0;
    }


     

    展开全文
  • 项目中遇到需要用电脑通过串口来控制单片机IO口,查询了一些资料,可以...配合单片机程序单片机进行控制。 python实现的串口助手代码如下: import time; #需要调用延时函数 import serial #需要调用串口库 ...
  • Proteus仿真—40个单片机初学程序.

    热门讨论 2009-04-13 13:00:56
    作为单片机的指令的执行的时间是很短,数量大微秒级,因此,我们要求的闪烁时间间隔为0.2秒,相对于微秒来说,相差太大,所以我们在执行某一指令时,插入延时程序,来达到我们的要求,但这样的延时程序是如何设计呢...
  • 以前也有过用89c58换89c52,晶振也由12m改为24m时就出现同样问题,同样的程序下载进去运行出错,当时想到的就是24m比12m晶振高一倍,于是将程序中的需要延时的地方适当更改,延长点时间来解决问题。 由...
  • 汇编延时程序算法详解(范文) 第 PAGE \* Arabic 1 页第 PAGE \* Arabic 1 页 汇编延时程序算法详解 摘要 计算机反复执行一段程序以达到延时的目的称为软件延时单片机应用程序中经常需要短时间延时有时要求很高的精度...
  • 实例21:用for语句控制蜂鸣器鸣笛次数#include //... //sound位定义为P3.7/****************************************函数功能:延时形成1600Hz音频****************************************/void delay1600(voi...
  • 相当一部分人对此仍很模糊,授人鱼,不如授之以渔,本文以12MHZ晶振为例,详细讲解MCS-51单片机中汇编程序延时的精确算法。  关键词 51单片机 汇编 延时算法  指令周期、机器周期与时钟周期 指令周期:CPU...
  • 汇编延时程序算法详解

    千次阅读 2011-03-18 10:01:00
    但在部分算法讲解中发现有错误之处,而且延时的具体算法讲得并不清楚,相当一部分人对此仍很模糊,授人鱼,不如授之以渔,本文以12MHZ晶振为例,详细讲解MCS-51单片机中汇编程序延时的精确算法。  指令周期、...
  • 你想知道的PC\SP在这里 ... 另外怎样避免中断程序不破坏延时参数? 可以在中断中启用不同的工作寄存器组;也可以原工作器组的数据进行保护,中断服务完了再返回去。 ...
  • 51单片机应用开发从入门到精通在单片机的实时控制系统中,常常需要用到延时操作,所以,延时程序往往是编写单片机程序中不可缺少的一部分。延时方法有硬件延时和软件延时,硬件延时将在后面有...
  • 例:让该端口输出高电平的语句是:SETB P1.0让该端口输出低电平的语句是:CLR P1.0好了,现在我们小灯接在单片机的P1.0端口上,如下图所示: 由上图可知,当端口P1.0输出高电平时,小灯D不亮,因为小灯中不会有...
  • c语言实现单片机的键盘程序 #include "SST89x5x4.H" #include #define uchar unsigned char #define uint unsigned int #define _Nop() _nop_() unsigned char code Key_Value_Table[16]={0xff,0x00,0x01,0xff,0x...
  • 单片机数模转换程序 da#include <reg52.h> //52系列单片机头文件 #include #define uchar unsigned char #define uint unsigned int sbit dula=P2^6; //申明U1锁存器的锁存端 sbit wela=P2^7; //申明U2锁存器的...
  • //毫秒级延时函数 void delay(unsigned int x) { unsigned char i; while(x--) { for(i = 0;i ;i++); } } //字符发送函数 void putchar(unsigned char data1) { SBUF = data1; //待发送的字符送入发送缓冲...
  • 汇编延时程序算法详解2010-01-04 摘要 计算机反复执行...而且延时的具体算法讲得并不清楚,相当一部分人对此仍很模糊,授人鱼,不如授之以渔,本文以12MHZ晶振为例,详细讲解MCS-51单片机中汇编程序延时的精确算法。
  • 功能: 数据c发送出去,可以是地址,也可以是数据,发完后等待应答,并对 此状态位进行操作.(不应答或非应答都使ack=0 假) 发送数据正常,ack=1; ack=0表示被控器无应答或损坏。 -------------------------------...
  • 基于msp430的单片机的DES加密程序

    千次阅读 2016-07-31 10:36:54
    上课的时候做的一个课程设计,因为对单片机编程知识学习的比较少,所以,在自学了一些知识后,编写的程序, 其中,对于时钟也是根据for循环的延时来编写的,大家如果有更好的代码可以告诉我。  它的主要功能是,...
  • 但是PWM控制舵机的程序实现方式多种多样,有的使用延时(delay(ms)),有的使用定时器(time),而网上搜到的大部分控制代码却质量一般,控制精度都需要提高,就要对单片机定时器有详细的了解,否则延时将出现偏差。...
  • 汇编 延时

    千次阅读 2012-05-28 19:45:42
    摘要 计算机反复执行一段程序以达到延时的目的称为...相当一部分人对此仍很模糊,授人鱼,不如授之以渔,本文以12MHZ晶振为例,详细讲解MCS-51单片机中汇编程序延时的精确算法。  关键词 51单片机 汇编 延时算法
  • 单片机因具有体积小、功能强、成本低以及便于实现分布式控制而有非常广泛的应用领域。单片机开发者在编制各种应用程序时经常会遇到实现精确延时的问题,比如按键去抖...为此我特意的如何在C51程序中精确延时进行了...
  • 淘宝上卖的16路PWM舵机驱动模块的51单片机程序 部分程序如下 #include <reg52.h> #include <intrins.h> #include #include typedef unsigned char uchar; typedef unsigned int uint; sbit scl=P1^3; //时钟...
  • #include"reg52.h" ... //利用重定义unsigned简化为u16 sbit led1=P2^0; void delay(u16 i )//延时函数,其实质是一个循环递减语句。 { while (i--); } void main() { while(1) { ...
  • 在循环中不断的进行开关,这就是逻辑其实挺简单的,但是中间需要有一个延时,如果不延时就不会看到效果。 在这里需要用到C语言里面的一个重定义关键字: unsigned andsigned int 分为无符号 unsigned 和有...

空空如也

1 2 3 4 5 ... 8
收藏数 143
精华内容 57
关键字:

单片机将程序延时