Hallo Allerseits, bin recht neu auf dem Gebiet der PIC's und hätte diesbezüglich mal eine Frage, ich steuere ein Motor durch einen PWM Signal von einem PIC16F690, bzw. durch Erhöhung der Duty-cycle bis zu 90% und danach schalte ich diesen direkt aus zu 0% und das immer wieder, der Motor und der PIC werden durch LiIon Batterien betrieben. Der Motor hat zusätzlich zum PWM Eingang noch einen Drehzahlausgang. Ich will diesen benützen um zu erkennen wann ne bestimmte Drehzahl erreicht ist, bei welcher der Motor ausgeschaltet werden soll, damit ich so auch die Batterien verschohne. Für den PWM Ausgang benütze ich schon den Port C und den Timer2 bei dem internen 8 Mhz Resonator. Habt Ihr ne Idee wie ich gleichzeitig auch den Timer0 benützen könnte und die Capture-Compare Einheit vom Port A? Ich danke euch schonmal im voraus!
Hallo, der 16F690 ist schon eine gute Wahl, der ist wenigstens nicht mega-alt... Du bringst da ein paar Begriffe etwas durcheinander. Für die PWM benutzt Du nicht den Port C - Du nutzt das "enhanced Capture/Compare/PWM Modul", dessen Ausgänge auf Pins von Port C geschaltet sind, wenn das Modul aktiviert wird. Das PWM-Modul benutzt Timer2 als Zeitbasis. Port A hat gar keine Capture-Compare-Einheit. Diese eine Einheit hast Du schon für das PWM genutzt. Was für ein Signal bekommst Du denn für die Drehzahl ? Man könnte diese Takte mit Timer0 zählen lassen und mit Timer1 eine z.B. 0,1s Zeitbasis o.ä. schaffen, wo dann in einer Interrupt-Routine Timer0 immer ausgelesen wird...
Danke für die schnelle Antwort, das Drehzahlsignal ist ein frequenzmodulierter Rechtecksignal wo die Frequenz direkt von der Periodendauer ablesbar ist. Sollte dann der Timer0 als counter eingestellt werden und asynchron zum Takt zählen und der Timer1 als ein timer? Meine Frequenz ändert sich ja ständig und ich will das mein Motor bei einer Drehzahl höher als 1kHz abschaltet.
Du nutzt das einzige Compare-etc-Modul für das PWM, das ist OK. Dann bleibt aber nichts mehr übrig. Ich würde da folgendes machen: Timer1 wird von OSC/4 gespeist. Das Drehzahl-Signal kommt auf einen Eingang, der einen Interrupt-On-Change macht, am besten INT0 (da spart man weitere Arbeit). Wenn das Signal High geht, wird ein IRQ ausgelöst. Timer 1 stoppen. In dem IRQ wird den Inhalt von Timer1 als Länge der Periode gespeichert. Ist allerdings Timer1IF gesetzt, ist Timer1 übergelaufen - Periode=65535! Anschließend wird Timer1 gelöscht. Timer1 starten. Timer1IF löschen. Das Hauptprogramm wertet dann die Timer1-Kopie aus und wartet auf den Wert 2000... (vor der Abfrage GIE löschen und danach wieder setzen um Änderungen von Highbyte/Lowbyte während der Abfrage zu vermeiden.) Ich schreibe solche Programme i.d.R. immer in 3 Teilen: -Init-Teil, der die Funktionseinheiten einstellt, -Interrupt-Routinen, die schnell auf die IRQs der Funktionsmodule reagieren, -Hauptprogramm in Endless-Loop, das die Werte der Int-Routinen auswertet. Ist alles kein großes Ding, man muß sich mal mit IRQs und Assembler auseinandersetzen. Alle Variablen, die die Int-Routinen benutzen lege ich in Page0, die Hardware-Register liegen da oft schon, dann ist das Banking nicht ganz so schwierig. Den Rest schreibe ich in Basic, das geht am schnellsten.
Hilfe! ich habe es logisch versucht und bin jetzt schlussendlich am rumprobieren. Die Interrupt routine macht nicht reproduzierbare Abbrüche der Main-Schleife. Bin am Ende mit meinem Latein. Anbei das Programm
1 | #include <pic.h> |
2 | |
3 | __CONFIG(INTIO & WDTDIS & PWRTEN & MCLREN & UNPROTECT \ |
4 | & UNPROTECT & BORDIS & IESODIS & FCMDIS); |
5 | |
6 | #define FOSC 8000000L
|
7 | |
8 | #define _delay_us(x) { unsigned char us; \
|
9 | us = (x)/(12000000/FOSC)|1; \
|
10 | while(--us != 0) continue; }
|
11 | |
12 | int Periode; |
13 | |
14 | void _delay_ms(unsigned int ms) |
15 | {
|
16 | unsigned char i; |
17 | do { |
18 | i = 4; |
19 | do { |
20 | _delay_us(164); |
21 | } while(--i); |
22 | } while(--ms); |
23 | }
|
24 | |
25 | _interrupt(void) |
26 | {
|
27 | |
28 | if (INTF !=0) |
29 | {
|
30 | |
31 | TMR1ON = 0; |
32 | if((INTCON &TMR1IF)!= 0) |
33 | {
|
34 | Periode = 65535; |
35 | }
|
36 | else
|
37 | {
|
38 | Periode = TMR1H; |
39 | }
|
40 | |
41 | TMR1L = 0x00; |
42 | TMR1H = 0x00; |
43 | TMR1ON = 1; |
44 | TMR1IF = 0; |
45 | INTF = 0; |
46 | }
|
47 | |
48 | }
|
49 | |
50 | void main(void) |
51 | {
|
52 | |
53 | TMR1IF = 0; |
54 | T1CON = 0b00000001; |
55 | GIE = 1; |
56 | PEIE = 1; |
57 | TMR1IE = 1; |
58 | |
59 | |
60 | unsigned int ipwm; |
61 | |
62 | OSCCON=0x70; |
63 | TRISC = 0x00; |
64 | ANSEL = 0x00; |
65 | ANSELH = 0x00; |
66 | PORTC = 0x00; |
67 | CCP1CON=0b00001100; |
68 | CCPR1L=0; |
69 | T2CON=0b00000101; |
70 | PR2=0x65; |
71 | TMR2=0; |
72 | |
73 | PSTRCON=0b00000100; |
74 | |
75 | for(;;) { |
76 | ipwm=30; |
77 | GIE = 0; |
78 | INTE = 1; |
79 | _interrupt(); |
80 | while (ipwm < 100 && Periode > 18 ) |
81 | {
|
82 | CCPR1L = ++ipwm; |
83 | _delay_ms(5); |
84 | _interrupt(); |
85 | |
86 | }
|
87 | _delay_ms(2000); |
88 | CCPR1L = 0x00; |
89 | _delay_ms(500); |
90 | |
91 | }
|
92 | }
|
Vielen Dank für deine Hilfe schonmal!!!!!!!!!!!!!!!!!!!!!!!!!!!!
Da sieht man mal wieder, wie man mit C derart unlesbaren Code erzeugt... Die Routine "interrupt" ist jetzt aber eher ein Unterprogramm als das es eine Interrupt-Service-Routine ist - oder ?
... Bei Periode=TMR1H wird jetzt aber TMR1L sträflich vernachlässigt.
Hasst Du einen Verbesserungsvorschlag für die Routine "interrupt"? Ich müsste diese bis Morgen zum laufen kriegen:(
Weißt du denn überhaupt was ein Interrupt ist? Ich denke nicht... Ein Interruptfunktion ruft man nicht selber auf, sie wird automatisch aufgerufen, wenn ein bestimmtes Ereignis auftritt.
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.