Forum: Mikrocontroller und Digitale Elektronik dsPIC A/D-Wandlung berechnen und über UART ausgeben


von Lars Herzfeld (Gast)


Lesenswert?

Hallo,

ich habe ein Problem mit der Berechnung der Werte des A/D-Wandlers.
Momentan bin ich dabei ein Beispielprogramm in MPLAB mit dem C30 
Compiler zu schreiben. Dabei verwende ich MPLAB Sim als Simulator.
Nun mein Problem. Ich lese am ADCBUF0 einen Wert über den Stimulus ein. 
Dieser Wert wird mir auch im entsprechenden Register im Watch Window 
angezeigt. Diesen Wert möchte ich dann weiterverarbeiten und über den 
UART ausgeben. Leider habe ich inzwischen keine Idee mehr, wie ich den 
eingelesenen Wert berechne, so dass ich später im SIM UART1 den 
richtigen Wert angezeigt bekomme.

Bsp.: Ich lese über die Datei ADC.txt im ADCBUF0 eine 5 (dezimal) ein. 
Dann zeigt mir das Watch Windoe für den ADCBUF0 als HEX 0x0005 und DEC 5 
an. Wenn ich diesen Wert in das U1TXREG schiebe gibt mir das UART Sim 
richtigerweise den entsprechenden ASCII Wert für 05 aus. Wie führe ich 
jetzt die Berechnung durch, dass ich in das U1TXREG entsprechend meinen 
5V Spannung, die ich ausgegeben habe eine 0x0035 schiebe und damit im 
UART Sim eine 5 angezeigt bekomme?

Das simpelste ist natürlich, dass ich dem Wert 0x0005 mit 0x0030 addiere 
nur kann ich mir nicht vorstellen, dass das funktioniert, wenn ich 
später mit einem dsPIC 30F4012 eine Spannung messen möchte. Vor allem 5V 
ist momentan das Bsp. Wie mache ich das bspw. für 1,5V?

Hat jemand noch ein Beispiel zur Verwendung der uart.h?
Hier mein bisheriger Programmcode.

#include <p30fxxxx.h>
#include <delay.h>

_FOSC(CSW_FSCM_OFF & HS);
_FWDT(WDT_OFF);
_FBORPOR(MCLR_EN & PWRT_OFF);
_FGS(CODE_PROT_OFF);

int main (void);
void lars (void);

int main (void)
{

// Setze alle Ports als Ausgang
  TRISB = 0;
  TRISC = 0;
  TRISD = 0;
  TRISE = 0;
  TRISF = 0;
  TRISBbits.TRISB2 = 1;
  ADPCFG = 0xFFFF;
  ADPCFGbits.PCFG2 = 0;
  ADCON2bits.VCFG = 3;
  ADCON3bits.ADRC = 1;
  ADCON3bits.ADCS = 0;
  ADCON2bits.CHPS = 0;
  ADCON1bits.SIMSAM = 0;
  ADCSSL = 0x0000;
  ADCHS = 0x0002;
  ADCON1bits.SSRC = 7;
  ADCON3bits.SAMC = 1;
  ADCON1bits.FORM = 0;
  ADCON2bits.SMPI = 0;
  ADCON1bits.ADON = 1;

  U1BRG = 0x0081;
  U1MODEbits.PDSEL = 0;
  U1MODEbits.STSEL = 1;

  while(1)
  {
    //lars();

    int ADC;

    ADCON1bits.SAMP = 1;
    Delay_1S_Cnt;
    ADCON1bits.SAMP = 0;
    while(!ADCON1bits.DONE);
    ADC = ADCBUF0;

    U1MODEbits.UARTEN = 1;
    U1STAbits.UTXEN = 1;
    U1TXREG = ADC;
    U1MODEbits.UARTEN = 0;
  }
  return 0;
}

Danke für die hoffentlich zahlreiche Hilfe.


Gruß Lars

von Gerhard (Gast)


Lesenswert?

Hallo Lars

für die Hex-ASCII UMwandlung gibts in der Bibliothek die 
sprintf-Funktion, oder falls dir sprintf zu viele Resourcen kostet 
schreib dir selber ein itoa()

Gerhard

von Dieter Werner (Gast)


Lesenswert?

Der aus dem A/D Wandler gelesene "Rohwert" sollte erst mit einem 
passenden Skalierungsfaktor multiplizirt werden bevor man ihn ausgibt, 
dann kann auch z.B. 5V einem Wert von 317 entsprechen.

von Zoch (Gast)


Lesenswert?

Weshalb den dsPIC rechnen lassen, wenn der PC das viel besser kann ?

Z.

von Lars Herzfeld (Gast)


Lesenswert?

@all

Danke für die schnellen Antworten.

@ Gerhard

werde ich mal suchen und schauen, wieviel Platz das benötigt.

@ Dieter

Ich dachte an die Formel: Messwert * (Refspannung/1024) bei 10 Bit 
Wandlung, nur habe ich wohl irgendwie "nen Brett vorm Kopf", weil ich es 
dann nicht wieder als Ausgabe umgerechnet bekomme.

@ Zoch

Ich muss den dsPIC rechnen lassen, weil er in einem Messgerät eingesetzt 
werden soll, welches in aller letzter Konsequenz die berechneten Werte 
auf nem LCD anzeigt. Möchte das bloß jetzt testweise dann über die UART 
an den PC schicken. Muss hinterher auch noch ne FFT auf die Werte 
basteln, da ich aus den gewandelten Werten den Frequenzanteil brauche. 
Aber ich möchte alles schrittweise aufbauen und dazu gehört als erstes 
für mich, die AD-Wandlung und dann die Ausgabe über UART an den PC.

Über weitere Tipps bin ich dankbar.

Danke

Lars

von Andi (Gast)


Lesenswert?

Hallo Lars

Zuerst skalierst du den Messwert so, dass du bei 5V den Wert 500 erhälst 
(bei 3.3V Eingang hast du dann 330 usw). Diesen Wert rechnst du nun 
durch 100 und bekommst die Hunderter. Dazu addierst du 0x30 und hast den 
ASCII Wert für die Hunderter. Dann zählst du vom skalierten Messwert die 
Hunderter*100 ab und teilst durch 10 - so bekommst du die Zehner, wieder 
+ 0x30 und du hast den ASCII Wert usw. bis zu den Einern. Zwischen dem 
Hunderter und dem Zehner-ASCII Wert sendest du noch den Dezimalpunkt und 
der PC wird 5 . 0 0 erhalten.

Gruss Andi

von Lars H. (larsherzfeld)


Lesenswert?

Hallo,

danke nochmal für die Vorschläge und Antworten.

Ich habe das Problem jetzt anders lösen können.

Es geht mit der printf-Funktion.

Es gibt aber einen Bug in der 2.04/2.05 Release der Software und 
deswegen konnte ich printf nicht nutzen.

Hier ein Link der den Bug beschreibt:

http://forum.microchip.com/printable.aspx?m=116714

Ich hatte das gleicht Problem, wie nau001133, aber die Antwort von 
cawilkie hat geholfen.

Mein Code sieht jetzt so aus:

#include <p30fxxxx.h>
#include <dsp.h>
#include <stdio.h>
#include <delay.h>
#include <math.h>
#include <libpic30.h>

_FOSC(CSW_FSCM_OFF & HS);
_FWDT(WDT_OFF);
_FBORPOR(MCLR_EN & PWRT_OFF);
_FGS(CODE_PROT_OFF);


int U2MODEbits;
int U2TXREG;
int U2BRG;
int U2STAbits;


int main (void);
void lars (void);

int main (void)
{

// Setze alle Ports als Ausgang
  TRISB = 0;
  TRISC = 0;
  TRISD = 0;
  TRISE = 0;
  TRISF = 0;
  TRISBbits.TRISB2 = 1;
  ADPCFG = 0xFFFF;
  ADPCFGbits.PCFG2 = 0;
  ADCON2bits.VCFG = 3;
  ADCON3bits.ADRC = 1;
  ADCON3bits.ADCS = 0;
  ADCON2bits.CHPS = 0;
  ADCON1bits.SIMSAM = 0;
  ADCSSL = 0x0000;
  ADCHS = 0x0002;
  ADCON1bits.SSRC = 7;
  ADCON3bits.SAMC = 1;
  ADCON1bits.FORM = 0;
  ADCON2bits.SMPI = 0;
  ADCON1bits.ADON = 1;

  U1BRG = 0x0081;
  U1MODEbits.PDSEL = 0;
  U1MODEbits.STSEL = 1;

  while(1)
  {
    //lars();



    double ADC;
    ADCON1bits.SAMP = 1;
    Delay_1S_Cnt;

    while(!ADCON1bits.DONE);
    ADC = ADCBUF0;
    ADCON1bits.SAMP = 0;
    ADC = ADC*5/1023;
    printf("%f \n", ADC);


  }
  return 0;
}

Gruß Lars

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.