- 3D-Druck Einstieg und Tipps         
Ergebnis 1 bis 5 von 5

Thema: Schreiben und Lesen aus dem EEProm unzuverlässig

  1. #1
    Erfahrener Benutzer Roboter-Spezialist
    Registriert seit
    08.01.2006
    Ort
    Gratkorn
    Alter
    34
    Beiträge
    207

    Schreiben und Lesen aus dem EEProm unzuverlässig

    Anzeige

    Praxistest und DIY Projekte
    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:

    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

  2. #2
    Erfahrener Benutzer Robotik Einstein Avatar von SprinterSB
    Registriert seit
    09.06.2005
    Ort
    An der Saar
    Beiträge
    2.802
    -- 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...
    Disclaimer: none. Sue me.

  3. #3
    Erfahrener Benutzer Roboter-Spezialist
    Registriert seit
    08.01.2006
    Ort
    Gratkorn
    Alter
    34
    Beiträge
    207
    Zitat Zitat von SprinterSB
    -- 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??

    Zitat Zitat von SprinterSB
    -- 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

  4. #4
    Erfahrener Benutzer Robotik Einstein Avatar von SprinterSB
    Registriert seit
    09.06.2005
    Ort
    An der Saar
    Beiträge
    2.802
    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...
    Disclaimer: none. Sue me.

  5. #5
    Erfahrener Benutzer Roboter-Spezialist
    Registriert seit
    08.01.2006
    Ort
    Gratkorn
    Alter
    34
    Beiträge
    207
    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

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
  •  

MultiPlus Wechselrichter Insel und Nulleinspeisung Conrad