Forum: Mikrocontroller und Digitale Elektronik Spannungsmessung mit PIC16F877A -->LCD-Anzeige


von Robert (Gast)


Lesenswert?

Hi,

ich habe ein neues Projekt angefangen und habe im ersten Schritt erstmal 
eine Spannungsmessung mit dem PIC realisiert und wollte sie mir zu 
Testzwecken auf einem LCD anzeigen lassen.

Es ist eine Weile her, dass ich das letzte Mal programmiert habe(also 
seid bitte etwas nachsichtig mit mir xD) und ich habe jetzt ein paar 
Fragen zu meinem Programm:

Also wenn ich "float adc" als feste Zahl definiere läuft das Programm 
ohne Probleme aber wenn ich "float adc=5/1024" verwende, bekomme ich nur 
ne 0 als Ergebnis auf dem LCD angezeigt.

In meiner Vin_Calculation-Funktion muss ich für jeden Rechenschritt eine 
neue Variable verwenden sonst kommt nichts raus, kann mir einer 
vielleicht erklären warum es nicht mit einer klappt (ich vermute mal hat 
was mit der internen Verarbeitung der Befehle im PIC zu tun oder 
so...(overflow oder was weiß ich)?)

Und dann ganz unten im Code stelle ich ja Spannung auf dem LCD dar, bei 
mir ist die zahl 8bit lang, wie kann das sein? Ich habe doch "txt1" 
definiert müsste er nicht einfach nach 6bits abschneiden?

PS: verwende zum compilieren MicroC PRO for PIC und testen konnte ich 
das ganze nur in einer Simulation (Proteus8), da ich zur Zeit noch 
keinen PIC zur Verfügung habe.
1
int i;
2
float adc=0.0048828125;
3
unsigned Vtemp;
4
float Vpv,Vtemp1,Vtemp2,Vtemp3;
5
char text_1[] = "Spannungsmessung";
6
char text_2[] = "Vpv:[V]";
7
char txt1[5];
8
9
// Lcd pinout settings
10
sbit LCD_RS at RC2_bit;
11
sbit LCD_EN at RC3_bit;
12
sbit LCD_D7 at RC7_bit;
13
sbit LCD_D6 at RC6_bit;
14
sbit LCD_D5 at RC5_bit;
15
sbit LCD_D4 at RC4_bit;
16
17
// Pin direction
18
sbit LCD_RS_Direction at TRISC2_bit;
19
sbit LCD_EN_Direction at TRISC3_bit;
20
sbit LCD_D7_Direction at TRISC7_bit;
21
sbit LCD_D6_Direction at TRISC6_bit;
22
sbit LCD_D5_Direction at TRISC5_bit;
23
sbit LCD_D4_Direction at TRISC4_bit;
24
25
float Vin_Calculation(){                     // Calculation of Vinput
26
 Vpv=0;
27
 for(i=1;i<=4;i++){                          // i time read ADC input
28
  Vtemp=ADC_Read(0);                         // ADC result from pin A0
29
  Delay_us(100);                             // time for the Capacitor
30
  Vpv=Vpv+Vtemp;
31
 }
32
 Vtemp1=Vpv*10;                                 // potential divider
33
 Vtemp2=Vtemp1*adc;
34
 Vpv=Vtemp2/(i-1);
35
36
 return Vpv;
37
 }
38
39
40
void main() {
41
 
42
 Lcd_Init();                        // Initialize LCD Module
43
 Lcd_CMD(_LCD_CURSOR_OFF);          // Cursor OFF
44
 Lcd_Cmd(_Lcd_Clear);               // Clear display
45
 Lcd_Out(1,1,text_1);               // Text on LCD 1row
46
 Lcd_Out(2,1,text_2);               // Text on LCD 2row
47
 
48
 do{
49
50
  Vpv=Vin_Calculation();
51
  FloatToStr(Vpv,txt1);
52
  Lcd_Out(2,8,txt1);
53
  
54
 } while(1);
55
}

von Max H. (hartl192)


Lesenswert?

Ich würde Flieskommaarithmetik auf einem 8bit uC wenn's geht vermeiden. 
Den ADC kann man problemlos mit Festkomma auswerten...

Wenn du bei Float bleiben willst, versuch es mal so: adc=5.0/1024.0

: Bearbeitet durch User
von Karl H. (kbuchegg)


Lesenswert?

Robert schrieb:

> Also wenn ich "float adc" als feste Zahl definiere läuft das Programm
> ohne Probleme aber wenn ich "float adc=5/1024" verwende, bekomme ich nur
> ne 0 als Ergebnis auf dem LCD angezeigt.


logisch.
5 ist ein Integer
1024 ist ein Integer

Also wird die Division 5 / 1024 als Integer Division durchgeführt. Die 
aber liefert keine Nachkommastellen. Die funktioniert so, wie du das 
damals in der Grundschule gelernt hast:
13 / 5   ergibt 2, Rest 3

Nur das hier der Rest nicht weiter interessiert.

Das du dann das Ergebnnis der Division an einen float zuweist, ist zwar 
nett. Ist aber völlig uninteresant. Der COmpiler kümmert sich bei der 
Auswahl wie eine Operation zu implmentieren ist nie darum was mit dem 
Ergebnis weiter passiert. Entscheidend sind immer nur die beiden 
Operanden. Die bestimmen, wie eine Operation implementiert wird. Und int 
durch int ist nun mal eine int-Division.

Dieses Vorgehen ist eigentlich in so ziemlich allen Programmierprachen 
so. Bis auf die Pascal-Schiene, in der es 2 getrennte 
Divisions-Operatoren gibt, je nachdem welche Division (Integer oder 
Floating Point) man haben will.

: Bearbeitet durch User
von Robert (Gast)


Lesenswert?

Ach ja, hab den Wald vor lauter Bäumen nicht mehr gesehen logisch.
Hätte ich wohl ein paar Minuten länger drüber nachdem sollen.
hab jetzt einfach float adc=(float)5/1024 draus gemacht...

@Max naja es kommt ja noch bisschen Programm dazu und ich will noch paar 
Divisionen etc. durchführen und da finde ich es persönlich von Vorteil 
es erstmal alles auf einen gemeinsamen Nenner (float) zu bringen.

von Robert B. (robertb42)


Lesenswert?

sry wegen des Doppelposts aber was ist den anderen Fragen?...

von Max H. (hartl192)


Lesenswert?

Robert schrieb:
> Und dann ganz unten im Code stelle ich ja Spannung auf dem LCD dar, bei
> mir ist die zahl 8bit lang, wie kann das sein? Ich habe doch "txt1"
> definiert müsste er nicht einfach nach 6bits abschneiden?
Meinst du mit 8bit 8 Stellen/Zeichen?
Du übergibst der Funktion nur einen Pointer auf das erste Element deiner 
String, die Funktion weiß nicht wie lange deine String ist und 
überschreibt auch nicht deklarierten Speicher. Sieh dir mal in der Hilfe 
an, was die Funktion gerne in die String schreiben würde.

Für die LCD_Out endet der String erst dort, wo die FloatToStr die 
Nullterminierung gesetzt hat.

: Bearbeitet durch User
von Robert B. (robertb42)


Lesenswert?

Ah ok

und kann ich den string irgendwie begrenzen also ab z.B. nach der 5 
Stelle abschneiden?

von Max H. (hartl192)


Lesenswert?

text[5]=0x00;

dann würde ich die String aber min 6 Elemente groß machen.

von Robert B. (robertb42)


Lesenswert?

Ok hab das jetzt soweit hinbekommen.

Ich habe jetzt weiter programmiert und meine Spannungsmessung ist jetzt 
in der while und ich möchte sie trotzdem auf dem LCD anzeigen, jedoch 
ohne viel Zeit einzubüßen. Also wenn ich den lcd_out Befehl einfach in 
die while Schreibe kommt ja nur Mist raus, da diese ja viel zu schnell 
ist und wenn ich mit delay arbeite verlangsamere ich meine while 
Schleife was ich nicht will. Gibt es eine Möglichkeit, wie ich sagen wir 
mal alle 5sek den aktuellen Wert der Spannung auf dem lcd Anzeigen lasse 
ohne die while zu verlangsamen?

von Karl H. (kbuchegg)


Lesenswert?

Robert B. schrieb:

> Ich habe jetzt weiter programmiert und meine Spannungsmessung ist jetzt
> in der while und ich möchte sie trotzdem auf dem LCD anzeigen, jedoch
> ohne viel Zeit einzubüßen. Also wenn ich den lcd_out Befehl einfach in
> die while Schreibe kommt ja nur Mist raus, da diese ja viel zu schnell
> ist und wenn ich mit delay arbeite verlangsamere ich meine while
> Schleife was ich nicht will. Gibt es eine Möglichkeit, wie ich sagen wir
> mal alle 5sek den aktuellen Wert der Spannung auf dem lcd Anzeigen lasse
> ohne die while zu verlangsamen?

Eine Möglichkeit ist natürlich, dass du dir mit einem Timer einen 
Basistakt ins Programm einziehst

FAQ: Timer

Den Timer stellst du so ein, dass er zb alle 0.1 Sekunden die ISR 
aufruft. IN der ISR zählst du eine Variable bis 50 (das sind dann 
logischerweise 0.1 Sekunden mal 50, oder eben 5 Sekunden) und wenn das 
der Fall ist, setzt du dir eine globale (volatile) Variable auf 1.
In der Hauptschleife machst du, was es zu machen gibt und wenn dann auch 
noch die Variable auf 1 ist, dann machst du die Ausgabe und setzt die 
Variable wieder auf 0 zurück, auf das die ISR sie 5 Sekunden später 
wieder auf 1 setzt.

Timingsachen bedeuten praktisch immer den Einsatz eines Timers. Vergiss 
bitte delays. Wenn du mit den großen Jungs spielen willst, dann musst du 
das Sandspielzeug 'delay' (ausser für ganz spezielle Fälle) zur Seite 
legen.

1
....
2
3
volatile uint8_t needUpdate;
4
5
ISR( ... )
6
{
7
  static uint8_t updateCounter;
8
9
  updateCounter++;
10
  if( updateCounter == 50 ) {
11
    updateCounter = 0;
12
    needUpdate = 1;
13
  }
14
}
15
16
int main()
17
{
18
  .....
19
20
  sei();
21
  while( 1 ) {
22
23
     .....
24
    if( needUpdate ) {
25
      needUpdate = 0;
26
27
      mache den Update aufs LCD wobei du nach Möglichkeit keinen
28
      Clear machst, sondern alles so hinbiegst, dass der neue Wert
29
      den alten überschreibt. Dein LCD (und letzten Endes dein Benutzer)
30
      wird es dir mit Flackerfreihet danken
31
    }
32
  }
33
}

Diese Technik der sog. 'Job-Flags' ist eine sehr allgemeine Technik und 
du wirst sie noch oft brauchen. generell funktionieren Programme, die 
scheinbar mehrere Dinge gleichzeitig machen oft genau so:
IN der Hauptschleife werden nacheinander die Jobflags abgeklappert und 
nachgesehen ob es in einem Teilbereich etwas zu tun gibt. Wenn ja (wenn 
also das Flag gesetzt ist), dann wird die Arbeit ausgeführt und das Flag 
auf 0 zurück gesetzt. Wenn irgendein anderes Teilsystem eine Arbeit 
erledigt haben will, dann setzt es das entsrpechende Jobflag auf 1.

Und delays - die sind, bis auf ganz kurze Delays, schlicht und 
ergreifend verboten. Denn sie sind der Tod jeden Programmes, das sich um 
mehrere Dinge   'gleichzeitig' kümmern muss.

: Bearbeitet durch User
von Stefan (Gast)


Lesenswert?

Wieso kommt da nur Mist raus, wenn
du den LCD_OUT in der WHILE Schleife ohne
delay hast ? Da stimmt doch was nicht.

von Robert B. (robertb42)


Lesenswert?

@stefan o
Ich meine damit, dass die Loop ja recht schnell ist, sich somit also die 
Zahl auf dem lcd auch viel zu schnell wechselt.

@ Karl werde mich mal bisschen einlesen danke für den Tipp ...

von Robert B. (robertb42)


Lesenswert?

Ich wollte jetzt den Timer0 verwenden aber irgendwie komme ich damit 
nicht klar.

Also in der FAQ steht ich muss erstmal die Bits im OPTION Register 
setzen, also ich hab eine Frequenz von 10MHz und möchte mit Prescaler 
256 rechnen, damit komme ich auf ~38 Interrupts pro Sekunde.

Aus der FAQ:
1
void t0_ini ()
2
{
3
        // Datenblatt Seite 83
4
  OPTION   = 0b11000100;    
5
     // 1-------  (Betrifft nicht Timer0)
6
     // -1------  (Betrifft nicht Timer0)
7
     // --0-----  Internen Takt für Timer0 verwenden
8
     // ---0----  Bei externem Takt an steigender Flanke inkrementieren
9
     //     (in diesem Fall egal ob 1 oder 0 weil der interne Takt verwendet wird)
10
     // ----0---  Prescaler für Timer0 verwenden
11
     // -----100  Prescaler 1:32
12
 
13
  T0IF  = 0;    // Interruptflag von Timer0 löschen
14
  GIE   = 1;    // Alle nichtmaskierten Interrupts erlauben
15
  T0IE   = 1;    // Timer0 Interrupt erlauben
16
 
17
}

in meinem Fall muss ich ja bloß die letzten 2 Bits zu einer 1 machen, 
damit der prescaler 256 ist oder? Aber irgendwie kann ich es nicht 
kompilieren. Ich bekomme die Fehlermeldung undeclared identifier OPTION.

Damit habe ich ja bloß den Counter, jetzt muss ich ja irgendwo die 
Overflows speichern oder? Dann kann ich z.B. nach 38 Overflows(also nach 
einer Sekunde) meine Werte auf dem LCD anzeigen und dann den Counter 
wieder auf 0 setzen. Soweit richtig?
z.B. so:
1
void ISR(TOIF){
2
  static int counter;
3
  counter++;
4
  if(counter==38){
5
    counter=0;
6
    needUpdate=1;
7
  }
8
}
9
10
int main()
11
{
12
  .....
13
14
  while( 1 ) {
15
16
     .....
17
    if( needUpdate ) {
18
      needUpdate = 0;
19
20
      LCD Ausgabe
21
    }
22
  }
23
}

von Stefan (Gast)


Lesenswert?

Versuch es mal so:

//Timer0
//Prescaler 1:128; TMR0 Preload = 61; Actual Interrupt Time : 9,984 ms

//Place/Copy this part in declaration section
void InitTimer0(){
  OPTION_REG   = 0x86;
  TMR0     = 61;
  INTCON   = 0xA0;
}

void Interrupt(){
  if (TMR0IF_bit){
    TMR0IF_bit   = 0;
    TMR0     = 61;
    //Enter your code here
  }
}

Nun läßt du eine Variable 100 mal hochzählen, dann
hast du ca. 1 Sekunde. Dann verzweigst du zu deinem
LCD und gibst Daten auf dem LCD aus.
Also im Hauptprogramm abfragen wann deine Variable 100
erreicht hat.

von Robert B. (robertb42)


Lesenswert?

Habe es jetzt so zum laufen bekommen:
1
void InitTimer0(){                      //Timer0 initialisation
2
  OPTION_REG=0b11000111;               //Prescaler 256
3
}
4
5
void ISR(){                           //Overflow-Counter
6
  if (TMR0IF){                        // if Overflow
7
   counter++;                         // counter++
8
  }
9
  if(counter==38){                    // counter=38 --> 1sec left
10
   counter=0;                         // reset counter
11
   needUpdate=1;                      // Update LCD
12
  }
13
}
14
15
void main{
16
17
 while(1){
18
  
19
  ISR();
20
  ...
21
22
  if(needUpdate==1){
23
   needUpdate=0; 
24
   LCD Anzeige
25
  }
26
 }
27
}

ist das programmiertechnisch in Ordnung? Also das Programm läuft damit 
auch soweit und scheint auch ca. jede Sekunde die Zahl auf dem LCD zu 
ändern aber ich verstehe nicht ganz wie der Algorithmus genau 
funktioniert. Ich rufe ja in jedem while Durchlauf die Funktion ISR auf 
und dann guckt die ob ich Overflow habe oder nicht und je nach dem zählt 
der counter dann hoch. Aber habe ich nicht immer nen Overflow im TMR0IF 
stehen, da der ja schneller Overflow erreicht als ich die while durch 
habe und ich somit eigentlich nicht wirklich 1 Sekunde vergeht bis ich 
was auf dem LCD sehe sondern 38 while loops?

Ich hoffe ihr versteht was ich meine und es kann mir vielleicht einer 
Licht ins Dunkel bringen.

von Stefan (Gast)


Lesenswert?

Wenn du mein Beitrag lesen würdest, dann
erübrigt sich deine Frage.

von Max H. (hartl192)


Lesenswert?

Robert B. schrieb:
> ist das programmiertechnisch in Ordnung?
Nein, die ISR wird von der Hardware automatisch aufgerufen wenn der 
Timer überläuft, die musst du nicht mehr aufrufen, dann musst du das 
TMR0-Interrupt und die Globalen Interrupts erst enablen.

von Robert B. (robertb42)


Lesenswert?

Max H. schrieb:
> Robert B. schrieb:
>> ist das programmiertechnisch in Ordnung?
> Nein, die ISR wird von der Hardware automatisch aufgerufen wenn der
> Timer überläuft, die musst du nicht mehr aufrufen, dann musst du das
> TMR0-Interrupt und die Globalen Interrupts erst enablen.

Wenn ich die ISR nicht in der while abrufe funktioniert es nicht. So wie 
es jetzt ist läuft das Ganze....

Ne Idee was da falsch sein könnte?

von Stefan (Gast)


Lesenswert?

Lies dir im Datenblatt mal durch, welche
Register du setzen mußt für den TIMER 0.
Da fehlt noch einiges.

von Max H. (hartl192)


Lesenswert?

Robert B. schrieb:
> Ne Idee was da falsch sein könnte?
Interrupts enabled?

von Robert B. (robertb42)


Lesenswert?

Also muss ich noch:
1
void InitTimer0(){                      
2
 OPTION_REG=0b11000111;              
3
 TMR0IF=0;
4
 GIE=1;
5
 TMR0IE=1;
6
}
schreiben oder???

der Compiler sagt dann aber "assigning to non-lvalue"

von Robert B. (robertb42)


Lesenswert?

Also ich habe jetzt:
1
void InitTimer0(){                      
2
 TMR0=0;
3
 OPTION_REG=0b11000111;               
4
 INTCON.TMR0IF=0;
5
 INTCON.GIE=1;
6
 INTCON.TMR0IE=1;
7
}
8
9
void ISR(){                           
10
  if (TMR0IF){                        
11
   INTCON.TMR0IF=0;                   
12
   counter++;                        
13
  }
14
  if(counter==38){                   
15
   counter=0;                        
16
   needUpdate=1;                   
17
  }
18
}
19
20
main(){
21
 ...
22
 while(1){
23
  
24
  ISR();
25
  ...
26
  if(needUpdate==1){                                 
27
   needUpdate = 0;
28
   LCD Anzeige
29
  }
30
 }
31
}
Also so wie ich es verstehe macht das Programm jetzt folgendes:
1.)gucken ob in TMR0IF eine 1 steht wenn ja dann ist overflow und er 
setzt  es zurück und zählt mit dem counter einen hoch.
2.)geht zurück in die while und läuft sie durch
3.)guckt wieder ob overflow vorliegt und es geht wieder von vorne los

Es ist nur jetzt so, dass er nicht genau genug Zählt oder? Er muss ja 
erst die while-Scheife durchlaufen(was ja auch seine Zeit kostet) und 
dann checkt er erst ob overflow vorliegt und je nach dem zählt er den 
Counter hoch.

Ich will aber, dass er unabhängig von der while den Counter hochzählt 
und so bald der Counter den eingestellten Wert erreicht hat, die 
if-Anweisung also die LCD Anzeige ausgeführt wird.

Was muss ich dazu ändern und ist es so wie ich es mir Vorstelle 
überhaupt richtig und möglich???

: Bearbeitet durch User
von Stefan (Gast)


Lesenswert?

Nein das ist falsch.
Alle ca. 22ms wird der Interrupt bei dir aufgerufen.
Und dann wird dein Hauptprogramm weiter geführt.
In der Hauptschleife kommt kein Aufruf für
die ISR. Du mußt nur die Interrupts zulassen.
Ein Beispielcode habe ich oben geschrieben.

von Max H. (hartl192)


Lesenswert?

Du musst die ISR nicht aufrufen, diese wird, wenn du Timer und 
Interrupt richtig eingestellt hast automatisch aufgerufen sobald der 
Timer überläuft.
Lies dir mal was zu Interrupts durch: 
http://www.sprut.de/electronic/pic/int/int.htm

: Bearbeitet durch User
von Robert B. (robertb42)


Lesenswert?

Sry stehe irgendwie voll auf dem Schlauch, vielleicht weil ich schon 
solange an dem Problem sitze. Kann jemand von euch vielleicht so Gütig 
sein und mir posten wie es in meinem Beispiel richtig geht?

von Max H. (hartl192)


Lesenswert?

Die Initialisierung dem Timers/Interrupt sollte so passen, lass einfache 
den Aufruf der ISR in der while weg.

von Robert B. (robertb42)


Lesenswert?

Max H. schrieb:
> Die Initialisierung dem Timers/Interrupt sollte so passen, lass einfache
> den Aufruf der ISR in der while weg.

also
1
void InitTimer0(){                      
2
 TMR0=0;
3
 OPTION_REG=0b11000111;               
4
 INTCON.TMR0IF=0;
5
 INTCON.GIE=1;
6
 INTCON.TMR0IE=1;
7
}
8
9
void ISR(){                           
10
  if (TMR0IF){                        
11
   INTCON.TMR0IF=0;                   
12
   counter++;                        
13
  }
14
  if(counter==38){                   
15
   counter=0;                        
16
   needUpdate=1;                   
17
  }
18
}
19
20
main(){
21
 ...
22
 while(1){
23
  
24
  //ISR();
25
  ...
26
  if(needUpdate==1){                                 
27
   needUpdate = 0;
28
   LCD Anzeige
29
  }
30
 }
31
}

so funktioniert es nicht....


@Stefan mein Programm ist doch im Grunde genommen fast gleich mit dem 
was du gepostet hast...

: Bearbeitet durch User
von Max H. (hartl192)


Lesenswert?

Post mal den gesamten Code. Ist "needUpdate" als volatile deklariert?

von Chris B. (dekatz)


Lesenswert?

Nimm die  "void Interrupt()" welche <Stefan> um 14:58
gepostet hat. An der Stelle in der Interruptroutine wo "//enter your 
code here" steht fügst du ein: needUpdate--;

In deiner Main vor dem while(1) kommt:
  needUpdate = 100;

Das ISR() fliegt raus.

Dann deine Endlosschleife:
while(1) {
  if( needUpdate == 0) {
    needUpdate = 100;
    LCD Anzeige
    .....
    .....
   }
}

von hagi (Gast)


Lesenswert?

1
main(){
2
 InitTimer0();   // <-- der Timer muß auch initialisiert werden!!
3
 while(1){
4
  
5
  //ISR();
6
  ...
7
  if(needUpdate==1){                                 
8
   needUpdate = 0;
9
   LCD Anzeige
10
  }
11
 }
12
}

von Robert B. (robertb42)


Lesenswert?

Ja natürlich sry habe mich vertippt, der wird bei mir auch initialisiert 
aber funktioniert trotzdem nicht

von Robert B. (robertb42)


Lesenswert?

Habe jetzt
1
volatile needUpdate;
2
3
void InitTimer0(){
4
  OPTION_REG=0x86;
5
  TMR0=61;
6
  INTCON=0xA0;
7
}
8
9
void Interrupt(){
10
  if (TMR0IF){
11
    INTCON.TMR0IF=0;
12
    TMR0=61;
13
    needUpdate--;
14
  }
15
}
16
17
main(){
18
 InitTimer0();
19
 needUpdate=100;
20
 ...
21
 while(1){
22
  ...
23
  if(needUpdate==0){                                 
24
   needUpdate=100;                                    
25
   LCD Anzeige
26
  }
27
 }
28
}

keine Besserung immer noch keine Anzeige....

von hagi (Gast)


Lesenswert?

1
void Interrupt(){
2
  if (TMR0IF){     // <-- vielleicht INTCON.TMR0IF ??
3
    INTCON.TMR0IF=0;
4
    TMR0=61;
5
    needUpdate--;
6
  }
7
}

von Robert B. (robertb42)


Lesenswert?

hagi schrieb:
>
1
> void Interrupt(){
2
>   if (TMR0IF){     // <-- vielleicht INTCON.TMR0IF ??
3
>     INTCON.TMR0IF=0;
4
>     TMR0=61;
5
>     needUpdate--;
6
>   }
7
> }
8
>

schon probiert bringt auch nix

von Chris B. (dekatz)


Lesenswert?

Robert B. schrieb:
> Habe jetzt
>
1
>.........
2
> 
3
> main(){
4
>  InitTimer0();
5
>  needUpdate=100;
6
>  ...
7
>  while(1){
8
>   ...
9
>   if(needUpdate==0){
10
>    needUpdate=100;
11
>    LCD Anzeige
12
>   }
13
>  }
14
> }
>
> keine Besserung immer noch keine Anzeige....

Ist das alles?? Wenn ja, dann fehlt die Initialisierung des LCD!
Und LCD Anzeige ist ja wohl kein Funktionsaufruf.
Stell mal das GESAMTE Programm als Anhang rein....

von Robert B. (robertb42)


Lesenswert?

Die Initialisierung steht selbstverständlich im richtigen Programm drin.

Mich wundert bloß warum funktioniert das ganze wenn ich die ISR() in der 
while Aufrufe und wenn ich die weg lasse passiert nix....

so wie ich das verstehe sieht die while schleife die needUpdate variable 
gar nicht... vielleicht läuft der Timer ja auch ohne ISR Funktion in der 
while aber der Wert wird bloß nicht übergeben oder so und deswegen führt 
er die if Anweisung nicht aus und ich sehe nix auf dem LCD

: Bearbeitet durch User
von hagi (Gast)


Lesenswert?

1
 void Interrupt(){

Vielleicht erwartet dein Compiler einen anderen Namen für die ISR.
Immerhin muß er ja wissen das "Interrupt" die ISR sein soll.
Ohne diese Kenntnis wird deine ISR niemals (automatisch) aufgerufen.

Zum Compiler gehören normalerweise auch einige Beispiele.
Da ist bestimmt etwas mit einer ISR dabei.

Da ich deinen Compiler nicht kenne, mußt du das Manual selber lesen ;)

von Stefan (Gast)


Lesenswert?

Setz folgenden Befehl nach dem InitTimer0:
TMR0IE_bit = 1

von Robert B. (robertb42)


Lesenswert?

hagi schrieb:
>
1
>  void Interrupt(){
2
>
>
> Vielleicht erwartet dein Compiler einen anderen Namen für die ISR.
> Immerhin muß er ja wissen das "Interrupt" die ISR sein soll.
> Ohne diese Kenntnis wird deine ISR niemals (automatisch) aufgerufen.
>
> Zum Compiler gehören normalerweise auch einige Beispiele.
> Da ist bestimmt etwas mit einer ISR dabei.
>
> Da ich deinen Compiler nicht kenne, mußt du das Manual selber lesen ;)


sowas in der Art denke ich mir auch ich benutze MicroC for PIC weiß ich 
die ISR da nennen muss, damit er sie erkennt??

Anbei hier mal der gesamte Quellcode:
1
int i;
2
volatile needUpdate;
3
static int counter=0;
4
float adc=(float)5/1024;
5
unsigned Vtemp;
6
float Vpv,Vtemp1,Vtemp2,Vtemp3;
7
char text_1[] = "Spannungsmessung";
8
char text_2[] = "Vpv:[V]";
9
char txt1[7];
10
11
// Lcd pinout settings
12
sbit LCD_RS at RC2_bit;
13
sbit LCD_EN at RC3_bit;
14
sbit LCD_D7 at RC7_bit;
15
sbit LCD_D6 at RC6_bit;
16
sbit LCD_D5 at RC5_bit;
17
sbit LCD_D4 at RC4_bit;
18
19
// Pin direction
20
sbit LCD_RS_Direction at TRISC2_bit;
21
sbit LCD_EN_Direction at TRISC3_bit;
22
sbit LCD_D7_Direction at TRISC7_bit;
23
sbit LCD_D6_Direction at TRISC6_bit;
24
sbit LCD_D5_Direction at TRISC5_bit;
25
sbit LCD_D4_Direction at TRISC4_bit;
26
27
void InitTimer0(){
28
 TMR0=0;
29
 OPTION_REG=0x86;
30
 INTCON.TMR0IF=0;
31
 INTCON.GIE=1;
32
 INTCON.TMR0IE=1;
33
}
34
35
ISR(){
36
  if (INTCON.TMR0IF){
37
   INTCON.TMR0IF=0;
38
   counter++;
39
  }
40
   if(counter==38){
41
    counter=0;
42
    needUpdate=1;
43
  }
44
}
45
46
float Vin_Calculation(){                     // Calculation of Vinput
47
 Vpv=0;
48
 for(i=1;i<=4;i++){                          // i time read ADC input
49
  Vtemp=ADC_Read(0);                         // ADC result from pin A0
50
  Delay_us(100);                             // time for the Capacitor
51
  Vpv=Vpv+Vtemp;
52
 }
53
 Vtemp1=Vpv*10;                                 // potential divider
54
 Vtemp2=Vtemp1*adc;
55
 Vpv=Vtemp2/(i-1);
56
57
 return Vpv;
58
 }
59
60
61
void main() {
62
63
 InitTimer0();
64
65
 Lcd_Init();                        // Initialize LCD Module
66
 Lcd_CMD(_LCD_CURSOR_OFF);          // Cursor OFF
67
 Lcd_Cmd(_Lcd_Clear);               // Clear display
68
 Lcd_Out(1,1,text_1);               // Text on LCD 1row
69
 Lcd_Out(2,1,text_2);               // Text on LCD 2row
70
71
 while(1){
72
73
  Vpv=Vin_Calculation();
74
  
75
  if(needUpdate==1){
76
   needUpdate=0;
77
   FloatToStr(Vpv,txt1);
78
   Lcd_Out(2,11,txt1);
79
  }
80
 }
81
 
82
}

Edit: @hagi genau daran hat's gelegen. Ich danke dir vielmals jetzt 
läuft es einwandfrei.

: Bearbeitet durch User
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.