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
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ß
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
>>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
Ja es ist der Überlauf der Variable! Aber wie macht man sowas am elegansten? Mit if Anweisugen`?
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.
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?
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
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?
@ 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
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.
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ß
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
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.