Forum: Mikrocontroller und Digitale Elektronik Led PWM in Stufen


von kazoo (Gast)


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

von Werner (Gast)


Lesenswert?


von Falk B. (falk)


Lesenswert?

Siehe PWM und LED-Fading

MFG
Falk

von kazoo (Gast)


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
1
#include <stdint.h>
2
#include <avr/io.h>
3
#include <avr/interrupt.h>
4
#include <util/delay.h>
5
#ifndef F_CPU
6
#define F_CPU           1000000                   // processor clock frequency
7
#warning kein F_CPU definiert
8
#endif
9
 #define true 1
10
#define false 0
11
#define STK500 false
12
#include <inttypes.h>
13
#include <avr/io.h>
14
#include <util/delay.h>
15
#include <avr/pgmspace.h>
16
#define KEY_DDR         DDRD
17
#define KEY_PORT        PORTD
18
#define KEY_PIN         PIND
19
#define KEY0            7
20
#define KEY1            6
21
#define KEY2            5
22
#define ALL_KEYS        (1<<KEY0 | 1<<KEY1 | 1<<KEY2)
23
 
24
#define REPEAT_MASK     (1<<KEY1 | 1<<KEY2)       // repeat: key1, key2
25
#define REPEAT_START    50                        // after 500ms
26
#define REPEAT_NEXT     20                        // every 200ms
27
 
28
#define LED_DDR         DDRC
29
#define LED_PORT        PORTC
30
#define LED0            3
31
#define LED1            4
32
#define LED2            5
33
 
34
volatile uint8_t key_state;                                // debounced and inverted key state:
35
                                                  // bit = 1: key pressed
36
volatile uint8_t key_press;                                // key press detect
37
 
38
volatile uint8_t key_rpt;                                  // key long press and repeat
39
 // global variables
40
 
41
uint16_t pwmtable_8A[4]   PROGMEM = {0, 16, 64, 255};
42
int16_t tmp;
43
44
// long delays
45
 
46
void my_delay(uint16_t milliseconds) {
47
    for(; milliseconds>0; milliseconds--) _delay_ms(1);
48
}
49
 
50
// 8-Bit PWM with only 4 different settings
51
 
52
53
 
54
ISR( TIMER0_OVF_vect )                            // every 10ms
55
{
56
  static uint8_t ct0, ct1, rpt;
57
  uint8_t i;
58
 
59
  TCNT0 = (uint8_t)(int16_t)-(F_CPU / 1024 * 10e-3 + 0.5);  // preload for 10ms
60
 
61
  i = key_state ^ ~KEY_PIN;                       // key changed ?
62
  ct0 = ~( ct0 & i );                             // reset or count ct0
63
  ct1 = ct0 ^ (ct1 & i);                          // reset or count ct1
64
  i &= ct0 & ct1;                                 // count until roll over ?
65
  key_state ^= i;                                 // then toggle debounced state
66
  key_press |= key_state & i;                     // 0->1: key press detect
67
 
68
  if( (key_state & REPEAT_MASK) == 0 )            // check repeat function
69
     rpt = REPEAT_START;                          // start delay
70
  if( --rpt == 0 ){
71
    rpt = REPEAT_NEXT;                            // repeat delay
72
    key_rpt |= key_state & REPEAT_MASK;
73
  }
74
}
75
 
76
///////////////////////////////////////////////////////////////////
77
//
78
// check if a key has been pressed. Each pressed key is reported
79
// only once
80
//
81
uint8_t get_key_press( uint8_t key_mask )
82
{
83
  cli();                                          // read and clear atomic !
84
  key_mask &= key_press;                          // read key(s)
85
  key_press ^= key_mask;                          // clear key(s)
86
  sei();
87
  return key_mask;
88
}
89
 
90
///////////////////////////////////////////////////////////////////
91
//
92
// check if a key has been pressed long enough such that the
93
// key repeat functionality kicks in. After a small setup delay
94
// the key is reported beeing pressed in subsequent calls
95
// to this function. This simulates the user repeatedly
96
// pressing and releasing the key.
97
//
98
uint8_t get_key_rpt( uint8_t key_mask )
99
{
100
  cli();                                          // read and clear atomic !
101
  key_mask &= key_rpt;                            // read key(s)
102
  key_rpt ^= key_mask;                            // clear key(s)
103
  sei();
104
  return key_mask;
105
}
106
 
107
///////////////////////////////////////////////////////////////////
108
//
109
uint8_t get_key_short( uint8_t key_mask )
110
{
111
  cli();                                          // read key state and key press atomic !
112
  return get_key_press( ~key_state & key_mask );
113
}
114
 
115
///////////////////////////////////////////////////////////////////
116
//
117
uint8_t get_key_long( uint8_t key_mask )
118
{
119
  return get_key_press( get_key_rpt( key_mask ));
120
}
121
///////////////////////////////////////////////////////////////////
122
123
124
125
126
 
127
int main( void )
128
{ 
129
    KEY_DDR &= ~ALL_KEYS;                // konfigure key port for input
130
    KEY_PORT |= ALL_KEYS;                // and turn on pull up resistors
131
    TCCR0 = (1<<CS02)|(1<<CS00);      // divide by 1024
132
    TIMSK = 1<<TOIE0;        // enable timer interrupt
133
  LED_PORT = 0xFF;
134
  LED_DDR = 0xFF;                    
135
  int16_t a;
136
    int16_t step_time=100;
137
   int16_t tmp;
138
 
139
#if STK500
140
    TCCR1A = 0xC1;          // inverted PWM on OC1A, 8 Bit Fast PWM
141
#else
142
    TCCR1A = 0x81;          // non-inverted PWM on OC1A, 8 Bit Fast PWM
143
#endif
144
    TCCR1B = 0x08;
145
 
146
    TCCR1B &= ~0x7;         // clear clk setting
147
    TCCR1B |= 2;  
148
149
150
151
  while(1){
152
153
 /*   if( get_key_short( 1<<KEY1 ))
154
155
  {DDRB |= (1<<PB1); 
156
    OCR1A =  pgm_read_word(pwmtable_8A+1);
157
      my_delay(100);
158
  }
159
  
160
 
161
    if( get_key_s( 1<<KEY1 ))
162
       
163
    
164
    {
165
   DDRB |= (1<<PB1); 
166
    OCR1A =  pgm_read_word(pwmtable_8A+3);
167
      my_delay(100);
168
    }
169
 */
170
                                                  // single press and repeat
171
 
172
    if( get_key_press( 1<<KEY2 ) || get_key_rpt( 1<<KEY2 )){
173
      uint8_t i ;
174
     DDRB |= (1<<PB1);
175
       i++;
176
       OCR1A =  pgm_read_word(pwmtable_8A+i);
177
      _delay_ms(100);
178
    }
179
  }
180
}


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
1
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ß

von kazoo (Gast)


Lesenswert?

keiner eine Idee?

von Flo (Gast)


Angehängte Dateien:

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

von Werner (Gast)


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

von kazoo (Gast)


Lesenswert?

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

von JojoS (Gast)


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.

von kazoo (Gast)


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?

von Werner (Gast)


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

von kazoo (Gast)


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?

von Falk B. (falk)


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

von Karl H. (kbuchegg)


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.

von kazoo (Gast)


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ß

von adfas (Gast)


Lesenswert?

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

von kazoo (Gast)


Lesenswert?

hat da keiner einen Tipp für mich Parat?

von Volker S. (volkerschulz)


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

von Stefan B. (stefan) Benutzerseite


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 :)

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.