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