PWM mit ATMEGA168

#2585439
Lesenswert?

Hallo Commmunity,

ich habe mal wieder eine Frage, udn da mir bisher immer gut geholfen 
werden konnte, hoffe ich auch diesmal auf eure Hilfe:

Wie funktioniert das mit der PWM, damit ich eine LED Dimmen kann bei 
einem ATMEGA168.

Ich habe mir schon Applicationsnotes und andere Quellen über Software 
PWM mit einem ATMEGA durchgelesen, konnte aber kein ansatzweise 
laufendes Programm erstellen. um das mal zu testen.

Nun meine Frage, kann mir wer ein kleines Beispiel für eine Softwarepwm 
für den ATMEGA 168 zeigen und erklären? Es reicht völlig, wenn in diesem 
Beispiel nur 1 LED z.B. die led an PORTD PIN3 auf die hälfte gedimmt 
wird, wenn ich PORTB PIN0 auf 0V ziehe.

Vielen Dank
Gast #2585507
Lesenswert?

Du mußt dir im Datenblatt nur den passenden PWM-Mode aus dem Datenblatt 
raussuchen und die Register entsprechend setzen. Der Rest läuft dann per 
Timer und PWM-Hardware des Prozessors selbständig. Zur Änderung des 
Tastverhältnis muß dann nur z.B. eines der Output Compare Register 
geändert werden.
z.B.
Beitrag "Ansteuerung einer RGB LED (PWM)"

Es geht natürlich auch per Software:
Beitrag "8-fach 12-Bit Soft-PWM LED-Dimmer für mega48"
#2585796
Lesenswert?

Hallo,

habe jetzt einen Code gefunden und umgeschrieben, womit ich alle meine 
LED'S Dimmen kann.
Der Code war für einen ATMEGA 8 und ich habe ihn schon soweit 
umgeschrieben, das er auf einem MEGA168 läuft.
Meine Frage ist jetzt, wo muss ich eingreifen, bzw. was ändern/löschen, 
damit die nicht wie es ja zu demo zwecken ist, die ganze zeit dimmen. 
sondern das ich die LEDS mit einem POTI am Analogeingang PC5 dimmen 
kann. Der Poti soll dann für Später einen Fototransiostor simulieren. 
Also die LEDS sollen dauerhaft an sein, udn durch den POTI gedimmt 
werden können.

Wäre klasse, wenn mir wer da helfen könnte.
#2585813
Lesenswert?

Tobias xxx schrieb:
> Hallo,
>
> habe jetzt einen Code gefunden und umgeschrieben, womit ich alle meine
> LED'S Dimmen kann.
> Der Code war für einen ATMEGA 8 und ich habe ihn schon soweit
> umgeschrieben, das er auf einem MEGA168 läuft.
> Meine Frage ist jetzt, wo muss ich eingreifen, bzw. was ändern/löschen,
> damit die nicht wie es ja zu demo zwecken ist, die ganze zeit dimmen.
> sondern das ich die LEDS mit einem POTI am Analogeingang PC5 dimmen
> kann. Der Poti soll dann für Später einen Fototransiostor simulieren.
> Also die LEDS sollen dauerhaft an sein, udn durch den POTI gedimmt
> werden können.
>
> Wäre klasse, wenn mir wer da helfen könnte.

Hatte leider vergessen, den CODE anzuhängen:
1
// Software-PWM by PoWl - 25.10.08
2
// webmaster@the-powl.de
3

4
// ATmega168 @ 8Mhz
5

6
#include <avr/io.h>
7
#include <avr/interrupt.h>
8
#include <util/delay.h>
9
#include <stdbool.h>
10

11

12
// Sinustabelle für Demo
13
const uint8_t sinetable[] = {
14
128, 131, 134, 137, 140, 143, 146, 149, 152, 155, 158, 162, 165, 167,
15
170, 173, 176, 179, 182, 185, 188, 190, 193, 196, 198, 201, 203, 206,
16
208, 211, 213, 215, 218, 220, 222, 224, 226, 228, 230, 232, 234, 235,
17
237, 238, 240, 241, 243, 244, 245, 246, 248, 249, 250, 250, 251, 252,
18
253, 253, 254, 254, 254, 255, 255, 255, 255, 255, 255, 255, 254, 254,
19
254, 253, 253, 252, 251, 250, 250, 249, 248, 246, 245, 244, 243, 241,
20
240, 238, 237, 235, 234, 232, 230, 228, 226, 224, 222, 220, 218, 215,
21
213, 211, 208, 206, 203, 201, 198, 196, 193, 190, 188, 185, 182, 179,
22
176, 173, 170, 167, 165, 162, 158, 155, 152, 149, 146, 143, 140, 137,
23
134, 131, 128, 124, 121, 118, 115, 112, 109, 106, 103, 100, 97, 93,
24
90, 88, 85, 82, 79, 76, 73, 70, 67, 65, 62, 59, 57, 54, 52, 49, 47,
25
44, 42, 40, 37, 35, 33, 31, 29, 27, 25, 23, 21, 20, 18, 17, 15, 14,
26
12, 11, 10, 9, 7, 6, 5, 5, 4, 3, 2, 2, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0,
27
1, 1, 1, 2, 2, 3, 4, 5, 5, 6, 7, 9, 10, 11, 12, 14, 15, 17, 18, 20,
28
21, 23, 25, 27, 29, 31, 33, 35, 37, 40, 42, 44, 47, 49, 52, 54, 57,
29
59, 62, 65, 67, 70, 73, 76, 79, 82, 85, 88, 90, 93, 97, 100, 103,
30
106, 109, 112, 115, 118, 121, 124 };
31

32

33

34
// -------------------------- 8-Bit PWM --------------------------- //
35
// An - 254 Graustufen - Aus
36

37
#define CHANNELS 12
38

39
uint8_t pwm_mask_PORTC_A[CHANNELS + 1];
40
uint8_t pwm_mask_PORTD_A[CHANNELS + 1];
41
uint8_t pwm_timing_A[CHANNELS + 1];
42

43
uint8_t pwm_mask_PORTC_B[CHANNELS + 1];
44
uint8_t pwm_mask_PORTD_B[CHANNELS + 1];
45
uint8_t pwm_timing_B[CHANNELS + 1];
46

47
uint8_t *ptr_PORTC_main = &pwm_mask_PORTC_A;
48
uint8_t *ptr_PORTD_main = &pwm_mask_PORTD_A;
49
uint8_t *ptr_timing_main = &pwm_timing_A;
50

51
uint8_t *ptr_PORTC_isr = &pwm_mask_PORTC_B;
52
uint8_t *ptr_PORTD_isr = &pwm_mask_PORTD_B;
53
uint8_t *ptr_timing_isr = &pwm_timing_B;
54

55
uint8_t pwm_value[CHANNELS];
56
uint8_t pwm_queue[CHANNELS];
57

58
volatile uint8_t pwm_cycle;
59
volatile bool pwm_change;
60

61
uint8_t pwm_pin[CHANNELS] = { PC0, PC1, PC2, PC3, PC4, PD0, PD1, PD2, PD3, PD4, PD6, PD7 };
62

63
uint8_t **pwm_port[CHANNELS] = {
64
  &ptr_PORTC_main,
65
  &ptr_PORTC_main,
66
  &ptr_PORTC_main,
67
  &ptr_PORTC_main,
68
  &ptr_PORTC_main,
69
  &ptr_PORTD_main,
70
  &ptr_PORTD_main,
71
  &ptr_PORTD_main,
72
  &ptr_PORTD_main,
73
  &ptr_PORTD_main,
74
  &ptr_PORTD_main,
75
  &ptr_PORTD_main
76
};
77

78

79
void pwm_update(void)
80
{
81
  pwm_change = 0;
82

83
  // Sortieren mit InsertSort
84

85
  for(uint8_t i=1; i<CHANNELS; i++)
86
  {
87
    uint8_t j = i;
88

89
    while(j && pwm_value[pwm_queue[j - 1]] > pwm_value[pwm_queue[j]])
90
    {
91
      uint8_t temp = pwm_queue[j - 1];
92
      pwm_queue[j - 1] = pwm_queue[j];
93
      pwm_queue[j] = temp;
94

95
      j--;
96
    }
97
  }
98

99
  // Maske generieren
100

101
  for(uint8_t i=0; i<(CHANNELS + 1); i++)
102
  {
103
    ptr_PORTC_main[i] = 0;
104
    ptr_PORTD_main[i] = 0;
105
    ptr_timing_main[i] = 0;
106
  }
107

108
  uint8_t j = 0;
109

110
  for(uint8_t i=0; i<CHANNELS; i++)
111
  {
112
    // Sonderfall "ganz AUS" ausschließen:
113
    //  - Pins garnicht erst anschalten
114
    //  - Pins die vorher "ganz AN" waren müssen trotzdem noch deaktiviert werden, deshalb nur folgendes in der if
115
    if(pwm_value[pwm_queue[i]] != 0)
116
    {
117
      (*pwm_port[pwm_queue[i]])[0] |= (1 << pwm_pin[pwm_queue[i]]);
118
    }
119

120
    // Sonderfall "ganz AN" ausschließen:
121
    //  - Nicht in Timing-Tabelle übernehmen da sonst die Pointer niemals getauscht werden
122
    //  - Pins die "ganz AN" sind müssen nicht abgeschaltet werden
123
    if(pwm_value[pwm_queue[i]] != 255)
124
    {
125
      (*pwm_port[pwm_queue[i]])[j + 1] |= (1 << pwm_pin[pwm_queue[i]]);
126

127
      ptr_timing_main[j] = pwm_value[pwm_queue[i]];
128
    }
129

130
    if(pwm_value[pwm_queue[i]] != pwm_value[pwm_queue[i + 1]])
131
    {
132
      j++;
133
    }
134
  }
135

136
  /*
137
  // Der ISR etwas Arbeit abnehmen
138
  for(uint8_t i=1; i<(CHANNELS + 1); i++)
139
  {
140
    ptr_PORTC_main[i] = ~ptr_PORTC_main[i];
141
    ptr_PORTD_main[i] = ~ptr_PORTD_main[i];
142
  }
143
  */
144

145
  pwm_change = 1;
146
}
147

148

149
int main(void)
150
{
151
  // PWM initialisieren
152
  for(uint8_t i=0; i<CHANNELS; i++)
153
  {
154
    pwm_queue[i] = i;
155
  }
156

157
  DDRC = 0b00011111;
158
  DDRD = 0b11011111;
159
  DDRB = 0x00;
160

161

162
  // Timer für PWM
163
  OCR1A = 255;
164
  TIMSK1 = (1 << OCIE1A) | (1 << OCIE1B);
165
  TCCR1B = (1 << WGM12) | 4;
166

167
  sei();
168

169

170
  uint8_t pos = 0;
171

172
  while(1)
173
  {
174
    for(uint8_t i=0; i<CHANNELS; i++)
175
    {
176
      pwm_value[i] = sinetable[(uint8_t) (pos + i * 20)];
177
    }
178

179
    pwm_update();
180
    pos++;
181

182
    _delay_ms(5);
183
  }
184
}
185

186

187

188
ISR(TIMER1_COMPA_vect)
189
{
190
  pwm_cycle = 0;
191

192
  PORTC |= ptr_PORTC_isr[0];
193
  PORTD |= ptr_PORTD_isr[0];
194

195
  OCR1B = ptr_timing_isr[0];
196
}
197

198

199

200
ISR(TIMER1_COMPB_vect)
201
{
202
  pwm_cycle++;
203

204
  PORTC &= ~ptr_PORTC_isr[pwm_cycle];
205
  PORTD &= ~ptr_PORTD_isr[pwm_cycle];
206

207
  if(ptr_timing_isr[pwm_cycle] != 0)
208
  {
209
    OCR1B = ptr_timing_isr[pwm_cycle];
210
  }
211
  else if(pwm_change)
212
  {
213
    pwm_change = 0;
214

215
    uint8_t *temp_ptr;
216

217
    temp_ptr = ptr_PORTC_main;
218
    ptr_PORTC_main = ptr_PORTC_isr;
219
    ptr_PORTC_isr = temp_ptr;
220

221
    temp_ptr = ptr_PORTD_main;
222
    ptr_PORTD_main = ptr_PORTD_isr;
223
    ptr_PORTD_isr = temp_ptr;
224

225
    temp_ptr = ptr_timing_main;
226
    ptr_timing_main = ptr_timing_isr;
227
    ptr_timing_isr = temp_ptr;
228
  }
229
}

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren