PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Schreiben und Lesen aus dem EEProm unzuverlässig



Razer
29.08.2006, 10:53
Hallo an alle

Bei meinem Gesichtsbräunertimer hab ich noch ein paar Probleme.

Doch leider funktioniert noch nicht alles ganz zuverlässig. Am Auslesen
des EEproms happerts noch ein bisschen. Woran kann das liegen??

Und was mir noch aufgefallen ist, wenn ich KEY0 gedrückt halte, dann
zählt er viel langsamer die Variable time herunter als wenn ich KEY1
gedrückt halte und er nach oben zählt.

Hier mal der Source Code:



/*******************************************
Title: Belichtungstimer
Author: Robert Schilling
Date: 9.8.2006
Hardware: Atiny26 + Board
********************************************/

#include <avr/io.h>
#include <stdlib.h>
#include <avr/eeprom.h>
#include <avr/interrupt.h>

#define LEDPORT PORTA
#define LED_A PA0
#define LED_B PA1
#define LED_C PA2
#define LED_D PA3
#define LED_E PA4
#define LED_F PA5
#define LED_G PA6

#define RELAISPORT PORTA
#define RELAISPIN PA7

#define TASTER_TRANSPORT PORTB

#define KEY_PIN PINB
#define KEY0 4
#define KEY1 5
#define KEY2 6

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

#define EEP_ADRESS_MIN 0x01
#define EEP_ADRESS_SEC 0x02

#define DONE 0x01
#define UNDONE 0x00
#define TIMER_1SEC_ENABLED 0x01
#define TIMER_1SEC_DISABLED 0x00

#define _D 0x0B
#define _O 0x0C
#define _N 0x0D
#define _E 0x0E

const uint8_t symbol[]={0x3F, //0
0x05, //1
0x5B, //2
0x4F, //3
0x65, //4
0x6E, //4
0x7E, //5
0x07, //6
0xFF, //7
0x6F, //8
0x08, //9
0x5D, //d
0x5C, //o
0x54, //n
0x7A}; //E

const uint8_t active_position[] = {0x78,
0x74,
0x72,
0x71};

uint8_t segment[4];
uint8_t position;

volatile uint16_t time = 0;
volatile uint8_t done = UNDONE;
volatile uint8_t counter;
volatile uint8_t timer_1sec = TIMER_1SEC_DISABLED;
volatile uint8_t counter_1sec = 0;

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

uint8_t key_rpt; // key long press and repeat

void time2dispay(void);
void eeprom_read(void);
void eeprom_write(void);
void init(void);
void update_display(void);
void timer_init(void);
uint8_t get_key_press(uint8_t key_mask);
uint8_t get_key_rpt(uint8_t key_mask);
uint8_t get_key_short(uint8_t key_mask);
uint8_t get_key_long(uint8_t key_mask);


void timer_init(void)
{
TCCR1B = ((1 << CS12) | (1 << CS11) | (1 << CTC1)); //Prescaler = 32; Enabale CTC Mode
OCR1C = 0xFA; //Compare Interrupt at 250
TIMSK |= (1 << OCIE1A);
}

void time2display(void) //ZEit wird zerlegt in die einzelnen Ziffern
{
uint16_t rest;

segment[0] = time / 600;
rest = time % 600;

segment[1] = rest / 60;
rest %= 60;

segment[2] = rest / 10;
rest %= 10;

segment[3] = rest;
}

void eeprom_read(void) //EEProm wird ausgelesen und Zeit wird berechnet
{
time = (eeprom_read_byte((uint8_t *)EEP_ADRESS_MIN) * 60) + eeprom_read_byte((uint8_t *)EEP_ADRESS_SEC);
time2display();
}

void eeprom_write(void)
{
uint8_t minuten, sekunden;

minuten = time / 60; //Zeit wird in Minuten und Sekunden Zerlegt
sekunden = time % 60;

if(minuten != eeprom_read_byte((uint8_t *)EEP_ADRESS_MIN)) //Zuerst wird der EEPROM ausgelesen
eeprom_write_byte((uint8_t *)EEP_ADRESS_MIN, minuten); //Falls die Werte nicht übereinstimmen,
//wird der EEPROM neu beschrieben
if(sekunden != eeprom_read_byte((uint8_t *)EEP_ADRESS_SEC))
eeprom_write_byte((uint8_t *)EEP_ADRESS_SEC, sekunden);
}

void init(void)
{
DDRA = 0xFF; //PORTA als Ausgang
DDRB = 0x0F; //PORTB 0 - 3 als Ausgang, 4 - 6 als Eingang
PORTB = 0x70; //Aktiver die Pullups an PB4, PB5, PB6

position = 0;

eeprom_read();
timer_init();

counter = 0;
counter_1sec = 0;
timer_1sec = TIMER_1SEC_DISABLED; //Deaktiviere die 1sec ISR
counter_1sec = 0;
}

void update_display(void)
{
position++;

if(position > 3)
position = 0;

TASTER_TRANSPORT = active_position[position] | 0x70;
LEDPORT = symbol[segment[position]];
}

ISR(TIMER1_CMPA_vect)
{
static uint8_t ct0, ct1, rpt;
uint8_t i;

counter++;

if(counter == 5) //5ms
{
//Debounceroutine von Peter Danegger
i = key_state ^ ~KEY_PIN; // 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

if( (key_state & REPEAT_MASK) == 0 ) // check repeat function
rpt = REPEAT_START; // start delay

if( --rpt == 0 )
{
rpt = REPEAT_NEXT; // repeat delay
key_rpt |= key_state & REPEAT_MASK;
}

counter = 0;
counter_1sec++;

if(time > 0)
time2display();

update_display();

if((counter_1sec == 200) && (timer_1sec == TIMER_1SEC_ENABLED)) //1sec ISR
{
counter_1sec = 0;
time--;
time2display();

if(time == 0)
{
RELAISPORT &= ~(1 << RELAISPIN); //Switsch OFF Relais
done = DONE;

segment[0] = _D; //"DONE"
segment[1] = _O;
segment[2] = _N;
segment[3] = _E;

timer_1sec = TIMER_1SEC_DISABLED; //Disable 1sec interrupt
}
}
}
}

uint8_t get_key_press(uint8_t 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;
}


uint8_t get_key_rpt(uint8_t 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;
}


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


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

void tastenauswertung(void)
{
if(done == DONE && (get_key_press(1 << KEY0) || get_key_press(1 << KEY1) || get_key_press(1 << KEY2)))
{
done = UNDONE;
init();
}

if(get_key_press(1 << KEY2)) //START
{
RELAISPORT |= (1 << RELAISPIN); //Switsch On Relais
eeprom_write();
timer_1sec = TIMER_1SEC_ENABLED;
}

if(get_key_rpt(1 << KEY0) && get_key_rpt(1 << KEY1) && timer_1sec == TIMER_1SEC_ENABLED)
init();

if(get_key_rpt(1 << KEY0) && time > 0 && timer_1sec != TIMER_1SEC_ENABLED)
time--;

if(get_key_press(1 << KEY0) && time > 0 && timer_1sec != TIMER_1SEC_ENABLED)
time--;

if(get_key_rpt(1 << KEY1) && time < 3600 && timer_1sec != TIMER_1SEC_ENABLED) //1 Stunde
time++;

if(get_key_press(1 << KEY1) && time < 3600 && timer_1sec != TIMER_1SEC_ENABLED) //1 STunde
time++;
}

int main(void)
{
init();
sei();
time2display();

while(1)
{
tastenauswertung();
}

}


Warum ist denn das so??

Ich hoffe es kann mir helfen

Gruß Robert

SprinterSB
29.08.2006, 12:15
-- weshalb bist du sicher, daß das Problem beim EEPROM liegt
-- bist du sicher, daß die ISR zuende ist bevor ein neuer IRQ getriggert wird? Der Code in der ISR ist ja recht barock...
-- bist du sicher, daß nicht-atomarer Zugriff auf time keine Probleme macht? Schau dazu mal bei RN-Wissen->C-Quellcode->Fallstricke...

Razer
29.08.2006, 12:46
-- bist du sicher, daß die ISR zuende ist bevor ein neuer IRQ getriggert wird? Der Code in der ISR ist ja recht barock...


Wie kann ich das überprüfen??



-- bist du sicher, daß nicht-atomarer Zugriff auf time keine Probleme macht? Schau dazu mal bei RN-Wissen->C-Quellcode->Fallstricke...


Das hab ich vergessen. Ich hab derzeit jetztt nur bei bei den EEprom Zugriffen die Interrupts dekativiert.

Das mit de EEprom funktioniert jetzt eigentlich.

Jetzt hab ich noch das Problem, dass bei gedrückter Taste das inkremntieren schneller als das dekremntieren. Warum das???

Weiters tritt manchsmal der Effekt auf, wenn die Zeit angelaufen ist, und DONE an den Segmentanzeigen steht, und ich die mittlere Taste drücke (KEY1) dann steht nicht der zuletzt gestartete Timewert am Display sondern 00.01. Wenn ich dann Start drücke, dan fängt er wieder zum dekrementieren beim alten Wert an zb 50sec. Warum denn das???
Wenn ich in dieser Phase inkrementiere und Starte fängt er auch beim alten Wert an zu dekrementieren.

Noch ein Problem: Wenn ich noch immer dekremntiere mit dem TAster obwohl ich schon bei einer Sekunde bin (er zeigt immer 1 sekunde an was ja richtig ist) und dann starte, dann bin ich mit der Zeit irgendwo. Warum ist das so??

Danke im Voraus

Gruß Robert

SprinterSB
29.08.2006, 13:13
Die EE-Zugriffe sollten auch funzen, ohne sie als Atom zu verpacken.

Probleme sind aber dann vorprogrammiert, wenn du auf Objekte wie 'time' im Programm nicht-atomar zugreifst (davor schützt dich volatie nicht!) und in einer ISR ebenfalls verwendest. Für 'segment' trifft das auch zu, nur das es dort kein Problem ist (ausser vielleicht ein ästhetisches, Anzeigeflackern oder so).

Das nur als Tipp. Dein Programm weiter angeschaut hab ich nicht...

Razer
29.08.2006, 15:09
Eigentlich läuft alles jetzt sehr zuverlässig.

Einen Schönheitsfehler hat das Programm aber noch. Das Inkrementieren bei gedrückter Taste geht viel schneller als das Dekrementieren.

Woran kann das liegen???

Gruß Robert