Hallo,
ich möchte eine LED mit einer Frequenz von 1kHz blinken lassen. Dies
will ich erreichen, indem ich den internen Oszillator verwenden. Ich
nutze einen PIClf1509. Die Idee war, dass ich den Timer2 nulle, und dann
den Timer bis zu einem bestimmten Wert hochlaufen lasse. Ich verwende
eine Frequenz von 500 kHz was bedeutet, dass bei jedem Schritt den der
Timer zählt 8 us vergehen
(500 kHz / 4 = 125 kHz /instruction cycle = 8 us).
Um jetzt die LED mit 1 kHz blinken zu lassen mache ich die LED an, warte
63 ticks und mache die LED anschließend aus und warte wieder 63 ticks.
Hier der CODE:
1
#include<xc.h> // include processor files - each processor file is guarded.
2
3
typedefunsignedintuint;
4
/***** CONFIGURATION *****/
5
// ext reset, internal oscillator (no clock out), no watchdog timer
6
#pragma config MCLRE = ON, FOSC = INTOSC, CLKOUTEN = OFF, WDTE = OFF
OPTION_REGbits.PSA=1;// if '0' assign's prescaler to Timer0
27
// OPTION_REGbits.PS = 0b111; // prescale 1:128
28
// -> increment TMR0 every 4 us
29
// configure Timer2
30
T2CONbits.TMR2ON=1;// Timer for sending
31
}
32
voidManchesterOne(void){
33
Send=0;
34
TMR2=0;
35
while(TMR2<Delay);
36
Send=1;
37
TMR2=0;
38
while(TMR2<Delay);
39
}
40
voidManchesterZero(void){
41
Send=1;
42
TMR2=0;
43
while(TMR2<Delay);
44
Send=0;
45
TMR2=0;
46
while(TMR2<Delay);
47
}
48
voidManchester_Encoding(unsignedcharData){
49
uint_Index=0;
50
51
Send=1;
52
// i = 128 for sending ascii letters == 7 Bits
53
for(_Index=128;_Index!=0;_Index/=2){
54
(_Index&Data)?ManchesterOne():ManchesterZero();
55
}
56
Send=1;
57
58
}
59
// *** Main Programm ***
60
voidmain(){
61
init();
62
unsignedcharData2=0b11111111;
63
while(1){// run forever
64
Manchester_Encoding(Data2);
65
}
66
}
Das ganze soll für die Manchester Kodierung verwendet werden. Das
Problem ist, dass ich den Ausgang des Microcontrollers mit einem
Oszilloskop gemessen habe und die Periode nur eine Frequenz von ~730 Hz
haben. Außerdem sind die Impulse nicht gleich lang und variieren stark.
Liegt das am internen Oszillator bzw. am C Code?? Muss ich um genau die
1 kHz zu erreichen einen externen Oszillator benutzten?
Gruß
Seto
Ich kenne den PIC nicht genau. Möglicherweise kannst du den Zähler des
Counters nicht einfach so auf 0 setzen während er läuft. Da könnte es
Einschränkungen geben.
Irgendwie habe ich aber das Gefühl, dass der Fehler im nicht gezeigten
Code steckt. Da fehlt doch noch was, zum Beispiel die Definition von
Delay und Send.
Erstens:
500 kHz Prozessortakt macht den PIC extrem langsam. Wie Du selbst schon
errechnet hast, gibt das 8µs für jeden Maschinenbefehl, und jede
C-Anweisung braucht in der Regel mehrere Maschinenbefehle zur
Verarbeitung! Wenn Du nicht auf extrem wenig Stromaufnahme angewiesen
bist, solltest Du den PIC mit hoher Taktfrequenz laufen lassen (16 oder
evtl. geht bei dem auch 32MHz mit dem internen Oszi)
Zweitens:
Besser, als den Timer zum Reset zu Nullen ist es, den letzten Delay-Wert
vom aktuellen Timerwert abzuziehen ("TMR2 -= Delay;"). Dadurch kürzen
sich Programmlaufzeiten weitestgehend heraus.
Seto schrieb:> uint _Index = 0;
Nebenbei: In C sind Bezeichner, die mit Unterstrich + Großbuchstabe oder
zwei Unterstrichen anfangen, im normalen Code verboten und der Standard
Bibliothek vorbehalten.
Hallo,
danke für die Antworten. Der PIC16lf1509 hat einen internen Oszillator
der Frequenzen von 16Mhz nutzen kann. Ich werde das dann mal damit
versuchen.
Für den Delay habe ich einfach die Anzahl der Ticks, hier dann 63,
definiert.
1
intDelay=63;// ticks for delay Period 63 x 8 us = 504 us
Send habe ich ganz oben im Code definiert.
1
#define Send LATAbits.LATA1 // Turn's LED on/off
Ich werde das ganze dann mal Testen und gucken ob genauere Werte für die
Impulse rauskommen. Die Laufvariable für die for-Schleife werde ich dann
auch noch anpassen ^^.
Viel Grüße
Seto
Seto schrieb:> Für den Delay habe ich einfach die Anzahl der Ticks, hier dann 63,> definiert.
Bei 16MHz musst Du den TMR2 natürlich mit einer geeigneten
Prescaler-Einstellung betreiben. 1:16 wäre bei 16 MHz passend, gibt dann
4µs pro Timer-Tick, also 125 Ticks für 500µs.
Nochwas: Präziser, als der Vergleich ("if (TMR2 > Delay)...") dürfte die
Prüfung des Timer-Interrupt Flags sein ("if (TMR2IF)...".
Noch besser: die ganze Manchester-Codierung per Timer-Interrupt (naja,
später dann...)
Hallo,
für mich ist der ansatz völlig sinnfrei/unsinnig, weil das die timer2
hw peripherie standalone macht. sprich nach init ohne weiteren sw
support.
entweder über das period register/compare mode oder über das pwm module,
wenn du auch das tastverhältnis definieren willst.
vielleicht zuerst mal das manual lesen!
das ist auch keine "esoterik" sondern common sense!
mt
Harald W. schrieb:> Da würde ich einen 555 nehmen...
Ich nicht, denn:
Seto schrieb:> Das ganze soll für die Manchester Kodierung verwendet werden.
Da wird es an anderer Stelle wieder dekodiert werden sollen und da ist
wahrscheinlich der 555 weder genau genug, noch in der Lage, eine
solche Kodierung durchzuführen.
MfG Paul
Apollo M. schrieb:> für mich ist der ansatz völlig sinnfrei
Naja, ich würde es eher "ungeschickt" nennen - sinnlos wäre, wenn der
Ansatz so prinzipiell unmöglich funktionieren könnte.
Ein Ansatz könnte evtl. sein:
- Manchester-Ausgangssignal durch PWM-Hardware erzeugen lassen, dazu muß
aber ein geeigner Pin gewählt werden (RA1 hat keine PWM-Funktion!)
- Die PWM erzeugt fest eingestellt: 500 µs "an" und 500 µs "aus".
- per Software wird, je nach Manchester-Bitwert, dynamisch per
PMWPOL-Bit im PWMCON-Register die Polarität des PWM-Ausgangs
umgeschaltet (0 => "an"=high, "aus"=low, 1 => "an"=low, "aus"=high).
Die Umschaltung der Polarität könnte per Interrupt vorgenommen werden,
oder durch Abfrage des TMR2IF-Bits im Hauptprogramm, um den
Polaritätswechsel zum richtigen Zeitpunkt vorzunehmen.