自学单片机遇到的问题,请各位解答一下。

请问怎么修改才能使灯跟着按钮闪烁,按第一次三个灯之间闪烁间隔维一秒,按第二次闪烁间隔为两秒,第三次为4秒,第四次又回到1秒。
注:按钮接线IN=PB4,VCC=VDD,GND=GND.灯的接线CND=CND,红灯R=PB2黄Y=PB1绿G=PB0

img


#include <ny8.h>
#include "ny8_constant.h"
#define UPDATE_REG(x)    __asm__("MOVR _" #x ",F")
void delay(unsigned int t) {
    unsigned int i, j;
    for(i=0;i<t;i++)
        for(j=0;j<125;j++);  
    }  
void isr(void) __interrupt(1)
{
    static unsigned int i;
      static unsigned int a=0;
    if(INTFbits.T1IF)
    { 
        
        INTF= (unsigned char)~(C_INT_TMR1);
        if(i>=500)
        {
        i=0;
        if(a == 0)
        {
        PB0 =1; PB1 =0; PB2 =0;
        
        a=a+1;
        }
          else if(a == 1)
        {
        PB0 =0; PB1 =1; PB2 =0;
        
        a=a+1;
        }
        else if(a > 1)
         {
             
         PB0 =0; PB1 =0; PB2 =1;
         a=0;
         
         }    
            }
            
        else{
        i=i+1;     
}     
}
     if(INTFbits.T0IF)
    { 
        INTF= (unsigned char)~(C_INT_TMR0);    
    }
     if(INTFbits.WDTIF)
    { 
        INTF= (unsigned char)~(C_INT_WDT);
    }    
}
void main(void)
{


unsigned char R_shift_regl = 0xFF;
//;Initial GPIO     
    IOSTB =  C_PB5_Input | C_PB4_Input | C_PB3_Input;     // Set PB0 & PB1 to input mode,others set to output mode
    PORTB = 0x07;                           // PB0、PB1 & PB2 are output High
    DISI();
    
//;Initial Timer0
    PCON1 = C_TMR0_Dis;                        // Disable Timer0
    TMR0 = 0;                                // Load 0x00 to TMR0 (Initial Timer0 register)
    
    T0MD = C_PS0_TMR0 | C_PS0_Div8 ;        // Prescaler0 is assigned to Timer0, Prescaler0 dividing rate = 1:8,clock source is instruction clock
    
//;--Initial WDT (if WDT needs prescaler0 dividing rate )--------------------------------------------------                                       
//    T0MD = C_PS0_WDT                        // Prescaler0 is assigned to WDT, Prescaler0 dividing rate = 1:2 (WDT select interrupt)
//;--------------------------------------------------------------------------------------------------------        

//;Initial Timer1    
    TMR1 = 0xFF;                            // Load 0xFF to TMR1 (Initial Timer1 register)
    T1CR1 = C_TMR1_Reload | C_TMR1_En;      // Enable Timer1, Initial value reloaded from TMR1, Non-stop mode 
    T1CR2 = C_TMR1_ClkSrc_Inst | C_PS1_Div4;    // Enable Prescaler1, Prescaler1 dividing rate = 1:4, Timer1 clock source is instruction clock
    
//;Setting Interrupt Enable Register    
    INTE = C_INT_WDT | C_INT_TMR1 | C_INT_TMR0;    //        

//;Initial Power control register
    PCON = C_WDT_En | C_LVR_En;                // Enable WDT ,  Enable LVR
    
//;Enable Timer0 & Global interrupt bit 
    PCON1 = C_TMR0_En;                        // Enable Timer0
    ENI();                                    // Enable all unmasked interrupts            
    
    while(1);
}
}
if (buttonPressCount == 0) {
    delay(1000);  // 1秒延迟
} else if (buttonPressCount == 1) {
    delay(2000);  // 2秒延迟
} else if (buttonPressCount == 2) {
    delay(4000);  // 4秒延迟
} else if (buttonPressCount == 3) {
    delay(1000);  // 1秒延迟
}

【以下回答由 GPT 生成】

#include <ny8.h>
#include "ny8_constant.h"

#define UPDATE_REG(x)    __asm__("MOVR _" #x ",F")

void delay(unsigned int t) {
    unsigned int i, j;
    for (i=0; i<t; i++) {
        for (j=0; j<125; j++);
    }
}

void isr(void) __interrupt(1) {
    static unsigned int i;
    static unsigned int a=0;
    static unsigned int interval = 1000; // 初始间隔为1秒

    if (INTFbits.T1IF) {
        INTF = (unsigned char)~(C_INT_TMR1);
        if (i >= interval/2) { // 间隔的一半时间打开灯
            if (a == 0) {
                PB0 = 1;
                PB1 = 0;
                PB2 = 0;
                a = a + 1;
            }
            else if (a == 1) {
                PB0 = 0;
                PB1 = 1;
                PB2 = 0;
                a = a + 1;
            }
            else if (a > 1) {
                PB0 = 0;
                PB1 = 0;
                PB2 = 1;
                a = 0;
            }
        }
        else {
            i = i + 1;
        }

        if (i >= interval) { // 闪烁间隔时间到了
            i = 0;
        }
    }

    if (INTFbits.T0IF) {
        INTF = (unsigned char)~(C_INT_TMR0);
    }

    if (INTFbits.WDTIF) {
        INTF = (unsigned char)~(C_INT_WDT);
    }

    if (INTFbits.INTF) { // 检测按钮是否按下
        INTFbits.INTF = 0;
        interval *= 2; // 闪烁间隔翻倍
        if (interval > 4000) { // 如果闪烁间隔超过4秒,则重置为1秒
            interval = 1000;
        }
    }
}

解决方案解释:

  1. 首先,在代码中添加一个变量interval来存储闪烁的间隔时间,初始化为1秒(1000毫秒)。

  2. isr函数中,根据计时器i的值来控制灯的亮灭。当i的值大于等于interval/2时,打开相应的灯。

  3. 在每次执行完闪烁逻辑后,判断i的值是否大于等于interval,如果是,则重置为0,达到循环闪烁的效果。

  4. isr函数中,添加对按钮按下的检测。如果检测到按钮按下,则将interval翻倍。如果interval大于4000毫秒(4秒),则将其重置为1000毫秒。

注意事项:

  1. 由于代码中没有提供计时器的初始化和启动相关的代码,这部分功能需要根据具体的单片机型号和开发环境来实现。

  2. 请根据具体的硬件连接和单片机型号,确定按钮和灯的引脚定义是否正确,并在代码中进行相应的修改。

  3. 以上代码仅提供了逻辑的修改,具体的编译、下载和调试过程需要根据具体的开发环境和工具链来完成。


如果你已经解决了该问题, 非常希望你能够分享一下解决方案, 写成博客, 将相关链接放在评论区, 以帮助更多的人 ^-^