C 图中的去盎司按钮
我是PIC mcu的新手。我使用pic12f675 MPLAB和XC8制作LED多闪烁模式。 我对按钮也有问题(在检查后称之为Bounce and Debounce)。 有时当我按下按钮时,它会按顺序如1->2->3->4->5,但有时它会跳转如1->3->4->6等 请建议我如何在pic mcu中去抖动或以其他方式解决我的问题 多谢各位。各位 (PS.I连接带10K电阻器的按钮) 我的代码在下面C 图中的去盎司按钮,c,interrupt,pic,C,Interrupt,Pic,我是PIC mcu的新手。我使用pic12f675 MPLAB和XC8制作LED多闪烁模式。 我对按钮也有问题(在检查后称之为Bounce and Debounce)。 有时当我按下按钮时,它会按顺序如1->2->3->4->5,但有时它会跳转如1->3->4->6等 请建议我如何在pic mcu中去抖动或以其他方式解决我的问题 多谢各位。各位 (PS.I连接带10K电阻器的按钮) 我的代码在下面 #include <xc.h> #pragma config FOSC
#include <xc.h>
#pragma config FOSC=INTRCIO,WDTE=OFF,MCLRE=OFF,BOREN=OFF
#define _XTAL_FREQ 4000000
int cnt = 0;
int k = 0;
void __interrupt() MyISR(void){
if(INTCONbits.INTF) //If External Edge INT Interrupt
{
cnt++;
INTCONbits.GIE = 0;
INTCONbits.INTF = 0; // Clear the interrupt
INTCONbits.GPIF = 0;
if( cnt > 6 ){
cnt = 1;
}
}
INTCONbits.GIE = 1;
}
void main(void) {
ANSEL = 0;
CMCON = 0b00000111; //turns comparators off
TRISIO = 0b00000100;
GPIO = 0;
TRISIO2 = 1; // Make GP2 pin as input
INTCONbits.GIE = 1;
INTCONbits.INTE = 1;
INTCONbits.GPIF = 1;
INTCONbits.INTF = 0;
OPTION_REG = 0b01000000;
while(1){
if( cnt == 1 ){
GP0 = 1;
GP5 = 1;
}else if( cnt == 2 ){
for(k=0;k<30;k++){
GP5 = 1;
GP0 = 1;
}
k=0;
while(k<3){
GP5 = ~GP5;
__delay_ms(70);
GP0 = ~GP0;
__delay_ms(70);
k++;
}
}else if( cnt == 3 ){
for(k=0;k<5;k++){
GP5 = 1;
GP0 = 1;
__delay_ms(70);
GP5 = 0;
GP0 = 0;
__delay_ms(70);
}
GP5 = 0;
GP0 = 0;
__delay_ms(1200);
}else if( cnt == 4 ){
for(k=0;k<3;k++){
GP0 = 1;
__delay_ms(50);
GP0 = 0;
__delay_ms(50);
}
for(k=0;k<3;k++){
GP5 = 1;
__delay_ms(50);
GP5 = 0;
__delay_ms(50);
}
}else if( cnt == 5 ){
GP0 = 1;
GP5 = 1;
for(k=0;k<3;k++){
GP5 = 1;
__delay_ms(50);
GP5 = 0;
__delay_ms(50);
}
GP0 = 1;
GP5 = 1;
for(k=0;k<3;k++){
GP0 = 1;
__delay_ms(50);
GP0 = 0;
__delay_ms(50);
}
}else if( cnt == 6 ){
GP0 = 1;
GP5 = 1;
__delay_ms(20);
GP0 = 0;
GP5 = 0;
__delay_ms(3000);
}
}
return;
}
#包括
#pragma config FOSC=INTRCIO,WDTE=OFF,MCLRE=OFF,BOREN=OFF
#定义额外频率4000000
int-cnt=0;
int k=0;
void\uu中断()MyISR(void){
if(INTCONbits.INTF)//如果外部边缘INT中断
{
cnt++;
INTCONbits.GIE=0;
INTCONbits.INTF=0;//清除中断
INTCONbits.GPIF=0;
如果(碳纳米管>6){
cnt=1;
}
}
INTCONbits.GIE=1;
}
真空总管(真空){
ANSEL=0;
CMCON=0b00000111;//关闭比较器
TRISIO=0B000000100;
GPIO=0;
TRISIO2=1;//将GP2引脚作为输入
INTCONbits.GIE=1;
INTCONbits.INTE=1;
INTCONbits.GPIF=1;
INTCONbits.INTF=0;
选项_REG=0b01000000;
而(1){
如果(cnt==1){
GP0=1;
GP5=1;
}else如果(cnt==2){
对于(k=0;k我重写了您的代码,并在MPLAB模拟中对其进行了测试。它按预期工作。它按升序更改模式,然后在所选模式下运行,直到再次按下更改按钮,然后更改为下一个模式。您可以根据需要添加更多工作模式,也可以修改GPIOs闪烁的方式。没有延迟(),这就是为什么延迟在不消耗CPU的情况下运行。请在实际电路中进行测试并给我反馈
/*
* File: main.c
* Author: kozmotronik
*
*/
#define _XTAL_FREQ 4000000
#include <xc.h>
#include <stdint.h>
#include <stdbool.h>
#pragma config FOSC=INTRCIO,WDTE=OFF,MCLRE=OFF,BOREN=OFF
// Work mode definitions
#define MODE_IDLE 0
#define MODE_OFF 1
#define MODE_ON 2
#define MODE_SLOW 3
#define MODE_FAST 4
#define MODE_CANCEL 5
#define LAST_MODE MODE_FAST
// Button states
#define BUTTON_IDLE 0
#define BUTTON_PRESS_DETECTED 1
#define BUTTON_DEBOUNCING 2
#define BUTTON_PRESS_CONFIRMED 3
#define SYSTEM_CLOCK_MS 1
#define SYSTEM_CLOCK_uS (SYSTEM_CLOCK_MS * 1000)
#define _XTAL_FREQ_MHZ (_XTAL_FREQ / 1000000) // Oscillator freq in MHz
#define TMR0_RELOAD_VALUE 256 - ( (SYSTEM_CLOCK_uS * _XTAL_FREQ_MHZ) / (8 * 4) ) // Result must be 131
#define MS_TO_TICKS(msTime) (msTime / SYSTEM_CLOCK_MS)
typedef struct{
unsigned int start;
unsigned int ticks;
} time_t;
char mode = MODE_IDLE;
char lastMode = MODE_OFF;
char buttonState = BUTTON_IDLE;
char k = 0;
unsigned int systemTick = 0; // Time value count by Timer0
void __interrupt() MyISR(void){
if(INTCONbits.INTF) //If External Edge INT Interrupt
{
INTCONbits.INTF = 0; // Clear the interrupt
buttonState = BUTTON_PRESS_DETECTED; // Signal the detected press
}
// Check for 1 ms periodic interrupt for system clock
else if(INTCONbits.T0IF){
INTCONbits.T0IF = 0; // clear flag
TMR0 = TMR0_RELOAD_VALUE; // Reload the calculated value for 1 ms
systemTick++;
}
}
// Setup Timer0 for 1ms interrupt
void setupTimer0(){
#define PRESCALER_VALUE 2
#define PRESCALER_MASK ~7
OPTION_REG &= PRESCALER_MASK; // Clear prescaler bits
OPTION_REG |= PRESCALER_VALUE; // Set prescaler value for 1:8
OPTION_REGbits.PSA = 0; // Assign prescaler to Tim0
OPTION_REGbits.T0CS = 0; // Set internal oscillator as clock source
TMR0 = TMR0_RELOAD_VALUE;
INTCONbits.T0IF = 0;
INTCONbits.T0IE = 1; // Enable Timer0 interrupt
}
// Get count atomically
unsigned int getTickCount(){
unsigned int count;
di(); // disable interrupts
count = systemTick;
ei(); // enable interrupts again
return count;
}
void performMode(){
static time_t modeDelay;
static char slowModeState = 1;
static char fastModeState = 1;
switch(mode){
case MODE_OFF:
// Always must save the current mode before put it into the IDLE
lastMode = mode; // We have to save the last mode first then put it into the IDLE state
mode = MODE_IDLE; // The rollover bug caused by here since we haven't save the last mode before put it into the IDLE state
GP0 = 0; GP5 = 0;
break;
case MODE_ON:
GP0 = 1; GP5 = 1;
break;
case MODE_SLOW:
if(slowModeState == 1){
GP0 = 1; GP5 = 1;
modeDelay.ticks = MS_TO_TICKS(100);
modeDelay.start = getTickCount();
slowModeState = 2; // Proceed the next step
}
else if(slowModeState == 2){
if( !((getTickCount() - modeDelay.start) >= modeDelay.ticks) ){
// Delay not expired yet
return;
}
GP0 = ~GP0; GP5 = ~GP5; // Toggle
// Reload the start time
modeDelay.start = getTickCount();
}
break;
case MODE_FAST:
if(fastModeState == 1){
GP0 = 1; GP5 = 1;
modeDelay.ticks = MS_TO_TICKS(50);
modeDelay.start = getTickCount();
fastModeState = 2; // Proceed the next step
}
else if(fastModeState == 2){
if( !((getTickCount() - modeDelay.start) >= modeDelay.ticks) ){
// Delay not expired yet
return;
}
// Delay time expired, proceed toggle
GP0 = ~GP0; GP5 = ~GP5; // Toggle
// Reload the start time
modeDelay.start = getTickCount();
}
break;
case MODE_CANCEL:
// Cancel the current running mode, reset everything
modeDelay.start = 0;
modeDelay.ticks = 0;
slowModeState = 1;
fastModeState = 1;
// Also reset the outputs
GP0 = 0; GP5 = 0;
break;
default:
mode = MODE_IDLE;
}
}
void checkButton(){
#define DEBOUNCE_DELAY_MS 100u // Debounce delay is 100 ms
static time_t debounceTimer;
switch(buttonState){
case BUTTON_IDLE:
break;
case BUTTON_PRESS_DETECTED:
debounceTimer.ticks = MS_TO_TICKS(DEBOUNCE_DELAY_MS);
debounceTimer.start = getTickCount();
buttonState = BUTTON_DEBOUNCING;
break;
case BUTTON_DEBOUNCING:
if( !((getTickCount() - debounceTimer.start) >= debounceTimer.ticks) ){
// Debounce time has not expired yet
return;
}
// Debounce time has expired so check the button last time to confirm if it is still pressed
if(GPIObits.GP2 != 1){
// Not stable yet, debounce again
buttonState = BUTTON_PRESS_DETECTED;
}
// Button press is stable, confirm it
buttonState = BUTTON_PRESS_CONFIRMED;
break;
case BUTTON_PRESS_CONFIRMED:
buttonState = BUTTON_IDLE; // Change state so that it can process a new button press
if(mode != MODE_IDLE && mode != MODE_OFF){
// Cancel the running mode first
lastMode = mode; // save the last mode
mode = MODE_CANCEL; // purge the current one
performMode();
}
mode = lastMode + 1; // Switch to next mode
if(mode > LAST_MODE){
// Rewind mode to the beginning which is MODE_OFF
mode = MODE_OFF;
}
break;
default:
buttonState = BUTTON_IDLE;
}
}
void main(void) {
ANSEL = 0;
CMCON = 0b00000111; //turns comparators off
TRISIO = 0b00000100;
GPIO = 0;
TRISIO2 = 1; // Make GP2 pin as input
INTCONbits.INTF = 0;
INTCONbits.INTE = 1;
INTCONbits.GIE = 1;
OPTION_REG = 0b01000000; // Rising edge interrupt
setupTimer0();
// Super loop
while(1){
// Task 1: Button check
if(buttonState != BUTTON_IDLE){
checkButton();
}
// Task 2: Mode check
else if(mode != MODE_IDLE){
performMode();
}
}
return;
}
/*
*文件:main.c
*作者:科兹莫特罗尼克
*
*/
#定义额外频率4000000
#包括
#包括
#包括
#pragma config FOSC=INTRCIO,WDTE=OFF,MCLRE=OFF,BOREN=OFF
//工作模式定义
#定义模式\u空闲0
#定义模式_OFF 1
#在2上定义模式_
#定义模式3
#定义模式\u FAST 4
#定义模式\u取消5
#定义最后一个\u模式\u快速
//按钮状态
#定义按钮\u空闲0
#定义按钮\u按\u检测到1
#定义按钮_去抖动2
#定义按钮\u按\u确认3
#定义系统时钟1
#定义系统时钟(系统时钟*1000)
#定义_XTAL_FREQ_MHZ(_XTAL_FREQ/1000000)//振荡器频率(以MHZ为单位)
#定义TMR0_RELOAD_值256-((系统时钟频率*)/(8*4))//结果必须为131
#定义毫秒到毫秒刻度(毫秒时间)(毫秒时间/系统时钟)
类型定义结构{
无符号整数起始;
无符号整数刻度;
}时间;
char mode=mode_IDLE;
char lastMode=模式\关闭;
char buttonState=按钮空闲;
chark=0;
unsigned int systemTick=0;//按Timer0计算的时间值
void\uu中断()MyISR(void){
if(INTCONbits.INTF)//如果外部边缘INT中断
{
INTCONbits.INTF=0;//清除中断
buttonState=BUTTON\u PRESS\u DETECTED;//向检测到的按下发送信号
}
//检查系统时钟的1毫秒周期中断
else if(INTCONbits.T0IF){
INTCONbits.T0IF=0;//清除标志
TMR0=TMR0_RELOAD_VALUE;//重新加载计算值1毫秒
systemTick++;
}
}
//1ms中断的设置定时器0
void setupTimer0(){
#定义预分频器_值2
#定义预分频器\u掩码~7
选项\u REG&=预分频器\u掩码;//清除预分频器位
选项_REG |=预分频器_值;//将预分频器值设置为1:8
选项_REGbits.PSA=0;//将预分频器分配给Tim0
选项_REGbits.T0CS=0;//将内部振荡器设置为时钟源
TMR0=TMR0_重新加载_值;
INTCONbits.T0IF=0;
INTCONbits.T0IE=1;//启用定时器0中断
}
//原子计数
无符号int getTickCount(){
无符号整数计数;
di();//禁用中断
计数=系统滴答;
ei();//再次启用中断
返回计数;
}
void performMode(){
静态时间延迟;
静态字符慢模式=1;
静态字符数=1;
开关(模式){
案例模式_关闭:
//在将当前模式置于空闲模式之前,必须始终保存当前模式
lastMode=mode;//我们必须先保存最后一个模式,然后将其置于空闲状态
mode=mode_IDLE;//由于我们在将最后一个模式置于空闲状态之前没有保存它,因此此处导致的滚动错误
GP0=0;GP5=0;
打破
案例模式打开:
GP0=1;GP5=1;
打破
案例模式_慢:
if(slowModeState==1){
GP0=1;GP5=1;
modeDelay.ticks=毫秒到毫秒刻度(100);
modeDelay.start=getTickCount();
slowModeState=2;//继续下一步
}
else if(slowModeState==2){
if(!((getTickCount()-modeDelay.start)>=modeDelay.ticks)){
//延迟尚未到期
返回;
}
GP0=~GP0;GP5=~GP5;//切换
//重新加载开始时间
modeDelay.start=getTickCount();
}
打破
案例模式快速:
如果(FastModerate==1){
GP0=1;GP5=1;
modeDelay.ticks=毫秒到毫秒刻度(50);
modeDelay.start=getTickCount();
FastModerate=2;//继续下一步
}
否则如果(FastModerate==2){
if(!((getTickCount()-modeDelay.start)>=modeDelay.ticks)){
//延迟尚未到期
返回;
}
//延迟时间到期,继续切换
GP0=~GP0;