PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Power-Down-Modus beim Atmega88



Funky
12.10.2006, 09:36
Tag,

ich versuche gerade mal ein wenig mit dem Power Pown Modus zu experimentieren.

Dabei soll der Controller nach dem Start und der Initialisierung sofort in den Power-Down-Mode gehen. Durch einen gedrückten Taster ensteht dann ein Low-Pegel am INT1, welcher als Level Interrupt programmiert ist und den Controller aus dem Power-Down-Mode aufweckt. Das Programmm läuft..... Bis dahin läuft auch alles einwandfrei.

Nun mein Problem:

Durch erneutes drücken des Tasters, also erneuter Low-Pegel am INT1 soll der Controller wieder in den Power-Down-Mode gehen. Das funktioniert nur leider nicht. Vielleicht hat einer ne Idee woran das liegen kann?

Hier ist der Code:



#include<avr/io.h>
#include<avr/sleep.h>
#include<avr/interrupt.h>
#include <stdio.h>
#include <inttypes.h>

typedef unsigned char u8;
typedef signed short s16;

#define FOSC 14745600 //Clock Speed
#define BAUD 9600
#define UBRR ((FOSC / (BAUD * 16L)) - 1)

#define XTAL 1e6 // 1MHz

#define KEY_PIN PIND
#define KEY0 0
#define KEY1 1
#define KEY2 2
#define KEY3 3
#define KEY4 4

#define LED_DDR DDRB
#define LED_PORT PORTB
#define LED0 0
#define LED1 1
#define LED2 2
#define LED3 3
#define LED4 4

//#define REPEAT_MASK (1<<KEY1^1<<KEY2) // repeat: key1, key2
#define REPEAT_START 50 // after 500ms
#define REPEAT_NEXT 20 // every 200ms

//Initialisierung AD-Wandler
void ADC_wandlung();

//Initialisierung UART
void uart_init();


u8 key_state; // debounced and inverted key state:
// bit = 1: key pressed
u8 key_press; // key press detect

u8 key_rpt; // key long press and repeat

unsigned int pause;

unsigned char taster = 0xFF;
unsigned char a;


void uart_init()
{

/* Port als Ausgang */
//DDRB |= (1 << PB0) | (1 << PB1) | (1 << PB2) | (1 << PB3);

//PORTB |= (1 << PB0) | (1 << PB1) | (1 << PB2) | (1 << PB3);

/* Aktivieren des Empfängers, des Senders und des "Daten empfangen+Daten leer"-Interrupts */
UCSR0B = (1<<RXCIE0)|(1<<RXEN0) |(1<<TXEN0) | (1 << UDRIE0);

/* baud rate*/
UBRR0H = (unsigned char) (UBRR>>8);
UBRR0L = (unsigned char) UBRR;

/* frame format: 8data, 2stop bit*/
UCSR0C = (1 << USBS0) | (3 << UCSZ00);
}


ISR(TIMER0_OVF_vect ) // every 10ms
{
static u8 ct0, ct1;
u8 i;

TCNT0 = (u8)(s16)-(XTAL / 1024 * 10e-3 + 0.5); // preload for 10ms

i = key_state ^ ~taster; // key changed ?
ct0 = ~( ct0 & i ); // reset or count ct0
ct1 = ct0 ^ (ct1 & i); // reset or count ct1
i &= ct0 & ct1; // count until roll over ?
key_state ^= i; // then toggle debounced state
key_press |= key_state & i; // 0->1: key press detect
}


u8 get_key_press( u8 key_mask )
{
cli(); // read and clear atomic !
key_mask &= key_press; // read key(s)
key_press ^= key_mask; // clear key(s)
sei();
return key_mask;
}


u8 get_key_rpt( u8 key_mask )
{
cli(); // read and clear atomic !
key_mask &= key_rpt; // read key(s)
key_rpt ^= key_mask; // clear key(s)
sei();
return key_mask;
}


u8 get_key_short( u8 key_mask )
{
cli(); // read key state and key press atomic !
return get_key_press( ~key_state & key_mask );
}


u8 get_key_long( u8 key_mask )
{
return get_key_press( get_key_rpt( key_mask ));
}


int main( void )
{

//UART Initialisieren
uart_init();

TCCR0B = 1<<CS02^1<<CS00; // divide by 1024
TIMSK0 = 1<<TOIE0; // enable timer interrupt

DDRD &= ~( 1<< PD3) | (1 << PD0) | (1 << PD2);

SMCR &= ~(1 << SM0) | (1 << SM2); //Power Down Modus
SMCR |= (1 << SM1) | (1 << SE); //Power Down & Sleep Enable

EICRA &= ~(1 << ISC11) | (1 << ISC10); //Low Level of INT1 generates Interrupt Request
EIMSK |= (1 << INT1); //External Interrupt Request Enable
sei();

set_sleep_mode(SLEEP_MODE_PWR_DOWN);
sleep_mode();
EIMSK &= ~(1 << INT1); //External Interrupt Request Diable

LED_PORT = 0xFF;
LED_DDR = 0xFF;


for(;;){

ADC_wandlung();

if(!(PIND & (1 << PIND3)))
taster &= ~(1 << 4);

else
taster |= (1 << 4);

if( get_key_press( 1<<KEY4 )) //Interrupt at INT1
{
EIFR |= (1 << INTF1); //INT1 Interrupt Flag löschen
EIMSK |= (1 << INT1); //External Interrupt Request Enable
sleep_mode();
EIMSK &= ~(1 << INT1); //External Interrupt Request Diable

}

//erste LED
if((ADCH <=35) && (ADCH >= 30))
taster &= ~(1 << 0);

else
taster |= (1 << 0);

if( get_key_press( 1<<KEY0 ))
LED_PORT ^= 1<<LED0;


//zweite LED
if((ADCH <=110) && (ADCH >= 105))
taster &= ~(1 << 1);

else
taster |= (1 << 1);


if( get_key_press( 1<<KEY1 ))
LED_PORT ^= 1<<LED1;


//dritte LED
if((ADCH <=207) && (ADCH >= 202))
taster &= ~(1 << 2);

else
taster |= (1 << 2);

if( get_key_press( 1<<KEY2 ))
LED_PORT ^= 1<<LED2;

//vierte LED
if((ADCH <=253) && (ADCH >= 248))
taster &= ~(1 << 3);

else
taster |= (1 << 3);


if( get_key_press( 1<<KEY3 ))
LED_PORT ^= 1<<LED3;

}
}

void ADC_wandlung() //ADC0/PCINT - PORTC, Bit0
{
DDRC = 0x00; // Alle Pins von Port C als Eingang definiert
ADMUX &= ~((1<<MUX0)|(1<<MUX1)|(1<<MUX2)|(1<<MUX3)); //ADC0 eingestellt.
ADCSRA = (1<<ADEN)|(1<<ADPS0)|(1<<ADPS1)|(1<<ADPS2);
ADMUX |= (1<<REFS0) | (1 << ADLAR); //|(1<<REFS0);

ADCSRA |= (1<<ADSC); //AD Wandlung
while (ADCSRA & (1<<ADSC))
{
;
}

}

ISR(USART_UDRE_vect)
{
if(pause == 50000)
{
UDR0 = ADCH;
pause = 0;
}
pause++;
a = ADCH;

}


ISR(INT1_vect )
{
//EIMSK &= ~(1 << INT1); //External Interrupt Request Diable
}

SprinterSB
12.10.2006, 12:22
Der levelgetriggerte INTx ist nur sinnvoll, um ihn aufzuwecken. Sobald er wach ist, solltest du INTx auf Flanke stellen und vor dem Schalfengehen dann wieder auf Level-Trigger. Evtl die INTxFlags resetten.

Funky
16.10.2006, 15:08
Hey, jetzt klappt alles!

Die Abfrage war falsch. Muss nicht nur abfragen ob der Taster gedrückt ist, sondern auch ob er wieder losgelasssen wurde. Erst dann darf was passieren.

Ansonsten macht er ja schon zig Durchläufe in der ISR.

Gruß