Forum: Mikrocontroller und Digitale Elektronik LED mit vorgegebener Frequenz blinken lassen


von Seto (Gast)


Lesenswert?

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
typedef unsigned int uint;
4
/***** CONFIGURATION *****/
5
//  ext reset, internal oscillator (no clock out), no watchdog timer
6
#pragma config MCLRE = ON, FOSC = INTOSC, CLKOUTEN = OFF, WDTE = OFF
7
//  brownout resets enabled, low brownout voltage, no low-power brownout reset
8
#pragma config BOREN = ON, BORV = LO, LPBOR = OFF
9
//  no power-up timer, no code protect, no write protection
10
#pragma config PWRTE = OFF, CP = OFF, WRT = OFF
11
//  stack resets on, high-voltage programming
12
#pragma config STVREN = ON, LVP = OFF
13
14
#define _XTAL_FREQ  500000
15
#define Send LATAbits.LATA1                 // Turn's LED on/off
16
17
void init(void) {
18
TRISA = 0b000100;               // configure all PINS as an output except RA2  (0 -> output, 1 -> input)
19
    LATA = 0;                       // set RA1 low
20
// configure oscillator
21
    OSCCONbits.SCS1 = 1;            // select internal clock -- OSCCON oscillator control register
22
//    OSCCONbits.IRCF = 0b1100;       // internal oscillator = 2 MHz
23
    OSCCONbits.IRCF = 0b1010;       // 500 khz
24
        // configure Timer0
25
    OPTION_REGbits.TMR0CS = 0;      // select timer mode
26
    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
void ManchesterOne(void) {
33
    Send = 0;
34
    TMR2 = 0;
35
    while(TMR2<Delay);
36
    Send = 1;
37
    TMR2 = 0;
38
    while(TMR2<Delay);
39
}
40
void ManchesterZero(void) {
41
    Send = 1;
42
    TMR2 = 0;
43
    while(TMR2<Delay);
44
    Send = 0;
45
    TMR2 = 0;
46
    while(TMR2<Delay);
47
}
48
void Manchester_Encoding(unsigned char Data) {
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
void main(){
61
    init();
62
    unsigned char Data2 = 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

von Stefan F. (Gast)


Lesenswert?

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.

von Thomas E. (picalic)


Lesenswert?

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.

von Dr. Sommer (Gast)


Lesenswert?

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.

von Seto (Gast)


Lesenswert?

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
int Delay = 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

von Thomas E. (picalic)


Lesenswert?

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...)

: Bearbeitet durch User
von Apollo M. (Firma: @home) (majortom)


Lesenswert?

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

: Bearbeitet durch User
von Harald W. (wilhelms)


Lesenswert?

Seto schrieb:

> ich möchte eine LED mit einer Frequenz von 1kHz blinken lassen.

Da würde ich einen 555 nehmen...

von Paul B. (paul_baumann)


Lesenswert?

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

von Harald W. (wilhelms)


Lesenswert?

Paul B. schrieb:
> Harald W. schrieb:
>> Da würde ich einen 555 nehmen...
>
> Ich nicht, denn:

Hallo Paul, hast Du den virtuellen Smily übersehen?

von Thomas E. (picalic)


Lesenswert?

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.

: Bearbeitet durch User
Beitrag #5278319 wurde von einem Moderator gelöscht.
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
Noch kein Account? Hier anmelden.