mikrocontroller.net

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


Autor: Sebastian B. (m0nkey)
Datum:

Bewertung
0 lesenswert
nicht 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

#define F_CPU 8000000

#include <avr/io.h>
#include <avr/interrupt.h>
#include "taster.h"
#include <util/delay.h>
#define TEILER 0x2        // Teiler des Haupttaktes
#define INTRP (65536 - 49997)  // Anfangswert des Timers1

uint8_t tasttest = 0;

ISR(TIMER1_OVF_vect)       // Timer1 Interrupt
{
    TCNT1 = INTRP;      // Prescaler neu setzen
    taster_get_status(1, PIND & (1<<PD3));
    taster_get_status(2, PIND & (1<<PD4));
    taster_get_status(3, PIND & (1<<PD5));
    taster_get_status(4, PIND & (1<<PD6));
    taster_get_status(5, PIND & (1<<PD7));
    if (tastst != 5) tasttest = 0;
    

}

void long_delay(uint16_t ms) {
    for (; ms>0; ms--) _delay_ms(1);
}

    
void ioinit()
{
  DDRA |= (1<<PA2) | (1<<PA3) | (1<<PA4) | (1<<PA5) | (1<<PA6);  // DDR für Port A setzten
  PORTA = 0xFF;                           // Port für die LEDs auf Highe schaten (für STK500)
  DDRD = 0x00;
  PORTD = 0xFF;      // DDR für Port B setzen
  TCCR1B |= TEILER;       // Teiler setzten
  TIMSK |= (1 << TOIE1);    // Timer1 Interrupt freischalten
  TCNT1 = INTRP;        // Anfangswert laden
} 

int main()
{
  ioinit();          // Interface intialisieren
  sei();             // Interrupts global aktivieren
  while (1)
  {
    uint8_t tast = tastst;  // lokale Übergabevariable für Tastenstatus
    switch (tast)      // switch-case für die jeweiligen Tastenfunktionen
    {
      default:
      case NOT_PRESSED:
        break;

      case 1:        
        PORTA = 0b11111011;
        long_delay(1000);
        PORTA = 0xFF;
        break;

      case 2:
        PORTA = 0b11110111;
        long_delay(1000);
        PORTA = 0xFF;
        break;

      case 3:
        PORTA = 0b11101111;
        long_delay(1000);
        PORTA = 0xFF;
        break;

      case 4:
        PORTA = 0b11011111;
        long_delay(1000);
        PORTA = 0xFF;
        break;

      case 5:
        tasttest = 1;
        while(tasttest)
        {
          PORTA = 0b10111111;
          long_delay(1000);
          PORTA = 0xFF;
          long_delay(1000);
        }
        break;
    }
    
    if (tast != NOT_PRESSED) tastst = NOT_PRESSED;

  }
return 0;
}




taster_status.c

/********************************************
*                      *
*  Name: tasterabfrage.c          *
*  last updated: 02.12.2008        *
*  Author: Sebastian Baier          *
*                      *
*  Tastenentprellung und Statusabfrage    *
*                      *
*                      *
*                      *
*                      *
*                      *
********************************************/

#include "taster.h"

volatile uint8_t tastst = NOT_PRESSED; // Variable in der die Nummer der gedrückten Taste gespeichert wird

taste_t tasten[NUM_TASTER];  // Tastenarry definieren

void taster_get_status(const uint8_t num, uint8_t tasthw) // übergabe Tasternummer und Pinstatus
{
/*
Unterscheidung von low-ativen (TASTER_LEVEL 0)
und high-aktiven (TASTER_LEVEL 1) Tastern

siehe Header File taster.h
*/

#if TASTER_LEVEL
  tasthw = !!tasthw;
#else 
  tasthw = !tasthw;
#endif

if (tasten[num].old & tasthw) tastst = num;  // eigentliche Entprellung

tasten[num].old = tasthw;  // speichern des alten Tastenwertes
tasthw = NOT_PRESSED;    // rücksetzen der Variable für den Hardwarstatus des Tastes
}


taster.h

/****************************************
*                    *
*  Name: taster.h            *
*  last updated: 02.12.2008      *
*  Author: Sebastian Baier        *
*                    *
*  Header File für die Tastenabfrage  *
*                    *
*  Definition globaler Variablen und  *
*  Strukturen              *
*                    *
*                    *
*****************************************/
#include <stdint.h>

#ifndef _TASTER_H_
#define _TASTER_H_

#define NOT_PRESSED 0    // Wert 0 dem Status NOT_PRESSED zuordnen
#define NUM_TASTER 5    // Anzahl der Taster
#define TASTER_LEVEL 0    // Varible zur Unterscheidung von LOW- und HIGH-Tastern (0=lowaktiv; 1=highaktiv)

extern volatile uint8_t tastst;  // Variable zur Status übergabe global definieren

/*
Definition der Strukter für die Tasten, 
enthält nur Variable zur Speicherung 
des alten Tasterwertes
*/

typedef struct
{
  uint8_t old;  // Speicher für alten Tasterstatus
} taste_t;

extern taste_t tasten[]; // Array tasten global definieren

extern void taster_get_status (const uint8_t num, uint8_t tasthw); // Methode für Tasterabfrage global definieren

#endif

Autor: Zee (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Stefan Ernst (sternst)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
tasttest muss volatile sein.

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Sebastian B. (m0nkey)
Datum:

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

z.B. verstehe ich diese Zeile nicht wirklich:

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


das verstehe ich auch nicht ganz:
struct bits {
  u8 b0:1;
  u8 b1:1;
  u8 b2:1;
  u8 b3:1;
  u8 b4:1;
  u8 b5:1;
  u8 b6:1;
  u8 b7:1;
} __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.

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht 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:
>
>
>
> #define SBIT_(port,pin) ((*(volatile struct bits*)&port).b##pin)
> 

Das wird z.B. hier erklärt:
http://www.avrfreaks.net/index.php?name=PNphpBB2&f...

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

Autor: Sebastian B. (m0nkey)
Datum:

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

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht 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:
tasthw = NOT_PRESSED;    // rücksetzen der Variable für den Hardwarstatus des Tastes
}

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


Peter

Autor: Sebastian B. (m0nkey)
Datum:

Bewertung
0 lesenswert
nicht 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

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.