我目前使用PIC16F1827来触发闪烁模式 我们正在创建一个切换程序。 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);
}
答案 0 :(得分:3)
您的设计存在的问题是CPU大部分时间都停留在__delay_ms()
循环中。当它忙于通过多次调用__delay_ms(500)
来计数时,它无法响应按钮按下。
解决方案是不要使用忙循环来传递时间。相反,您必须允许CPU在您监视时间的推移时响应其他事件。一种方法是记录事件发生时的计时器滴答计数。然后反复将前一个刻度值与计时器当前刻度值进行比较while
循环(同时继续执行其他操作,例如检查是否按下了开关)。
由于你有一个__delay_ms()
函数,你可能有权访问另一个函数来获取计时器的当前刻度值。在下面的示例中,我假设此函数名为__get_tick()
,但它可能有不同的名称。
我还冒昧地将所有模式函数都缩减为多维数组。但是不要因此而分心。我推荐的真正解决方案是使用__get_tick()
代替__delay_ms()
。
#define NUM_PATTERNS 5
#define NUM_STEPS 4
uint8_t const patterns[NUM_PATTERNS][NUM_STEPS] = {
{0x00, 0x00, 0x00, 0x00}, // LEDs are off
{0x01, 0x02, 0x04, 0x08}, // pattern 1
{0x01, 0x03, 0x07, 0x0f}, // pattern 2
{0x0e, 0x0d, 0x0b, 0x07}, // pattern 3
{0x0e, 0x0c, 0x08, 0x00} // pattern 4
};
void main(void){
int current_pattern = 0;
int current_step = 0;
char prev_sw_data = 0;
uint32_t prev_tick = 0;
internal_osc();
io_int();
tmr0_int();
while(1){
bool was_switch_pressed = false;
bool has_500_ms_passed = false;
uint32_t current_tick = __get_tick();
// Check whether the switch has been pressed.
if (sw_data != prev_sw_data) {
was_switch_pressed = true;
// Remember the new sw_data setting.
prev_sw_data = sw_data;
// Change the pattern.
current_pattern = sw_data;
// Start at step 0 whenever the switch is pressed and
// the pattern is changed.
current_step = 0;
}
else {
// Check whether 500 ms has passed.
if ( (current_tick - prev_tick) > NUM_TICKS_IN_500_MS) )
{
has_500_ms_passed = true;
// Advance to the next step in the pattern
++current_step;
if (current_step >= NUM_STEPS) {
current_step = 0;
}
}
}
if (was_switched_pressed || has_500_ms_passed)
{
// Remember the new tick time.
prev_tick = current_tick;
PORTB = patterns[current_pattern][current_step];
}
}
}
答案 1 :(得分:1)
问题是当你处于一种模式时阻止了while(1)循环
一个想法是制作计数器并每1ms给你一个机智并做出以下改变:
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_data时,请不要忘记:
couter_for_next_step = 10;
port_change = 1;
这将允许您多次通过while(1)循环输入并检查按下按钮的状态
您还可以按下按钮事件来关闭指示灯
答案 2 :(得分:0)
您可以使用(高优先级软件)中断
在能够进行多线程的处理器或操作系统上,您可以使用不同的线程,在PIC上可以使用中断