Hallo zusammen,
PIC: PIC18F45550
Treiber: C18
Tools: MPLAB IDE 8.92
Problembeschreibung:
Wie kann ich wissen was für eine internal Oscillator hat das PIC nach
der folgende Konfiguration?
Das Pic ist wie folgenden konfiguriert:
#pragma config PLLDIV = 3
#pragma config CPUDIV = OSC1_PLL2
#pragma config USBDIV = 2
#pragma config FOSC = HSPLL_HS
Laut das Configuration Setting bedeuten diesen Einstellungen (Seh
bitte Anhang): (Microchip MPLAB IDE_Configuration Setting_PIC18F4450)
In der Clock Diagram (in der Datenblatt: Fig 2-1)ist noch einmal alles
geklärt.
Seh bitte Anhang ( PIC18F4550_Datenblatt_ClockDiagram)
Ich bin leider dadurch nich schlauer geworden: Mit welchen Frequnenz
soll ich das OSCI einstellen.
Danke
Wenn ich das richtig interpretiere, taktet die CPU und die Peripherals
mit 48MHz beim POR.
Wenn dir das so recht ist, brauchst du nichts mehr an den Registern
ändern
Little Basdart schrieb:> Wenn ich das richtig interpretiere, taktet die CPU und die Peripherals> mit 48MHz beim POR.
eben nicht weil:
OSC2 und OSC1 (seh bitte Anhang : " PIC18F4550_Datenblatt_ClockDiagram"
)Anschlüsse sind mit einem Osci (12MHZ) verbunden.
Diese ist wieder durch 3 dividiert (#pragma config PLLDIV = 3 )
Ist das so richtig?
ja, das ist so weit richtig.
Das muss so sein, weil die PLL nur 4MHz als Input erlaubt. Heraus kommt
dann 96MHz, die mit dem PLL_Postscaler durch 2 geteilt werden und auf
die CPU und Peripherals gegeben werden.
Little Basdart schrieb:> Das muss so sein, weil die PLL nur 4MHz als Input erlaubt. Heraus kommt> dann 96MHz, die mit dem PLL_Postscaler durch 2 geteilt werden und auf> die CPU und Peripherals gegeben werden.
@Danke
Toxic schrieb:> Wenn ich die Konfigurationseinstellungen richtig> interpretiere,muesste> der SystemClock nach einem POR tatsaechlich bei 48MHz liegen.> siehe Anhang
@Danke
Dazu habe ich folgenden:
Ich möchte einen Timer1 Interrupt einbauen.
Als erste habe ich den Timer1 initialisert:
IPR1bits.TMR1IP=1;/* set Timer1 overflow interrupt to HIGH priority */
10
T1CONbits.TMR1CS=0;/* user internal clock to increment Timer1 */
11
//Prescaler
12
T1CONbits.T1CKPS1=0;/* Prescaler 1:1 */
13
T1CONbits.T1CKPS0=0;
14
INTCONbits.GIE=1;/* Enable global interrupts */
15
16
}
Das heisst:
Internal Instruction Cycle = 1/[ 48MHZ/4 ] = 8.33 ns
TMR1 ist ein 16-Bit Register
Bis einen TimerOverflow gibt ist t(die nötige Zeit bist einen Overflow )
= 8.33 ns * 65536 = 0.0054 s.
Ist das so richtig?
dann überprüfe ich ob der Flag TMR1IF gesetzt und zwar wie folgenden:
Wenn es einen Timeroverflow springt das Prog direkt in der ISR Routine,
die so implementiert ist:
Sieht soweit richtig aus.
Aber beachte bei den Interrupts:
- Wenn du Interrupt Priorities nutzen willst, musst du noch RCON.IPEN =
1 setzen
- Wenn du keine Interrupt Priorities nutzen willst, musst du noch
INTCON.PEIE = 1 setzen
sonst wird der Interrupt nicht ausgelöst
Hans schrieb:> Internal Instruction Cycle = 1/[ 48MHZ/4 ] = 8.33 ns
1/[ 48MHZ/4 ] = 83.3ns
=================================
Hans schrieb:> Bis einen TimerOverflow gibt ist t(die nötige Zeit bist einen Overflow )> = 8.33 ns * 65536 = 0.0054 s.
83.3ns * 65536 = 5.46ms
Irgendwie verhaust Du dich (oder ich) hier und da mit den 10er-Potenzen
Eine Frage habe ich noch:
Wenn es einen Timeroverflow geschieht, springt das Prog direkt in der
ISR Methode.
und von dort an muss ich die HandlingsRoutine aufrufen die irgendwas
macht.
zB:
Hans schrieb:> Eine Frage habe ich noch:> Wenn es einen Timeroverflow geschieht, springt das Prog direkt in der> ISR Methode.
Ja
> und von dort an muss ich die HandlingsRoutine aufrufen die irgendwas> macht.> zB:>>
1
>voidYourHighPriorityISRCode()
2
>{
3
>...
4
>
Ja
> Ist mein Vorgehen richtig?
Das was du gepostet hast ist zumindest nicht falsch.
Es fehlt aber noch einiges das du aber vielleicht einfach nur nicht
gepostet hast ;-)
Ist der Interrupthandler als solcher markiert ?
(#pragma interrupt YourHighPriorytyISRCode)
Sind Sprünge an den Vektoren angelegt ?
1
/** I N T E R R U P T V E C T O R S ******************************************/
2
#pragma code high_vector=0x08
3
voidinterrupt_at_high_vector(void)
4
{
5
_asmgotoYourHighPriorytyISRCode_endasm
6
}
7
8
#pragma code low_vector=0x18
9
voidinterrupt_at_low_vector(void)
10
{
11
_asmgotolow_isr_endasm
12
}
13
#pragma code
Wenn generelle Anfänger-Probleme bestehen, dann kannst du auch mal in
dieses Skript
*uC_quick-X.pdf* -> 5.1 Timer_0 Interrupt (Blink Variante 3)
hier an der rechten Seite schauen -> http://www.hs-ulm.de/schilling
Aber Achtung!
Aus der ISR sollte nicht via return herausgesprungen werden. Ältere
compiler haben damit probleme, da diese dann [asm]ret[/asm] verwenden
anstatt [asm]retfie[/asm]
(siehe dazu instruction set summary deines Datenblatts)
Little Basdart schrieb:> wenn du den xc8-compiler verwendest, reicht das "interrupt" keyword:
Äh, ja sorry. Vieleicht war meine Annahme C18 Compiler gar nicht richtig
...
(aus original Post -> Treiber: C18)
Für neuere Projekte die mit C18 und XC8 verwendbar sein sollen verwende
ich folgenden Code (den man leider nicht mehr versteht)
1
/** I N T E R R U P T V E C T O R S ************* C18 compiler only **********/
2
3
#ifndef __XC8 // not XC8 compiler -->> C18 compiler
4
5
#pragma interrupt high_isr
6
#define interrupt // remove keyword
7
#pragma code high_vector=0x08
8
9
#ifdef USE_IR_PRIORITIES
10
voidinterrupt_at_high_vector(void)
11
{
12
_asmgotohigh_isr_endasm
13
}
14
#define low_priority // remove keyword
15
#pragma interruptlow low_isr
16
#pragma code low_vector=0x18
17
voidinterrupt_at_low_vector(void)
18
{
19
_asmgotolow_isr_endasm
20
}
21
#pragma code
22
#endif
23
#endif
24
25
/** D E C L A R A T I O N S ***************************************************/
Little Basdart schrieb:> Aber Achtung!> Aus der ISR sollte nicht via return herausgesprungen werden. Ältere> compiler haben damit probleme, da diese dann [asm]ret[/asm] verwenden> anstatt [asm]retfie[/asm]
Ups, mache ich eigentlich schon immer (sehr lange) so
und mit C18 ist noch nie ein Problem aufgetreten.
Volker SchK schrieb:> Little Basdart schrieb:>> Aber Achtung!>> Aus der ISR sollte nicht via return herausgesprungen werden. Ältere>> compiler haben damit probleme, da diese dann [asm]ret[/asm] verwenden>> anstatt [asm]retfie[/asm]>> Ups, mache ich eigentlich schon immer (sehr lange) so> und mit C18 ist noch nie ein Problem aufgetreten.
Das hat mir mein Mikrocontrollertechnik-Prof erklärt, der ist Fachmann
für Microchip. Offenbar hat er da schon schlechte Erfahrungen gemacht.
Gut möglich, dass die Compiler mittlerweile damit umgehen können, aber
ich hab mir (vor allem für die kleinen Controller) angewöhnt, kein
return zu verwenden.
Volker SchK schrieb:> Ist der Interrupthandler als solcher markiert ?> (#pragma interrupt YourHighPriorytyISRCode)>> Sind Sprünge an den Vektoren angelegt ?
Ja das habe ich auch so gemacht
Volker SchK schrieb:> Und funktioniert es so wie du dir das gedacht hast ?
nicht ganz
Ich beschreibe kurz meine Anwendung:
Mit dem Pic versuche ich 3 Signale, die ich von einen Subsystem bekomme
zu steueren.
Dieses 3 Signale müssen bestimmte Voraussetzungen erfüllen.
Diese Auswertung der Signale ist mit einer Pollingsverfahren realisiert
(was es nicht unbedingt ideal aber so ist halt der IstStand)
Wenn die Signale nicht da sind oder aus irgendwie einen Grund nicht da
sind dann schlägt das Watchdog und schaltet das Board aus.
Das Borad ist mit dem PC mittels USB verbunden.
Es wurde auch einen GUI oberfläsche (C++) entwickelt um das Borad zu
steuern ("HID").
Die Kommunikation lauft über einen genauen vordefinierten USB protokol.
Das ist ganz Grob was die Anwendung der Pic betrifft.
Die jetzigen Überlegung ist das WDT auszuschalten und stattdessen einen
Meldung auszugeben, wenn einen Timer1overflow gibt.
Wie gesagt Timeroverflow wird in der ISR Methode abgfragt
1
if(PIR1bits.TMR1IF)
.
Ist der "TMR1IF" ==1 dann muss einen Message in der GUI geben, die
besagt z.B Signal1, Signal2 oder Signal 3 nicht da ist.
--> Mir ist nur nicht ganz klar wie ich dieses Meldung zu den GUI
weiterleite
Wie gesagt die Kommunikation mit der Board ist über einen USB
schnittstelle.
Die Befehle werden über einen Protokoll gesendet und von der pic
abgearbeitet.
Ich hoffe, dass ich gut geklärt habe
Hans schrieb:> Das Borad ist mit dem PC mittels USB verbunden.> Es wurde auch einen GUI oberfläsche (C++) entwickelt um das Borad zu> steuern ("HID").> Die Kommunikation lauft über einen genauen vordefinierten USB protokol.Hans schrieb:> --> Mir ist nur nicht ganz klar wie ich dieses Meldung zu den GUI> weiterleite
Im "genau vordefinierten Protokoll", wird da irgendwas vom PIC zum PC
geschickt, oder immer nur vom PC zum PIC ?
Wenn was zurückgeschickt wird, dann geht das für die neue Meldung
genauso ...
Volker SchK schrieb:> Im "genau vordefinierten Protokoll", wird da irgendwas vom PIC zum PC> geschickt, oder immer nur vom PC zum PIC ?
@ auch von PIC zu PC
Was genau ist dein Problem ?
Woher stammt dein vorgegebenes Protokoll ?
Es wird doch schon was zurückgeschickt,
warum machst du es nicht genau so ?
Vermutlich gibt es da eine ID als erstes Byte in der Nachricht oder so
...
Volker S. schrieb:> Was genau ist dein Problem ?
Mein Problem ist:
1) Wie kann ich den Timmer1Overflow (Eintritt von Interrupt) zu der GUI
(Visual Studio) weiterleiten?
Ich habe es folgenden gemacht:
1) Timer1 initialisiert
2) in der ISR Routine der Flag abgefragt :
1
if(PIR1bits.TMR1IF)
Der Timeroverflow tritt bei einen Zeitüberschreitung von 43.69 ms.
Dieses Wert wurde auch gemessen und es stimmt auch.
> Woher stammt dein vorgegebenes Protokoll ?
Das Protokoll wurde vor meine Zeit erstellt.
Es handelt sich eigentlich um Befehle bzw. Kommunikationsprotokoll.
z.B: Messung wird mit dem Befehl Nr: 26 und dieses wird in einen switch
case ( MPLAB IDE, C18) ja nachdem was für einen Befehl ist ausgeführt.
Alle Kommunikation mit dem Board funktionieren nach dieses Muster.
Befehl schicken und auf eine Antwort warten
> Es wird doch schon was zurückgeschickt,> warum machst du es nicht genau so ?
Das mache ich auch genau so, aber einen Interrupt abzufangen ist halt
anders.
Man schickt keinen Timeroverflow sondern prüft, ob es geschehen ist.
Das Geschehen wird sowiso in der ISR Routine abgefangen, aber wie leite
ich das weiter zu den GUI?
Hans schrieb:> Alle Kommunikation mit dem Board funktionieren nach dieses Muster.> Befehl schicken und auf eine Antwort warten
Stell dir doch für den Anfang einfach mal vor,
du schickst eine Antwort obwohl du keinen Befehl bekommen hast ...
In deinem PC Programm bekommst du dann (k)eine Antwort auf keinen
Befehl.
Die schon bestehenden Antworten werden doch auch irgendwie ausgewertet.
(anhand einer ID oder so) Jetzt kommt einfach eine neue dazu.
Wenn du vieleicht dein Konzept überdenken willst, ich hätte da einen
Vorschlag.
Leider Postest du ja nicht eine Zeile deines Codes, also alles was ich
hier schreibe sind nur Annahmen, die ich mit meinen Ideen erweitere.
Da du einen timeout abfangen willst, hast du vermutlich sowas:
1
while(warte_auf_signal==0){
2
// weiter warten, nichts tun
3
}
Du weißt zwar durch deinen Timer Interrupt, dass ein Timeout entstanden
ist, jedoch muss ja auch dein Programm darauf reagieren:
Was genau in MessageTimerOverflow() gemacht wird, kann dir leider immer
noch niemand sagen. Mach doch mal eine Arschbombe in die Protokoll-Doku
und suche dir eine Möglichkeit, Fehlermeldungen auszugeben. Wenn es
diese Möglichkeit nicht gibt (grober Designfehler!), dann musst du das
Protokoll eben erweitern.
Little B. schrieb:> Aber warum den Umweg über die ISR gehn?
Wenn es einen TimerOverflow eintritt springt das Prog nicht direkt in
die ISR Routine oder liege ich falsch?
Hans schrieb:> Little B. schrieb:>> Aber warum den Umweg über die ISR gehn?>> Wenn es einen TimerOverflow eintritt springt das Prog nicht direkt in> die ISR Routine oder liege ich falsch?
Die ISR wird nur aufgerufen, wenn du
1
PIE1bits.TMR1IE=1;
setzt (so wie du es gerade tust).
Wenn du das aber auf 0 lässt, wird die ISR nicht angesprungen, aber das
Flag trotzdem gesetzt, wenn ein Overflow auftritt.
Aber das ist nur nebensächlich. Dein Hauptproblem ist gerade das
USB-HID-Protokoll, über das du die Fehlermeldung ausgeben willst. Und
das solltest du tunlichst nicht in der ISR machen!
Little B. schrieb:> Aber das ist nur nebensächlich. Dein Hauptproblem ist gerade das> USB-HID-Protokoll, über das du die Fehlermeldung ausgeben willst. Und> das solltest du tunlichst nicht in der ISR machen!
Das habe ich nicht ganz verstanden was du genau meinst?
Little B. schrieb:> Du weißt zwar durch deinen Timer Interrupt, dass ein Timeout entstanden> ist, jedoch muss ja auch dein Programm darauf reagieren:while (> (warte_auf_signal == 0) && (Timer1Flag.Bit.Timeout == 0) ){> // weiter warten, nichts tun> }> if (Timer1Flag.Bit.Timeout == 1) {> MessageTimerOverflow();> return;> }>> Aber warum den Umweg über die ISR gehn? Du kannst ja auch direkt das> Hardwareflag auswerten while ( (warte_auf_signal == 0) &&> (PIR1bits.TMR1IF == 0) ){> // weiter warten, nichts tun> }> if (PIR1bits.TMR1IF == 1) {> MessageTimerOverflow();> return;> }
Das tue ich:
1
while ( (warte_auf_signal == 0) &&
2
> (PIR1bits.TMR1IF == 0) ){
3
> // weiter warten, nichts tun
4
> }
Das heisst die Abfrage, ob einen Timeroverflow da ist muss ich nur in
ISR Routine überprüfen und von dort einen MessageOverflow geben richtig?
Hans schrieb:> Das heisst die Abfrage, ob einen Timeroverflow da ist muss ich nur in> ISR Routine überprüfen und von dort einen MessageOverflow geben richtig?
Du kannst das gerne probieren, aber ich empfehle dir, in der ISR keine
USB-Zugriffe durchzuführen. Denn das hat das potential, sehr lange zu
dauern oder sogar selbst einen Interrupt zu verursachen.
Du musst aber auch einen Schritt weiter denken. Was passiert, nachdem
die Meldung rausgeschickt wurde? Was macht dein Programm? Soll es weiter
in der Endlosschleife hängen bleiben? "Fehlerbehandlung" ist das
Schlagwort.
Und ich sage es gern nochmals: Solang du deine Informationen nicht
postest, kann man dir hier schlecht helfen.
Und damit meine ich nicht deine init-routine und deinen ISR-Ansatz,
sondern das komplette projekt mit dem USB-Protokoll.
(Bevor du das postest, solltest du aber zunächst abklären, ob du diese
Daten veröffentlichen darfst)
Little B. schrieb:> Und ich sage es gern nochmals: Solang du deine Informationen nicht> postest, kann man dir hier schlecht helfen.> Und damit meine ich nicht deine init-routine und deinen ISR-Ansatz,> sondern das komplette projekt mit dem USB-Protokoll.> (Bevor du das postest, solltest du aber zunächst abklären, ob du diese> Daten veröffentlichen darfst)
Veröffentlich das darf ich sowiso nicht.
Ich habe nachgedacht und du hast vollkommen recht.
Aus dem Grund ändere ich folgende in der Funktion InitTimer():
1
PIE1bits.TMR1IE=0;/* desable interupt on timer1 */
und versuche ich was du vorgeschlagen hast zu setzen.
Aber mir ist immer noch nit ganz klar wie ich die MessageTimeroverflow
zu der GUI weiterreiche
Hans schrieb:> Aber mir ist immer noch nit ganz klar wie ich die MessageTimeroverflow> zu der GUI weiterreiche
Von wo jetzt genau ?
Der ganze Weg von der Generierung der Message bis zur GUI ?
Wir können dir da nicht helfen, ohne den Code zu sehen ...
((( Wie werden die "Antworten" weitergeleitet ? )))
Kennst du das Demoprojekt aus den MLA (Microchip Libraries of
Applications)
Läuft das bei deinem Projekt ähnlich ?
Die Verarbeitung eines Kommandos sieht etwa so aus:
1
switch(ReceivedDataBuffer[0])//Look at the data the host sent, to see what kind of application specific command it sent.
2
{
3
caseCOMMAND_TOGGLE_LED://Toggle LEDs command
4
LED_Toggle(LED_USB_DEVICE_HID_CUSTOM);
5
break;
6
caseCOMMAND_GET_BUTTON_STATUS://Get push button state
7
//Check to make sure the endpoint/buffer is free before we modify the contents
8
if(!HIDTxHandleBusy(USBInHandle))
9
{
10
ToSendDataBuffer[0]=0x81;//Echo back to the host PC the command we are fulfilling in the first uint8_t. In this case, the Get Pushbutton State command.
11
if(BUTTON_IsPressed(BUTTON_USB_DEVICE_HID_CUSTOM)==false)//pushbutton not pressed, pull up resistor on circuit board is pulling the PORT pin high
12
{
13
ToSendDataBuffer[1]=0x01;
14
}
15
else//sw3 must be == 0, pushbutton is pressed and overpowering the pull up resistor
16
{
17
ToSendDataBuffer[1]=0x00;
18
}
19
//Prepare the USB module to send the data packet to the host
Das Kommando steht im ReceivedDataBuffer[0]
Die Antwort wird in den ToSendDataBuffer geschrieben.
Wobei [0] wieder die ID der Antwort und die weiteren Bytes der Inhalt
der Antwort sind.
Mit
USBInHandle=HIDTxPacket(CUSTOM_DEVICE_HID_EP,uint8_t*)&ToSendDataBuffer[
0],64);
wird der Buffer dann zum Abholen für den Host freigegeben.
Volker S. schrieb:> Von wo jetzt genau ?> Der ganze Weg von der Generierung der Message bis zur GUI ?
Ja
Volker S. schrieb:> Läuft das bei deinem Projekt ähnlich ?
Ja
--> mein Projekt läuft sehr ähnlich.
z.B: Ich habe folgende:
1
switch(ReceivedDataBuffer[0]) //Look at the data the host sent, to see what kind of application specific command it sent.
2
{
3
case COMMAND_TOGGLE_LED: //Toggle LEDs command
4
LED_Toggle(LED_USB_DEVICE_HID_CUSTOM);
5
break;
6
case COMMAND_GET_BUTTON_STATUS: //Get push button state
7
//Check to make sure the endpoint/buffer is free before we modify the contents
8
if(!HIDTxHandleBusy(USBInHandle))
9
{
10
ToSendDataBuffer[0] = 0x81; //Echo back to the host PC the command we are fulfilling in the first uint8_t. In this case, the Get Pushbutton State command.
11
if(BUTTON_IsPressed(BUTTON_USB_DEVICE_HID_CUSTOM) == false) //pushbutton not pressed, pull up resistor on circuit board is pulling the PORT pin high
12
{
13
ToSendDataBuffer[1] = 0x01;
14
}
15
else //sw3 must be == 0, pushbutton is pressed and overpowering the pull up resistor
16
{
17
ToSendDataBuffer[1] = 0x00;
18
}
19
//Prepare the USB module to send the data packet to the host