Hallo liebe Community,
ich bin Quereinsteiger bei der PIC-Programmierung. Ich habe Erfahrungen
bei der Programmierung eines PIC16 in Assembler und möchte mich nun an
einem PIC18 mit C-Programmierung versuchen. Dafür habe ich mir vom
Franzis-Verlag ein Lernpaket für PIC-µC gekauft und versuche nun damit
ein wenig eigenständig zu arbeiten.
Leider stehe ich bei der Ausgabe eines PWM-Signals völlig auf dem
Schlauch und würde mich sehr freuen, falls mir jemand helfen könnte!
Probleme:
1) im Datasheet
(http://ww1.microchip.com/downloads/en/DeviceDoc/41412E.pdf) auf Seiten
184 ff. ist unter dem Kapitel 14.3 das Vorgehen (eigentlich)
beschrieben.
Unter dem Punkt 14.3.2 ist beschrieben, dass ich je nach TMRx
(TMR2,TMR4,TMR6) in den Registern CCPTMRSx die Bits setzen soll. Leider
kann ich damit nichts anfangen; welche der 5 möglichen Bit-Paare soll
ich für die Nutzung welches Timers setzen ... ?
2) Ich habe gelesen, dass die PWM-Ausgänge gemultiplext werden müssen in
der Config-Datei. Wie genau soll das funktionieren ... ?
Meinen bisherigen Code habe ich einfach mal nach bestem Gewissen
erstellt, leider funktioniert bisher nur, dass die LED nach ein paar
Sekunden Verzögerung einmalig angeht, stattdass ein Sinus o.Ä.
durchlaufen wird .... Wenn ich mir über das Watch-Fenster die Werte
anzeigen lassen, werden die Werte des Sinus "eigentlich" in das CCPR5L
Register übernommen und naja, ich weiß leider nicht weiter!
Vorab vielen Dank für jegliche Hilfestellung!
PS: Leider habe ich keine klare Vorgabe bzgl. der Vorgehensweise mit dem
Code gefunden und füge ihn daher sowohl als Text als auch als Datei an.
1
/** I N C L U D E S *******************************************/
2
#include<htc.h>
3
#include<pic18f23k22.h>
4
#include"Config.h" //Konfigurationsbits
5
6
7
/** D E F I N E S *********************************************/
8
#define TASTER PORTBbits.RB0 //Taster liegt an Port B RB0
9
#define LED LATAbits.LATA4 //LED liegt an Port A RA4
10
11
/** P R O T O T Y P E S ***************************************/
12
voidinterruptisr_high(void);
13
voidinterruptlow_priorityisr_low(void);
14
voiddelay(intms);
15
voidsetupTouch(void);
16
intgetKey(charkey);
17
voidsetLED(shortlight);
18
19
/** I N T E R R U P T S ***************************************/
20
voidinterruptisr_high(void){
21
22
}
23
24
voidinterruptlow_priorityisr_low(void){
25
26
}
27
28
/** H A U P T P R O G R A M M *********************************/
29
voidmain(void)
30
{
31
charbutton=0;
32
volatileunsignedcharsinus[40]={127,147,166,185,202,217,230,240,248,252,254,252,248,240,230,217,202,185,166,147,127,107,88,69,52,37,24,14,6,2,0,2,6,14,24,37,52,69,88,107};//Array mit berechneten Sinuswerten
33
volatilechara=1;//Zählervariable zum Auslesen des Arrays
34
shortsin_wert=0;
35
36
//Port A
37
LATA=0x00;
38
TRISA=0x00;//Alle Pins von Port A sind Ausgänge
39
ANSELA=0x00;//Alle Pins von Port A sind digitale I/O's
40
//Port B
41
LATB=0x00;
42
TRISB=0xFF;//Alle Pins von Port B sind Eingänge
43
ANSELB=0x00;//Alle Pins von Port A sind digitale I/O's
Marco schrieb:> Unter dem Punkt 14.3.2 ist beschrieben, dass ich je nach TMRx> (TMR2,TMR4,TMR6) in den Registern CCPTMRSx die Bits setzen soll. Leider> kann ich damit nichts anfangen; welche der 5 möglichen Bit-Paare soll> ich für die Nutzung welches Timers setzen ... ?
Du kannst in den Registern CCPTMRSx wählen, welcher Timer für welchen
PWM-Ausgang zuständig ist (TMR2/4/6). So hast du 3 voneinander
unabhänige PWM-Ausgänge, die halt unterschiedliche Frequenzen und
Duty-Cycles haben können. Mit dem CCPRxL Register und den beiden Bits im
CCPxCON-Register kannst du die Duty-Cycle-Ratio einstellen, also wieviel
High und wieviel Low pro Periode sein soll. Mit dem Vorteiler des Timers
und dem PRx Register stellst du die Frequenz ein.
Marco schrieb:> 2) Ich habe gelesen, dass die PWM-Ausgänge gemultiplext werden müssen in> der Config-Datei. Wie genau soll das funktionieren ... ?
Du kannst in der Konfiguration einstellen, wo P2B ist (für Single-Mode
uninteressant), wo CCP2 und wo CCP3 sein soll. Genauer gesagt im
High-Byte des dritten Configuration Register.
Zum Code:
Ansich initialisiert man einmal am Anfang das PWM-Modul. Also CCPxCON,
CCPTMRSx, PRx, Timer-Prescaler usw. Fürs Faden wird das ansich ja nicht
mehr geändert, zumindest in deinem Fall erstmal unnötig. Danach
schraubst du einfach die Dutycyleratio hin und her. Also einmal
Configurieren und dann die Werte aus dem Array direkt in das CCPRxL
schreiben. Sprich, alles was da steht (bis auf die Zeile mit dem CCPR5L)
gleich unter die Main. Und dann kannst du, statt es in sin_wert zu
schreiben, direkt in das CCPR5L schreiben. Die Funktion kannst du dir
dann sparen.
Tip: Ich mache es immer so, das ich eine init()-Funktion habe. Da kommt
alles rein, TRISA..., ADCON, CCP, CMx.. TxCON, OSCCON usw. Die kommt bei
mir dann direkt unter das "void main(){"
OSCCON seh ich bei dir z.B. nicht. Klar hat das Register Reset-Werte,
aber die passen bei mir meist nicht zu dem was ich brauche und dazu
fühle ich mich sicherer, wenn ich alles nochmal explizit hinschreibe.
Das sind wenige µs einmalig beim "Hochfahren".
Hallo und vorab vielen Dank für deine Antwort,
bevor ich wieder Unsinn fabriziere:
Wo genau ist denn beschrieben welchem PWM-Ausgang ich welchen Timer
zuordne .. ? Es gibt ja nur TMR2,TMR4 und TMR6. Jedoch die Register 1-5,
so dass sich mir leider spontan kein logischer Zusammenhang offenbart.
Wenn es "nur" 1-4 geben würde, würde ich eine Addition vermuten aber so
bin ich leider einfach ratlos wie ich die Register setzen muss, um
einfach TMR2 meinem PWM-Signal des CCP5 zuzuordnen.
Ich dachte die Wahl des Oszillators sei einmalig mit der
Konfigurationsdatei abgedeckt und man kann nur den TMR0 nochmal separat
auf einen "anderen" Oszialltor legen? Oder geht das bei dem PIC18 nun
auch mit den anderen Timern?
Vielleicht könntest du mir als kleine Hilfestellung eine von dir
kommentierte init() Datei bzw. ein PWM-Beispiel für einen PIC18 in C
anhängen, damit ich mich ein wenig orientieren kann?
Ich finde im Internet leider so wenige konkrete Beispiele, die nicht in
Assembler programmiert sind und habe deshalb leider nur diese
Flickeschusterei von oben zustandegebracht ....
Vorab vielen Dank!
Sorry, ich hab total verpeilt, dass du nochmal geschrieben hast.
Also:
Marco G. schrieb:> Es gibt ja nur TMR2,TMR4 und TMR6. Jedoch die Register 1-5,> so dass sich mir leider spontan kein logischer Zusammenhang offenbart.
Du hast die beiden Register CCPTMRS0 und CCPTMRS1 (Seite 208).
Dort kannst du sagen, welcher CCP welchen Timer als Grundlage hast. Wenn
du zum Beispiel nur den CCP5 brauchst und Timer 2 als Basis haben
willst, brauchst du einfach nur dafür sorgen, dass Bit 2+3 vom Register
CCPTMRS1 00 sind. Also z.B. "CCPTMRS1 = 0;".
Da steht ja als Erklärung:
1
bit 3-2 C5TSEL<1:0>: CCP5 Timer Selection bits
2
00 = CCP5 – Capture/Compare modes use Timer1, PWM modes use Timer2
3
01 = CCP5 – Capture/Compare modes use Timer3, PWM modes use Timer4
4
10 = CCP5 – Capture/Compare modes use Timer5, PWM modes use Timer6
5
11 = Reserved
Mit den beiden Bits sagst du, welcher Timer benutzt werden soll. Und da
steht dann "PWM modes use Timer2". Das heißt, wenn du CCP5 als
PWM-Ausgang konfiguriest (im CCP5CON-Register) wird Timer2 benutzt.
Marco G. schrieb:> Ich dachte die Wahl des Oszillators sei einmalig mit der> Konfigurationsdatei abgedeckt und man kann nur den TMR0 nochmal separat> auf einen "anderen" Oszialltor legen? Oder geht das bei dem PIC18 nun> auch mit den anderen Timern?
Du kannst da Einstellen, ob der PLL Ein- oder Abgeschaltet sein soll
(Wenn aus, ist er wirklich aus, wenn an, dann kann man ihn trotzdem per
Register an und ausschalten) und welche Taktquelle er hat. Z.b. Externer
RC-Oscillator, HS, XT, Intern, usw.
Jetzt hast du gewählt, welche Quelle du haben willst, aber gerade bei
der Verwendung des internen Oscillators ist das OSCCON-Register
nützlich. Auf Seite 28 ist die Übersicht des Oscillator-Blocks. Da
siehst du z.B., dass, wenn man den internen Oscillator benutzt,
auswählen kann, auf welche Frequenz der interne Takt geteilt werden
soll. Die Auswahl dazu ist im OSCCON-Register. Mit dem OSCTUNE-Register
kann man den Internen Takt leicht beeinflussen, um ihn zu Kalibrieren.
Marco G. schrieb:> Vielleicht könntest du mir als kleine Hilfestellung eine von dir> kommentierte init() Datei bzw. ein PWM-Beispiel für einen PIC18 in C> anhängen, damit ich mich ein wenig orientieren kann?
Hier mal meine Init und ein auf die schnelle zusammengeschriebenes
Programm. Ungetestet aber sollte gehen.
T2CON=0b00000111;// Timer2 an, Prescaler 16 (Also läuft der Timer mit 500kHz)
17
PR2=124;// PR2 = 124. Formel auf Seite 187 zur Periodenberechnung -> (124+1)*4*(1/8MHz)*16=1ms-> 1kHz
18
TRISA=0b00001111;// DIO's Einstellen
19
TRISB=0b01110111;
20
TRISC=0;
21
TRISE=0;
22
PORTA=0;
23
PORTB=0;
24
PORTC=0;
25
PORTE=0;
26
LATA=0;
27
LATB=0;
28
LATC=0;
29
LATE=0;
30
}
31
32
33
voidmain(){
34
charmode=0,counter=0;
35
volatileunsignedcharsinus[40]={127,147,166,185,202,217,230,240,248,252,254,252,248,240,230,217,202,185,166,147,127,107,88,69,52,37,24,14,6,2,0,2,6,14,24,37,52,69,88,107};//Array mit berechneten Sinuswerten
Hallo Michael,
vorab vielen Dank für deine Hilfe und die kleine "Erinnerungsmail" ;)
Ich bin leider erst gestern Abend dazu gekommen den Code zu
implementieren und auszutesten, klappt wunderbar. Also vielen Dank!
Ich bin gerade dabei das PWM-Signal nun auf den Controller
zurückzukoppeln, indem ich eine Spule mit dem Signal beaufschlage.
Ziel meines kleinen Projektes ist eine Induktivitätsmessung mit
möglichst einfachen Mitteln. Der obige Ansatz hat noch auf die Messung
einer Phasenverschiebung bzw. eines frequenzabhängigen Widerstandes
hinausgezielt, momentan bin ich aber sogar noch mehr angetan von
folgender Idee:
ich beaufschlage mein RL-Glied mit einem PWM-Signal bzw. mit einer
Gleichspannung. Beim Zeitpunkt des Beginns der Beaufschlagung starte ich
einen Counter. An einem CCP-Modul messe ich wann ein Referenzwert
erreicht wird, zB der Wert von 3 tau. Das Überschreiten dieses Wertes
stoppt den Counter und ich kann mich rechnerisch über tau = L/(3*R) an
die Berechnung meiner Induktivität begeben.
In bestimmten Intervallen wird über einen Mess-Shunt eine reine Messung
des Wirkwiderstandes vorgenommen, um etwaige temperaturbedingte
Schwankungen auszugleichen. Quasi eine Kalibrierung des Systems.
Was haltet ihr von dieser Idee?
Was sind mögliche Probleme? Ich habe spontan an den Wirkwiderstand
gedacht, weil tau ja doch "sehr abhängig" davon ist. Sehr ihr noch
weitere Trouble-Spots?
Vorab vielen Dank für Tipps und nachträglich nochmal vielen Dank für die
bereits erfolgte Hilfe ;)