Forum: Mikrocontroller und Digitale Elektronik AVR Tiny2313 eeprom vergesslich?


von Une E. (une_e)


Lesenswert?

Hallo,

um unsere Mediacenter PC's per Fernbedienung einschalten zu können haben 
ein Kollege und ich einen Tiny und IRMP verwendet.

Dies funktioniert auch tadellos, nur vergisst der Tiny manchmal den 
angelernten und im eeprom abgelegten ir-Code.
Anbei der c-Code, worann kan es liegen, dass der IR-Code manchmal 
wiedergefunden und manchmal vergessen wird (bei ca. 1 von 5 Versuchen, 
also Spannungslos machen und wieder Spannung, wird der Ir-Code 
vergessen.
1
/*---------------------------------------------------------------------------------------------------------------------------------------------------
2
 * main.c - Ir-einschalter mit AtTiny2313 mit IRMP
3
 *
4
 * ATTINY2313 @ 8 MHz
5
 *
6
 * Fuses: lfuse: 0xE4 hfuse: 0xDF efuse: 0xFF
7
 *
8
 * This program is free software; you can redistribute it and/or modify
9
 * it under the terms of the GNU General Public License as published by
10
 * the Free Software Foundation; either version 2 of the License, or
11
 * (at your option) any later version.
12
 *---------------------------------------------------------------------------------------------------------------------------------------------------
13
 */
14
15
#include <inttypes.h>
16
#include <avr/io.h>
17
#include <util/delay.h>
18
#include <avr/pgmspace.h>
19
#include <avr/interrupt.h>
20
#include "irmp.h"
21
#include "irmpconfig.h"
22
#include "avr/eeprom.h"
23
24
#ifndef F_CPU
25
#error F_CPU unkown
26
#endif
27
28
// Defines fuer den Taster-Input
29
#define Taster_PORT                               PORTB
30
#define Taster_DDR                                DDRB
31
#define Taster_PIN                                PINB
32
#define Taster_BIT                                2       // use PB2 as Taster on AVR
33
// Defines fuer die LED
34
#define Led_PORT                               PORTB
35
#define Led_DDR                                DDRB
36
#define Led_PIN                                PINB
37
#define Led_BIT                                0       // use PB0 as Taster on AVR
38
// Defines fuer den Schaltausgang
39
#define Schalt_PORT                               PORTB
40
#define Schalt_DDR                                DDRB
41
#define Schalt_PIN                                PINB
42
#define Schalt_BIT                                1       // use PB1 as Taster on AVR
43
// EEPROM Variablen anlegen
44
uint16_t Ziel_Command EEMEM = 12345;
45
uint8_t CodeErlernt EEMEM = 0;
46
47
void timer_init(void) {
48
  OCR1A = (F_CPU / F_INTERRUPTS) - 1; // compare value: 1/10000 of CPU frequency
49
  TCCR1B = (1 << WGM12) | (1 << CS10); // switch CTC Mode on, set prescaler to 1
50
  TIMSK = 1 << OCIE1A; // OCIE1A: Interrupt by timer compare
51
}
52
53
/*---------------------------------------------------------------------------------------------------------------------------------------------------
54
 * timer 1 compare handler, called every 1/10000 sec
55
 *---------------------------------------------------------------------------------------------------------------------------------------------------
56
 */
57
// Timer 1 output compare A interrupt service routine
58
ISR(TIMER1_COMPA_vect)
59
{
60
  (void) irmp_ISR(); // call irmp ISR
61
}
62
63
/*---------------------------------------------------------------------------------------------------------------------------------------------------
64
 * Hilfsroutinen
65
 *---------------------------------------------------------------------------------------------------------------------------------------------------
66
 */
67
68
uint8_t key_pressed(const volatile uint8_t *inputreg, uint8_t inputbit) {
69
  static uint8_t last_state = 0;
70
71
  if (last_state == !(*inputreg & (1 << inputbit))) {
72
    return 0; /* keine Änderung */
73
  }
74
75
  /* Wenn doch, warten bis etwaiges Prellen vorbei ist: */
76
  _delay_ms(20);
77
78
  /* Zustand für nächsten Aufruf merken: */
79
  last_state = !(*inputreg & (1 << inputbit));
80
81
  /* und den entprellten Tastendruck zurückgeben: */
82
  return !(*inputreg & (1 << inputbit));
83
}
84
85
/*---------------------------------------------------------------------------------------------------------------------------------------------------
86
 * MAIN: main routine
87
 *---------------------------------------------------------------------------------------------------------------------------------------------------
88
 */
89
int main(void) {
90
  IRMP_DATA irmp_data;
91
  char learning = 0;
92
  char learned = eeprom_read_byte(&CodeErlernt);
93
  uint16_t zielCommandSram = eeprom_read_word(&Ziel_Command);
94
95
  // Setzen der DatenRichtungsRegister
96
  Led_DDR |= (1 << Led_BIT);
97
  Schalt_DDR |= (1 << Schalt_BIT);
98
99
  irmp_init(); // initialize rc5
100
  timer_init(); // initialize timer
101
  sei ();  // enable interrupts
102
103
  for (;;) {
104
    if (key_pressed(&Taster_PIN, Taster_BIT)) {
105
      learning = 1; // setzen der learning Variable
106
      Led_PORT |= (1 << Led_BIT); // Einschalten der learning Led
107
    }
108
109
    if (learning && irmp_get_data(&irmp_data)) {
110
      // Speichern des IR-Codes im eeprom
111
      zielCommandSram = irmp_data.command;
112
      eeprom_write_word(&Ziel_Command, zielCommandSram);
113
      Led_PORT &= ~(1 << Led_BIT); // Ausschalten der learning Led
114
      learning = 0;
115
      learned = 1;
116
      eeprom_write_byte(&CodeErlernt, learned);
117
    }
118
119
    if (learned && irmp_get_data(&irmp_data)) {
120
      // Vergleichen des IR-Codes mit dem im eeprom
121
      if (irmp_data.command == zielCommandSram) {
122
        //Einschalten des Schaltports fuer 500ms
123
        Schalt_PORT |= (1 << Schalt_BIT); // Einschalten des Schaltausgangs
124
        Led_PORT |= (1 << Led_BIT); // Einschalten der Led
125
        _delay_ms(500);
126
        Schalt_PORT &= ~(1 << Schalt_BIT); // Ausschalten des Schaltausgangs
127
        Led_PORT &= ~(1 << Led_BIT); // Ausschalten der Led
128
129
      } //else {
130
        //Led_PORT |= (1 << Led_BIT); // Einschalten der Led
131
        //_delay_ms(100);
132
        //Led_PORT &= ~(1 << Led_BIT); // Ausschalten der Led
133
134
      //}
135
    }
136
  }
137
}

Ich hoffe irgendwer kann uns weiterhelfen.

von Stefan P. (form)


Lesenswert?

Une E. schrieb:
> uint16_t Ziel_Command EEMEM = 12345;
> uint8_t CodeErlernt EEMEM = 0;


Die Adresse 0 im EEPROM wird manchmal bei unsauberer Versorgung 
überschrieben.
Definier davor noch ein DummyByte:

uint8_t DummyByte EEMEM = 0;
uint16_t Ziel_Command EEMEM = 12345;
uint8_t CodeErlernt EEMEM = 0;

von Une E. (une_e)


Lesenswert?

Danke, das werde ich heute ausprobieren.

von Charly B. (charly)


Lesenswert?

Stefan P. schrieb:
> Die Adresse 0 im EEPROM wird manchmal bei unsauberer Versorgung
> überschrieben.

Gab sogar mal ein erata von Atmel darueber

schreib mal obs dann weg ist wenn du die eepromzelle 0
nicht verwendest

vlG
Charly

von Peter D. (peda)


Lesenswert?

Une E. schrieb:
> hfuse: 0xDF

Das ist falsch.
Bei Nutzung des EEPROM muß das BOR aktiviert werden:
hfuse = 0xD9


Peter

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.