Marten83
06.10.2009, 21:11
Guten Abend,
ich benötige mal wieder weiter Augen.
Es geht darum einen Taster einer Matrix als POWER-Taste zu verwenden und meinen Mikrocontroller in den Schlaf zu schicken. Das scheint auch bisher zu funktionieren.
Dann soll er allerdings, nach erneutem drücken der POWER-Taste durch den Watchdog Reset das Programm neu starten.
Manchmal Startet er wieder, gibt aber nur Murks auf dem Display aus und reagiert dann auch nicht mehr. Oder er reagiert überhaupt nicht mehr.
Hier der relevante Teil meines Codes:
#include "includes.h"
//------------------------------------------
//Makros und Definitionen
#define KP_ROWDIR DDRD
#define KP_COLDIR DDRB
#define KP_ROWPORT PORTD
#define KP_COLPORT PORTB
#define KP_ROWPIN PIND
#define KP_COLPIN PINB
#define KP_ROWS 0b00110000
#define KP_COLUMNS 0b00000111
#define KP_ROWSHIFT 4
#define KP_COLSHIFT 0 //Rechtsshift um bei 0 anzufangen
#define KP_COLVAR 3 //Anzahl verwendeter Spalten
#define KP_ISR_VECT PCINT1_vect
#define KP_PCMSK PCMSK1
#define KP_PCIFR PCIF1
#define ENABLE_KP_PCINT PCICR |= (1<<PCIE1)
#define DISABLE_KP_PCINT PCICR &= ~(1<<PCIE1)
#define ENABLE_SLEEP_MODE SMCR |= (1<<SM1)
#define DISABLE_SLEEP_MODE SMCR &= ~(1<<SM1)
#define SLEEP SMCR |= (1<<SE)
#define WAKEUP SMCR &= ~(1<<SE)
#define PWRBUTTON 5
#define RESET {asm("ldi r30,0"); asm("ldi r31,0"); asm("ijmp");}
//--------------------------------------------------
//Globale Variablen
//volatile uint8_t key_altState;
volatile struct _key_code key_code;
/*Hier Dinge vor dem schlafen gehen ausführen*/
void
Power_down (void)
{
PCA9533_LED_select (0x30);
}
//----------------------------------------------------------------------
//Initialisierung der Tastaturmatrix
void keypad_init(void)
{
/* Ports initialisieren*/
KP_ROWDIR |= KP_ROWS; //Zeilen als Ausgang definieren
KP_COLPORT |= KP_COLUMNS; //Pullups für Spalten aktivieren
/*Timer0 initialisieren*/
//
//Zeit bis zum Timeroverflow sollte mehr als 5ms
//betragen um Prellen des Tasters abzuwarten
//TCCR0B |= (1<<CS02); //Prescaler = 256 !Testeinstellung!
TCCR0B |= (1<<CS00) | (1<<CS02); //Prescaler = 1024
/*Pin change Interrupt aktivieren*/
KP_PCMSK |= KP_COLUMNS;
ENABLE_KP_PCINT;
ENABLE_SLEEP_MODE;
}//keypad_init
//------------------
//
unsigned char
get_key(void)
{
if(key_code.updated != 0)
{
key_code.updated = 0;
return key_code.scan;
}
else
{
return 0xff;
}
}
//-----------------------------------------------------------
//PCINT deaktivieren und Timer aktivieren
ISR(KP_ISR_VECT)
{
DISABLE_KP_PCINT;
WAKEUP;
/*Timer0 vorbereiten und aktivieren*/
TCNT0 = 0; //Rücksetzen des Registers
TIMSK0 |= (1<<TOIE0); //Aktivieren des Timers
}
//-------------------------
//ISR zum auslesen der Matrix
ISR(TIMER0_OVF_vect)
{
TCNT0 = 0;
/*Deaktivieren von Timer0*/
TIMSK0 &= ~(1<<TOIE0);
/*Lokale Variablen*/
uint8_t lineResult;
uint8_t tempScan = 0xFF;
/*Einlesen der gedrückten Spalte*/
lineResult = (KP_COLPIN & KP_COLUMNS);
if(lineResult != KP_COLUMNS)
{
/*Invertieren der Pinrichtungen*/
KP_ROWPORT |= KP_ROWS; //Zeilen auf 'high' setzen
KP_COLPORT &= ~KP_COLUMNS; //Deaktivieren der Pullups für Spalten
KP_ROWDIR &= ~KP_ROWS; //Zeilen als Eingang definieren (Pullups werden aktiviert)
KP_COLDIR |= KP_COLUMNS; //Spalten als Ausgang definieren
tempScan = 0;
lineResult >>= KP_COLSHIFT;
while(lineResult & 0x01)
{
lineResult >>= 1;
tempScan++;
}
/*Einlesen der gedrückten Zeile*/
lineResult = (KP_ROWPIN & KP_ROWS);
/*Rücksetzen auf vorherige Pinrichtungen*/
KP_ROWPORT &= ~KP_ROWS; //Zeilen auf 'low'setzen
KP_COLPORT |= KP_COLUMNS; //Spalten auf 'high' setzen
KP_ROWDIR |= KP_ROWS; //Zeilen als Ausgang definieren
KP_COLDIR &= ~KP_COLUMNS; //Spalten als Eingang definieren (Pullups werden aktiviert)
if(lineResult != KP_ROWS)
{
lineResult >>= KP_ROWSHIFT;
while(lineResult & 0x01)
{
lineResult >>= 1;
tempScan += KP_COLVAR;
}
/**/
key_code.scan = tempScan;
key_code.updated = 1;
}
}
if (tempScan == PWRBUTTON && key_code.sleep == 0)
{
tempScan = 0xFF;
Power_down ();
key_code.sleep = 1;
SLEEP;
}
if (tempScan != PWRBUTTON && key_code.sleep == 1)
{
SLEEP;
}
if (tempScan == PWRBUTTON && key_code.sleep == 1)
{
cli();
wdt_enable(WDTO_60MS);
}
/*Pinchange Interrupt wieder aktivieren*/
ENABLE_KP_PCINT;
PCIFR |= (1<<KP_PCIFR);
}
Kennt sich damit jemand aus und kann mir sagen was ich falsch mache?
Vielen Dank!
MfG,
Marten83
ich benötige mal wieder weiter Augen.
Es geht darum einen Taster einer Matrix als POWER-Taste zu verwenden und meinen Mikrocontroller in den Schlaf zu schicken. Das scheint auch bisher zu funktionieren.
Dann soll er allerdings, nach erneutem drücken der POWER-Taste durch den Watchdog Reset das Programm neu starten.
Manchmal Startet er wieder, gibt aber nur Murks auf dem Display aus und reagiert dann auch nicht mehr. Oder er reagiert überhaupt nicht mehr.
Hier der relevante Teil meines Codes:
#include "includes.h"
//------------------------------------------
//Makros und Definitionen
#define KP_ROWDIR DDRD
#define KP_COLDIR DDRB
#define KP_ROWPORT PORTD
#define KP_COLPORT PORTB
#define KP_ROWPIN PIND
#define KP_COLPIN PINB
#define KP_ROWS 0b00110000
#define KP_COLUMNS 0b00000111
#define KP_ROWSHIFT 4
#define KP_COLSHIFT 0 //Rechtsshift um bei 0 anzufangen
#define KP_COLVAR 3 //Anzahl verwendeter Spalten
#define KP_ISR_VECT PCINT1_vect
#define KP_PCMSK PCMSK1
#define KP_PCIFR PCIF1
#define ENABLE_KP_PCINT PCICR |= (1<<PCIE1)
#define DISABLE_KP_PCINT PCICR &= ~(1<<PCIE1)
#define ENABLE_SLEEP_MODE SMCR |= (1<<SM1)
#define DISABLE_SLEEP_MODE SMCR &= ~(1<<SM1)
#define SLEEP SMCR |= (1<<SE)
#define WAKEUP SMCR &= ~(1<<SE)
#define PWRBUTTON 5
#define RESET {asm("ldi r30,0"); asm("ldi r31,0"); asm("ijmp");}
//--------------------------------------------------
//Globale Variablen
//volatile uint8_t key_altState;
volatile struct _key_code key_code;
/*Hier Dinge vor dem schlafen gehen ausführen*/
void
Power_down (void)
{
PCA9533_LED_select (0x30);
}
//----------------------------------------------------------------------
//Initialisierung der Tastaturmatrix
void keypad_init(void)
{
/* Ports initialisieren*/
KP_ROWDIR |= KP_ROWS; //Zeilen als Ausgang definieren
KP_COLPORT |= KP_COLUMNS; //Pullups für Spalten aktivieren
/*Timer0 initialisieren*/
//
//Zeit bis zum Timeroverflow sollte mehr als 5ms
//betragen um Prellen des Tasters abzuwarten
//TCCR0B |= (1<<CS02); //Prescaler = 256 !Testeinstellung!
TCCR0B |= (1<<CS00) | (1<<CS02); //Prescaler = 1024
/*Pin change Interrupt aktivieren*/
KP_PCMSK |= KP_COLUMNS;
ENABLE_KP_PCINT;
ENABLE_SLEEP_MODE;
}//keypad_init
//------------------
//
unsigned char
get_key(void)
{
if(key_code.updated != 0)
{
key_code.updated = 0;
return key_code.scan;
}
else
{
return 0xff;
}
}
//-----------------------------------------------------------
//PCINT deaktivieren und Timer aktivieren
ISR(KP_ISR_VECT)
{
DISABLE_KP_PCINT;
WAKEUP;
/*Timer0 vorbereiten und aktivieren*/
TCNT0 = 0; //Rücksetzen des Registers
TIMSK0 |= (1<<TOIE0); //Aktivieren des Timers
}
//-------------------------
//ISR zum auslesen der Matrix
ISR(TIMER0_OVF_vect)
{
TCNT0 = 0;
/*Deaktivieren von Timer0*/
TIMSK0 &= ~(1<<TOIE0);
/*Lokale Variablen*/
uint8_t lineResult;
uint8_t tempScan = 0xFF;
/*Einlesen der gedrückten Spalte*/
lineResult = (KP_COLPIN & KP_COLUMNS);
if(lineResult != KP_COLUMNS)
{
/*Invertieren der Pinrichtungen*/
KP_ROWPORT |= KP_ROWS; //Zeilen auf 'high' setzen
KP_COLPORT &= ~KP_COLUMNS; //Deaktivieren der Pullups für Spalten
KP_ROWDIR &= ~KP_ROWS; //Zeilen als Eingang definieren (Pullups werden aktiviert)
KP_COLDIR |= KP_COLUMNS; //Spalten als Ausgang definieren
tempScan = 0;
lineResult >>= KP_COLSHIFT;
while(lineResult & 0x01)
{
lineResult >>= 1;
tempScan++;
}
/*Einlesen der gedrückten Zeile*/
lineResult = (KP_ROWPIN & KP_ROWS);
/*Rücksetzen auf vorherige Pinrichtungen*/
KP_ROWPORT &= ~KP_ROWS; //Zeilen auf 'low'setzen
KP_COLPORT |= KP_COLUMNS; //Spalten auf 'high' setzen
KP_ROWDIR |= KP_ROWS; //Zeilen als Ausgang definieren
KP_COLDIR &= ~KP_COLUMNS; //Spalten als Eingang definieren (Pullups werden aktiviert)
if(lineResult != KP_ROWS)
{
lineResult >>= KP_ROWSHIFT;
while(lineResult & 0x01)
{
lineResult >>= 1;
tempScan += KP_COLVAR;
}
/**/
key_code.scan = tempScan;
key_code.updated = 1;
}
}
if (tempScan == PWRBUTTON && key_code.sleep == 0)
{
tempScan = 0xFF;
Power_down ();
key_code.sleep = 1;
SLEEP;
}
if (tempScan != PWRBUTTON && key_code.sleep == 1)
{
SLEEP;
}
if (tempScan == PWRBUTTON && key_code.sleep == 1)
{
cli();
wdt_enable(WDTO_60MS);
}
/*Pinchange Interrupt wieder aktivieren*/
ENABLE_KP_PCINT;
PCIFR |= (1<<KP_PCIFR);
}
Kennt sich damit jemand aus und kann mir sagen was ich falsch mache?
Vielen Dank!
MfG,
Marten83