Forum: Mikrocontroller und Digitale Elektronik Messchieber Programm


von Remo Hug (Gast)


Lesenswert?

Hallo

Ich hab nun mal ein Programm in MikroC geschrieben, mit welchem ich die 
Billigmesschieber auslesen kann.

Das Programm funktioniert soweit.
Nun meine Fragen:

-Was würdet ihr anderst machen (Optimieren)?

Auch im Hinblick, dass ich 4 Messchieber einlesen will, den wert 
umrechnen und jeden wert auf einer separaten Achs-Anzeige anzeigen will.
Des weiteren sollte noch ständig eine Tastatur abgefragt werden.

-Wie würdet ihr das bei 4 Messchiebern lösen, wenn jeder Messchieber
 CLOCK- und DATA-Leitung hat und die an RB0 bis RB7 angeschlossen sind?


1
#include "Display_utils.h"
2
3
unsigned char Zaehler1 = 0;
4
unsigned char Wert_Lesen = 0;
5
unsigned char Read_Bit = 0;
6
unsigned char Minuswert = 0;
7
unsigned char Wert_Array[24];
8
9
unsigned long Wert_Eingelesen = 0;
10
unsigned long Rechnungswert = 0;
11
unsigned long Schlusswert = 0;
12
13
const float x = 806.299;
14
15
16
void interrupt(){
17
     
18
     if (INTCON.INTF){
19
        INTCON.INTF = 0;
20
        if (Wert_Lesen){
21
           Wert_Array[Read_Bit] = PORTB.F1;
22
           if (Read_Bit == 0){
23
              Wert_Lesen = 0;
24
              INTCON.GIE = 0;
25
           }
26
           --Read_Bit;
27
28
        }
29
        else{
30
           if (OPTION_REG.INTEDG){
31
              OPTION_REG.INTEDG = 0;
32
              TMR1H = 0xFE;
33
              TMR1L = 0x6F;
34
              T1CON.TMR1ON = 1;
35
           }
36
           else{
37
              OPTION_REG.INTEDG = 1;
38
              T1CON.TMR1ON = 0;
39
              PIR1.TMR1IF = 0;
40
           }
41
        }
42
     }
43
     
44
     if (PIR1.TMR1IF){
45
        PIR1.TMR1IF = 0;
46
        T1CON.TMR1ON = 0;
47
        Wert_Lesen = 1;
48
        Read_Bit = 23;
49
     }
50
     
51
52
}
53
54
55
void main()
56
{
57
58
59
60
    //* inizialisieren der PORT's *//
61
    ADCON1 = 0;
62
    TRISA = 0x00;                           // Set PORTA as output
63
    TRISB = 0xFF;                           // Set PORTB as input
64
    TRISD = 0x00;                           // Set PORTD as output
65
    PORTA = 0x00;
66
    PORTB = 0x00;
67
    PORTD = 0x00;
68
69
    //* Interrupts erlauben *//
70
    INTCON.GIE = 1;
71
    INTCON.PEIE = 1;
72
    INTCON.INTE = 1;
73
74
    //* inizialisieren des TIMER1 fuer 100us Interrupt *//
75
    PIE1.TMR1IE = 1;
76
    PIR1.TMR1IF = 0;
77
    T1CON.T1CKPS1 = 0;
78
    T1CON.T1CKPS0 = 0;
79
    T1CON.TMR1CS = 0;
80
    TMR1H = 0xFE;
81
    TMR1L = 0x6F;
82
    T1CON.TMR1ON = 0;
83
84
    //* Port RB0/INT für steigende Flanke Konfigurieren
85
    OPTION_REG.INTEDG = 1;
86
87
    //* main loop *//
88
89
    do {
90
    Zaehler1 = 0;
91
    Wert_Eingelesen = 0;
92
      do{
93
         if (Zaehler1 > 0){
94
            Wert_Eingelesen <<= 1;
95
            Wert_Eingelesen |= Wert_Array[Zaehler1];
96
            ++Zaehler1;
97
            }
98
         else{
99
            Minuswert = Wert_Array[Zaehler1];
100
            ++Zaehler1;
101
         }
102
      }while (Zaehler1 < 24);
103
104
      if (Minuswert){
105
         Rechnungswert = (~Wert_Eingelesen & 8388607);
106
      }
107
      else{
108
         Rechnungswert = Wert_Eingelesen;
109
      }
110
111
112
      Schlusswert = (Rechnungswert*100) / x;
113
114
      PORTD = mask(Schlusswert % 10u,0);
115
      PORTA = 0x01;
116
      Delay_us(250);
117
      PORTA = 0x00;
118
119
      PORTD = mask((Schlusswert / 10u) % 10u,0);
120
      PORTA = 0x02;
121
      Delay_us(250);
122
      PORTA = 0x00;
123
124
      PORTD = mask((Schlusswert / 100u) % 10u,1);
125
      PORTA = 0x04;
126
      Delay_us(250);
127
      PORTA = 0x00;
128
129
      PORTD = mask(Schlusswert / 1000u,0);
130
      PORTA = 0x08;
131
      Delay_us(250);
132
      PORTA = 0x00;
133
134
      INTCON.GIE = 1;
135
    }while (1);
136
}

freundliche Grüsse

Remo

von Remo (Gast)


Lesenswert?

Hallo

Das kann ja nicht sein, das ich ein Prog. schreibe, das nicht mehr
verbessert werden kann. ;-)

freundliche Grüsse

Remo

von Helmut -. (dc3yc)


Lesenswert?

Vielleicht kannste noch dazuschreiben, für welche Umgebung das Ganze 
ist: Prozessor, Compiler, Meßschieber usw.usf....

Servus,
Helmut.

von Karl H. (kbuchegg)


Lesenswert?

Zu deiner Interrupt Funktion kann ich nicht viel sagen, kenne deinen 
Prozessor nicht und weiß daher nicht, ob das so alles koscher ist. Die 
Routine selbst ist aber dem Ansehen nach ziemlich kurz und sieht soweit 
vernünftig aus.

Das hier
1
    do {
2
    Zaehler1 = 0;
3
    Wert_Eingelesen = 0;
4
      do{
5
         if (Zaehler1 > 0){
6
            Wert_Eingelesen <<= 1;
7
            Wert_Eingelesen |= Wert_Array[Zaehler1];
8
            ++Zaehler1;
9
            }
10
         else{
11
            Minuswert = Wert_Array[Zaehler1];
12
            ++Zaehler1;
13
         }
14
      }while (Zaehler1 < 24);

kannst du auch kürzer schreiben. den if-else in der innersten Schleife 
brauchst du im Grunde nicht, da gehts es ja nur darum, dass der erste 
Wert im Wert_Array anders behandelt wird. Das kannst du aber auch vor 
die Schleife ziehen
1
    Wert_Eingelesen = 0;
2
    Minuswert = Wert_Array[0];
3
    Zaehler1 = 1;
4
    do {
5
      Wert_Eingelesen <<= 1;
6
      Wert_Eingelesen |= Wert_Array[Zaehler1];
7
      ++Zaehler1;
8
    } while (Zaehler1 < 24);

Und damit könnte man dann auch die do-while Schleife gegen die 
universellere und hier wohl auch angebrachtere for-Schleife austauschen
1
    Wert_Eingelesen = 0;
2
    Minuswert = Wert_Array[0];
3
    for( Zaehler1 = 1; Zaehler1 < 24; ++Zaehler1 )
4
      Wert_Eingelesen = ( Wert_Eingelesen << 1 ) | Wert_Array[Zaehler1];

Zugegeben: die letzte Transformation ist mehr syntaktischer Zucker als 
sonst was.

Auch der Sinn der Variablen Minuswert ist dann etwas fraglich. Warum in 
eine andere Variable umkopieren und nicht in weiterer Folge nicht gleich 
Wert_Array[0] verwenden? OK. Der Compiler wird die Variable 
wahrscheinlich sowieso selbst rausschmeissen und diese Transformation 
machen, ich seh allerdings auch keinen wesentlichen dokumentarischen 
Wert in dieser Umkopiererei. Ein kleiner Kommentar an der Stelle
1
      if (Wert_Array[0]){           // wenn negativ
2
         Rechnungswert = (~Wert_Eingelesen & 8388607);
3
      }
4
      else{
5
         Rechnungswert = Wert_Eingelesen;
6
      }

erfüllt den gleichen Zweck und ist vielleicht klarer als der Umweg über 
eine Zwischenvariable.

Was du dir aber überlegen solltest (und da kommt jetzt wieder meine 
Unkentnis des Prozessors ins Spiel): Ich habe in main nichts gesehen, 
was mich an Interrupts zulassen/sperren erinnert. Was passiert 
eigentlich, wenn genau während dieser Ausleserei ein Interrupt zuschlägt 
und das Wert_Array verändert?

> Rechnungswert = (~Wert_Eingelesen & 8388607);

Das würde ich nicht so schreiben. Die Zahl 8399607 sieht da etwas 
seltsam aus. In Hex geschrieben, wäre das
1
   Rechnungswert = (~Wert_Eingelesen & 0x7FFFFF);

und jetzt sieht der kundige C-Leser dann auch, dass das offenbar eine 
Maskierung sein soll, die die untersten 23 Bits herausmaskiert. An 
dieser Stelle ist die Hex-Zahl dem Verständnis wesentlich zuträglicher 
als die Dezimalzahl.
(PS: Bist du dir sicher, dass negative Zahlen lediglich durch Bitumkehr 
dargestellt werden, also im Einerkomplement. Ist etwas unüblich. 
Normalerweise benutzt man das 2-er Komplement: Alle Bits umdrehen und 1 
dazuzählen.)

von Karl H. (kbuchegg)


Lesenswert?

> Auch im Hinblick, dass ich 4 Messchieber einlesen will, den wert
> umrechnen und jeden wert auf einer separaten Achs-Anzeige anzeigen will.
> Des weiteren sollte noch ständig eine Tastatur abgefragt werden.

Das hier
1
     PORTD = mask(Schlusswert % 10u,0);
2
      PORTA = 0x01;
3
      Delay_us(250);
4
      PORTA = 0x00;
5
6
      PORTD = mask((Schlusswert / 10u) % 10u,0);
7
      PORTA = 0x02;
8
      Delay_us(250);
9
      PORTA = 0x00;
10
11
      PORTD = mask((Schlusswert / 100u) % 10u,1);
12
      PORTA = 0x04;
13
      Delay_us(250);
14
      PORTA = 0x00;
15
16
      PORTD = mask(Schlusswert / 1000u,0);
17
      PORTA = 0x08;
18
      Delay_us(250);
19
      PORTA = 0x00;

soll offenbar sowas wie ein Multiplex des Anzeigen sein. Das würd ich 
als allererstes mal eliminieren. Die Wartezeiten bei der Ausgabe sind 
nicht schön. Dafür würd ich einen Timer einsetzen, der 
interruptgesteuert reihum die Anzeigen auf den neuesten Stand bringt.

Damit bist du dann auch erst mal dein wesentliches Zeitbestimmendes 
Problem in der Hauptschleife los und kannst dich neuen Schandtaten 
widmen :.-)

von Karl H. (kbuchegg)


Lesenswert?

Karl heinz Buchegger wrote:

> Zugegeben: die letzte Transformation ist mehr syntaktischer Zucker als
> sonst was.

Summa summarum würde sich dann beispielsweise folgender Code ergeben
1
  do {
2
    Wert_Eingelesen = 0;
3
    for( Zaehler1 = 1; Zaehler1 < 24; ++Zaehler1 )
4
      Wert_Eingelesen = ( Wert_Eingelesen << 1 ) | Wert_Array[Zaehler1];
5
6
    if (Wert_Array[0])           // wenn negativ, dann positiv machen
7
      Wert_Eingelesen = ~Wert_Eingelesen & 0x7FFFFF;
8
9
    Schlusswert = (unsigned long)( 100 * Wert_Eingelesen / x + 0.5 );
10
11
    PORTD = mask(Schlusswert % 10u,0);
12
    PORTA = 0x01;
13
    ....

Ist kürzer ohne dass die Übersichtlichkeit darunter gelitten hat.

Die Zahl 806.99 in x (warum heist das eigentlich x und nicht irgendein 
sinnvoller Name, der mir sagt von welchen Einheiten in welche 
umgerechnet wird) ist mir auch noch nicht ganz koscher. Wahrscheinlich 
ist das ja irgendein Quotient aus den technischen Daten des Schiebers. 
Wenn dein Proz eine Gleitkommaeinheit hat, ist das ok. Wenn nicht würde 
ich die Division tatsächlich hier in den Code mit reinziehen und auf 
Floating Point verzichten.

von Remo Hug (Gast)


Lesenswert?

Hallo Karl

Danke für deine ausführungen.

Der Prozessor ist ein PIC16F877A.

@Helmut:

Compiler: wie geschrieben MikroC
Messchieber: Wabeco -> Produkte -> Zubehör -> Messwerkzeuge -> Digitale 
Längenmessleisten (geht leider nicht zum verlinken)

freundliche Grüsse

Remo Hug

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.