Forum: Compiler & IDEs LED blinken lassen und ATMega16 schlafen lassen


von Sebastian B. (m0nkey)


Lesenswert?

Hi,
ich bins schon wieder, mit einem anderen Problem. :D

Ich wollte zum testen des Sleep-Modes "Power Done Mode" eine LED des 
STK500 auf Knopfdruck blinken lassen und bei nem anderen Knopf in den 
Sleep-Modus versetzen. Leider scheitere ich schon am blinken der LED, 
weiß nicht woran es liegt. Evtl könnt ihr mir ja auch generelle Tips zum 
Code geben:

main.c

1
#define F_CPU 8000000
2
3
#include <avr/io.h>
4
#include <avr/interrupt.h>
5
#include "taster.h"
6
#include <util/delay.h>
7
#define TEILER 0x2        // Teiler des Haupttaktes
8
#define INTRP (65536 - 49997)  // Anfangswert des Timers1
9
10
uint8_t tasttest = 0;
11
12
ISR(TIMER1_OVF_vect)       // Timer1 Interrupt
13
{
14
    TCNT1 = INTRP;      // Prescaler neu setzen
15
    taster_get_status(1, PIND & (1<<PD3));
16
    taster_get_status(2, PIND & (1<<PD4));
17
    taster_get_status(3, PIND & (1<<PD5));
18
    taster_get_status(4, PIND & (1<<PD6));
19
    taster_get_status(5, PIND & (1<<PD7));
20
    if (tastst != 5) tasttest = 0;
21
    
22
23
}
24
25
void long_delay(uint16_t ms) {
26
    for (; ms>0; ms--) _delay_ms(1);
27
}
28
29
    
30
void ioinit()
31
{
32
  DDRA |= (1<<PA2) | (1<<PA3) | (1<<PA4) | (1<<PA5) | (1<<PA6);  // DDR für Port A setzten
33
  PORTA = 0xFF;                           // Port für die LEDs auf Highe schaten (für STK500)
34
  DDRD = 0x00;
35
  PORTD = 0xFF;      // DDR für Port B setzen
36
  TCCR1B |= TEILER;       // Teiler setzten
37
  TIMSK |= (1 << TOIE1);    // Timer1 Interrupt freischalten
38
  TCNT1 = INTRP;        // Anfangswert laden
39
} 
40
41
int main()
42
{
43
  ioinit();          // Interface intialisieren
44
  sei();             // Interrupts global aktivieren
45
  while (1)
46
  {
47
    uint8_t tast = tastst;  // lokale Übergabevariable für Tastenstatus
48
    switch (tast)      // switch-case für die jeweiligen Tastenfunktionen
49
    {
50
      default:
51
      case NOT_PRESSED:
52
        break;
53
54
      case 1:        
55
        PORTA = 0b11111011;
56
        long_delay(1000);
57
        PORTA = 0xFF;
58
        break;
59
60
      case 2:
61
        PORTA = 0b11110111;
62
        long_delay(1000);
63
        PORTA = 0xFF;
64
        break;
65
66
      case 3:
67
        PORTA = 0b11101111;
68
        long_delay(1000);
69
        PORTA = 0xFF;
70
        break;
71
72
      case 4:
73
        PORTA = 0b11011111;
74
        long_delay(1000);
75
        PORTA = 0xFF;
76
        break;
77
78
      case 5:
79
        tasttest = 1;
80
        while(tasttest)
81
        {
82
          PORTA = 0b10111111;
83
          long_delay(1000);
84
          PORTA = 0xFF;
85
          long_delay(1000);
86
        }
87
        break;
88
    }
89
    
90
    if (tast != NOT_PRESSED) tastst = NOT_PRESSED;
91
92
  }
93
return 0;
94
}


taster_status.c

1
/********************************************
2
*                      *
3
*  Name: tasterabfrage.c          *
4
*  last updated: 02.12.2008        *
5
*  Author: Sebastian Baier          *
6
*                      *
7
*  Tastenentprellung und Statusabfrage    *
8
*                      *
9
*                      *
10
*                      *
11
*                      *
12
*                      *
13
********************************************/
14
15
#include "taster.h"
16
17
volatile uint8_t tastst = NOT_PRESSED; // Variable in der die Nummer der gedrückten Taste gespeichert wird
18
19
taste_t tasten[NUM_TASTER];  // Tastenarry definieren
20
21
void taster_get_status(const uint8_t num, uint8_t tasthw) // übergabe Tasternummer und Pinstatus
22
{
23
/*
24
Unterscheidung von low-ativen (TASTER_LEVEL 0)
25
und high-aktiven (TASTER_LEVEL 1) Tastern
26
27
siehe Header File taster.h
28
*/
29
30
#if TASTER_LEVEL
31
  tasthw = !!tasthw;
32
#else 
33
  tasthw = !tasthw;
34
#endif
35
36
if (tasten[num].old & tasthw) tastst = num;  // eigentliche Entprellung
37
38
tasten[num].old = tasthw;  // speichern des alten Tastenwertes
39
tasthw = NOT_PRESSED;    // rücksetzen der Variable für den Hardwarstatus des Tastes
40
}


taster.h

1
/****************************************
2
*                    *
3
*  Name: taster.h            *
4
*  last updated: 02.12.2008      *
5
*  Author: Sebastian Baier        *
6
*                    *
7
*  Header File für die Tastenabfrage  *
8
*                    *
9
*  Definition globaler Variablen und  *
10
*  Strukturen              *
11
*                    *
12
*                    *
13
*****************************************/
14
#include <stdint.h>
15
16
#ifndef _TASTER_H_
17
#define _TASTER_H_
18
19
#define NOT_PRESSED 0    // Wert 0 dem Status NOT_PRESSED zuordnen
20
#define NUM_TASTER 5    // Anzahl der Taster
21
#define TASTER_LEVEL 0    // Varible zur Unterscheidung von LOW- und HIGH-Tastern (0=lowaktiv; 1=highaktiv)
22
23
extern volatile uint8_t tastst;  // Variable zur Status übergabe global definieren
24
25
/*
26
Definition der Strukter für die Tasten, 
27
enthält nur Variable zur Speicherung 
28
des alten Tasterwertes
29
*/
30
31
typedef struct
32
{
33
  uint8_t old;  // Speicher für alten Tasterstatus
34
} taste_t;
35
36
extern taste_t tasten[]; // Array tasten global definieren
37
38
extern void taster_get_status (const uint8_t num, uint8_t tasthw); // Methode für Tasterabfrage global definieren
39
40
#endif

von Zee (Gast)


Lesenswert?

Du hast -noch- einen schönen programmierstil -rein formal-, versuch den 
so beizubehalten.
Allerdings finde ich Deinen Code zu umständlich. In der ISR würde ich 
nur Variablen setzen die dann im Hauptprg. ausgewertet werden. Das ganze 
geht auch ohne globale Variablen.
Tip: schau Dir nochmal die Definition zu switch() an.

von Stefan E. (sternst)


Lesenswert?

tasttest muss volatile sein.

von Peter D. (peda)


Lesenswert?

Zee wrote:
> Du hast -noch- einen schönen programmierstil -rein formal-, versuch den
> so beizubehalten.

Bis auf eines:
Das Delay 1000ms bereitet mir Bauchschmerzen.
In der Regel macht man damit jeden Programmfluß kaputt und verhindert 
eine ergonomische Bedienung.


Ich hatte kürzlich mal ein ähnliches Programm für nen ATtiny13 
geschrieben:

http://www.mikrocontroller.net/attachment/42337/sleep.zip

Die Taste schaltet: ein, blinken, aus usw.
Außer beim Blinken geht er in Powerdown.

Die Entprellroutine entprellt immer den ganzen Port (bis zu 8 Tasten), 
hier wird aber nur eine abgefragt.
Ein Tastenzustand wird übernommen, wenn er mindestens 4-mal 
hintereinander gleich war.
Nebenbei erfolgt noch ne Fankenerkennung, da man ja oft nur eine Aktion 
beim Drücken auslösen will und nicht, solange man drückt.


Peter

P.S.:
Stefan wird recht haben mit volatile.

von Sebastian B. (m0nkey)


Lesenswert?

Das sieht sehr kompakt aus, hilft mir aber nur wenn ich durch den Code 
durchsteige.

z.B. verstehe ich diese Zeile nicht wirklich:

1
#define SBIT_(port,pin) ((*(volatile struct bits*)&port).b##pin)


das verstehe ich auch nicht ganz:
1
struct bits {
2
  u8 b0:1;
3
  u8 b1:1;
4
  u8 b2:1;
5
  u8 b3:1;
6
  u8 b4:1;
7
  u8 b5:1;
8
  u8 b6:1;
9
  u8 b7:1;
10
} __attribute__((__packed__));


also ich weiß was du da machst, allerdings weiß ich nicht was du z.B. 
mit dem b0:1 machst oder was __attribute__((_packed_)) das bedeutet.

Und so einige andere Sachen auch nicht, da sich das C das ich gelernt 
hab von deinem Codestil unterscheidet.^^


Hab jetzt ein volatile vor die Variable tasttest gesetzte, es ändert 
sich alleridngs nicht, wenn ich case 5, also die LED blinkt, bin dann 
komm ich nicht mehr aus der while-schleife raus. Obwohl tasttest = 0 
ist.

von Peter D. (peda)


Lesenswert?

Sebastian Baier wrote:
> Das sieht sehr kompakt aus, hilft mir aber nur wenn ich durch den Code
> durchsteige.

Frag ruhig.


> z.B. verstehe ich diese Zeile nicht wirklich:
>
>
>
1
> #define SBIT_(port,pin) ((*(volatile struct bits*)&port).b##pin)
2
>

Das wird z.B. hier erklärt:
http://www.avrfreaks.net/index.php?name=PNphpBB2&file=viewtopic&t=67368&start=all

Im Steuerungsanwendungen ist es typisch, daß IO-Pins verschiedene 
Funktionen haben und daher wäre es übersichtlicher, wenn man sie auch 
separat ansprechen kann.
Einige MC-Compiler kennen deshalb Bitvariablen, wie z.B. der Keil C51.
Beim GCC kann man es mit diesem Macro machen.


> da sich das C das ich gelernt
> hab von deinem Codestil unterscheidet.^^

Kann ich mir gut vorstellen, da ich C nie offiziell gelernt habe.
Ich habs hauptsächlich im Selbststudium über Turbo-Pascal, Turbo-C, Keil 
C51 und WINAVR gelernt.


Peter

von Sebastian B. (m0nkey)


Lesenswert?

Danke Peter, allerdings interssiert mich trotzdem warum mein Programm 
nicht mehr aus der While-schleife raus spingt, hat da jemand ein ahnung?

von Peter D. (peda)


Lesenswert?

Sebastian Baier wrote:
> Danke Peter, allerdings interssiert mich trotzdem warum mein Programm
> nicht mehr aus der While-schleife raus spingt, hat da jemand ein ahnung?

Könnte daran liegen:
1
tasthw = NOT_PRESSED;    // rücksetzen der Variable für den Hardwarstatus des Tastes
2
}

Diese Zeile ist toter Code und wird vom Compiler auch rausgeschmissen.


Peter

von Sebastian B. (m0nkey)


Lesenswert?

Daran liegts nicht, es funktiniert und es lag am volatile. hab nur nicht 
gecheckt, dass es funktioniert da mich der simulator etwas irritiert 
hatte.

Vielen Dank

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.