Guten Morgen liebes Forum! Zuerst einmal wollte ich mich für das hilfreiche Programmier-"Ebook" bedanken, da mir dieses wirklich schon oft den Hintern gerettet hat. Leider konnte ich meine folgende Frage nicht aus dieser Zusammenschrift entnehmen, somit wende ich mich nun an euch! Die Aufgabenstellung, welche ich zu bewältigen habe, lautet : Steuere einen Servo mittels Timer und Poti an, so. Ansteuern möchte ich das Ganze mit dem FAST PWM. Ich soll bei einem Takt von 1,6MHz eine Frequenz von 50Hz bekommen,aber der Timer sollte nicht höher als 20ms "laufen". Meine Idee: Prescaler von 8 verwenden -> 4000 Schritte und diese dann bei der Einlesung von ICRA1 mit 5 multiplizieren - ist dies möglich? Den doppelten ADC wert hätte ich dann anschließend bei dem "Startwert" (OCCR1A) einfach subtrahiert? Es tut mir leid, falls diese Frage schon x-tausend Mal gestellt worden war, dennoch bin ich gerade am verzweifeln! Liebe Grüße, Manuel :)
:
Verschoben durch Moderator
Prinzipiell sieht der Code so aus, wobei sich der Servo nicht vom Fleck rührt:
1 | /*
|
2 | * Fastpwm_Servo.c
|
3 | *
|
4 | * Created: 10.03.2018 13:01:41
|
5 | * Author : Maenii
|
6 | */
|
7 | |
8 | #include <avr/io.h> |
9 | #define SETBIT(ADDRESS,BIT) (ADDRESS |= (1<<BIT))
|
10 | #define FLIPBIT(ADDRESS,BIT) (ADDRESS ^= (1<<BIT))
|
11 | #define CLEARBIT(ADDRESS,BIT) (ADDRESS &= ~(1<<BIT))
|
12 | #define POTI PORTC0
|
13 | #define servo PORTB1
|
14 | int val_adc; |
15 | double faktor; |
16 | |
17 | |
18 | //ADC aktivieren
|
19 | //-------------------------------------------------------------------------------------------------------------------------
|
20 | int adcIn(int channel) |
21 | {
|
22 | ADCSRA = (1<<ADEN) | (1<<ADPS1) | (1<<ADPS0);//ADEN: ADC Enable |
23 | ADMUX = channel; |
24 | |
25 | //ADMUX |= (1<<REFS1) | (1<<REFS0); // interne 1,1V Referenzspannung
|
26 | ADMUX |= (1<<REFS0); // +Ub als Referenzspannung |
27 | ADCSRA |= (1<<ADSC); // alles fertig eingestellt - jetzt start conversion |
28 | |
29 | while (ADCSRA & (1<<ADSC)); // warten bis Konversion zu ende |
30 | |
31 | ADCSRA &= ~(1<<ADEN); // weitere Konversionen verhindern und ADC ausschalten (enable - > 0) |
32 | return ADCW; // Wert retour liefern |
33 | }
|
34 | //--------------------------------------------------------------------------------------------------------------------------
|
35 | int main(void) |
36 | {
|
37 | |
38 | // Eingänge und Ausgänge festlegen
|
39 | SETBIT(DDRB,servo); |
40 | CLEARBIT(DDRC,POTI); |
41 | |
42 | // Fast-PWM mode 14 aktivieren -> WGM11,WGM12,WGM13 = set
|
43 | TCCR1A |= (1<<WGM11) | (1<<COM1A0); |
44 | TCCR1B |= (1<<WGM12) | (1<< WGM13); |
45 | |
46 | //Prescale 8 - CS11 = set
|
47 | SETBIT(TCCR1B, CS11); |
48 | |
49 | //Max-Wert für fast PWM festlegen - ICR1
|
50 | ICR1 = 39999; |
51 | |
52 | |
53 | /* Replace with your application code */
|
54 | while (1) |
55 | {
|
56 | val_adc = adcIn(POTI); |
57 | |
58 | faktor = 2*val_adc; |
59 | |
60 | SETBIT(PORTB,servo); |
61 | |
62 | OCR1A = ICR1 - (faktor + 2000); |
63 | }
|
64 | }
|
Wie sieht denn das aktuelle Ausgangssignal aus? Das kannst du mit einem Oszilloskop oder Logik-Analysator visualisieren. Kauf Dir ggf. einen, die kosten keine 20 Euro. Zur Fehlersuche könnte es hilfreich sein, erstmal den ADC raus zu lassen und ein Signal mit mittlerer Pulsbreite (1,5ms) zu erzeugen.
Lass uns das mal reverse analysieren:
1 | PB1 = OC1A |
2 | COM1A0 = non inverting mode für OC1A |
3 | WGM11+WGM12+WGM13 = Mode 14 fast PWM (TOP=ICR1) |
4 | CS11 = Prescaler CLK/8 |
5 | ICR1 = 3999 |
6 | CLK = 1,6Mhz (wirklich? das ist ungewöhnlich) |
7 | 1,6Mhz / 8 / 4000 = 50 Hz |
Bis hierhin passt alles. Ein Zählertakt dauert 1/(1,6Mhz/8) = 5µs Für 1ms Pulsbreite brauchst du 200 Takte Für 2ms Pulsbreite brauchst du 400 Takte Du musst also dafür sorgen, dass dein OC1A auf Werte zwischen 200 und 400 gesetzt wird. Ich nehme an, dass ist Dir bereits soweit klar. 2*val_adc ergibt Werte von 0 bis 2046. ICR1 - (faktor + 2000) ergibt Werte zwischen 1999 und -47. Merkst du was? Warum subtrahierst du überhaupt von ICR1?
Ein Servo sollte man immer langsam anfahren. D.h. die ersten Schritte langsam ausführen - besonders wenn noch Last dran hängt, die bewegt werden muss. Sonst dreht sich das Magnetfeld im Servo aber der Motor nicht. ;-) Bin das erste Mal auch drauf reingefallen.
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.