www.mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Led PWM in Stufen


Autor: kazoo (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Zusammen,

und zwar stehe ich vor folgendem Problem , ich möchte die Helligkeit von 
einer Led in 3 Stufen regeln(0= aus , 1= mittel 2 =maximal) das ganze 
soll von einem Taster eingeben werden(ist nicht das Problem!)
Jedoch fehlt mir jetzt der erste Schritt in die Richtung, hatt da jemand 
vielleicht einen Vorschlag(keine Lösung!) wie man in dieser Richtung 
vorgehen könnte?
Wie gesagt bin doch noch etwas neu in der AVR -Sache



Gruß
Jochen

Autor: Werner (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert

Autor: Falk Brunner (falk)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Siehe PWM und LED-Fading

MFG
Falk

Autor: kazoo (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Leute , ich hab heute den ganzen Nachmittag ein bisschen in 
Mikrocontroller rumgestöbert und hab mir da mal was zusammen gebastelt 
aus dem Led Fading Tutorial und Peter Danneggers Entrprell routine.Dabei 
habe ich sehr viel gelernt :)
Aber seht selbst
#include <stdint.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#ifndef F_CPU
#define F_CPU           1000000                   // processor clock frequency
#warning kein F_CPU definiert
#endif
 #define true 1
#define false 0
#define STK500 false
#include <inttypes.h>
#include <avr/io.h>
#include <util/delay.h>
#include <avr/pgmspace.h>
#define KEY_DDR         DDRD
#define KEY_PORT        PORTD
#define KEY_PIN         PIND
#define KEY0            7
#define KEY1            6
#define KEY2            5
#define ALL_KEYS        (1<<KEY0 | 1<<KEY1 | 1<<KEY2)
 
#define REPEAT_MASK     (1<<KEY1 | 1<<KEY2)       // repeat: key1, key2
#define REPEAT_START    50                        // after 500ms
#define REPEAT_NEXT     20                        // every 200ms
 
#define LED_DDR         DDRC
#define LED_PORT        PORTC
#define LED0            3
#define LED1            4
#define LED2            5
 
volatile uint8_t key_state;                                // debounced and inverted key state:
                                                  // bit = 1: key pressed
volatile uint8_t key_press;                                // key press detect
 
volatile uint8_t key_rpt;                                  // key long press and repeat
 // global variables
 
uint16_t pwmtable_8A[4]   PROGMEM = {0, 16, 64, 255};
int16_t tmp;

// long delays
 
void my_delay(uint16_t milliseconds) {
    for(; milliseconds>0; milliseconds--) _delay_ms(1);
}
 
// 8-Bit PWM with only 4 different settings
 

 
ISR( TIMER0_OVF_vect )                            // every 10ms
{
  static uint8_t ct0, ct1, rpt;
  uint8_t i;
 
  TCNT0 = (uint8_t)(int16_t)-(F_CPU / 1024 * 10e-3 + 0.5);  // preload for 10ms
 
  i = key_state ^ ~KEY_PIN;                       // key changed ?
  ct0 = ~( ct0 & i );                             // reset or count ct0
  ct1 = ct0 ^ (ct1 & i);                          // reset or count ct1
  i &= ct0 & ct1;                                 // count until roll over ?
  key_state ^= i;                                 // then toggle debounced state
  key_press |= key_state & i;                     // 0->1: key press detect
 
  if( (key_state & REPEAT_MASK) == 0 )            // check repeat function
     rpt = REPEAT_START;                          // start delay
  if( --rpt == 0 ){
    rpt = REPEAT_NEXT;                            // repeat delay
    key_rpt |= key_state & REPEAT_MASK;
  }
}
 
///////////////////////////////////////////////////////////////////
//
// check if a key has been pressed. Each pressed key is reported
// only once
//
uint8_t get_key_press( uint8_t key_mask )
{
  cli();                                          // read and clear atomic !
  key_mask &= key_press;                          // read key(s)
  key_press ^= key_mask;                          // clear key(s)
  sei();
  return key_mask;
}
 
///////////////////////////////////////////////////////////////////
//
// check if a key has been pressed long enough such that the
// key repeat functionality kicks in. After a small setup delay
// the key is reported beeing pressed in subsequent calls
// to this function. This simulates the user repeatedly
// pressing and releasing the key.
//
uint8_t get_key_rpt( uint8_t key_mask )
{
  cli();                                          // read and clear atomic !
  key_mask &= key_rpt;                            // read key(s)
  key_rpt ^= key_mask;                            // clear key(s)
  sei();
  return key_mask;
}
 
///////////////////////////////////////////////////////////////////
//
uint8_t get_key_short( uint8_t key_mask )
{
  cli();                                          // read key state and key press atomic !
  return get_key_press( ~key_state & key_mask );
}
 
///////////////////////////////////////////////////////////////////
//
uint8_t get_key_long( uint8_t key_mask )
{
  return get_key_press( get_key_rpt( key_mask ));
}
///////////////////////////////////////////////////////////////////




 
int main( void )
{ 
    KEY_DDR &= ~ALL_KEYS;                // konfigure key port for input
    KEY_PORT |= ALL_KEYS;                // and turn on pull up resistors
    TCCR0 = (1<<CS02)|(1<<CS00);      // divide by 1024
    TIMSK = 1<<TOIE0;        // enable timer interrupt
  LED_PORT = 0xFF;
  LED_DDR = 0xFF;                    
  int16_t a;
    int16_t step_time=100;
   int16_t tmp;
 
#if STK500
    TCCR1A = 0xC1;          // inverted PWM on OC1A, 8 Bit Fast PWM
#else
    TCCR1A = 0x81;          // non-inverted PWM on OC1A, 8 Bit Fast PWM
#endif
    TCCR1B = 0x08;
 
    TCCR1B &= ~0x7;         // clear clk setting
    TCCR1B |= 2;  



  while(1){

 /*   if( get_key_short( 1<<KEY1 ))

  {DDRB |= (1<<PB1); 
    OCR1A =  pgm_read_word(pwmtable_8A+1);
      my_delay(100);
  }
  
 
    if( get_key_s( 1<<KEY1 ))
       
    
    {
   DDRB |= (1<<PB1); 
    OCR1A =  pgm_read_word(pwmtable_8A+3);
      my_delay(100);
    }
 */
                                                  // single press and repeat
 
    if( get_key_press( 1<<KEY2 ) || get_key_rpt( 1<<KEY2 )){
      uint8_t i ;
     DDRB |= (1<<PB1);
       i++;
       OCR1A =  pgm_read_word(pwmtable_8A+i);
      _delay_ms(100);
    }
  }
}


Folgendes Problem:
Ich hab in der Anweisung wenn ein Taster mehrmals gedrückt wird , eine 
Zählvariable die Hochzählt.
Mit Hilfe dieser Zählvariable möchte ich nun die Helligkeit regeln , was 
ich mit
OCR1A =  pgm_read_word(pwmtable_8A+i);
 mache. Jedoch leuchtet die Led einfach zufällig in irgendeiner 
Helligkeitsstufe.
Wie macht man sowas am elegansten?

Gruß

Autor: kazoo (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
keiner eine Idee?

Autor: Flo (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,
Also zum Programm kann ich leider nichts sagen, da ich mit PICs arbeite.

Aber zum Ursprünglichen Problem.

Wenn du nur eine LED hast und nur zwei Helligkeitsstufen benötigst, 
würde ich zwei Pins parallel schalten. Sowie im Anhang gezeigt.

Gruß Flo

Autor: Werner (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>>Mit Hilfe dieser Zählvariable möchte ich nun die Helligkeit regeln , was
>>ich mit

>>OCR1A =  pgm_read_word(pwmtable_8A+i);

>> mache. Jedoch leuchtet die Led einfach zufällig in irgendeiner
>>Helligkeitsstufe.


... das hört sich für mich so an, als ob die Entprellung nicht 
funktioniert.
Will heißen:
Dein
>if( get_key_press( 1<<KEY2 ) || get_key_rpt( 1<<KEY2 ))
ist immer TRUE, wenn der Taster gedrückt wird. Damit wird Deine Variable 
i immer weiter hochgezählt.
BTW: Wo ist da der Schutz vorm Überlauf?
i zählt bis 255. Ist das so gewollt?
Was kommt bei
pgm_read_word(pwmtable_8A+200) raus? Vielleicht ungewollte Sachen?
Ich habe Dein Programm nur überflogen, aber sollte i nicht maximal 3 
sein?

Zurück zum Thema Flanke:
Vielleicht zum testen einfach mal eine zusätzliche Variable als 
Flankenmerker hinzufügen, also so z.B.

<pseudo-code>
if (( pin == aktiv ) && ( Flanke = 0 )){
  mach_was;
  Flanke = 1;
  delay(soundso);
}
if (( pin == false ) && ( Flanke = 1 ))
{
  Flanke = 0;
}
</pseudo-code>

Werner

Autor: kazoo (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ja es ist der Überlauf der Variable!
Aber wie macht man sowas am elegansten?
Mit if Anweisugen`?

Autor: JojoS (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
1. i ist nicht initialisiert
2. i ist an der falschen Stelle deklariert, d.h. bei verlassen des 
if-Blocks ist der Wert von i wieder futsch (vielleicht zufällig noch 
erhalten, aber das geht schnell schief wenn das Programm grösser wird)
3. nimmt man i typischerweise für Zählvariablen in Schleifen.

Also z.B.
int main(void)
{
   uint8_t power_index = 0;
...


if()
{
...
   power_index = (power_index + 1) % 4;
...

das '%' steht für modulo Division.

Autor: kazoo (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich verstehe irgendwie denn Sinn der Anweisung
power_index = (power_index + 1) % 4;
nicht wirklich?
Was macht diese Funtkion genau und vorallem aus welchen Grund verwendet 
man diese?

Autor: Werner (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
power_index = (power_index + 1) % 4:

power index wird um 1 erhöht und dann modulo 4 genommen:
wenn
  power_index + 1 dann irgendwann 4 wird bedeutet das:

  4 % 4 = 0 (es gibt keinen Rest. Lies nach, was der Modulo-Operator 
macht!)

also wird die Schleife folgende Ergebisse für power_index liefern:

0
1
2
3
0
1
2
3
usw.

Werner

Autor: kazoo (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Jetzt habe ich noch die allerletze Frage und zwar, wenn ich jetzt eine 
Led ständig blinken lassen will z.B mit slepp_ms(1000) dann kann ich ja 
eigentlich aus dieser Anweisung nimmer raus? Zum beispiel Ich drücke 
Taster 1 , die Leds blinken jetzt drücke ich Taster 2 nun sollen die 
Leds Dimmen?
Ich denke man soll hier an den Interrupts schrauben oder?

Autor: Falk Brunner (falk)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@  kazoo (Gast)

>Led ständig blinken lassen will z.B mit slepp_ms(1000) dann kann ich ja
>eigentlich aus dieser Anweisung nimmer raus?

Richtig.

> Zum beispiel Ich drücke
>Taster 1 , die Leds blinken jetzt drücke ich Taster 2 nun sollen die
>Leds Dimmen?
>Ich denke man soll hier an den Interrupts schrauben oder?

Anstatt 1x1000ms sollte man eher 100x10ms warten. Dann kann man nämlich 
zwischendurch 100 mal die Taster abfragen.

MFG
Falk

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Du sollst überhaupt nicht mit delays arbeiten!

Wozu soll der delay(1000) da überhaupt gut sein?

Wenn du die Repeat Rate verändern willst, dann benutze die 'Schrauben', 
die PeDa dafür vorgesehen hat

#define REPEAT_START    50                        // after 500ms
#define REPEAT_NEXT     20                        // every 200ms

Dort musst du ansetzen.
Die eine Zeit bestimmt, nach welcher Zeit der Autorepeat einsetzt, der 
andere mit welcher Rate der Autorepeat arbeitet.

Mit den richtigen Werten machen das die PeDa Routinen ganz von alleine, 
dass sie deiner Applikation bei dauerhaft gedrücktem Taster einen 
Tastendruch alle 1 Sekunde vorgaukeln. -> kein Delay notwendig.

Autor: kazoo (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ja das hab ich jetzt geändert  bzw. vorher übersehen.
Aber die Frage die mich noch beschäftigt ist wie man die Leds jetzt 
blinken lassen soll? Vielleicht über einen 2ten Timer?


Gruß

Autor: adfas (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
das würd mich auch mal stark interessieren wie man sowas löst!

Autor: kazoo (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
hat da keiner einen Tipp für mich Parat?

Autor: Volker Schulz (volkerschulz)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
kazoo schrieb:
> Aber die Frage die mich noch beschäftigt ist wie man die Leds jetzt
> blinken lassen soll? Vielleicht über einen 2ten Timer?

Hab Deinen Code jetzt nur schnell ueberflogen. Einen zweiten Timer 
brauchst Du nicht, Du hast doch ohnehin schon eine 
Timer-Interrupt-Routine, die regelmaessig (alle 10ms) aufgerufen wird. 
In dieser Routine dekrementierst Du einen Zaehler, den Du vorher auf 
einen bestimmten Wert gesetzt hast (bestimmt die Blinkfrequenz). Bei 
Ueberlauf des Zaehlers schaltest Du die LED um und setzt den Startwert 
erneut.

Beantwortet das Deine Frage?


Volker

Autor: Stefan B. (stefan) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
kazoo schrieb:

>>      uint8_t i ;
>>     DDRB |= (1<<PB1);
>>       i++;

> keiner eine Idee?

Rate doch selbst mal, welchen Wert i an der Stelle i++ hat :)

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.