C 如何通过软件改变LED闪烁模式

C 如何通过软件改变LED闪烁模式,c,embedded,microcontroller,pic,C,Embedded,Microcontroller,Pic,我目前使用PIC16F1827将开关切换到led闪烁模式 我们正在创建一个切换程序。 sw的输入为RA0,当您按下按钮时,它会下降到低 在创建程序时有一个问题。 例如,在处理pat1()时按sw键; 有时我想切换到下一个照明模式。 但是,直到处理pat1();完成后,将显示闪烁模式 它不会切换。 有没有办法在按下sw时切换闪烁模式 多谢各位 #include <stdio.h> #include <stdlib.h> #include <xc.h> #defi

我目前使用PIC16F1827将开关切换到led闪烁模式 我们正在创建一个切换程序。 sw的输入为RA0,当您按下按钮时,它会下降到低

在创建程序时有一个问题。 例如,在处理pat1()时按sw键; 有时我想切换到下一个照明模式。 但是,直到处理pat1();完成后,将显示闪烁模式 它不会切换。 有没有办法在按下sw时切换闪烁模式

多谢各位

#include <stdio.h>
#include <stdlib.h>
#include <xc.h>
#define _XTAL_FREQ 4000000
/*
 * CONFIG will be omitted
 */
void internal_osc();
void io_int();
void tmr0_int();
void sw_scan();
void pat1();
void pat2();
void pat3();
void pat4();
char tmr0_cnt;
char sw_data;
char SwStatus;
char cnt;

void main(void){
    internal_osc();
    io_int();
    tmr0_int();
    while(1){
        //sw_scan();
        switch(sw_data){
            case 1 :
                pat1();
                break;
            case 2 :
                pat2();
                break;
            case 3 :
                pat3();
                break;
            case 4 :
                pat4();
                break;
            default :
                PORTB = 0x00;
                break;
        }
    }
}

void interrupt ISR(void){
    INTCONbits.TMR0IF = 0;
    TMR0 = 130;
    cnt++;
    if(cnt>=15){
        cnt=0;
        sw_scan();
    }
}

void internal_osc(void){
    OSCCON = 0x6a;
}

void io_int(void){
    TRISA = 0x01;
    TRISB = 0x00;
    ANSELA = 0x00;
    ANSELB = 0x00;
}

void tmr0_int(void){
    OPTION_REG = 0x82;
    TMR0 = 130;
    INTCONbits.TMR0IE = 1;
    INTCONbits.GIE = 1;
}

void sw_scan(void){
    if(PORTAbits.RA0 == 0){
        __delay_ms(10);
        if(PORTAbits.RA0 == 0){
            if(SwStatus==0){
                SwStatus = 1;
                if(sw_data>4){
                    sw_data = 0;
                }
                sw_data++;
            }
        }
        else{
            SwStatus = 0;
        }
    }
    else{
        SwStatus = 0;
    }
}


void pat1(void){
    PORTB = 0x01;
    __delay_ms(500);
    PORTB = 0x02;
    __delay_ms(500);
    PORTB = 0x04;
    __delay_ms(500);
    PORTB = 0x08;
    __delay_ms(500);
}
void pat2(void){
    PORTB = 0x01;
    __delay_ms(500);
    PORTB = 0x03;
    __delay_ms(500);
    PORTB = 0x07;
    __delay_ms(500);
    PORTB = 0x0f;
    __delay_ms(500);
}
void pat3(void){
    PORTB = 0x0e;
    __delay_ms(500);
    PORTB = 0x0d;
    __delay_ms(500);
    PORTB = 0x0b;
    __delay_ms(500);
    PORTB = 0x07;
    __delay_ms(500);
}
void pat4(void){
    PORTB = 0x0e;
    __delay_ms(500);
    PORTB = 0x0c;
    __delay_ms(500);
    PORTB = 0x08;
    __delay_ms(500);
    PORTB = 0x00;
    __delay_ms(500);
}
#包括
#包括
#包括
#定义额外频率4000000
/*
* 配置将被省略
*/
无效内部_osc();
void io_int();
void tmr0_int();
void sw_scan();
无效pat1();
无效pat2();
无效pat3();
无效pat4();
char-tmr0_-cnt;
字符sw_数据;
字符状态;
碳纳米管;
真空总管(真空){
内部osc();
io_int();
tmr0_int();
而(1){
//sw_scan();
开关(sw_数据){
案例1:
pat1();
打破
案例2:
pat2();
打破
案例3:
pat3();
打破
案例4:
pat4();
打破
违约:
端口B=0x00;
打破
}
}
}
无效中断ISR(无效){
INTCONbits.TMR0IF=0;
TMR0=130;
cnt++;
如果(cnt>=15){
cnt=0;
sw_scan();
}
}
无效内部操作支持(无效){
OSCCON=0x6a;
}
无效io_int(无效){
TRISA=0x01;
TRISB=0x00;
ANSELA=0x00;
ANSELB=0x00;
}
无效tmr0_int(无效){
选项_REG=0x82;
TMR0=130;
INTCONbits.TMR0IE=1;
INTCONbits.GIE=1;
}
无效sw_扫描(无效){
if(PORTAbits.RA0==0){
__延迟时间(10);
if(PORTAbits.RA0==0){
如果(SwStatus==0){
SwStatus=1;
如果(sw_数据>4){
sw_数据=0;
}
sw_data++;
}
}
否则{
SwStatus=0;
}
}
否则{
SwStatus=0;
}
}
无效部分1(无效){
端口B=0x01;
__延迟μms(500);
端口B=0x02;
__延迟μms(500);
端口B=0x04;
__延迟μms(500);
端口B=0x08;
__延迟μms(500);
}
无效pat2(无效){
端口B=0x01;
__延迟μms(500);
端口B=0x03;
__延迟μms(500);
端口B=0x07;
__延迟μms(500);
端口B=0x0f;
__延迟μms(500);
}
无效第3页(无效){
端口B=0x0e;
__延迟μms(500);
端口B=0x0d;
__延迟μms(500);
端口B=0x0b;
__延迟μms(500);
端口B=0x07;
__延迟μms(500);
}
无效pat4(无效){
端口B=0x0e;
__延迟μms(500);
端口B=0x0c;
__延迟μms(500);
端口B=0x08;
__延迟μms(500);
端口B=0x00;
__延迟μms(500);
}
您可以为此使用(高优先级软件)中断

在能够进行多线程处理的处理器或操作系统上,您可以使用不同的线程;在PIC上,您可以使用中断


在能够进行多线程处理的处理器或操作系统上,您可以使用不同的线程;在PIC上,您可以使用中断。问题在于,当您处于模式中时,您正在阻塞while(1)循环

一个想法是制作计数器,每1ms给您一次tact,并进行以下更改:

while(1){
    check_if_50ms_passed{
        switch(sw_data){
            case 1  : pat1(); break;
            case 2  : pat2(); break;
            case 3  : pat3(); break;
            case 4  : pat4(); break;
            default : PORTB = 0x00;break;
        }
    }
}
您必须在每个图案中保留一个计数器:

void pat1(void){
    couter_for_next_step++;
    if(couter_for_next_step == 10)// 50ms * 10 steps = 500ms
    {
        couter_for_next_step = 0;

        switch(port_change){
            case 1 : PORTB = 0x01; break;
            case 2 : PORTB = 0x02; break;
            case 3 : PORTB = 0x04; break;
            case 4 : PORTB = 0x08; break;
            default: break;
    }
}
当您更改sw_数据时,不要忘记:

couter_for_next_step = 10;
port_change = 1;
这将允许您多次通过while(1)循环进入,并检查按下按钮的状态


您还可以在按下按钮事件时添加以关闭LED

问题在于,当您处于模式中时,您正在阻塞while(1)循环

一个想法是制作计数器,每1ms给您一次tact,并进行以下更改:

while(1){
    check_if_50ms_passed{
        switch(sw_data){
            case 1  : pat1(); break;
            case 2  : pat2(); break;
            case 3  : pat3(); break;
            case 4  : pat4(); break;
            default : PORTB = 0x00;break;
        }
    }
}
您必须在每个图案中保留一个计数器:

void pat1(void){
    couter_for_next_step++;
    if(couter_for_next_step == 10)// 50ms * 10 steps = 500ms
    {
        couter_for_next_step = 0;

        switch(port_change){
            case 1 : PORTB = 0x01; break;
            case 2 : PORTB = 0x02; break;
            case 3 : PORTB = 0x04; break;
            case 4 : PORTB = 0x08; break;
            default: break;
    }
}
当您更改sw_数据时,不要忘记:

couter_for_next_step = 10;
port_change = 1;
这将允许您多次通过while(1)循环进入,并检查按下按钮的状态


您还可以在按下按钮事件时添加以关闭LED。您的设计存在的问题是CPU大部分时间都停留在
\uuu delay\u ms()
循环中。当它忙于通过多次呼叫
\uu delay\u ms(500)
计数时,它无法响应按钮的按下

解决方法是不要使用忙循环来打发时间。相反,您必须允许CPU在监视时间流逝的同时响应其他事件。一种方法是记录事件发生时的计时器计时计数。然后在
while
循环中重复比较先前的滴答声值与计时器的当前滴答声值(同时继续执行其他操作,如检查开关是否按下)

由于您有一个
\uu delay\u ms()
函数,因此您可能可以访问另一个函数来获取计时器的当前刻度值。在下面的示例中,我假设此函数名为
\uu get\u tick()
,但它可能有不同的名称

我还将所有模式函数简化为多维数组。但是不要被它分心。我推荐的真正解决方案是使用
\uu get\u tick()
而不是
\uu delay\u ms()


您的设计存在的问题是,CPU的大部分时间都停留在
\uu delay\u ms()
循环中。当它忙于通过多次呼叫
\uu delay\u ms(500)
计数时,它无法响应按钮的按下

解决方法是不要使用忙循环来打发时间。相反,您必须允许CPU在监视时间流逝的同时响应其他事件。一种方法是记录事件发生时的计时器计时计数。然后在
while