Hallo an die Communtie, ich mache/schreibe zur zeit meine BA. Meine Stärken liegen eigentlich eher in der Hardwareerstellung und weniger in der Softwareerstellung. Leider kommt man nicht mehr um den µ-Controler rum. Benutzen tu ich den PIC16F685 und den Hi-Tech Compiler. Von Assembler habe ich null Ahnung, aber einigermaßen in C. Mein Problem was ich jetzt habe ist folgendes, am Eingang RB7 soll ein Interrupt auf Fallender Flanke ausgelöst werden. Dann soll ein Zähler gestartet werden der von der ersten fallenden Flanke bis zur nächsten fallenden Flanke zählt. Meine Frage an euch, wie löse ich einen solchen Interrupt an diesem Eingang aus? Wie muss ich diese Interrupt routine programmieren? Ehrlich gesagt hab ich auf diesem Gebiet mit Interrupts null Ahnung. Mein Betreuer kann mir auch nicht helfen weil er nur Ahnung von Assembler hat. Also seit bitte Nachsichtig und so erklären das es ein Vollidiot wie ich es versteh.
Du musst halt zuerst alles so konfigurieren wie du es haben willst. Also z.B. u.a. den Interrupt-on-change an dem Port und alle Interrupts einschalten. Bei neueren PIC16 gibts verschiedene Flags für fallende und steigende Flanke, was die Erkennung etwas erleichtert. Weiß nicht ob es der auch hat. Ich würd dir sowieso empfehlen einen enhanced-midrange, also einen 16F1xxx zu nehmen. PIC16 haben ja eh nur eine Interruptpriorität und einen Interruptvektor. Das heißt du brauchst auch in C nur eine ISR. In der fragst du dann ab, wer den Interrupt ausgelöst hat. Kennzeichnen tust du die ISR bei Hi-Tech mit "interrpupt" von dem Funktionsnamen. Also z.B. so:
1 | void interrupt my_isr(void) |
2 | {
|
3 | /***** Timer 0 Code *****/
|
4 | if((TMR0IE)&&(TMR0IF)) |
5 | {
|
6 | TMR0IF = 0; |
7 | }
|
8 | }
|
Was studierst du eigentlich? Aber nicht Elektrotechnik, oder?
Optoelektronik studiere ich. Muss ich die Interruptroutine im Hauptprogramm aufrufen oder ist das eine Routine die im Hindergrund läuft?
Aufrufen musst du sie gar nicht. Wenn ein Interrupt ausgelöst wurde, wird sie automatisch aufgerufen. Sie läuft nicht im Hintergrund, sondern unterbricht dein laufendes Programm (deswegen heißt's auch interrupt ;-) )
Quigon schrieb: > Muss ich die Interruptroutine im Hauptprogramm aufrufen oder ist das > eine Routine die im Hindergrund läuft? Der Sinn und Zweck eines Interruptes ist, dass man sich im "Normalen" Betrieb nicht darum kümmern muss. Einfachstes Beispiel du möchtest einen Eingang auf das vorhandensein des High-Pegels testen: Möglichkeit 1 - du frägst ihn ständig ab. Das nennt man Polling. Wenn das die einzige Aufgabe des µCs ist dann ist das ok - wenn du aber noch viele andere Dinge zu tun hast, dann geht dir das auf die Nerven, da es immer Zeit kostet, die anderen Vorgänge aufhält und du unter Umständen ein Ereignis (Highpegel) verpasst, weil dein µC gerade etwas anderes Berechnet und den Eingang gerade nicht abfrägt. Schlecht. Möglichkeit 2 - der Interrupt. Der läuft immer im Hintergrund und löst und dann aus, wenn z.B. ein Pegelwechsel stattgefunden hat. Jetzt wird dein Hauptprogramm unterbrochen und in die sog. ISR (Interrupt Service Routine) gesprungen. Da kannst du jetzt auswerten, welcher Pegel sich geändert hat und ggf. die Information der Pegeländerung weiterverarbeiten, etc. Ist die ISR vorbei (=durchgelaufen) erfolgt ein Sprung ins Hauptprogramm an die Stelle wo der Ablauf durch den auftretenden Interrupt gestört / unterbrochen wurde. So nun zu deinem Problem: Einen Interrupt können verschiedene Quellen auslösen. Eine kleine Einführung findet sich hier für PIC16 - für andere PICs gilt das analog. http://www.sprut.de/electronic/pic/int/int.htm Interessant für dich sind die Eingänge die bei einem Pegelwechsel einen Interrupt auslösen. Entweder ist das ein ganzer/halber Port oder ein spez. Pin. Meist ist es RB0, können auch mehrere Pins sein. Wichtig ist, dass du dir das Datenblatt deines PICs herunterlädst (Mircochip.de) und dann mal aufmerksam die Sektion die mit INTERRUPTS betitelt ist durchliest. Da steht ganz genau drin, welche Pins Interruptfähig sind und ob sie auf positive oder negative Flanken oder auf jeden Pegelwechsel reagieren sollen und und und. Vieles aus der Sektion kannst du weglassen (Schnittstelleninterrupts, etc..) Viel Erfolg
Hallo vielen Dank an euch. Softwaretechnisch dürfte es kein problem mehr sein. Aber jetzt nochmal ne vorsichtige Frage, der Interrupt wird von einem Monoflop am RB7 Interrupt of Change ausgelöst. Das Problem an der Sache ist oder eher ein Verständnisproblem. Am RB7 liegt durch das Monoflop ein High Pegel an, der Interrupt soll durch das kurze Schalten vom Monoflop auf Low Pegel den Interrupt auslösen. Wird dadurch trotzdem der Interrupt am RB7 ausgelöst? Oder muss ich so wie ich es vermute den Ausgang meines Monoflops vertauschen das dann der Interrupt durch ein High Pegel ausgelöst wird.
Geht beides. Lehrmann Michael schrieb: > Da steht ganz genau drin, welche Pins Interruptfähig sind > und ob sie auf positive oder negative Flanken oder auf jeden > Pegelwechsel reagieren sollen und und und. Positive Flanke - Wechsel von Low auf High Negative Flanke - Wechsel von High auf Low
Ich hab grad mal geschaut. Bei dem alten Controller, den du verwenden willst, löst bei jedem Wechsel ein Interrupt aus. Dann muss du halt selbst feststellen, ob es eine postive oder negative Flanke war und dann angemessen darauf reagieren. Die neueren kann man so einstellen, dass nur bei einer negativen Flanke ein Interrupt ausgelöst wird. Das hat den Vorteil, dass dein Programm nicht unnötig durch postive Flanken unterbrochen wird und du nicht selber feststellen musst, ob es negative oder positive Flanke war. Kannst dir ja z.B. mal den 16F1938 anschauen...
Ok danke. Das habe ich jetzt soweit verstanden, muss ich in meiner Interruptroutine reinschreiben ob er auf fallender Flanke reagieren soll oder wird dies automatisch gemacht? Und dann mein letztes Problem und das ist wirklich ein Verständnisproblem, ich will ein "software zähler" starten. Der Zähler soll beim ersten Interrupt starten und soll beim darauffolgenden Interrupt stoppen. beim Zählen soll eine Zeitverzögerung integriert werden. Zähler natürlich über for (i==0; i==255; i++) wie bring ich den zähler dann dazu das er beim nächsten Interrupt abbricht und muss ich die Zeitverzögerung über eine zählschleife realiesieren? oder kann ich da einfach sleep(Zahl) Zahl ein wert natürlich, schreiben? Bevor die Frage kommt für was braucht man das :) dieser wert i wird/soll am Ende ins PWM vergleichsregister geschoben werden.
Die Antwort auf deine erste Frage steht schon in meinem letzten Post. Hier ist noch ein dicker Bock drin, ich denk du findest ihn von selbst: for (i==0; i==255; i++) Über was für Zeitspannen reden wir denn da ungefähr? Wo willst du den Zähler inkrementieren? In deinem Hauptprogramm? Es gibt für solche Aufgaben eine fertige Einheit, nennt sich Capture Module. Unter der Rubrik "Capture/Compare/PWM module".
Da bin ich leider etwas eingengt durch mein Betreuer/Chef. Der PIC16F685 ist fix. Ok du sagt das ich das selber überprüfen muss ob fallende oder steigender Flanke, blöde frage wie mach ich das. Der Zähler wird in einem Unterprogramm sein, weil er nur in einem Fall benutzt wird :) und dieser Fall dritt dann ein wenn es ums Dimmen von LEDs geht.
Also du willst die Zeit zwischen 2 negativen Flanken messen, richtig? Benötigst du den Timer 1 schon für etwas? Der 16F685 hat auch eine Capture Einheit. Die funktioniert so: -du stellst sie so ein, dass sie bei jeder fallende Flanke reagiert. -jetzt kopiert die Einheit jedes Mal, wenn sie eine negative Flanke detektiert, den Zählerstand (16-bit) in ein Register und setzt ein Interruptflag -den Stand speicherst du dir dann in einer Variable -beim nächsten Mal hast du dann zwei Werte. Neuer minus alter und du hast die Differenz -Die Prescaler von Timer 1 musst du halt passend einstellen
Also hab mir die Capture angeschaut. Da ich das PWM benutzen tu weil ich dieses ja auch brauch. Kann ich die Capture nicht mehr nutzen oder? weil wenn ich das trotzdem nutzen kann dann ist das eine tolle sache Und wie Funktioniert das mit der Flankenüberprüfung?
Martin S. schrieb: > Ich hab grad mal geschaut. Bei dem alten Controller, den du verwenden > willst, löst bei jedem Wechsel ein Interrupt aus. Dann muss du halt > selbst feststellen, ob es eine postive oder negative Flanke war und dann > angemessen darauf reagieren. > > Die neueren kann man so einstellen, dass nur bei einer negativen Flanke > ein Interrupt ausgelöst wird. Das hat den Vorteil, dass dein Programm > nicht unnötig durch postive Flanken unterbrochen wird und du nicht > selber feststellen musst, ob es negative oder positive Flanke war. Wenn der PIC16F685 fix ist, dann nimm das CCP (Capture/Compare/PWM) Modul. Ist zwar ein kleiner Missbrauch dessen - eignet sich aber hervorragend: http://ww1.microchip.com/downloads/en/devicedoc/41262a.pdf Datenblatt S. 116 11.1 Capture Mode In Capture mode, CCPR1H:CCPR1L captures the 16-bit value of the TMR1 register when an event occurs on pin RC5/CCP1/P1A. An event is defined as one of the following and is configured by CCP1CON<3:0>: • Every falling edge • Every rising edge • Every 4th rising edge • Every 16th rising edge When a capture is made, the interrupt request flag bit, CCP1IF (PIR1<2>), is set. The interrupt flag must be cleared in software. If another capture occurs before the value in register CCPR1 is read, the old captured value is overwritten by the new captured value. Also dein Eingangspin in RC5. Ein Capture wird nur gemacht, wenn das richtige Ereignis • Every falling edge • Every rising edge • Every 4th rising edge • Every 16th rising edge eintritt. Welches das richtige Ereignis ist wird im Register CCP1CON von den Bits 0 bis 3 bestimmt. Siehe Dateblatt. Nachdem der Capture nur bei dem richtigen Ereignis gemacht wird, wird auch der Interrupt für einen Capture nur beim richtigen Eregins gesetzt und entsprechend nur dann in die ISR gesprungen. Da hast du was du suchst. Quigon schrieb: > Und dann mein letztes Problem und das ist wirklich ein > Verständnisproblem, > ich will ein "software zähler" starten. Der Zähler soll beim ersten > Interrupt starten und soll beim darauffolgenden Interrupt stoppen. beim > Zählen soll eine Zeitverzögerung integriert werden. Dann schau dir das Capture-Modul weiter an: In Capture mode, CCPR1H:CCPR1L captures the 16-bit value of the TMR1 register when an event occurs on pin RC5/CCP1/P1A. Also dein Timer1 läuft ja permanent durch, zum Zeitpunkt des Interruptsauftretens wird dieser Wert in die beiden je 8 bit breiten Register CCPR1H und CCPR1L gesichert. 2x8bit = 16bit = max. Timerwert. Mit dem gesicherten Wert, kannst du dann weiterarbeiten, ihn als Basis verwenden oder was auch immer. Musst mal noch genauer beschreiben was die Aufgabenstellung ist.
Also der Pin ist bei mir ein Ausgang für das PWM. Was jetzt eh erstmal wichtig ist, ist der Interrupt das dieser Funktioniert. Da ich den RA2 Eingang noch frei habe, werde ich von meinem Ursprüngliche Eingang RB7 eine Leitung auf den RA EIngang legen. Und mit dem RA2 Eingang werd ich den Interrupt aufbauen. Soviel wie ich gelesen hab kann ich an diesem Eingang sehr gut mit dem Interrupt arbeiten. Den das Problem ist, es ist eine kleine Firma und im Prinzip arbeite ich schon mit einer fertigen Platine also das heist keine änderungen möglich. Hab schon davor zwei von den Prototypplatinen zwei kaputt gemacht. und wenn ich jetzt noch hergehe und des ganze layout umwerf, dann reist mir glaub mein chef den kopf ab :). Ja das hört sich nach verzweiflung an. Aber alle andere Programmteile funktionieren bis auf Interrupt und der Zähler. Kurze Verständnis wie das ganze funktionieren soll, also über das mono wird ein Interrupt ausgelöst. Der Zähler dient dazu wie schon gesagt zwischen den ersten und zweiten interrupt zu zählen mit jeweils einer zeitverzögerung. Dieser Wert wird soll dann ist PWM vergleichsregister geschoben werden und somit die LEDs dim up bzw. dim down. Aber auch dieser wert soll im eeprom gespeichert werden. Aber das sind alles einfache dinge die schon funktionieren bis auf zähler und interrupt halt :)
Quigon schrieb: > Der Zähler dient dazu wie schon gesagt > zwischen den ersten und zweiten interrupt zu zählen mit jeweils einer > zeitverzögerung. Dieser Wert wird soll dann ist PWM vergleichsregister > geschoben werden und somit die LEDs dim up bzw. dim down. Aber auch > dieser wert soll im eeprom gespeichert werden. Zu gut Deutsch: du brauchst die Zeit zwischen den beiden Interrupts? Okay das ist nicht soo schwer. Also du nimmst einen Timer und den Timerinterrupt. Durch diesen bekommst du eine Zeitbasis. Das heißt dein Timer (z.B. 8bit Timer -> siehe Sektion TIMER im Datenblatt) zählt (ohne dein Zutun) von 0 bis 255, immer wieder, unendlich lang. Jedesmal wenn der Timerwert bei 255 angelangt ist, geht es wieder bei 0 weiter. Diesen Sprung von 255 -> 0 nennt man Überlauf (das 8 bit Timerwertregister ist voll) und dieser ist eine Interruptquelle (siehe Sektion INTERRUPTS im Datenblatt). D.h. deine ISR wird auch im Falle eines Timerüberlaufes (255->0) ausgelöst. Das kann man insofern zuverlässig nutzen, dass (solange keine anderen nennenswerten / zeitintensiven Interrupts auftreten) so alle gewisse Zeitabstände der Timerüberlaufinterrupt auftritt (Timer hat von 0 bis 255 gezählt). Dies gibt dir eine Zeitbasis. Die TimerTickZeit (Zeit die der Timer zum erhöhen seines Wertes um den Wert 1 braucht, 0 -> 1 -> 2 -> 3 -> ....) ist in gewissen Grenzen einstellbar (siehe Sektion TIMER im Datenblatt). Wenn du also weißt wielange es dauert bis der Wert um 1 erhöht wurde, kannst du dir ausrechnen wie lange es dauert, bis ein Überlauf des Timers auftritt (256 x TimerTickZeit). In der ISR des Timerüberlaufes zählst du dann deine Variable (ich nenne sie time_count) jeweils um eines hoch: time_count++; Also dann der ganze Ablauf: erster Interrupt (in der ISR des I/O-Interrupts schauen, ob entsprechende Flanke auftaucht, etc) -> Timer nullen (Timerwert=0) -> Timerinterrupts aktivieren -> ersten Interrupt löschen nicht vergessen jetzt läuft die ISR des Timerinterrupts ständig duch, die Zählvariable time_count erhöht sich mit jedem Timerinterrupt. Währenddessen kann im Hauptprogramm ständig was passieren, diese wird ja immer unterbrochen, sobald ein Timerinterrupt auftritt. Was nicht sein sollte, ist dass noch andere Interrupts auftreten, da diese u.U dazu führen könnten, dass der Timerinterrupt nicht rechtzeitig bearbeitet wird (da gerade ein andere Interrupt aktiv ist). Abgesehen von dem zu erwartenden Interrupt für die nächste Flanke, der wird ja erst aktiv, wenn die Flanke auch auftaucht und dann ist die Timerinterrupt ja nichtmehr interessant. zweiter Interrupt ausgelöst durch die zweite Flanke des mono. Timerinterrupts deaktiveren (time_count kann somit nichtmehr erhöht werden). time_count "sichern" -> Wert in andere Variable geben. time_count wiede =0 setzen, Timerinterrupts wieder aktivieren, die nächste Zeitspanne wird gemessen. Wir erinnern uns, dass wir time_count vorhin gesichert hatten. Das ist enorm wichtig - wir wissen wie oft der Timerinterrupt aufgetaucht ist (time_count bzw. die Sicherung dessen verrät uns das) und wir wissen, wie lange es dauert, bis ein Timerinterrupt auftaucht. Druch die Anzahl der Timerüberlauf und die Zeit, wie lange es dauert, bis ein Überlauf zu Stande kam, wissen wir wieviel Zeit zwischen den beiden I/O-Interrupts (Flanken) vergangen ist. Das ist deine gesuchte Zeit. Die können wir dann z.B. im Hauptprogramm (bloss außerhalb der ISR) weiterverarbeiten. In der Zwischenzeit läuft bereits die nächste Messung bis zur nächsten Flanke, ...... .... hoffe geholfen zu haben
Interrupt Routine geschieben, Er macht nichts wenn ein interrupt ausgelöst wird. Hier der code #include <htc.h> #include <pic.h> #include <pic16f685.h> #include <math.h> #include <stdio.h> #ifndef _XTAL_FREQ // Unless specified elsewhere, 20MHz system frequency is assumed #define _XTAL_FREQ 20000000 #endif #define Hand !RC3 #define Auto RC3 #define DimUp !RC4 #define DimDown RC4 //********************************************************************** *********************************// //Globale Variabeln //Variable a ist Usereingestellte PWM Wert der Eingelesen wird vom EEPROM bzw. noch erstellt werden muuss //Variable c und z dienen zur Speicherung und Auslesen vom EEPROM //********************************************************************** *********************************// volatile char a; volatile unsigned char c,z; int i; long int j; void handfkt(void); void autofkt(void); void not(void); void pwm(void); void init() { //**********************************************************POR********* *********************************// //POR an PORT B IOCB = 0b11110000; PORTB = 0b00000000; TRISB = 0b11110000; //POR an PORT C ANSEL = 0b11111111; ANSELH = 0b00001111; CCP1CON = 0b00000000; PORTC = 0b00000000; TRISC = 0b11111111; //*********************************************************PORTINI****** *********************************// PORTA = 0b00111111; TRISA2 = 0b00111111; //PORTB TRISB = 0b11000000; PORTB = 0b11110000; //PORTC TRISC = 0b11011111; PORTC = 0b11111111; ANSEL = 0b00111111; ANSELH = 0b00000000; //PWM CCP1CON = 0b00001101; T2CON = 0b01111110; //Interrupt INTCON = 0b11011011; IOCB = 0b11110000; IOCA2 = 0b00111111; } void interrupt InterruptRutine(void) // Interruptroutine { char schalter; schalter=PORTC &0b00001000; GIE=0; if(INTF) { switch (schalter) { case 0: handfkt(); case 1: autofkt(); } INTF=0; // Flag zurücksetzen } } int main() { init(); turn:; INTEDG=0; // Fallende Flanke am RA2 GIE=1; // Interrupts erlauben INTE=1; goto turn; }
Wenn du den Eingang oderso verlegst, wieso nicht grad auf RB7? Musst du nicht noch IOCA2 aktivieren wenn du den IOC benutzten willst? Deine Programmierkünste lassen etwas noch etwas zu wünschen übrig... Quigon schrieb: > char schalter; > schalter=PORTC &0b00001000; > GIE=0; > > if(INTF) > { > switch (schalter) Wieso nicht einfach: switch (RB3) Quigon schrieb: > turn:; > > goto turn; so macht man in C keine Schleife, schreib lieber: while(1) { //Dauerschleife } Quigon schrieb: > INTEDG=0; // Fallende Flanke am RA2 > GIE=1; // Interrupts erlauben > INTE=1; Wieso machst du das ständig? Reicht doch einmal in der Initialisierung. Und wenn du die Interrupts bei einer ISR ausschalten willst, dann schalte sie einfach am Ende wieder an.
IOCA2 war ein verschreiber muss heisen IOCA GIE=1 hab ich in die Interrupt geschoben unter INF=0 das gleiche auch mit INTE=1 das INTEDG=0 in die ini jetzt steht nur noch in init(); while(1); und das programm hängt jetzt in main bei init() und reagiert auch nicht auf interrupt. Solangsam bekomm ich echt die krise mit dem .... nichts funktioniert. Und hab echt keinen schimmer mehr was ich machen soll.
Quigon schrieb: > #include <stdio.h> Himmel hilf ... das ist doch nicht dein Ernst oder? Wofür brauchst du StandartInputOutput in diesem Projekt? Quigon schrieb: > //********************************************************************** *********************************// > //Globale Variabeln > //Variable a ist Usereingestellte PWM Wert der Eingelesen wird vom > EEPROM bzw. noch erstellt werden muuss > //Variable c und z dienen zur Speicherung und Auslesen vom EEPROM > //********************************************************************** *********************************// > volatile char a; > > volatile unsigned char c,z; Alles was wir nicht brauchen wird im Fehlerfalle rausgenommen oder auskommentiert. Apropos - läuft der PIC überhaupts - kannst du das irgendwie Verifizieren? Wie siehts mit den Configbits aus? Was für welche hast du gewählt? Quigon schrieb: > IOCB = 0b11110000; > PORTB = 0b00000000; > TRISB = 0b11110000; Zuerst der TRIS, dann der PORT! Nähmen wir mal an, der Port wäre als Input konfiguriert. Dann schreibst du (recht sinnlos) das Register PORTB mit Nullen voll. Im nächsten Augenblick steht aber sofort wieder der Wert der am Port anliegt drin. Bevor od. Während du sagst ob Eingang oder Ausgang. Dann setzt du alles als Ausgang und siehe da im PortRegister steht das was am Port anlag und nicht deine 0. Quigon schrieb: > ANSEL = 0b11111111; > ANSELH = 0b00001111; Ich glaube nicht, dass du alle Eingänge als analoge Eingänge nutzen möchtest! Ist genau falsch. Datenblatt Seite 98: 1 = Analog input. Pin is assigned as analog input.(1) 0 = Digital I/O. Pin is assigned to port or special function. Note 1: Setting a pin to an analog input automatically disables the digital input circuitry, weak pull-ups, and interrupt-on-change if available. The corresponding TRIS bit must be set to Input mode in order to allow external control of the voltage on the pin. Man beachte Note1 !! Quigon schrieb: > PORTC = 0b00000000; > TRISC = 0b11111111; hatten wir schonmal den Fehler Quigon schrieb: > PORTA = 0b00111111; Willst du wirklich zuerst eine Kombination an den Ausgang legen? Was soll das werden? > TRISA2 = 0b00111111; Dieses Register gibt es nicht. Es gibt zwar glaube ich ein Bit mit dem Namen TRISA2 aber das meinst du nicht und es wäre nur ein Bit (1 oder 0) Das hier ist nix! Ich nehme an die "2" gehört weg. Eingänge / Ausgänge musst du selbst schauen, dass das passt. 1=Eingang , 0=Ausgang Quigon schrieb: > //PORTB > TRISB = 0b11000000; > PORTB = 0b11110000; > > //PORTC > > TRISC = 0b11011111; > PORTC = 0b11111111; > > ANSEL = 0b00111111; > ANSELH = 0b00000000; Und weils so schön war gleich mehrmal alles initaliseren - am besten auch nochmal falsch =) Quigon schrieb: > T2CON = 0b01111110; So jetzt wird spannend: Erzähl mal wie du das jetzt durchgerechnet hast - alle wieviel Zeiteinheiten bekommst du denn jetzt deinen Interrupt geliefert? Erzähl mal, nur damit wir sehen, dass du es verstanden hast. Quigon schrieb: > INTCON = 0b11011011; 1 = Enables all unmasked interrupts (OK) 1 = Enables all unmasked peripheral interrupts (OK) 0 = Disables the TMR0 interrupt (OK) 1 = Enables the RA2/INT external interrupt (Na wo hast du denn nun deinen Eingang eigentlich hingelegt) 1 = Enables the PORTA/PORTB change interrupt (OK) 0 = TMR0 register did not overflow 1 = The RA2/INT external interrupt occurred (must be cleared in software) (So du setzt also einfach mal dieses Bit und löst in der Software einen Interrupt aus ?! Was soll das?) 1 = When at least one of the PORTA or PORTB general purpose I/O pins changed state (must be cleared in software) (So du setzt also einfach mal dieses Bit und löst in der Software einen Interrupt aus ?! Was soll das?) Note 1: IOCA or IOCB register must also be enabled. Quigon schrieb: > IOCB = 0b11110000; Gleich mal alles einschalten?! Warum das - um möglichst viele Fehler von offenen Pins die undefinierte Zustände einnehmen zu bekommen ? Sinn? Quigon schrieb: > IOCA2 = 0b00111111; Schonwieder ein Regist das es nicht gibt. Das Bit IOCA2 gibt es zwar aber das kann man so nicht ansprechen! Das willst du auch nocht - du meinst IOCA - auch hier wieder ... hauptsache möglichst viele Interrupts anschalten? Sinn? Zweck? Nachgedacht? Quigon schrieb: > schalter=PORTC &0b00001000; Erklärung was das soll? Quigon schrieb: > GIE=0; Wenn du meinst .... Quigon schrieb: > if(INTF) Unterscheidest du garnicht von welcher Quelle (Timer, I/O, ... der Interrupt kommt)???? Also egal welcher Interrupt auftritt, z.B. der aktivierte Timerinterrupt, egal hauptsache ausführen ? Oo Quigon schrieb: > switch (schalter) > { > case 0: handfkt(); > case 1: autofkt(); > } Das kannst du dir sparen - Null wird das nie. Da ein paar Zeilen vorher: > schalter=PORTC &0b00001000; Quigon schrieb: > INTF=0; // Flag zurücksetzen Gut - Interrupt einschalten (GIE=1) hast du vergessen. GIE schaltet man auch eigentlich nicht ab ... außer es wäre notwendig. Quigon schrieb: > turn:; > > INTEDG=0; // Fallende Flanke am RA2 warum kommt das nicht in der Init ? > GIE=1; // Interrupts erlauben Lass das - einfach garnicht ausschalten - am besten einfach in der Init einmal an und fertig! > INTE=1; Bist du sicher, dass du so auf Bits zugereifen kannst? Sorry kenne Hitech nicht so gut. Eigentlich kann man nicht so einfach auf ein Bit zugreifen. Kann mich aber täuschen. Bei meinem C18 geht das so: INTCONbits.INTE = 1; > > > goto turn; Merke dir das eine Gesetz: Verwende NIE NIE NIE NIE NIE "Goto" in C und schon gleich NIE NIE NIE NIE NIE NIE NIE NIE NIE NIENIE NIE NIE NIE NIE NIE NIE NIE NIE NIE NIE NIE NIE NIE NIE NIE NIE NIE NIE NIE NIE NIE NIE NIE NIE wieder auf einem Mikrocontroller !!!! while(1){ ... } statt > turn:; turn: // kein ; !!!!! ... goto turn; Puuh hoffe geholfen zu haben
Also das ist das einzige positive an HI-TECH das du das PORTbits.... nicht brauchst. Ich glaube ich geh jetzt lieber mal zum Optiker und lass mir ne brille verschreiben man man .... Ich greif auf kein Timer zu. Aber wenn man den GIE auf Null setzt dann wird die Routine abgearbeitet ist das eigentlich nicht ein Vorteil? So werd es jetzt nochmal probieren.....
void init() { //**********************************************************POR********* *********************************// //POR an PORT B IOCB = 0b11110000; TRISB = 0b11110000; PORTB = 0b00000000; //POR an PORT C ANSEL = 0b00100000; ANSELH = 0b00000000; CCP1CON = 0b00000000; TRISC = 0b11111111; PORTC = 0b00000000; //*********************************************************PORTINI****** *********************************// TRISA = 0b00000100; PORTA = 0b00111111; //PORTB TRISB = 0b11000000; PORTB = 0b11110000; //PORTC TRISC = 0b11011111; PORTC = 0b11111111; ANSEL = 0b00111111; ANSELH = 0b00000000; //PWM CCP1CON = 0b00001101; T2CON = 0b01111110; //Interrupt INTCON = 0b11011011; IOCB = 0b11110000; IOCA = 0b00111111; INTEDG =0; GIE =1; } void interrupt isr() // Interruptroutine { char schalter; schalter=PORTC &0b00001000; if(INTF) { GIE=0; switch (schalter) { case 1: handfkt(); case 0: autofkt(); } INTF=0; // Flag zurücksetzen GIE=1; INTE=1; } } int main() { init(); while(1); } so siehts jetzt aus und auf interrupt reagiert er nicht...... Config bits setz ich über MPLAB
Wenn du eh nicht liest was man dir schreibt, wozu das dann überhaupt? Setz doch erst mal ALLES um, was mach dir so geschrieben hat!
Quigon schrieb: > Ich greif auf kein Timer zu. Quigon schrieb: > T2CON = 0b01111110; so dann schau mal nach, was für einen Zweck T2CON hat. Jetzt steht in der init() immernoch so viel Müll und immernoch alles doppelt. Ist es denn so schwer das mal zu bereinigen. Du hast ja keinerlei Übersicht - hätte ich auch nicht. Ich hab doch so gut wie zu jeder Zeile eine Anmerkung gemacht. Vielleicht denkst du mal drüber nach was ich da geschrieben habe und ziehst Konsequenzen daraus. Quigon schrieb: > Also das ist das einzige positive an HI-TECH das du das PORTbits.... > nicht brauchst. Asche auf mein Haupt - sorry .... Quigon schrieb: > Config bits setz ich über MPLAB Mir egal wo du sie setzt - wichtig ist welche du setzt. Läuft denn der PIC überhaupts an. KontrollLED dazuschalten, die einfach beim Programmstart angeht. Oder lass die LED angehen, wenn er zum ersten mal in die ISR springt, dann siehst du zumindest, ob überhaupts ein Interrupt auftritt. Vielleicht ist es ja auch ein Fehler in deiner Schaltung. Quigon schrieb: > void interrupt isr() // Interruptroutine > { Ist das überhaupts eine valide ISR in HiTech? Wie gesagt ich kenn den Compiler nicht. Wie sieht denn deine Beschaltung überhaupts jetzt aus? Ich glaube du verwendest RA2/INT als Interruptpin.
Ok machen wir es so wie in der Schule :( Stept by Step) das ist die Initialiesierung void init() { //**********************************************************POR********* *********************************// //POR an PORT B IOCB = 0b11110000; TRISB = 0b11110000; PORTB = 0b00000000; //POR an PORT C ANSEL = 0b00100000; ANSELH = 0b00000000; CCP1CON = 0b00000000; TRISC = 0b11111111; PORTC = 0b00000000; //*********************************************************PORTINI****** *********************************// TRISA = 0b00000100; PORTA = 0b00111111; //PORTB TRISB = 0b11000000; PORTB = 0b11110000; //PORTC TRISC = 0b11011111; PORTC = 0b11111111; ANSEL = 0b00111111; ANSELH = 0b00000000; //PWM CCP1CON = 0b00001101; T2CON = 0b01111110; //Interrupt INTCON = 0b11011000; IOCA = 0b00000000; IOCB = 0b00000000; INTEDG =0; GIE =1; } IOCA/IOCB brauch ich dann eigentlich nicht wenn ich am RA2 über das Monoflop einen Interrupt also extern auslöse oder sehe ich das grad falsch. Du kannst dir vorstellen ich drücke einen Schalter schalter drück monoflop senden kurzer low impuls. Schalter loslassen zweiter kurzer low impuls. Das heist ich kann den abstand zwischen interrupt1 und 2 frei varieren und dadurch das pwm bzw das dimmen regeln. Zum T2CON also dies ist der Timer für das PWM :) bit7 ist 0 über den bit6-3 stell ich den teiler ein für das pwm bit2 timer on bit1-0 der teiler für timer ist das soweit jetzt mal richtig? oder hab ich was überlesen?
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.