www.mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik mit pic18f4550 2 PWM signale getrennt erzeugen


Autor: Jonas Kiefer (johnnyk)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

habe einen PIC18f4550 mit 20MHz quarz.

Ich versuche mit diesem nun 2 voneinander unabhängig arbeitende 
PWM-Signale zu erzeugen. Die PWM Signale gehen auf einen L293d welcher 
wiederum 2 Motoren ansteuert (3v Gleichstrom). Durch das PWM will ich 
nun die Drehzahl der Motoren regeln allerdings unabhängig voneinander.
Wie erzeuge ich nun 2 voneinander unabhängige PWM Signale, welche ich 
allerding noch durch analoge Signale steuern kann (Fototransistoren).
Die Signale der 2 Sensoren habe ich bereits eingelesen über den pin a0 & 
a1.


Quellcode der sensoren:

void main(void)  // Beginn Hauptprogramm
{
ini();
    while(1)
    {
    sensorBan=an;

    if (ADCON0bits.GO_DONE==0)
    {
      sbr=ADRESH;


      ADCON0bits.CHS0=1;// schaltet AN0 ein (sensor boden rechts)
      ADCON0bits.GO_DONE=1;
    }

    Delay10KTCYx(1);

    if (ADCON0bits.GO_DONE==0)
    {
      sbl=ADRESH; // schaltet AN1 ein (sensor boden links)


      ADCON0bits.CHS0=0;
      ADCON0bits.GO_DONE=1;
    }

    Delay10KTCYx(1);

}



Ich hoffe mir kann jemand helfen.
mfg

Autor: Martin S. (drunkenmunky)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi,
hast du das Programm getestet? Wenn ja wie?

Du verwendest nur das High-Byte des Ergebnisses vom AD-Wandler. Hast du 
das Ergebnis linksbündig in ADRESH und ADRESL drinstehen?
Du verschenkst damit Auflösung. Lese doch beide Register aus und 
speichere sie dann in einer Variable, z.B. so
unsigned short sbr;
sbr = ( ADRESH << 8 ) | ADRESL;

Dazu muß es aber rechtsbündig drinstehen.

Zur PWM:
Der Controller hat doch 2 Hardware PWM Module. Diese musst du zuerst 
konfugieren  mit den richtigen Einstellungen wie z.B. Frequenz und so. 
Dann kannst du das PWM Verhältnis so wie du es willst in Abhängigkeit 
von deinen AD Werten immer wieder aktualisieren.

Im Datenblatt steht es relativ genau drinnen, wie man vorgehen muss.

Wenn du konkrete Fragen hast, schreibe wieder!

Autor: Jonas Kiefer (johnnyk)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Danke für die schnelle Antwort.

ich habe das ergebnis des ad linksbündig stehen und lese nur high aus.
Dass mit der Auflösung ist grundsätzlich eine gute idee allerdings sehe 
ich für meine zwecke keinen großen sinn darin. Die 2 sensoren sollen nur 
eine schwarze linie erkennen aber trotzdem danke schonma für diese idee 
vllt werde ich sie noch brauchen.

Ich habe mich schon durch das Datenblatt gekämpft allerdings komme ich 
da nicht weiter auf welcher seite steht es den beschrieben?

mfg

Autor: Martin S. (drunkenmunky)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Kapitel 15.4 PWM Mode (Seite 150)

Die Ausgänge sind dann CCP1 (RC2) und CPP2 (RC1 oder RB3).

Du hast ein "normales" PWM Modul, das nicht so kompliziert ist und ein 
enhanced PWM Module.

Aber steht alles drinnen:
15.4.4 SETUP FOR PWM OPERATION
The following steps should be taken when configuring
the CCPx module for PWM operation:
1. Set the PWM period by writing to the PR2
register.
2. Set the PWM duty cycle by writing to the
CCPRxL register and CCPxCON<5:4> bits.
3. Make the CCPx pin an output by clearing the
appropriate TRIS bit.
4. Set the TMR2 prescale value, then enable
Timer2 by writing to T2CON.
5. Configure the CCPx module for PWM operation.

des englischen solltest du schon halbwegs mächtig sein...

Autor: Martin S. (drunkenmunky)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
hab mir grad nochmal des Programm angeschaut. Für was sind die 
Wartezeiten? Wahrscheinlich dafür, dass die Wandlung sicher zu Ende ist, 
ode? Ist so nicht schön gemacht. Du kannst auch das GOnDone Bit so lange 
abfragen bis es wieder null ist und dann erst weiter gehen. So wie ich 
es gemacht hab. Nennt sich polling.
Noch schöner wäre es natürlich, wenn du das Ergebnis in einer Interrput 
Service Routine abspeicherst. Dann verbräts du nicht so viel Rechenzeit

void main(void)  // Beginn Hauptprogramm
{
ini();
    
while(1)
{
    sensorBan=an;          // ??

    ADCON0bits.CHS0=0;     // Kanal einstellen
    ADCON0bits.GO_DONE=1;  // Wandlung starten

    while (ADCON0bits.GO_DONE==0) continue;   // warten bis Wandlung fertig

    sbr=ADRESH; // Ergebnis speichern

    ADCON0bits.CHS0=1;     // Kanal wechseln
    ADCON0bits.GO_DONE=1;  // Wandlung starten

    while (ADCON0bits.GO_DONE==0) continue;   // warten bis Wandlung fertig

    sbl=ADRESH; // schaltet AN1 ein (sensor boden links)

}

Autor: Jonas Kiefer (johnnyk)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,
Hier mein Programm zur Erzeugung von PWM-Signalen an CCP1 pin RC0.
Aber wie bekomme ich jetzt parallel dazu an CCP2 pin RC1 ein weiteres 
PWM-Signal?
Über das CCPRxL Register kann ich ja jeweils die dc einstellen ?!?



void main(void)             // Beginn Hauptprogramm
{
TRISD=0x00;          //Port D ausgang (L293d ports)
TRISC=0x00;          //Port C ausgang (L293d enableports)

PORTB=0x00;          //Port B clear (8 LEDs)

PR2=0b11111111;       // maximale periodendauer

CCPR1L=0b00111111;      //dc ccp1 pin
CCPR2L=0b00111111;      //dc ccp2 pin


CCP1CON=0x0C;      //PWM Mode ausgewählt
CCP2CON=0x0C;      //PWM Mode ausgewählt

T2CON=0b01111001;    //1:16 prostscale, Timer 2 off, Prescale = 4
T2CONbits.TMR2ON = 1;   // Timer2 an

    while(1)
    {          //anfang dauerschleife

    vorM1();      //motor1 vorwärts


  while (TNR2==CCPR1L) continue;    //warten bis dc ccp1 erreicht

    einszweiEN=0;        //Motor 1 enabled RC0


  while (TNR2==PR2) continue;    //warten bis maximale periodendauer 
erreicht

    einszweiEN=1;        //Motor 1 disabled RC0

    }  //ende dauerschleife
}

Autor: Jonas Kiefer (johnnyk)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
hat keiner eine idee?

Autor: Martin S. (drunkenmunky)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
funktioniert denn schon der eine PWM Ausgang? Ich denke mal eher 
nicht...

Ich glaube du verstehst da was grundsätzlich falsch. Du hast eine 
Hardware PWM in diesem Controller, das heißt du stellst die notwendigen 
Register ein wie du sie haben willst und dann läuft die PWM "von 
alleine" ohne dass du ständig in der while(1) irgendwas dafür tun mußt. 
Die Frequenz läßt man ja meist konstant und ändert nur bei Bedarf in der 
while(1) Schleife den duty_cycle.

Über das CCPRxL und noch über 2 Bits im CCPXCON stellst du den 
duty_cycle ein (zusammen also 10-bit Auflösung). Du kannst auch nur über 
CCPRxL einstellen, hast dann halt nur 8 bit Auflösung.

und wenn du Code postest, dann alles. Es weiß keiner was hier gemacht 
wird:
vorM1();

Also, änder des erst mal ab und dann könnnen wir nach dem 2. PWM Ausgang 
schauen. Hast du die Möglichkeit des zu testen?

Autor: Jonas Kiefer (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,
also vorM1(); ist für euch nicht von Interesse. Da wird lediglich die 
Richtung der Motoren bestimmt.
Also ich habe es schon mal getestet die Motoren drehen unterschiedlich 
schnell --> Funktioniert

Jetzt bin ich aber nicht mehr weiter gekommen bei folgendem.
Ich habe 2 Sensoren die über die 2 Eingänge A0 & A1 angeschlossen sind. 
Die Werte werden Analog ausgelesen und dann in einem 8 Bit Register 
gespeichert soweit richtig?

Jetzt ist das CCPRxL Register auch 8 Bit lang. Ich habe versucht die 
werte die mir der AD-Wandler liefert direkt in die CCPRxL Register zu 
schreiben leider nimmt er diese nicht an.


Hier mal der Quelltext:
void ini (void)
{
ADCON1=0b00001101;      // AN0 & AN1 Analog

TRISA=0xFF;          // PortA eingang
TRISB=0x00;          // PortB ausgang
TRISD=0x00;          // PortD ausgang
TRISC=0x00;          // PortC ausgang

PORTB=0x00;          // PortB gelöscht

PR2=0xFF;           // Maxiamale Periodendauer

CCPR1L=0b01010111;      // dc RC2-Pin Startwert
CCPR2L=0b01010111;      // dc RC1-Pin Startwert

CCP1CON=0b00111111;      // PWM Mode ausgewählt
CCP2CON=0b00111111;      // PWM Mode ausgewählt

T2CON=0b00000100;      // Timer 2 an, Vorteiler = 4

sensorBan=an;        // Sensoren Boden an (Transistor)
vorM1();          // motor1 vorwärts
vorM2();          // motor2 vorwärts

}

void main(void)                         // Beginn Hauptprogramm
{
ini();                        // aufruf der initialisierung;

    while(1)
    {                      // anfang dauerschleife

      ADCON0bits.CHS0==0;            // Kanal einstellen
      ADCON0bits.GO_DONE=1;          // Wandlung starten

       while (ADCON0bits.GO_DONE==0) continue;    // warten bis Wandlung fertig
    
      sbr=ADRESH;                // Ergebnis speichern
      PORTB=sbl;                // ausgabe der binärzahl an LED0..7
      CCPR1L=ADRESH;              // dc für Motor2 anpassen
        

      ADCON0bits.CHS0=1;            // Kanal einstellen
      ADCON0bits.GO_DONE=1;          // Wandlung starten
    
    while (ADCON0bits.GO_DONE==0) continue;   // warten bis Wandlung fertig
    
      sbl=ADRESH;               // Ergebnis speichern
      PORTB=sbl;                // ausgabe der binärzahl an LED0..7
      CCPR2L=ADRESH;              // dc für Motor1 anpassen

    }                      // ende dauerschleife
}

Autor: Martin S. (drunkenmunky)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Jonas Kiefer schrieb:
> ADCON0bits.CHS0==0;            // Kanal einstellen

da ist wohl ein = zuviel. Dann stellt er den Kanal 0 nicht ein.

Ansonsten sieht auf den ersten Blick richtig aus.

Der zweite Motor hat auch nicht funktioniert? Mit der Ausgabe, die du 
gemacht hast, kannst du ja sehen ob die AD-Wandlung richtig 
funktioniert.

Mit welchen Gerät programmierst du?

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.