Forum: Mikrocontroller und Digitale Elektronik for Schleife einsetzen


von Francis C. (Firma: Privat) (danger19xx)


Angehängte Dateien:

Lesenswert?

Hallo Z'men,

anhang eines AD-Wandlers von AT89C51CC03 habe das Programm unten 
geschrieben geschrieben. Aber ich weiss nicht genau, wo die For-Schleife 
einzubringen ist, wenn ich die Messwerte im Bereich 150MicroS und 
4200MicroS auch mit jedem Potis P16 und P17 einlesen moechte, denn ich 
die Werte mit beiden Potis im Bereich von 1ms - 256ms.

Lange Rede kurzer Sinn, hier das Programm:

1
/****************************************************************************************************/
2
    /*  Dieses Programm namens "recht_2.C" gibt ein zeitlich komplett parametrierbares                  */
3
    /*  Rechtecksignal am Port-Pin P1.0 aus.                                                            */
4
    /* Damit kann man waehrend des Betriebs die Breitenwerte des Signals einstellen                     */
5
    /* -->fuer die positive Impulsbreite tp wird der Trimm-Poti P1.6 im Bereich 1ms bis 256ms verwendet */
6
    /* -->fuer die negative Impulsbreite tn wird der Trimm-Poti P1.7 im Bereich 1ms bis 256ms verwendet */
7
    /* Der A/D-Wandler wird im 8-Bit-Modus betrieben                                                    */
8
    /*                                                                                                  */
9
    /****************************************************************************************************/
10
11
/*** Einbinden von Include-Dateien ***/
12
#include<stdio.h>
13
#include<at89c51cc03.h>
14
15
16
17
void main (void)     // Start des Hauptprogramms
18
{
19
    unsigned int wert_p16, wert_p17;  //Variablen zur Aufnahme des Teilergebnisses von Trimm-Poti p1.6 und p1.7
20
    unsigned int wert;              //Variable zur Aufnahme des zusammengesetzten Gesamtergebnisses
21
22
    /**************************************************************/
23
    /*  Initialisierung der seriellen Schnittstelle 0 des CC03ers */
24
    /*  Schnittstellenparameter: 9600Baud, 8 Datenbit, 1 Stopp-Bit*/
25
    /*  asynchroner Betrieb                                       */
26
    /**************************************************************/
27
    SCON=0x52;
28
    TMOD |=0x20;
29
    TH1=0xfd;
30
    TR1=1;
31
    TI=1;
32
    
33
    /* Initialisierung des A/D-Wandlers */
34
    ADCF = 0xc0;    // Port P1.6 und P1.7 als Analogeingang definieren,
35
                    // d.h., CH6 und CH7 sollen angesprochen werden
36
    ADCON = 0x20;   // Enable ADC, mit ADEN =1 und
37
                    // SCH2, SCH1, SCH2 sollen respektiv die Werte 110 und 111
38
                    // um den P1.0 steuern zu können...
39
40
41
    printf("\x1b\x48\x1b\x4a"); //löschen des Bildschirms
42
 
43
    while(1)
44
    {
45
        ADCON &= ~0x07;             // Sicher stellen, dass SCH2, SCH1, SCH0 auf null initialisiert sind
46
        ADCON |= 0x06;              // Auswahl von CH6
47
        ADCON &= ~0x40;             // Standard Mode
48
        ADCON = ADCON | 0x08;       // Start der Wandlung
49
        
50
        while ((ADCON & 0x10)==0);  //warten bis Wandlung fertig ist
51
52
        ADCON = ADCON & 0xef;       // End of Conversion Bit löschen
53
        wert_p16 = ADDH;            //Ergebnis des eingestellten Wertes von Poti P1.6 speichern
54
55
        /*Das vermeiden vom Programmabsturz */
56
        if(wert_p16==0)
57
        {
58
            wert_p16++;
59
        }
60
        _wait_ms(wert_p16);
61
        printf("tp hat den wert: %u ms\n\n", wert_p16); // Ausgabe von tp(positive Impulbreite)
62
63
64
        ADCON &= ~0x07;             // Sicher stellen, dass SCH2, SCH1, SCH0 auf null initialisiert sind
65
        ADCON |= 0x07;              // Auswahl von CH7
66
        ADCON &= ~0x40;             // Standard Mode
67
        ADCON = ADCON | 0x08;       // Start der Wandlung
68
        
69
        while ((ADCON & 0x10)==0);  //warten bis Wandlung fertig ist
70
71
        ADCON = ADCON & 0xef;       // End of Conversion Bit löschen
72
        wert_p17 = ADDH;             //Ergebnis des eingestellten Wertes von Poti P1.7 speichern
73
74
        
75
        /*Das vermeiden vom Programmabsturz */
76
        if(wert_p17==0)
77
        {
78
            wert_p17++;
79
        }
80
        _wait_ms(wert_p17);
81
        printf("tn hat den wert: %u ms\n\n", wert_p17); // Ausgabe von tn
82
83
        wert = wert_p16 + wert_p17; //tp + tn zusammenfuegen
84
85
    
86
        printf("die gesamte Impulsbreite ist: %u ms\n\n", wert);  //Ausgabe der gesamten Impulsbreite --> (tp + tn)
87
      
88
89
90
    }//end while
91
    
92
 
93
94
} //end main()

von Bitflüsterer (Gast)


Lesenswert?

Ist ja furchtbar. Fang das am Besten nochmal von vorne an.

Es ist wesentlich besser, die Speicherung des AD-Wandlungsergebnises und 
die Umstellung des Kanals in einer Interrupt-Routine zu erledigen.

Dann, wenn das funktioniert, stellst Du in (ich würde mal sagen in der 
selben Interrupt-Routine) das Timerregister für die PWM um.

Die Hauptschleife ist im wesentlichen leer (falls Du die Ausgabe nicht 
wirklich brauchst).

Eine For-Schleife kommt da überhaupt nicht vor.

von Bitflüsterer (Gast)


Lesenswert?

Ach, und noch ein Hinweis:

Die Bits in den Steuerregistern haben Namen, die auch in at89c51cc03.h 
definiert sind. Verwende die und nicht irgendwelche Literale, die Du 
dann in Kommentaren lang und breit erklären musst.

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Für den Anfang kann man die Interrupts (die das Ganze nicht einfacher 
machen) auch weglassen und Alles in der Hauptschleife machen. Nur für 
die PWM muss eben ein Hardwaretimer herhalten. Aber genau dafür sind die 
ja auch im uC eingebaut...

von Peter D. (peda)


Lesenswert?

Wo hast Du den Code her?
Er funktioniert nicht, die printf dauern ja schon >1ms je Zeichen.

Für 150 .. 4200µs mußt Du den Timer T2 nehmen und in dessen Interrupt 
das RCAP2 entsprechend umladen.

von Francis C. (Firma: Privat) (danger19xx)


Lesenswert?

Danke erstmal fuer die schnelle Antwort ;)

@Bitfluesterer
Heuuu, leider haben wir noch nicht den Interrupt-Kapitel behandelt. es 
gilt auch fuer die PMW...
Zur Aufgabe habe ich als Hinweise, die For-Loop zu benutzen, um den 
Zeitbereich zw 150ms und 4200ms darzustellen.

@Lothar
damit die Werte im Bereich 150microS und 4200microS auch mit dem 
Oszilloskop geprueft/dargestellt werden koennen, gaben sie mir als 
Hinweis eine For-Loop zu benutzen. ich habe folgendes z.B direkt nachdem 
wait_ms()-Funktion probiert und natuerlich als Datentyp "float" 
deklariert:
1
        for(wert_p17==0.150; wert_p17<=4.2; (wert_p17++*0.001))
2
        {
3
            printf("tn hat den wert: %3.2f ms\n\n", wert_p17);
4
        }


@Peter,
ich habe das Programm selber geschrieben ;) und es laeuft(Halleluja)
Es ist wahr, dass ich printf mit 1ms schon laeuft, aber waehrend ich an 
den Potis drehe, wird die Impulsbreite immer groesser(max 510ms). 
Hauptsache ist es, dass ich kein NULL im meiner wait_ms()funktion habe, 
um den Abstuerz des Programms zu vermeiden(deshalb die if-loop).

Danke nochmal fuer die Hilfe.

von Easylife (Gast)


Lesenswert?

g r u s e l i g.

a) statt
1
if(wert_p17==0)
2
{
3
    wert_p17++;
4
}
5
_wait_ms(wert_p17);

kannst du doch auch einfach schreiben:
1
if(wert_p17>0) {
2
  _wait_ms(wert_p17);
3
}


b) wie soll "for(wert_p17==0.150; wert_p17<=4.2; (wert_p17++*0.001))" 
denn compilieren?

"wert_p17==0.150" ist ein Vergleich.
Vermutlich wolltest du "wert_p17=0.150" hier schreiben.

Was soll "(wert_p17++*0.001)" machen?
Ich nehme mal an, es soll "(wert_p17+=0.001)" heissen?

Und was genau soll diese Schleife jetzt hilfreiches machen, ausser dass 
sie dir 4050 Float-Werte zwischen 0.15 und 4.2 auf den Schirm 
printet????


Mit viel Phantasie und einigen runden Glasgegenständen lese ich heraus, 
dass es dir eigentlich darum geht, deine Potiwerte von 0-255 in 
Delay-Werte zwischen 150us und 4200us umrechnen möchtest.

Für das eigentliche Delay nützt dir dann allerdings die Funktion 
"_wait_ms()" wenig.

Weiter sagt mir die Glaskugel, dass du statt "_wait_ms()" eine 
For-Schleife verwenden willst, um Delays im us-Bereich zu bekommen.

Ich sehe in deinem Programm allerdings auch keine Anweisungen, die einen 
Output-Port toggeln würden, damit du deine PWM mit einem Oszilloskop 
sichtbar machen könntest.

Offenbar reicht dir bisher die printf Ausgabe auf deinem Schirm, dass 
die Delay-Werte überhaupt berechnet wurden?

Rätsel,....

von Francis C. (Firma: Privat) (danger19xx)


Lesenswert?

Hi Easylife,

das sind sehr wertvolle Hinweise von dir, die ich NIE dazugekommen 
waere.

Du hast eine sehr gute Glaskugel!

Ich folge diese Hinweise und poste meine Ergnisse erneuert.

VG

von Daniel F. (df311)


Lesenswert?

und ich frage mich schon seit mindestens 10 Minuten warum oben von 
Leitwerten anstatt von Widerständen die Rede ist. An falsch geschriebene 
Sekunden hätte ich nicht gedacht...

Francis Chaleu schrieb:
> (deshalb die if-loop)

if-schleifen gibt es nicht, hat es noch nie gegeben und wird es auch nie 
geben...

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Daniel F. schrieb:
> if-schleifen gibt es nicht, hat es noch nie gegeben und wird es auch nie
> geben...

Das ist bei Programmiersprachen wie bei idiotensicheren Systemen auch:

Hat man erstmal was idiotensicher bekommen, erfinden sie einen besseren 
Idioten ...

von Easylife (Gast)


Lesenswert?

Ich kann mir gut vorstellen, dass If-Schleifen irgendwann PLEASE mal in 
INTERCOM auftauchen werden. "COME FROM" gibt's da ja schon ;-)

von Francis C. (Firma: Privat) (danger19xx)


Lesenswert?

Soooli...

Oh je!!

Ihr habt mir eine richtige Lektion erteilt (Nie Wieder schreiben oder 
denken, dass "if" eine Schleife ist, auch wenn man es nicht so gemeint 
hat ;) )
Auf jeden Fall bin ich ein Stueck weiser geworden. Danke!!!

Weiser bin ich auch in sofern geworden, da ich anhang die guten Hinweise 
von Easylife das Programm verbessert habe (um ehrlich zu sein, habe 
ich eigentlich die mir gestellte Aufgabe besser verstanden).

Anbei, wie versprochen, das bearbeitete Programm. Ich muss zugeben, dass 
ich mir noch etwa schwer tue, was die for-Schleife (am Ende des 
Programms) anbelangt.

Also mit der For-Schleife soll es moeglich sein, die werte zw. 
150microSekunden und 4200microSekunden darzustellen. Hiermit danke ich 
euch im Voraus fuer die Inputs...
1
    /**********************************************************************************************************/
2
    /*  Dieses Programm namens "recht_3.C" gibt ein zeitlich komplett parametrierbares                         */
3
    /*  Rechtecksignal am Port-Pin P1.0 aus.                                                                   */
4
    /* Damit kann man waehrend des Betriebs die Breitenwerte des Signals einstellen                            */
5
    /* -->fuer die positive Impulsbreite tp wird der Trimm-Poti P1.6 im Bereich 1micros bis 10micros verwendet */
6
    /* -->fuer die negative Impulsbreite tn wird der Trimm-Poti P1.7 im Bereich 1micros bis 10micros verwendet */
7
    /* Der A/D-Wandler wird im 8-Bit-Modus betrieben                                                           */
8
    /*                                                                                                         */
9
    /***********************************************************************************************************/
10
11
/*** Einbinden von Include-Dateien ***/
12
#include<stdio.h>
13
#include<at89c51cc03.h>
14
15
unsigned char bit dIn_out @ 0x90;   // Port-Pin P1.0 bekommt den Variablen-Namen 
16
                                    //zugeordnet
17
18
19
void main (void)     // Start des Hauptprogramms
20
{
21
   float wert_p16, wert_p17;  //Variablen zur Aufnahme des Teilergebnisses von Trimm-Poti p1.6 und p1.7
22
   float wert;              //Variable zur Aufnahme des zusammengesetzten Gesamtergebnisses
23
24
    /**************************************************************/
25
    /*  Initialisierung der seriellen Schnittstelle 0 des CC03ers */
26
    /*  Schnittstellenparameter: 9600Baud, 8 Datenbit, 1 Stopp-Bit*/
27
    /*  asynchroner Betrieb                                       */
28
    /**************************************************************/
29
    SCON=0x52;
30
    TMOD |=0x20;
31
    TH1=0xfd;
32
    TR1=1;
33
    TI=1;
34
    
35
    /* Initialisierung des A/D-Wandlers */
36
    ADCF = 0xc0;    // Port P1.6 und P1.7 als Analogeingang definieren,
37
                    // d.h., CH6 und CH7 sollen angesprochen werden
38
    ADCON = 0x20;   // Enable ADC, mit ADEN =1 und
39
                    // SCH2, SCH1, SCH2 sollen respektiv die Werte 0, 0, 0
40
                    // um den P1.0 steuern zu können...
41
42
43
    printf("\x1b\x48\x1b\x4a"); //löschen des Bildschirms
44
 
45
46
    /*Endlosschleife*/
47
    while(1)
48
    {
49
        ADCON &= ~0x07;             // Sicher stellen, dass SCH2, SCH1, SCH0 auf null initialisiert sind
50
        ADCON |= 0x06;              // Auswahl von CH6
51
        ADCON &= ~0x40;             // Standard Mode
52
        ADCON = ADCON | 0x08;       // Start der Wandlung
53
        
54
        while ((ADCON & 0x10)==0);  //warten bis Wandlung fertig ist
55
56
        ADCON = ADCON & 0xef;       // End of Conversion Bit löschen
57
        wert_p16 = ADDH;            //Ergebnis des eingestellten Wertes von Poti P1.6 speichern
58
59
        wert_p16=((wert_p16*10.0)/255.0)+0.04; //Umwandlung in microSekunde mit Skala von 0.040 microSekunden
60
       
61
        dIn_out=0; //High Pegel am Port-Pin P1.0
62
        printf("tp hat den Wert: %3.3f microSekunde\n\n", wert_p16);
63
64
65
66
        ADCON &= ~0x07;             // Sicher stellen, dass SCH2, SCH1, SCH0 auf null initialisiert sind
67
        ADCON |= 0x07;              // Auswahl von CH7
68
        ADCON &= ~0x40;             // Standard Mode
69
        ADCON = ADCON | 0x08;       // Start der Wandlung
70
        
71
        while ((ADCON & 0x10)==0);  //warten bis Wandlung fertig ist
72
73
        ADCON = ADCON & 0xef;       // End of Conversion Bit löschen
74
        wert_p17 = ADDH;             //Ergebnis des eingestellten Wertes von Poti P1.7 speichern
75
        
76
        wert_p17=((wert_p17*10.0)/255.0)+0.04; //Umwandlung in microSekunden mit Skala von 0.040 microSekunden
77
78
        dIn_out=1; // Low Pegel am Port-Pin P1.0
79
        printf("tn hat den Wert: %3.3f microSekundes\n\n", wert_p17);
80
81
82
        wert = wert_p16 + wert_p17; //gesamte Impulsbreite tp + tn 
83
84
        for(wert=0.15; wert<=4.2; wert+=0.04)
85
        {
86
            printf("die gesamte Impulsbreite ist: %3.3f microSekundes\n\n", wert);  //Ausgabe der Impulsbreite
87
        }
88
      
89
90
91
    }//end while
92
    
93
 
94
95
} //end main()

von Easylife (Gast)


Lesenswert?

Leider hast du die Aufgabe eben gar nicht verstanden.

Deine printf() Aufrufe musst du rausnehmen. Die brauchen viel zu viel 
Zeit.

Ich versuche dir mal die Aufgabe zu erklären:

Du sollst ein Programm schreiben, das auf einem I/O Pin eine PWM macht, 
die du mit einem Oszilloskop messen kannst.

D.h. du hast dann sowas wie
1
while(1)
2
{
3
  dIn_out=1;    // output pin auf high setzen
4
  wait(t_on);   // eine gewisse Zeit warten
5
  dIn_out=0;    // output pin auf low setzen
6
  wait(t_off);  // wieder eine gewisse Zeit warten
7
}

Da deine Wartezeiten im Bereich von 150us bis 4200us (=4.2ms) sein 
sollen, kannst du für "wait()" nicht die Funktion "_wait_ms()" nehmen.

Stattdessen wurde dir empfohlen das Delay über eine For-Schleife zu 
machen, und das sieht dann so aus:
1
void wait(unsigned t)
2
{
3
  unsigned i;
4
  for (i=0; i<t; i++)
5
    ;
6
}

D.h. du benutzt einfach eine leere for-schleife, die nichts anderes tut 
als i von 0 bis t zählen zu lassen.
Dafür braucht der Microcontroller eine gewisse Zeit, dadurch entsteht 
ein Delay.
Wie viel Zeit in Abhängigkeit von t vergeht, musst du mit dem 
Oszilloskop messen, und dann t mit einem entsprechenden Faktor 
multiplizieren um auf eine genau definierte Zeit zu kommen.

Es kann auch sein, dass die Schleife so schnell durchläuft, dass du 
damit keine 4200us mehr hinbekommst, in dem Fall musst wait() 
entsprechend mehrmals aufrufen, bzw. 2 Schleifen ineinander schachteln.

Am besten testest du erstmal mal folgendes aus:
1
  unsigned i;
2
  unsigned t = 10000;
3
4
  while(1)
5
  {
6
    dIn_out=1;    // output pin auf high setzen
7
8
    for (i=0; i<t; i++)
9
      ;
10
11
    dIn_out=0;    // output pin auf low setzen
12
13
    for (i=0; i<t; i++)
14
      ;
15
  }

und misst mal die Frequenz auf dem Output pin.
Dann kann man dir weiterhelfen einen entsprechenden Faktor zu berechnen.


Am Ende musst du auch noch berücksichtigen, dass ja dein Potentiometer 
abgefragt werden soll, daher wäre es auch wichtig zu prüfen, ob eine A/D 
Wandlung innerhalb der 150us überhaupt zu machen ist.

von Michael R. (Firma: Brainit GmbH) (fisa)


Lesenswert?

Easylife schrieb:
> Stattdessen wurde dir empfohlen das Delay über eine For-Schleife zu
> machen, und das sieht dann so aus:
1
void wait(unsigned t)
2
{
3
  unsigned i;
4
  for (i=0; i<t; i++)
5
    ;
6
}
Ich fürchte nur der Compiler bzw. dessen Optimizer wird dir einen 
gröberen Strich durch die Rechnung machen...

von Easylife (Gast)


Lesenswert?

Dann stell halt -O0 ein
;-)

von Francis C. (Firma: Privat) (danger19xx)


Lesenswert?

Hoi Zämen,

Vielen Vielen Dank Easylife!

Ich bin nur überrascht, wie du mein Anliegen besser als mich kennst.
Obwohl ich es zigmal gelesen habe, bin ich auf diese Lösung nie 
gekommen.

Aber so gut erklaert und ganz besonders sehr gut detailliert.
Phenomenal und sensationell, wenn man sich sehr gut auskennt ;-)

Danke fuer die investierte Zeit(!), denn es ist nicht immer 
selbsverstaendlich.

Deine Hinweise werde ich im Programm einsetzen und natuerlich sofort 
Posten!!!!

VG

von bones (Gast)


Lesenswert?

Moin,

ich möchte dieses Beispiel gern aufgreifen, da ich selber gerade damit 
beschäftigt bin und mir sich dieses Beispiel eines Delay in Form einer 
For-Schleife zwar in der Theorie erschließt, praktisch aber nicht 
funktioniert.
Bei dem von Easylife genannten Wert für t=10000, ergibt sich an Portpin 
1.0 eine Frequenz von 3,55 Hz, was einer Periodendauer T = 282 ms 
entspricht. Bei einem symmetrischen Rechtecksignal wäre tp und tn somit 
T/2 bzw. 141ms.
Um nun die Impulsbreite (tp) und die Impulspause (tn) mit beiden Poti´s 
von 0,150 ms bis 4,2 ms einstellen zu können ist genau welcher Faktor zu 
verwenden?

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.