Hallo,
ich experimentiere grade ein wenig mit Soft PWM. Jedoch bin ich in C
nicht wirklich fit, daher hab ich jetzt ein kleines schönheits Problem.
Hier erstmal der Code zum besseren verständnis:
1
#include<avr/io.h>
2
#include<avr/interrupt.h>
3
4
5
typedefstruct{
6
charledPin;
7
uint8_tpwm;
8
}pwmLed;
9
10
volatilepwmLedleds[15]={//PWM config für die Ports (15 Stück)
11
{0,0},
12
{1,16},
13
{2,32},
14
{3,48},
15
{4,64},
16
{5,80},
17
{6,96},
18
{7,112},
19
{10,128},
20
{11,144},
21
{12,160},
22
{13,176},
23
{14,192},
24
{15,208},
25
{16,224}
26
};
27
28
volatileuint8_tpwm_pulse_counter=0;
29
30
31
intmain(void){
32
uint8_ti=0;
33
inttempo=1;
34
35
//led ausgang
36
DDRA|=0xff;
37
DDRD|=0xff;
38
39
//timer -> 16bit timmer
40
TCCR1B|=(1<<WGM12);// timer aus CTC mode setzen -> wert in OCR1A
OCR1A=64;//-> 25600hz bei 16mhz und prescale 1 = 1 pwm zyklus 100hz
44
TCCR1B|=(1<<CS10);//timer auf prescale 1 setzen...
45
46
//interrupt handling starten
47
sei();// Enable global interrupts
48
49
50
//main loop
51
for(;;){
52
for(i=0;i<=14;i++){
53
leds[i].pwm-=2;
54
}
55
}
56
}
57
58
ISR(TIMER1_COMPA_vect){//Interupt funktion
59
uint8_ti=0;
60
61
pwm_pulse_counter++;//überlauf gewollt (8bit)
62
63
for(i=0;i<=14;i++){
64
if(pwm_pulse_counter<leds[i].pwm){
65
if(leds[i].ledPin==0)PORTA|=(1<<PA0);
66
elseif(leds[i].ledPin==1)PORTA|=(1<<PA1);
67
elseif(leds[i].ledPin==2)PORTA|=(1<<PA2);
68
elseif(leds[i].ledPin==3)PORTA|=(1<<PA3);
69
elseif(leds[i].ledPin==4)PORTA|=(1<<PA4);
70
elseif(leds[i].ledPin==5)PORTA|=(1<<PA5);
71
elseif(leds[i].ledPin==6)PORTA|=(1<<PA6);
72
elseif(leds[i].ledPin==7)PORTA|=(1<<PA7);
73
74
elseif(leds[i].ledPin==10)PORTD|=(1<<PD0);
75
elseif(leds[i].ledPin==11)PORTD|=(1<<PD1);
76
elseif(leds[i].ledPin==12)PORTD|=(1<<PD2);
77
elseif(leds[i].ledPin==13)PORTD|=(1<<PD3);
78
elseif(leds[i].ledPin==14)PORTD|=(1<<PD4);
79
elseif(leds[i].ledPin==15)PORTD|=(1<<PD5);
80
elseif(leds[i].ledPin==16)PORTD|=(1<<PD6);
81
}else{
82
if(leds[i].ledPin==0)PORTA&=~(1<<PA0);
83
elseif(leds[i].ledPin==1)PORTA&=~(1<<PA1);
84
elseif(leds[i].ledPin==2)PORTA&=~(1<<PA2);
85
elseif(leds[i].ledPin==3)PORTA&=~(1<<PA3);
86
elseif(leds[i].ledPin==4)PORTA&=~(1<<PA4);
87
elseif(leds[i].ledPin==5)PORTA&=~(1<<PA5);
88
elseif(leds[i].ledPin==6)PORTA&=~(1<<PA6);
89
elseif(leds[i].ledPin==7)PORTA&=~(1<<PA7);
90
91
elseif(leds[i].ledPin==10)PORTD&=~(1<<PD0);
92
elseif(leds[i].ledPin==11)PORTD&=~(1<<PD1);
93
elseif(leds[i].ledPin==12)PORTD&=~(1<<PD2);
94
elseif(leds[i].ledPin==13)PORTD&=~(1<<PD3);
95
elseif(leds[i].ledPin==14)PORTD&=~(1<<PD4);
96
elseif(leds[i].ledPin==15)PORTD&=~(1<<PD5);
97
elseif(leds[i].ledPin==16)PORTD&=~(1<<PD6);
98
}
99
}
100
}
Ich möchte gerne den Pin der vom Timer Interrupt geschalten werden soll
mit in der pwmLed Struktur speichern. Zurzeit hab ich das, wie man
sieht, recht unschön gelöst, indem ich einfach eine Id hinterlege, diese
im Interrupt auswerte und den entsprechenden Pin schalte.
Mein Ziel ist eigentlich das die Interrupt-Routine am ende so aussieht:
1
ISR(TIMER1_COMPA_vect){//Interupt funktion
2
uint8_ti=0;
3
4
pwm_pulse_counter++;//überlauf mit 255 beabsichtigt
5
6
for(i=0;i<=14;i++){
7
leds[i].pin=pwm_pulse_counter<leds[i].pwm;
8
}
9
}
wie stell ich das am dümmsten an? Ich habs vorns erstmal mit nem Zeiger
auf den PortX probiert, aber das hat den Compiler schon nicht gepasst.
Über ein paar tipps würde ich mich freuen. Danke...
Achja... wo ich hier grade nochmal drüberschaue. Wie kann ich die Anzahl
der gePWMten Ports zentrall festlegen? Ich jetzt einmal oben beim
Initialisieren die Anzahl angegeben, im Interrupt in der fot Schleife
und in der main loop auch nochmal. Gibts da auch ne elegantere Lösung?
Habs vorns mit #define LED_COUNT 15 versucht, das mag der Compiler aber
nicht und bricht schon bei
1
volatilepwmLedleds[LED_COUNT]={
ab. Wie gesagt bin nicht wirklich Fit in C. Vor 4 Jahren hatte ich mal
20 Stunden C/C++ und dann höhrts mit meinen C Kenntnissen auch schon
wieder auf.
Ein Port ist nichts anderes als eine Variable vom Typ "volatile
uint8_t", die an einer besonderen Adresse liegt. Dies wird eben so
realisiert, in dem eine Zahl auf einen Pointer gecastet wird, und gleich
danach wird dieser Pointer dereferenziert.
Daher ist ein Pointer auf einen Port vom Typ "volatile uint8_t *".
Viel einfacher sind "Pins", deren defines sehen nämlich so aus:
1
#define PA1 1
In diesem Fall bietet sich ein "uint8_t" als Datentyp an.
Das würde dann so aussehen:
1
typedefstruct{
2
volatileuint8_t*port;
3
uint8_tpin;
4
uint8_tpwm;
5
}pwmLed;
6
7
volatilepwmLedleds[3]={//PWM config für die Ports (15 Stück)
8
{&PORTA,PA1,0},
9
{&PORTA,PA2,16},
10
{&PORTA,PA3,32}
11
};
Was hat denn Dein Compiler an der Arraydefinition auszusetzen? Das muss
funktionieren, vorausgesetzt das Define steht davor!
Wie die Interrupt Routine aussieht, darft Du Dir mal selbst überlegen -
oder mich am Montag fragen! ;-)
Grüße und viel Erfolg,
Christian
Danke für deine Hilfe. Habs hinbekommen... hatte ja gestern schon
versucht das ganze mit Zeigern zu lösen. Aber wenn man keine ahnung hat
wie Zeiger in C richtig angewendet werden kann das ja nix werden ;)
Und das problem mit #define lag an einem ;. Ich hab "#define PWM_COUNT
15;" geschreiben. Nachdem ich mir heute nochmal die Fehlermeldung genau
angeschaut hatte war das Problem sofort klar.
So sieht der Code jetzt aus:
1
#include<avr/io.h>
2
#include<avr/interrupt.h>
3
4
#define PWM_COUNT 15
5
6
//Led config
7
typedefstruct{
8
volatileuint8_t*port;
9
uint8_tpin;
10
uint8_tpwm;
11
}pwmLed;
12
13
volatilepwmLedleds[PWM_COUNT]={
14
{&PORTA,PA0,0},
15
{&PORTA,PA1,0},
16
{&PORTA,PA2,0},
17
{&PORTA,PA3,0},
18
{&PORTA,PA4,0},
19
{&PORTA,PA5,0},
20
{&PORTA,PA6,0},
21
{&PORTA,PA7,0},
22
{&PORTD,PD0,0},
23
{&PORTD,PD1,0},
24
{&PORTD,PD2,0},
25
{&PORTD,PD3,0},
26
{&PORTD,PD4,0},
27
{&PORTD,PD5,0},
28
{&PORTD,PD6,0}
29
};
30
31
32
volatileuint8_tpwm_pulse_counter=0;
33
34
35
intmain(void){
36
uint8_ti=0,temp=0;
37
38
//led ausgang
39
DDRA|=0xff;
40
DDRD|=0xff;
41
42
//timer -> 16bit timmer
43
TCCR1B|=(1<<WGM12);// timer aus CTC mode setzen -> wert in OCR1A