Forum: Mikrocontroller und Digitale Elektronik ATMEGA16 Timer


von Lukas B. (lukas-1992) Benutzerseite


Angehängte Dateien:

Lesenswert?

Hallo,
ich versuche eine kleine Software zu schreiben, welche eine kleine 
Ausschaltverzögerung nachbildet.
Folgende Funktionen sollte sie können:
- Taster über Pullup angeschlossen PA0
- Poti zum einstellen der ausschaltverzögerung ADC4
- PWM ausgang OCR0

wird der Taster gedrückt, soll OCR0 = 255 sein, nach dem loslassen des 
Tasters soll der Wert bis zum ablaufen einer Zeitspanne (einstellbar 
über Poti (max. 30s)) konstannt gehalten werden (am sugang der PWM 
ändert sich nichts). Ist die Zeit abgelaufen, soll der PWM wert auf 0 
heruntergedimmt werden.

Leider funktioniert das Herunterdimmen bei mir überhaupt nicht, der PWM 
Port blinkt manchmal kurz auf und erlischt wieder. Weiters stimmt die 
Zeit nicht, in welcher der Timer durchlaufen wird, ich habe ein wenig 
herumpobiert und so stimmt der Wert irgendwie, weiß nur nicht was an 
meiner Berechnung falsch ist.

Könnt ihr mir bitte ein wenig helfen?

Grüße
Lukas

von Stefan E. (sternst)


Lesenswert?

Lukas B. schrieb:
> Leider funktioniert das Herunterdimmen bei mir überhaupt nicht, der PWM
> Port blinkt manchmal kurz auf und erlischt wieder.

Kein Wunder, wenn du gleich im ersten Schleifendurchlauf OCR0 auf 0 (und 
nebenbei i auf 1) setzt. ;-)

von Lukas B. (lukas-1992) Benutzerseite


Lesenswert?

Hallo,
habe vergessen OCR0 = 0 auszukommentieren, habe dies zum testen gemacht 
und funktioniert auch, leider funktioniert das dimmen gar nicht, wenn 
ichs mit dem simplen code mache:
1
    if((count >= adc_wert) && (start == 0x01)) 
2
    {
3
      count = 0;
4
      PORTC = 0x00;     // PORTC auf 0 (Debugg)
5
      start = 0x00;    // Hilfsvariable auch auf 0
6
    
7
8
      //OCR0 = 255;
9
      // Wenn der count = dem ADC Wert entspricht
10
      // sollte der PWM Ausgang auf 0 heruntergedimmt werden, Zeit ist vorerst 
11
      // egal.
12
13
/*      // Code für Dimmung funktioniert nicht, OCR0 leuchtet kurz auf und geht wieder aus, keine Ahnung warum
14
      int i;
15
      for (i = 255; i>0; i--)
16
        {
17
18
           OCR0 = i;
19
           _delay_us(10000);
20
           if(i = 1)
21
           {
22
               OCR0 = 0;
23
            break;
24
           }
25
        }
26
        */
27
    _delay_ms(5);
28
        OCR0 = 250;
29
    _delay_ms(5);
30
        OCR0 = 200;
31
    _delay_ms(5);
32
        OCR0 = 100;
33
    _delay_ms(5);
34
        OCR0 = 0;
35
        
36
    }

funktionierts auch nicht, ich verstehe überhaupt nicht was da los ist, 
vl weis irgandhemand von euch an was es liegt.

Grüße
Lukas

von Karl H. (kbuchegg)


Lesenswert?

Funktioniert denn deine ADC Abfrage?
Funktioniert das Dimmen für sich alleine?

Schreib dir doch fürs erste mal eine wirklich simple Anwendung, womit du 
die Einzelteile testest.

Erst mal muss PWM ohne irgendetwas anderes funktionieren
1
int main()
2
{
3
  uint8_t i;
4
5
   ... timer initialisieren
6
7
  while( 1 ) {
8
    i++;
9
    OCR0 = i;
10
    _delay_ms( 10 );
11
  }
12
}

das sollte eine schön auf- (oder ab-) dimmende LED ergeben.
Funktioniert das?

WEnn das funktioniert, dann nimm den ADC mit dazu
1
int main()
2
{
3
  ... timer initialisieren
4
  ... adc initialisieren
5
6
  while( 1 ) {
7
    OCR0 = adc_wert;
8
  }
9
}

drehen am Poti muss die Helligkeit der LED verändern.

Und erst dann, wenn das alles funktioniert, machst du die Zeitsteuerung 
mit dazu. Wobei du das durchaus problemlos innerhalb der Interrupt 
Handler Routine machen kannst. Die paar Anweisungen kannst du dir ohne 
Bedenken dort leisten.
Wobei du wieder nicht sofort zum Rundumschlag ausholst, sondern in 
Stufen vorgehst. Bei Tastendruck soll die LED eingeschaltet werden und 
nach einer gewissen fixen Zeitdauer (nach dem Loslassen) einfach 
ausgeschaltet werden.

Du machst das, indem du in der ISR einen Zeitzähler um 1 verminderst, 
wenn er nicht schon 0 war, und wenn nach dem Runterzählen um 1 die Zeit 
zu 0 geworden ist, schaltest du die LED aus.
1
uint8_t WarteZeit;
2
3
SIGNAL( ... )
4
{
5
  ...
6
7
    if( WarteZeit > 0 ) {
8
      WarteZeit--;
9
      if( WarteZeit == 0 )
10
        OCR0 = 0;
11
    }
12
  }
13
}

Ein Tastendruck setzt die Wartezeit auf eine bestimmte Zeitdauer und 
schaltet die LED ein. Der Timer läuft und zählt die Wartezeit wieder 
runter und wenn sie dann vorbei ist (0 erreicht), dann schaltet er die 
LED aus.

Erst mal nur ausschalten.
Danach ersetzt du die bis dahin fixe Wartezeit, die du bei gedrückter 
Taste zuweist durch einen Wert, den du vom ADC bekommst. Damit kannst du 
dann die Leuchtdauer durch das Poti einstellen.

Und wenn das dann alles klappt, dann fadest du mit dem ISR Mechanismus 
die LED langsam aus, anstelle dass du sie durch Setzen von OCR0 einfach 
ausschaltest.


Nicht zuviel auf einmal machen! Einzelkomponenten testen!
Schrittweise aufs Ziel hinarbeiten - egal wie einfach das Endziel auch 
am Anfang aussehen mag.

von Lukas B. (lukas-1992) Benutzerseite


Lesenswert?

Hallo Karl Heiz,
vielen dank für deine ausführliche Vorgehensweise!
ich habe nun den Code so geändert:
1
/**************************************************************/
2
/*    Title:    Testversion Firmware ausschaltverzögerung                                          */
3
/*    Author:   Bitschnau Lukas                                            */
4
/*    Date:     11/2009                                        */
5
/*    Purpose:  Toggeln aller 8 LEDs                          */
6
/*    Software: AVR-GCC / AVR Studio 4.12                      */
7
/*    Hardware: ATmega16/Megacard                              */
8
/*    Note:     fclk=12MHz                                    */
9
/**************************************************************/
10
#include <AVR/io.h>
11
#include <AVR/interrupt.h>
12
#include <AVR/signal.h>
13
#include <until/delay.h>
14
15
16
int main( void )
17
{
18
19
//Timer Initialisierung
20
21
  TCCR0 = 0b01100001;            // Kein Timer Vorteiler
22
  /*
23
  kein Vorteiler 
24
  keine Invertierung 
25
  fast PWM 
26
  normale Port operation
27
  */
28
  TIMSK = 0x01;             // Timer Interrupt Aktiviern
29
30
// Port Initialisierung
31
32
//  DDRC  = 0x01;    // LED0 als Ausgang
33
  DDRC  = 0xFF;    // PORTC als Ausgang (zum Debuggen)
34
  DDRD = 0xFF;
35
  DDRA  = 0x00;    // port A als eingang
36
  DDRB = 0xFF;     // OCR0 Port als ausgang (PWM ausgang)
37
  PORTA = 0x01;    // Pullup an Pin 1 einschalten (fur Schalteingang)1
38
39
  sei();            //alle Interrupts enablen
40
  unsigned int i;
41
42
  while(1) 
43
  {
44
    i++;
45
    OCR0 = i;
46
    _delay_ms(10);
47
  }
48
49
}

dabei tritt folgendes Verhalten auf:
zu beginn ist die LED an OCR0 aus, nach ca 3 sec. schaltet sie auf ganze 
Helligkeit und dann wird si richtig ruckartig heller und dünkler, geht 
aber nie ganz aus.
an was kann es liegen, bin voll ratlos?!

Grüße
Lukas

von Lukas B. (lukas-1992) Benutzerseite


Angehängte Dateien:

Lesenswert?

falls es relevant ist, ich verwende folgende Fuses (siehe Bild)

von Karl H. (kbuchegg)


Lesenswert?

Lukas B. schrieb:
> Hallo Karl Heiz,
> vielen dank für deine ausführliche Vorgehensweise!
> ich habe nun den Code so geändert:
> [c]
> /**************************************************************/
> /*    Title:    Testversion Firmware ausschaltverzögerung
> */
> /*    Author:   Bitschnau Lukas
> */
> /*    Date:     11/2009                                        */
> /*    Purpose:  Toggeln aller 8 LEDs                          */
> /*    Software: AVR-GCC / AVR Studio 4.12                      */
> /*    Hardware: ATmega16/Megacard                              */
> /*    Note:     fclk=12MHz                                    */
> /**************************************************************/
> #include <AVR/io.h>
> #include <AVR/interrupt.h>
> #include <AVR/signal.h>
> #include <until/delay.h>
>
>
> int main( void )
> {
>
> //Timer Initialisierung
>
>   TCCR0 = 0b01100001;            // Kein Timer Vorteiler
>   /*
>   kein Vorteiler
>   keine Invertierung
>   fast PWM
>   normale Port operation
>   */

Dein Kommentar stimmt nicht.

Tu dir doch selbst einen Gefallen und schreib das NICHT mit einer 
Binärzahl

   TCCR0 = ( 1 << WGM00 ) |     // Phase correct PWM
           ( 1 << COM01 ) |     // Clear on Up-match, Set on Down-match
           ( 1 << CS00 );       // Prescaler: 1

so liest sich das viel besser und es lässt sich auch viel leichter mit 
dem Datenblatt kontrollieren, als wie wenn man ständig im Datenblatt hin 
und her scrollen muss um zu kontrollieren, welche Bits du da eigentlich 
gesetzt hast und was sie bedeuten.

>   TIMSK = 0x01;             // Timer Interrupt Aktiviern

Detto
    TIMSK = ( 1 << OCIE0 );

Du gibst also den Output Compre Interrupt vom Timer 0 frei. Wenn du das 
tust, dann musst du auch eine ISR schreiben. Hast du keine ISR, dann 
wird beim ersten Interrupt der µC resettet.

> an was kann es liegen, bin voll ratlos?!

liegt wahrscheinlich an der ISR, die du nicht implementiert hast. Für 
dieses Beispiel brauchst du sie nicht. Also gib den Interrupt einfach 
nicht frei.

Die PWM müsste damit funktionieren. Allerdings

* Warum Phase Correct Mode, anstelle von Fast PWM MOde
* denn: Mit dem Compare Match Interrupt wirst du nicht viel anfangen
  können, wenn es um die Zeitsteuerung geht. Da ist der Fast-PWM
  mit seinen regelmässigen Overflow Interrupts viel besser geeignet.

von Lukas B. (lukas-1992) Benutzerseite


Angehängte Dateien:

Lesenswert?

Hallo Karl Heinz,
vielen Dank für deine Hilfestellung!
Ich habe ein wenig gearbeitet und mit Hilfe des Tutorials und des 
Datenblattes einen funktionierenden Code geschrieben, ich habe in Mal in 
den Anhang gestellt. Ich werde jetzt noch die Platine fertig designen, 
den Print anschließend bestücken und dan das Fertige Projekt in der 
Codesammlung veröffentlichen.

Grüße
Lukas

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.