Forum: Mikrocontroller und Digitale Elektronik PIC18F87K22 Timer/Counter und PWM Problem


von Georg D. (georgdonner)


Angehängte Dateien:

Lesenswert?

Hallo,
ich habe folgendes Problem und bin schon echt am verzweifeln mit dem 
PIC.

Vorgeschichte:

Ich habe für ein elektrisches Einziehfahrwerk für einen Modelljet (11kg 
schwer) eine Steuerungselektronik gebaut. Die Motoren der Fahrwerke 
verfügen über magnetische Encoder um die Lage der Fahrwerksbeine zu 
bestimmen. Die Impulse der Encoder werden über die Timer 0, 3 und 5 
gezählt. Beim Referenzieren fahren die Beine auf Anschlag und schalten 
mittels Überstrom ab. Die dabei gezählten Impulse werden gespeichert.

Über das ECCP1 wird das Fernsteuerungssignal ausgewertet und das 
Fahrwerk fährt entweder ein oder aus. Zur Ansteuerung der 3 Motoren 
verwende ich drei VNH5180 Motortreiber. Diese besitzen einen PWM-Eingang 
der jeweils mit einem CCP-Modul (CCP 7, 8, 9) verbunden ist. Die 
Geschwindigkeit (Einschaltdauer des PWM-Signals) kann in einem Menü für 
jedes Fahrwerksbein separat eingestellt werden.


Problem:

Die Abschaltung der Fahrwerksbeine mit den gezählten Impulsen 
funktioniert nur korrekt, wenn die Einschaltzeit 100% beträgt. Sobald 
für den Ausgang 2 und einen anderen Ausgang die Einschaltzeit des PWM 
geringer ist schaltet der Timer 3 (zählt die Impulse des Motor2) zu früh 
ab. Je geringer die Einschaltdauer ist, desto früher kommt es beim Timer 
3 zu einem Interrupt, der die Motoren stoppt. Wenn ich nur bei einem 
Fahrwerksbein ein PWM-Signal einstelle so funktioniert auch alles. Der 
Fehler tritt nur beim Ausgang 2 auf, wenn auch bei einem zweiten Ausgang 
die Einschaltdauer geringer ist.

Ich habe leider keine Ahnung, woher der Fehler kommt.
Ich hoffe, dass mir jemand eine Tipp geben kann, um das Problem zu 
lösen.

Zur Programmierung des PICs verwende ich MPLAB X mit dem XC8 Compiler in 
der 60 Tage Pro Version.

Anbei ein Foto des Fahrwerks mit dem Teststand und der betroffene Teil 
des Quellcodes.

Vielen Dank für eure Hilfe.


High Interrupt
1
#include "Definition.h"
2
3
4
void interrupt high_isr(void)
5
{
6
    if(TMR0IE == 1 && TMR0IF == 1)
7
    {
8
        TMR0IF = 0;     //Flag lösche
9
        INA1 = 0;       //Motor stoppen
10
        INB1 = 0;
11
        motor1 = 0;     //Variable für Motor = 0 => Motor ausgeschaltn
12
        CCPR7L = 200;   //PWM auf 100% für die Bremsung
13
        if(Richt == 1)  //Wenn die Richtung = 1 = Ausfahren => Enpostion = 0 = Ausgefahren
14
            F1pos = 0;
15
        if(Richt == 0)  //Wenn die Richtung = 0 = Einfahren => Enpostion = 2 = Eingefahren
16
             F1pos = 2;
17
        CuError1 = 0;   //Überttromfehler keiner
18
        savep++;        //Endpostion im main speichern, wenn alle Fahrwerk in Endpostion
19
        return;
20
    }
21
22
    if(TMR3IE == 1 && TMR3IF == 1)
23
    {
24
        TMR3IF = 0;
25
        INA2 = 0;
26
        INB2 = 0;
27
        motor2 = 0;
28
        CCPR8L = 200;
29
        if(Richt == 1)
30
            F2pos = 0;
31
        if(Richt == 0)
32
            F2pos = 2;
33
        T3CONbits.TMR3ON = 0;
34
        CuError2 = 0;
35
        savep++;
36
        return;
37
    }
38
39
    if(TMR5IE == 1 && TMR5IF == 1)
40
    {
41
        TMR5IF = 0;
42
        INA3 = 0;
43
        INB3 = 0;
44
        motor3 = 0;
45
        CCPR9L = 200;
46
        if(Richt == 1)
47
            F3pos = 0;
48
        if(Richt == 0)
49
            F3pos = 2;
50
        T5CONbits.TMR5ON = 0;
51
        CuError3 = 0;
52
        savep++;
53
        return;
54
    }
55
}



Timer- und CCP-Einstellungen
1
    //Interrupt-Einstellungen
2
    INTCON = 0b11100000;    //TMR0-Interrupt eingeschalten
3
    INTCON2 = 0b10000100;   //TMR0-Interrupt High priority
4
    INTCON3 = 0b00000000;   //External Interrupts = 0 => unwichtig
5
    PIR1 = 0;               //Flag bits = 0
6
    PIR2 = 0;               //Flag bits = 0
7
    PIR3 = 0;               //Flag bits = 0
8
    PIR4 = 0;               //Flag bits = 0
9
    PIR5 = 0;               //Flag bits = 0
10
    PIR6 = 0;               //Flag bits = 0
11
    PIE1 = 0b01000000;      //ADC-Interrupt
12
    PIE2 = 0b00000010;      //TMR3-Interrupt eingeschalten
13
    PIE3 = 0b00000110;      //Interrupt für ECCP1 und ECCP2 eingeschalten
14
    PIE4 = 0b00000001;      //Interrupt Enable bits = 0
15
    PIE5 = 0b00000011;      //TMR5- & TMR4-Interrupt eingeschalten
16
    PIE6 = 0;               //Interrupt Enable bits = 0
17
    IPR1 = 0;               //Alle diese Interrupts haben Low priority
18
    IPR2 = 0b00000010;      //TMR3-Interrupt High priority
19
    IPR3 = 0;               //Alle diese Interrupts (ECCP1 und ECCP2) haben Low priority
20
    IPR4 = 0;               //Alle diese Interrupts haben Low priority
21
    IPR5 = 0b00000010;      //TMR5-Interrupt High priority
22
    IPR6 = 0;               //Alle diese Interrupts haben Low priority
23
    RCONbits.IPEN = 1;      //Priority levels sind aktiviert
24
25
26
    //ADC
27
    ANCON1bits.ANSEL9 = 1;  //RF4 als analoger Eingang
28
    ANCON2bits.ANSEL18 = 1; //RG2 als analoger Eingang (ISENSE3)
29
    ANCON2bits.ANSEL20 = 1; //RH3 als analoger Eingang (ISENSE2)
30
    ANCON2bits.ANSEL23 = 1; //RH0 als analoger Eingang (ISENSE1)
31
    ADCON1 = 0b01110000;    //Special trigger: CTMU; VREF+: 4,096V; VREF-: Masse; Neg. Chanel: Masse;
32
    ADCON2 = 0b10001101;    //Right; ACQU: 2xTAD; FOSC/16
33
34
35
    //Counter-Einstellungen
36
    T0CON = 0b00101000;     //TMR0: Stop, 16-Bit, T0CKI, kein Prescaler
37
    T3GCON = 0b00000000;    //TMR3: Gate-Funktionen ausgeschalten
38
    T3CON = 0b10000110;     //TMR3: Stop, 16-Bit-Mode, nicht synchronisieren, T3CKl, Prescaler 1:1, Signale von T3CKl
39
    T5GCON = 0b00000000;    //TMR5: Gate-Funktionen ausgeschalten
40
    T5CON = 0b10000110;     //TMR5: Stop, 16-Bit-Mode, nicht synchronisieren, T5CKl, Prescaler 1:1, Signale von T5CKl
41
42
43
    //Timer-Einstellungen
44
    T1CON = 0b00000011;     //TMR1: Instruction Clock, Prescaler 1:1, 16Bit-Mode
45
    T1GCON = 0;             //Gate Control ausgeschalten
46
    T2CON = 0b00000100;     //TMR2 eingeschalten, Prescaler 1:1
47
    PR2 = 199;              //TMR2 auf 20kHz eingestellt
48
49
    T4CON = 0b01111111;     //TMR4: Postscaler: 1:16; Prescaler: 1:16, TMR4: ON
50
    PR4 = 156;              //=> 0,25ns*16*16*156=9984ns => ~10ms gibt es einen Interrupt
51
52
53
    //Capture-Einstellungen
54
    CCPTMRS0 = 0;           //Alle ECCP Timer 1
55
    CCP1CON = 0b00000100;   //Capture eingestellt, steigende Flanke
56
    
57
58
    //PWM-Einstellungen
59
    CCPTMRS1 = 0b00000000;  //CCP4-7: TMR1/TMR2
60
    CCPTMRS2 = 0b00010000;  //CCP8-9: TMR1/TMR2; CCP10: TMR7/TMR2


Impulse in Register schreiben und Motoren starten
1
        //Ausfahren des Fahrwerks
2
        if((1000 <= imp1alt && imp1alt <= 1495 && 1000 <= imp1neu && imp1neu <= 1495 && VBATlow == 0) || VBATlow == 1)  //Nur ausfahren, wenn der neu under alte Impuls im selben Bereich liegen
3
        {                                                                                                               //Fahrwerk ausfahren, wenn die Akkuspannung zu gering ist
4
            if(F1pos == 2 && F2pos == 2 && F3pos == 2)      //Vorgang nur starten, wenn das Fahrwerk in der Enposition "Eingefahren" ist
5
            {
6
                TMR0H = F1impH;                 //Impulse in die Timer schreiben
7
                TMR0L = F1impL;
8
                TMR3H = F2impH;
9
                TMR3L = F2impL;
10
                TMR5H = F3impH;
11
                TMR5L = F3impL;
12
13
                eeprom_write(0x00, 1);          //Fahrwerk befindet sich in keiner Endpostion
14
                F3pos = F2pos = F1pos = 1;
15
                Richt = 1;                      //Richt => Ausfahren
16
17
                CCPR7L = 100 + 10 * runos1;     //Einschaltdeur der PWMs festlegen
18
                CCPR8L = 100 + 10 * runos2;
19
                CCPR9L = 100 + 10 * runos3;
20
21
                CCP7CON = 0b00001100;   //PWM7 eingeschalten (Motor 1)
22
                CCP8CON = 0b00001100;   //PWM8 eingeschalten (Motor 2)
23
                CCP9CON = 0b00001100;   //PWM9 eingeschalten (Motor 3)
24
25
                T0CONbits.TMR0ON = 1;   //Timer0 einschalten
26
                motorausf(1);
27
28
                T3CONbits.TMR3ON = 1;   //Timer3 einschalten
29
                motorausf(2);
30
31
                T5CONbits.TMR5ON = 1;   //Timer5 einschalten
32
                motorausf(3);
33
34
                Anlauf = 1;
35
                PWM = 1;
36
37
                WriteIns(0x80);
38
                WriteBuch('R'); //R
39
                WriteBuch('u'); //u
40
                WriteBuch('n'); //n
41
                WriteBuch('-'); //Space
42
                WriteBuch('O'); //O
43
                WriteBuch('u'); //u
44
                WriteBuch('t'); //t
45
                WriteBuch(' '); //Space
46
            }
47
        }
48
49
50
//----------------------------------------------------------------------------------------------------
51
//----------------------------------------------------------------------------------------------------
52
53
        //Einfahren des Fahrwerks
54
        if(1505 <= imp1alt && imp1alt <= 2000 && 1505 <= imp1neu && imp1neu <= 2000  && VBATlow == 0)
55
        {
56
            if(F1pos == 0 && F2pos == 0 && F3pos == 0)  //Vorgang nur starten, wenn das Fahrwerk in der Enposition "Ausgefahren" ist
57
            {
58
                TMR0H = F1impH;
59
                TMR0L = F1impL;
60
                TMR3H = F2impH;
61
                TMR3L = F2impL;
62
                TMR5H = F3impH;
63
                TMR5L = F3impL;
64
65
                eeprom_write(0x00, 1);
66
                F3pos = F2pos = F1pos = 1;
67
                Richt = 0;
68
69
                CCPR7L = 100 + 10 * runis1;
70
                CCPR8L = 100 + 10 * runis2;
71
                CCPR9L = 100 + 10 * runis3;
72
73
                CCP7CON = 0b00001100;   //PWM1 eingeschalten
74
                CCP8CON = 0b00001100;   //PWM2 eingeschalten
75
                CCP9CON = 0b00001100;   //PWM3 eingeschalten
76
77
                T0CONbits.TMR0ON = 1;   //Timer0 einschalten
78
                motoreinf(1);
79
80
                T3CONbits.TMR3ON = 1;   //Timer3 einschalten
81
                motoreinf(2);
82
83
                T5CONbits.TMR5ON = 1;   //Timer5 einschalten
84
                motoreinf(3);
85
86
                Anlauf = 1;
87
                PWM = 1;
88
89
                WriteIns(0x80);
90
                WriteBuch('R'); //R
91
                WriteBuch('u'); //u
92
                WriteBuch('n'); //n
93
                WriteBuch('-'); //Space
94
                WriteBuch('I'); //I
95
                WriteBuch('n'); //n
96
                WriteBuch(' '); //Space
97
                WriteBuch(' '); //Space
98
            }
99
        }
100
101
        
102
//------------------------------------------------------------------------------------------------------------
103
//------------------------------------------------------------------------------------------------------------
104
105
        Ueberstromabschaltung();
106
107
        if(motor1 == 0 && motor2 == 0 && motor3 == 0 && PWM == 1)
108
        {
109
            PWM = 0;
110
            __delay_ms(40);
111
            CCP7CON = 0;
112
            CCP8CON = 0;
113
            CCP9CON = 0;
114
        }

von Max H. (hartl192)


Lesenswert?

Georg Donner schrieb:
> P1030957.JPG
> 5 MB, 0 Downloads
> P1030961.JPG
> 5 MB, 0 Downloads
Bildformate

von Georg D. (georgdonner)


Lesenswert?

Sorry.
Wie kann ich die Fotos ändern?

von Georg D. (georgdonner)


Lesenswert?

Bitte diesen Thread löschen. Ich habe einen neuen eröffnet, in dem die 
Fotos das richtige Format haben.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Ich sehe keinen neuen Thread von dir, und ich hatte sie dann sowieso
schon runterskaliert.  Also eigentlich könnte es hier dann zu Sache
kommen.

von Georg D. (georgdonner)


Lesenswert?

Okay, vielen Dank.

von Carsten M. (ccp1con)


Lesenswert?

Na da hast du dir ja einen mega PIC ausgesucht!

Deine ISR ist nicht als high oder low gekennzeichnet. Ich weiß nicht, 
was der Compiler daraus macht. Better to tell him:
1
void interrupt high_priority your_ISR(void)
2
{
3
}
4
5
void interrupt low_priority your_low_ISR(void)
6
{
7
}

gibt es eine zweite ISR?
was machen TMR1 und TMR4?
die returns in der ISR sind unnötig und könnten stören.

von Georg D. (georgdonner)


Lesenswert?

Hallo,
vielen Dank für deine Hilfe Carsten. Leier haben deine Vorschläge keine 
merkliche Verbesserung gebracht.

Den Timer 1 verwendet das ECCP1 Modul zum Auswerten der Pulsbreite des 
Empfängersignals. Den Timer 4 habe ich verwendet, um alle 250ms eine 
Messung des ADCs (Akkuspannung) auszulösen. Der TMR4 löst alle 10ms 
einen Low Interrupt aus und erhöht die Variable mess. Wenn die Variable 
mess den Wert 25 erreicht wird eine Messung der Akkuspannung im main 
gestartet.

Es gibt eine zweite ISR, diese habe ich richtig mit "interrupt 
low_priority ..." gekennzeichnet gehabt. Bei der High ISR habe ich das, 
wie von dir vorgeschlagen umgeändert. Ich konnte aber den Tests keinen 
Unterschied erkennen.
In der Low-ISR wird das Signal der Fernsteuerung ausgewertet, der TMR4 
Interrupt verarbeitet und der ADC Interrupt.

Die "returns" habe ich hingeschrieben, weil es in der Hilfe von MPLAB X 
auch so geschrieben wird. Ich habe die returns für die Tests einmal 
weggelassen, aber es gab keine Änderung.

Weiters habe ich bei Tests den verschiedenen CCP-Modulen 
unterschiedliche Timer zugeteilt (CCP7 -> TMR2; CCP8 -> TMR6; CCP9 -> 
TMR4). Für die Tests habe ich für die Messung der Akkuspannung (alle 
250ms) den TMR4 durch den TMR12 ersetzt, um ihn für das CCP9 frei zu 
bekommen. Bei diesen Tests habe ich eine deutliche Verbesserung 
feststellen können. Das Fahrwerk am Ausgang 2 fuhr, wenn das PWM 
eingeschalten war, zwar noch immer nicht exakt in die Endposition und 
schaltete zu früh ab, allerdings fuhr es jetzt weiter als vorher.

Nochmals vielen Dank für deine Hilfe, aber leider hält sich das Problem 
hartnäckig.

mfg
Georg Donner


1
#include "Definition.h"
2
3
void interrupt low_priority isr_low(void)
4
{
5
    if(CCP1IE == 1 && CCP1IF == 1)
6
    {
7
        capalt1 = capneu1;
8
        capneu1 = CCPR1H;
9
        capneu1 = capneu1 << 8;
10
        capneu1 = capneu1 + CCPR1L;
11
12
        if(CCP1M0 == 0)
13
        {
14
            imp1alt = imp1neu;
15
            if(capneu1 > capalt1)
16
                imp1neu = ((capneu1 - capalt1) / 4)+14;
17
            if(capneu1 < capalt1)
18
                imp1neu = ((65536 - capalt1 + capneu1) / 4) + 14;
19
        }
20
21
        if(CCP1M0 == 0)
22
        {
23
            CCP1M0 = 1;
24
        }
25
        else
26
        {
27
            CCP1M0 = 0;
28
        }
29
30
        CCP1IF = 0;
31
        return;
32
    }
33
34
35
    if(ADIE == 1 && ADIF == 1)
36
    {
37
        ADIF = 0;
38
        ADfin = 1;
39
        return;
40
    }
41
42
43
    if(TMR4IE == 1 && TMR4IF == 1) //Für die Tests habe ich das auf den TMR12 geändert
44
    {
45
        TMR4IF = 0;
46
        mess++;
47
        return;
48
    }
49
}

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.