www.mikrocontroller.net

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


Autor: uCnewbie (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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!

Autor: Bernd Rüter (Firma: Promaxx.net) (bigwumpus)
Datum:

Bewertung
0 lesenswert
nicht 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...

Autor: uCnewbie (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Bernd Rüter (Firma: Promaxx.net) (bigwumpus)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: uCnewbie (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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
#include <pic.h>

__CONFIG(INTIO & WDTDIS & PWRTEN & MCLREN & UNPROTECT \
  & UNPROTECT & BORDIS & IESODIS & FCMDIS);

#define FOSC 8000000L

#define  _delay_us(x) { unsigned char us; \
           us = (x)/(12000000/FOSC)|1; \
           while(--us != 0) continue; }
 
int Periode;

void _delay_ms(unsigned int ms)
{
  unsigned char i;
  do {
    i = 4;
    do {
      _delay_us(164);
    } while(--i);
  } while(--ms);
}

_interrupt(void)
{ 
  
  if (INTF !=0)
  { 
   
  TMR1ON = 0;
    if((INTCON &TMR1IF)!= 0)
       {
        Periode = 65535;
       }
    else
       {
         Periode = TMR1H; 
       } 
        
        TMR1L = 0x00;
        TMR1H = 0x00;
        TMR1ON = 1; 
        TMR1IF = 0;             
          INTF = 0;           
  }

}

void main(void)
{
   
  TMR1IF  = 0;  
  T1CON   = 0b00000001;
  GIE     = 1;  
  PEIE   = 1;  
  TMR1IE   = 1;
    

  unsigned int ipwm;

  OSCCON=0x70;
  TRISC = 0x00;
  ANSEL = 0x00;
  ANSELH = 0x00;
  PORTC = 0x00;
  CCP1CON=0b00001100;
  CCPR1L=0;           
  T2CON=0b00000101;
  PR2=0x65;
  TMR2=0;

  PSTRCON=0b00000100;
   
  for(;;) {
    ipwm=30;
    GIE = 0; 
    INTE = 1;
    _interrupt();
    while (ipwm < 100 && Periode > 18 ) 
    { 
      CCPR1L = ++ipwm;
     _delay_ms(5);
      _interrupt();
    
    } 
     _delay_ms(2000);    
     CCPR1L = 0x00;                    
     _delay_ms(500);
      
  }
}

Vielen Dank für deine Hilfe schonmal!!!!!!!!!!!!!!!!!!!!!!!!!!!!

Autor: Bernd Rüter (Firma: Promaxx.net) (bigwumpus)
Datum:

Bewertung
0 lesenswert
nicht 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 ?

Autor: Bernd Rüter (Firma: Promaxx.net) (bigwumpus)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
...
Bei Periode=TMR1H wird jetzt aber TMR1L sträflich vernachlässigt.

Autor: uCnewbie (Gast)
Datum:

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

Autor: Martin S. (drunkenmunky)
Datum:

Bewertung
0 lesenswert
nicht 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.

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.