Forum: Mikrocontroller und Digitale Elektronik PIC16F690 PWM Ansteuerung Drehzahl abhängig


von uCnewbie (Gast)


Lesenswert?

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!

von Bernd R. (Firma: Promaxx.net) (bigwumpus)


Lesenswert?

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

von uCnewbie (Gast)


Lesenswert?

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.

von Bernd R. (Firma: Promaxx.net) (bigwumpus)


Lesenswert?

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.

von uCnewbie (Gast)


Lesenswert?

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!!!!!!!!!!!!!!!!!!!!!!!!!!!!

von Bernd R. (Firma: Promaxx.net) (bigwumpus)


Lesenswert?

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 ?

von Bernd R. (Firma: Promaxx.net) (bigwumpus)


Lesenswert?

...
Bei Periode=TMR1H wird jetzt aber TMR1L sträflich vernachlässigt.

von uCnewbie (Gast)


Lesenswert?

Hasst Du einen Verbesserungsvorschlag für die Routine "interrupt"? Ich 
müsste diese bis Morgen zum laufen kriegen:(

von Martin S. (drunkenmunky)


Lesenswert?

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
Noch kein Account? Hier anmelden.