Forum: Mikrocontroller und Digitale Elektronik Atmega 8 löst undefiniert Tastendruck aus


von Chris T. (chris0086)


Angehängte Dateien:

Lesenswert?

Hallo Leute,
ich hab mal wieder ien Problem und zwar hab ich einen Atmega 8 hier.
Dieser soll gemäß unten stehender Software bei einem langen Tastendruck 
die blaue LED anschalten und dann immer bei einem kurzen die rote LED 
aufleuchten lassen ( und jeweils ein Relais schalten).
Das funktioniert bei einem Druck auf die Taste prima.
Das Problem ist bloß, es funktioniert auch manchmal wenn ich den 
Prozessor berühre oder in die Nähe komme.
Aber hier erstmal der Quellcode:
1
/************************************************************************/
2
/*                                                                      */
3
/*                      Debouncing 8 Keys                               */
4
/*                      Sampling 4 Times                                */
5
/*                      With Repeat Function                            */
6
/*                                                                      */
7
/*              Author: Peter Dannegger                                 */
8
/*                      danni@specs.de                                  */
9
/*                                                                      */
10
/************************************************************************/
11
12
#include <stdint.h>
13
#include <avr/io.h>
14
#include <avr/interrupt.h>
15
#include <util/delay.h>
16
#ifndef F_CPU
17
#define F_CPU           7372800                   // processor clock frequency
18
#warning kein F_CPU definiert
19
#endif
20
21
#define KEY_DDR         DDRC
22
#define KEY_PORT        PORTC
23
#define KEY_PIN         PINC
24
#define KEY1            5
25
26
#define ALL_KEYS        ( 1<<KEY1 )
27
28
#define REPEAT_MASK     (1<<KEY1)       // repeat: key1, key2
29
#define REPEAT_START    100                        // after 500ms
30
#define REPEAT_NEXT     10                        // every 200ms
31
32
#define LED_DDR         DDRB
33
#define LED_PORT        PORTB
34
35
#define LED1            0
36
#define LED2            1
37
38
volatile uint8_t key_state;                                // debounced and inverted key state:
39
                                                  // bit = 1: key pressed
40
volatile uint8_t key_press;                                // key press detect
41
42
volatile uint8_t key_rpt;                                  // key long press and repeat
43
44
45
ISR( TIMER2_OVF_vect )                            // every 10ms
46
{
47
  static uint8_t ct0, ct1, rpt;
48
  uint8_t i;
49
50
  TCNT0 = (uint8_t)(int16_t)-(F_CPU / 1024 * 10e-3 + 0.5);  // preload for 10ms
51
52
  i = key_state ^ ~KEY_PIN;                       // key changed ?
53
  ct0 = ~( ct0 & i );                             // reset or count ct0
54
  ct1 = ct0 ^ (ct1 & i);                          // reset or count ct1
55
  i &= ct0 & ct1;                                 // count until roll over ?
56
  key_state ^= i;                                 // then toggle debounced state
57
  key_press |= key_state & i;                     // 0->1: key press detect
58
59
  if( (key_state & REPEAT_MASK) == 0 )            // check repeat function
60
     rpt = REPEAT_START;                          // start delay
61
  if( --rpt == 0 ){
62
    rpt = REPEAT_NEXT;                            // repeat delay
63
    key_rpt |= key_state & REPEAT_MASK;
64
  }
65
}
66
67
///////////////////////////////////////////////////////////////////
68
//
69
// check if a key has been pressed. Each pressed key is reported
70
// only once
71
//
72
uint8_t get_key_press( uint8_t key_mask )
73
{
74
  cli();                                          // read and clear atomic !
75
  key_mask &= key_press;                          // read key(s)
76
  key_press ^= key_mask;                          // clear key(s)
77
  sei();
78
  return key_mask;
79
}
80
81
///////////////////////////////////////////////////////////////////
82
//
83
// check if a key has been pressed long enough such that the
84
// key repeat functionality kicks in. After a small setup delay
85
// the key is reported being pressed in subsequent calls
86
// to this function. This simulates the user repeatedly
87
// pressing and releasing the key.
88
//
89
uint8_t get_key_rpt( uint8_t key_mask )
90
{
91
  cli();                                          // read and clear atomic !
92
  key_mask &= key_rpt;                            // read key(s)
93
  key_rpt ^= key_mask;                            // clear key(s)
94
  sei();
95
  return key_mask;
96
}
97
98
///////////////////////////////////////////////////////////////////
99
//
100
// check if a key is pressed right now
101
//
102
uint8_t get_key_state( uint8_t key_mask )
103
104
{
105
  key_mask &= key_state;
106
  return key_mask;
107
}
108
109
///////////////////////////////////////////////////////////////////
110
//
111
uint8_t get_key_short( uint8_t key_mask )
112
{
113
  cli();                                          // read key state and key press atomic !
114
  return get_key_press( ~key_state & key_mask );
115
}
116
117
///////////////////////////////////////////////////////////////////
118
//
119
uint8_t get_key_long( uint8_t key_mask )
120
{
121
  return get_key_press( get_key_rpt( key_mask ));
122
}
123
124
int main( void )
125
{
126
  LED_PORT = 0x00;
127
  LED_DDR = 0xFF;
128
129
  // Configure debouncing routines
130
  KEY_DDR = 0x00;                // configure key port for input
131
  KEY_PORT = 0xFF;                // and turn on pull up resistors
132
133
  TCCR2 |= (1<<CS22)| (1<<CS21) | (1<<CS20);         // divide by 1024
134
  TCNT2 = (uint8_t)(int16_t)-(F_CPU / 1024 * 10e-3 + 0.5);  // preload for 10ms
135
  TIMSK |= 1<<TOIE2;                   // enable timer interrupt
136
  uint8_t setting = 0;
137
  uint8_t p_val = 0;
138
139
  sei();
140
  //PIN 3 Port D auf Ausgang Relais1
141
  DDRD |= (1<<DDD3);
142
143
  //PIN 4 Port D auf Ausgang Relais2
144
  DDRD |= (1<<DDD4);
145
  //PORTD |= (1<<PD4); //Einschalten
146
  DDRD  &= ~(1<<PD2);  /* Pin PC7 als Eingang */
147
  PORTD |= (1<<PD2);    /* internen Pull-Up an PC7 aktivieren */
148
  DDRD  &= ~(1<<PD5);  /* Pin PC7 als Eingang */
149
  PORTD |= (1<<PD5);    /* internen Pull-Up an PC7 aktivieren */
150
  DDRD  &= ~(1<<PD6);  /* Pin PC7 als Eingang */
151
  PORTD |= (1<<PD6);    /* internen Pull-Up an PC7 aktivieren */
152
  DDRD  &= ~(1<<PD7);  /* Pin PC7 als Eingang */
153
  PORTD |= (1<<PD7);    /* internen Pull-Up an PC7 aktivieren */
154
155
156
  while(1){
157
    if( (get_key_short( 1<<KEY1 )) && (setting == 1))
158
    {
159
      LED_PORT  &= ~(1<<LED1);
160
161
      if (p_val == 0)
162
      {
163
        LED_PORT ^= 1<<LED1;
164
        _delay_ms(250);
165
        LED_PORT ^= 1<<LED1;
166
167
      }
168
      if (p_val == 1)
169
      {
170
        LED_PORT ^= 1<<LED1;
171
        PORTD ^= (1<<PD3); //schalten
172
        _delay_ms(250);
173
        LED_PORT ^= 1<<LED1;
174
        _delay_ms(250);
175
        LED_PORT ^= 1<<LED1;
176
        PORTD ^= (1<<PD3); //schalten
177
        _delay_ms(250);
178
        LED_PORT ^= 1<<LED1;
179
180
      }
181
      if (p_val == 2)
182
      {
183
        LED_PORT ^= 1<<LED1;
184
        PORTD ^= (1<<PD4); //schalten
185
        _delay_ms(250);
186
        LED_PORT ^= 1<<LED1;
187
        _delay_ms(250);
188
        LED_PORT ^= 1<<LED1;
189
        _delay_ms(250);
190
        LED_PORT ^= 1<<LED1;
191
        _delay_ms(250);
192
        LED_PORT ^= 1<<LED1;
193
        PORTD ^= (1<<PD4); //schalten
194
        _delay_ms(250);
195
        LED_PORT ^= 1<<LED1;
196
197
198
      }
199
      p_val++;
200
      if(p_val == 3)
201
        p_val =0;
202
    }
203
204
205
    if( get_key_long( 1<<KEY1 ))
206
    {
207
      LED_PORT ^= 1<<LED2;
208
      setting = !setting;
209
      // PORTD ^= (1<<PD3); //schalten
210
    }
211
212
213
214
  }
215
}
Also die internen Pullup Widerstände sollten aktiviert sein ebenso hab 
ich versucht den ungenutzten Pins auch auf Eingang zu setzen und die 
Pullups zu aktivieren.
Weiterhin hab ich den Eingang vom Taster einen C mit 100nF gegen VCC 
spendiert.
Der Controller stürzt nicht ab da ja dann die blaue LED ausgehen würde.
Aber ich kann am Oszi am Tastereingang einen Spannungseinbruch 
feststellen wenn er mal wieder willkürlich schaltet. Also als ob jemand 
den Taster drücken würde.
Das einizge was ich am Aufbau wohl falsch gemacht hbe ist das ich AREF 
auf VCC gelgt habe, aber kann das denn auch daran liegen?
Hier noch in Video um die Sache zu verdeutlichen (auf 1 Minute spulen):
http://www.vidup.de/v/kWpFh/

Was kann ich machen damit er richtig funktioniert? Liegts an der 
Software?
Bei dem Video wurde derController über den Programmer versorgt, also 
nicht über den Schaltregler der auf dem Board ist.

von Felix P. (fixxl)


Lesenswert?

In der ISR sollte in deinem Fall TCNT2 und nicht TCNT0 gesetzt werden.

AREF auf VCC zu setzen sollte lt. Datenblatt in Ordnung sein, solange du 
keine Referenz für den ADC einstellst (Bit REFS1 und REFS0 im 
ADMUX-Register müssen 0 sein).

Ein 100nF-Kondensator von RESET nach GND fehlt mir noch.

von Chris T. (chris0086)


Lesenswert?

Hab das mit TCNT2 umgestellt und ihm noch einen C am Reset verpasst 
leider immernoch keine Besserung.

von Karl H. (kbuchegg)


Lesenswert?

Chris tian schrieb:


> Also die internen Pullup Widerstände sollten aktiviert sein ebenso hab
> ich versucht den ungenutzten Pins auch auf Eingang zu setzen und die
> Pullups zu aktivieren.
> Weiterhin hab ich den Eingang vom Taster einen C mit 100nF gegen VCC
> spendiert.

Das war keine so prickelnde Idee. Das Pollin Board ist bekannt dafür 
unzuverlässig zu sein, eben weil da Kondensatoren kurz geschlossen 
werden und das kleine Spikes auf der Versorungungsspannung verursacht.

> Der Controller stürzt nicht ab da ja dann die blaue LED ausgehen würde.
> Aber ich kann am Oszi am Tastereingang einen Spannungseinbruch
> feststellen wenn er mal wieder willkürlich schaltet.

Hast du dir schon mal die Versorgungsspannung angesehen? Gibt es dort 
auch Glitsches, wenn du auf der Platine rumfingerst?

Du könntest mal probeweise einen externen Pullup-Widerstand an den 
Eingangspin anhängen. Größenordnung so um die 10k.


> Was kann ich machen damit er richtig funktioniert? Liegts an der
> Software?

Normalerweise würde ich bei solchen Symptomen sagen, du hast dir 
irgendwo die Pullups irrtümlich weggeschaltet. Allerdings kann ich im 
Code nichts entdecken. M.M nach ist der Code ok. Ich tippe auf ein 
Hardware Problem.

(Ok, die Sache mit TCNT2 bzw TCNT0. Ist aber uninteressant. Im Grunde 
kann man das Vorladen des Timers auch weg lassen. Ob die ISR jetzt alle 
5ms kommt oder alle 7ms oder 10 oder 15, spielt keine Rolle)

von Chris T. (chris0086)


Lesenswert?

Was mich wundert ist das der µC ungewöhnlich warm wird. Aber wüsste 
nicht warum, die Relais die geschlatet werden sind aus. und sonst hängen 
ja nur die zwei LED dran.

von Karl H. (kbuchegg)


Lesenswert?

Chris tian schrieb:
> Was mich wundert ist das der µC ungewöhnlich warm wird. Aber wüsste
> nicht warum

Irgendwo eine kleine Lötbrücke?
Die können sich fies verstecken

von Chris T. (chris0086)


Angehängte Dateien:

Lesenswert?

So Leute ich bin mir zu 99,9% sicher den Fehler gefunden zu haben.
Bin natürlich selbst schuld.
Im Anhang ist der Fehler zu sehen. Den konnte ich aber nicht entdecken 
als ich die einzelnen Pins gegenseitig auf Durchgang geprüft habe.
Eine Leitung ist die Tasterleitung, die andere RX auf der anderen Seite 
des Max232 der aber aktuell nicht gebraucht wird. Ich hab mich auch 
immer schon gewundert warum der MAx auch ungewöhnlich warm wird auf dem 
IR Bild.

Naja das  kommt davon wenn man zum schluss keinen ERC macht.
ICh hoffe das war der Fehler und bedanke mich trotzdem bei allen die mir 
hier geholfen haben.

Edit: Sorry irgendwie ist was mit dem Bils schief gegangen.
Ist aber nicht schlimm da ist eigentlich nur das Via zu sehen das leider 
beide Leitungen verbindet.

von Falk B. (falk)


Lesenswert?

@ Chris tian (chris0086)

>Im Anhang ist der Fehler zu sehen.

Mein Monokel ist kaputt.

von Peter D. (peda)


Lesenswert?

Falk Brunner schrieb:
> Mein Monokel ist kaputt.

Ich erkenne auch rein garnichts.

Wenn hier von Bildformat beachten die Rede ist, dann ist damit nicht die 
Pixelzahl gemeint, 90 Pixel ist wirklich ne Zumutung.

Sondern es ist die Dateigröße gemeint, d.h. die Komprimierung erhöhen.
Das Format kann (sollte) ruhig Bildschirm füllend sein.

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.