mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Rechnen mit PIC18 und C18


Autor: Andreas Riegebauer (blackpuma)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo!

Ich bin erst vor ganz kurzem auf den C18 umgestiegen und das Teil nervt 
jetzt schon. Vielleicht kann mir jemand von euch helfen und sagen was da 
falsch läuft.

Genauer gesagt habe ich keine Ahnung wie die Rechung laufen soll! 
Irgendwas funktioniert dabei nicht. Es kommt immer nur 0.0V raus.

unsigned short long mess_erg, temp;
.
.
.
while(1) {
  Delay10KTCYx( 100 );

  ConvertADC();       // Start conversion
  while( BusyADC() );   // Wait for ADC conversion

  mess_erg  = ADRESH * 256;
  mess_erg += ADRESL;

  temp = (unsigned) mess_erg * 50;
  temp = (unsigned) temp / 1022;

  Einer = (int)(temp/10);
  Zehntel = (int)(temp%10);

  while(BusyUSART());
  WriteUSART(Einer|0x30);
  while(BusyUSART());  
  WriteUSART('.');
  while(BusyUSART());  
  WriteUSART(Zehntel|0x30);
  while(BusyUSART());  
  WriteUSART('V');
}

MfG
Andreas

Autor: Frank (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Was passiert wenn du "mess_erg" ausgibst?

Autor: Andreas Riegebauer (blackpuma)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wie kann ich mir das ausgeben lassen?

Autor: Der Micha (steinadler)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Der Fehler muss beim Lesen vom ADC auftreten.
Habe das mal eben durchsimuliert. Da treten nämlich keine Fehler auf.
Also die Rechnung selbst stimmt.
Wobei ich aus der 1022 eine 1024 machen würde.

Hast du denn den richtigen Kanal erst ausgewählt?

Autor: Andreas Riegebauer (blackpuma)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ja das muss ich noch ändern. die 1022 hab ich von cc5x übernommen.

Wenn ich mir ADRESL und ADRESH auf die Serielle schicke dann 
funktioniert das. Also Werte werden sicher gemessen. Hab da einen 
Drucksensor dran und wenn ich da reinpuste oder ansauge ändert sich der 
Wert.

Autor: Der Micha (steinadler)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Verunde mal die Werte mit den 10Bit nach dem Einlesen.

Also:
  mess_erg  = ADRESH * 256;
  mess_erg += ADRESL;
  mess_erg &= 0x3F

Autor: Gast (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
was für ein Datentyp soll denn das sein?

> unsigned short long mess_erg, temp;

entweder unsigned short
oder unsigned long

Eventl. hilft es sich die Werte von temp und mess_erg mal im Debugger 
anzuschauen wenn der PIC läuft.
Gruss K.

Autor: Der Micha (steinadler)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Habe jetzt nochmal probiert.
Aus unsigned short long werden übrigens 24Bit.

Mach es doch gleich so:
  mess_erg  = ADRES;

Autor: Andreas Riegebauer (blackpuma)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hab jetzt ein wenig umgebaut und ich schreibe die Ausgabe noch dazu.


void main(void)
{
  int mess_erg;
  unsigned temp;
  char Einer, Zehntel;

  init();

  while(1) {
    Delay10KTCYx( 100 );

    ConvertADC();       // Start conversion
    while( BusyADC() );   // Wait for ADC conversion
    mess_erg = ReadADC();  // Read result and put in temp

// Ausgabe der unbearbeiteten ADRESL und ADRESH
    while(BusyUSART());
    WriteUSART(ADRESH);
    while(BusyUSART());
    WriteUSART(ADRESL);
    while(BusyUSART());
    WriteUSART( ' ' );

    temp = (unsigned)mess_erg * 50;
    temp = (unsigned)temp / 1024;  // Ergibt den Messwert in Zehntel

    Einer = (char)(temp/10);
    Zehntel = (char)(temp%10);

    Einer |= 0x30;
    Zehntel |= 0x30;

    while(BusyUSART());
    WriteUSART(Einer);
    while(BusyUSART());
    WriteUSART('.');
    while(BusyUSART());
    WriteUSART(Zehntel);
    while(BusyUSART());
    WriteUSART('V');
[/c]

Das ist die Ausgabe die beim Hyperterminal ankommt:
~ ô.:V
 ô.:V
~ ô.:V
~ ô.:V
 ô.:V

Autor: Frank (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Versuch es mal hiermit:

Einer += 0x30;
Zehntel += 0x30;

Autor: Andreas Riegebauer (blackpuma)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hab das jetzt mit += gemacht und jetzt kommt das raus:

Die ersten beiden Kryptischen sind ADRESH und ADRESL.
 $.JV

Autor: Der Micha (steinadler)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Bist du sicher, dass das Ergebnis in ADCH:ADCL "right adjusted" ist???
ADCON2.ADFM musst du auf 1 setzen.

Autor: Frank (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Kann es mit der Typumwandlung von "unsigned temp" nach "signed char" zu 
tun haben? Versuch es doch mal mit "unsigned char"

Autor: Andreas Riegebauer (blackpuma)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Die Initialisierung des A/D-Wandlers sieht so aus.
// A/D Wandler initialisieren
  OpenADC(ADC_FOSC_8 & ADC_RIGHT_JUST & ADC_4_TAD,ADC_CH0 & ADC_INT_OFF & ADC_VREFPLUS_VDD & ADC_VREFMINUS_VSS,0b1110);
  SetChanADC(ADC_CH0);

Hab auch schon unsigned char versucht. Ohne Erfolg.

Autor: Andreas Riegebauer (blackpuma)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
So folgendes. Es funktioniert nun zum Teil. Im folgenden sind 2 
Programmcodes mit Ausgabe. Die erste funktioniert und die zweite nicht 
mehr. Vielleicht wisst ihr warum.

Ich habe lediglich den Multiplikator geändert und der Variablen string 
einen weiteren Wert spendiert.

Vielleicht könnt ihr auch einen Blick auf das Config Word machen und 
sagen ob noch etwas fehlt.

#include <p18f2410.h>
#include <usart.h>
#include <delays.h>
#include <adc.h>

#pragma config OSC  = INTIO67  // Interner Oszillator, Port function on RA6 u. RA7
#pragma config WDT  = OFF    // Watchdog Timer Off
#pragma config PWRT = ON
#pragma config LVP = OFF     //Low Voltage ICSP 

#pragma code

// **************************************************************************************
// init: Initialisierung des PIC
// **************************************************************************************

void init(void)
{
  OSCCONbits.IRCF1 = 1;    // CPU auf 4MHz einstellen

  TRISC = 0x00;

  // USART initialisieren
  OpenUSART(USART_TX_INT_OFF & USART_RX_INT_OFF & USART_ASYNCH_MODE & USART_EIGHT_BIT & USART_CONT_RX & USART_BRGH_HIGH, 25);

  // A/D Wandler initialisieren
  OpenADC(ADC_FOSC_8 & ADC_RIGHT_JUST & ADC_4_TAD,ADC_CH0 & ADC_INT_OFF & ADC_VREFPLUS_VDD & ADC_VREFMINUS_VSS,0b1110);
  SetChanADC(ADC_CH0);

} //init

// **************************************************************************************
// main: Hauptprogramm
// **************************************************************************************

void main(void)
{
  int mess_erg;
  unsigned short long temp;
  char string[10];

  init();

  while(1) {
    Delay10KTCYx( 100 );

    ConvertADC();       // Start conversion
    while( BusyADC() );   // Wait for ADC conversion
    mess_erg = ReadADC();  // Read result and put in mess_erg

    temp = mess_erg * (unsigned)50;
    temp = temp / (unsigned)1024;

    string[1]=(temp % 10) +'0';         // Modulo rechnen, dann den ASCII-Code von '0' addieren
      temp /= 10;
    string[0]=(temp % 10) +'0';         // Modulo rechnen, dann den ASCII-Code von '0' addieren

    while(BusyUSART());
    WriteUSART( string[0] );
    while(BusyUSART());  
    WriteUSART('.');
    while(BusyUSART());  
    WriteUSART( string[1] );
    while(BusyUSART());  
    WriteUSART('V');

    while(BusyUSART());    // Neue Zeile
    WriteUSART( 0x0D );
    while(BusyUSART());
    WriteUSART( 0x0A );
  } //while
}

Die Ausgabe stimmt. Ich habe sie mit einem Multimeter am Sensor 
gemessen.

4.3V
4.3V
4.3V
4.3V
4.3V
4.3V


Nachdem das erste Programm funktioniert wollte ich die mehr Genauigkeit 
also wollte ich eine Kommastelle mehr haben.

#include <p18f2410.h>
#include <usart.h>
#include <delays.h>
#include <adc.h>

#pragma config OSC  = INTIO67  // Interner Oszillator, Port function on RA6 u. RA7
#pragma config WDT  = OFF    // Watchdog Timer Off
#pragma config PWRT = ON
#pragma config LVP = OFF     //Low Voltage ICSP 

#pragma code

// **************************************************************************************
// init: Initialisierung des PIC
// **************************************************************************************

void init(void)
{
  OSCCONbits.IRCF1 = 1;    // CPU auf 4MHz einstellen

  TRISC = 0x00;

  // USART initialisieren
  OpenUSART(USART_TX_INT_OFF & USART_RX_INT_OFF & USART_ASYNCH_MODE & USART_EIGHT_BIT & USART_CONT_RX & USART_BRGH_HIGH, 25);

  // A/D Wandler initialisieren
  OpenADC(ADC_FOSC_8 & ADC_RIGHT_JUST & ADC_4_TAD,ADC_CH0 & ADC_INT_OFF & ADC_VREFPLUS_VDD & ADC_VREFMINUS_VSS,0b1110);
  SetChanADC(ADC_CH0);

} //init

// **************************************************************************************
// main: Hauptprogramm
// **************************************************************************************

void main(void)
{
  int mess_erg;
  unsigned short long temp;
  char string[10];

  init();

  while(1) {
    Delay10KTCYx( 100 );

    ConvertADC();       // Start conversion
    while( BusyADC() );   // Wait for ADC conversion
    mess_erg = ReadADC();  // Read result and put in mess_erg

    temp = mess_erg * (unsigned)500;
    temp = temp / (unsigned)1024;

    string[2]=(temp % 10) +'0';         // Modulo rechnen, dann den ASCII-Code von '0' addieren
      temp /= 10;
    string[1]=(temp % 10) +'0';         // Modulo rechnen, dann den ASCII-Code von '0' addieren
      temp /= 10;
    string[0]=(temp % 10) +'0';         // Modulo rechnen, dann den ASCII-Code von '0' addieren

    while(BusyUSART());
    WriteUSART( string[0] );
    while(BusyUSART());  
    WriteUSART('.');
    while(BusyUSART());  
    WriteUSART( string[1] );
    while(BusyUSART());  
    WriteUSART( string[2] );
    while(BusyUSART());  
    WriteUSART('V');

    while(BusyUSART());    // Neue Zeile
    WriteUSART( 0x0D );
    while(BusyUSART());
    WriteUSART( 0x0A );
  } //while
}

Die ausgabe stimmt nun nicht mehr.

0.53V
0.53V
0.53V
0.53V
0.53V
0.53V

Danke für eure Hilfe! Ich kämpfe schon den ganzen Tag mit dem Zeug.
Andreas

Autor: eProfi (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
temp = mess_erg * (unsigned)500;

vermutlich wird temp zu groß werden, um in 24 Bits zu passen.

Autor: Der Micha (steinadler)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
eProfi wrote:
> temp = mess_erg * (unsigned)500;
>
> vermutlich wird temp zu groß werden, um in 24 Bits zu passen.

Das glaube ich eher nicht, denn
1024 * 500 =   512000 (0x7D000)

Probiers mal so:
temp = (unsigned short long)mess_erg * (unsigned short long)500;
temp = temp / (unsigned short long)1024;

Autor: Andreas Riegebauer (blackpuma)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Micha:
Danke hat funktioniert. Kannst du mir erklären was das jetzt eigentlich 
macht das ich auf die Lösung auch selber kommen kann? Jetzt bekomme ich 
als Ergebnis

4.389V
4.389V
4.384V
4.384V
4.389V

Bei noch einer Kommastelle mehr hab ich das gleiche Problem das die 
Werte wieder nicht passen.

Ich habe im Moment einen 10Bit Wandler aber möchte bald einen 12 od. 14 
Bit Wandler und da brauche ich die bessere Auflösung.

Danke
Andreas

Autor: Michael Wilhelm (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Durch diesen Cast auf der rechten Site der Rechnung wird der Compiler 
gezwungen die ganze Rechnung mit den größten Datentyp durchzuführen. 
Vorher, bei 16 Bit , hat es einen Überlauf gegeben.

MW

Autor: Der Micha (steinadler)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Also ich habe die Erfahrung gemacht, dass es sich am besten rechnen 
lässt, wenn man die Werte vorher alle in den Ergebnisdatentyp castet.

Du musst erst einmal sicherstellen, dass alle Rechnungen auch in deinen 
Ergebnisdatentyp reinpassen.
z.B. passt bei einem 12-Bit-Wandler (4096 * 5000) nicht mehr in 24 bit.
Hierzu müsstest du dann unsigned long nehmen (ohne short).

Bzgl. der weiteren Kommastelle musst du deine Ausgaberoutine nochmal 
anpassen, da hier auch die Tausender mit berücksichtigt werden müssen.

Autor: Andreas Riegebauer (blackpuma)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
OK Danke. Das mit dem cast hat funktioniert. Die Ausgabe sollte auch für 
einen 12 bit A/D Wandler passen.
4.38476V
4.38964V
4.38964V
4.24316V
4.37500V
4.38964V
4.38964V

Danke euch allen.

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.