Forum: Mikrocontroller und Digitale Elektronik PIC18f1220 ADU Problem


von Fff T. (teichert)


Angehängte Dateien:

Lesenswert?

Hallo,

wir arbeiten gerade an einem Studienprojekt. Es soll ein Fahrpult für 
eine digitale Modelleisenbahn erstellt werden (CCD-Protokoll).

Hierzu verwenden wir eine selbergelötete Platine mit einem PIC18f1220. 
Um die gewünschte Geschwindigkeit zu ermitteln, wird ein analoger Wert 
eines Potis (10kOhm) eingelesen, umgewandelt, daraus eine 
Rechteckspannung erzeugt und soll ausgegeben werden.

Um das Board zu testen, habe ich den 10Bit-ADU sozusagen auf 1Bit 
Genauigkeit beschränkt und das Bit an dem Ausgangsport ausgegeben, an 
dem sich eine LED befindet. Diese LED ist die einzige 
Debugging-Möglichkeit, die wir haben!

Bewege ich nun das Poti über die Mittelstellung hinaus, beginng die LED 
zu leuchten! so soll es sein. Allerdings leuchtet sie nicht permanent, 
sondern blinkt. Es scheint als würde der ADU ab und zu falsche Werte 
liefern.

Kennt jemand das Problem oder eine geeignete Lösung dazu?

Zum Programmieren verwenden wir die MCC18-Studenten-Version. Zum 
Programmieren das PIKKIT2 (weil wir es leihen konnten..).

In dem Datenblatt steht etwas davon, dass der ADU über höchstens 2,5kOhm 
geladen werden darf - wir verwenden aber 10kOhm. Daher habe ich versucht 
diesen zu überbrücken. Leider ließ sich der Fehler dadurch nicht 
beheben.

Die LED am Ausgang wird ohne externen Vorwiderstand betrieben. Ich meine 
a ber, dass die verwendeteten LEDS einen besitzen. Wird beispielsweise 
der Ausgang nur auf HIGH gesetzt, leuchtet die LED durch, sodass ich 
nicht davon ausgehe, dass die Spannung zusammenbricht, weil die LED 
zuviel Strom zieht o.ä. .

Vielen Dank.

MfG

von Schoasch (Gast)


Lesenswert?

Hi

1. LEDs brauchen immer einen Vorwiderstand!!!! Ansonst zerstörst du die 
LED und den Pin!

2. 10kOhm sind schon recht hoch. Hast du dir mal TAD Ausgerechnet? Die 
Formel dazu findest du im Datenblatt. Ich hab jetzt nicht nachgerechnet 
oder mit deinem Code verglichen... aber verlänger einmal die Wartezeit.
Falls dir das zu lange dauert, musst du dann entweder das Poti kleiner 
machen, oder aber eine Treiber vorschalten.

mfg Schoasch

von Fff T. (teichert)


Lesenswert?

Vielen Dank für die Antwort.

Die LEDs haben einen Vorwiderstand eingebaut - habe nochmal nachgesehen.

die TAD habe noch nicht ausgerechnet. Habe aber alle möglichen 
TAD-Zeiten durchprobiert und konnte keine Veränderung des Problems 
feststellen. Außerdem habe ich ja das Poti überbrückt und dieselben 
Probleme erhalten.

Andere Ideen?

MfG

von Schoasch (Gast)


Lesenswert?

Hi

Ich will nicht unhöflich sein, aber dein C-Code ist sehr unangenhem zu 
lesen. Kannst du mal ein File anhängen in dem nur der Code drinn ist, 
der für das PRoblem wirklich gebraucht wird.

Was mir abgeht, ist die Initialisierung der TRIS-Registers.Soll das das 
sein?:
1
        DDRB = 0x0E;
2
  DDRA = 0x03;
(DDRx kenn ich nur von den ATMega... bei den PIC hab ich so ein register 
noch nie gsehen ;-))

Hast du schon mal Probiert, ohne den Funktionen aus der adc.h das 
AD-Wandlermodul zu betreiben. Also echt von Hand die ganzen Bits setzen?
Ich würd dir da eifnach empfehlen, dass du dir selbst deine Init routine 
zusammenstellst. ISt nicht viel aufwand, aber dann lernst du was und die 
Fehlersucher wird einfacher.

mfg schoasch

PS.: Ich habs nochmal überflogen... ich seh hier nirgends einen Zugriff 
auf ein TRIS-Regsiter! Ausserdem solltest du beim schreiben nicht ins 
Port-Register sondern ins LAT-Register schreiben. Damit vermeidest du 
read-modify-write Probleme.

von Fff T. (teichert)


Lesenswert?

Ja, der Code hat etwas "Baustellen-Charakter" ..

Ich habe ihn mal etwas gesäubert.

Ich hatte eigentlich gehofft, durch die Verwendung der herstellereigenen 
Libraries das manuelle Setzen einzelner Bits zu vermeiden. Ich gehe 
davon aus, dass die Libraries fehlerfrei implementiert sind. Habe aber 
keine Ahnung, ob ich mich darauf unbedingt verlassen könnte.

Vielleicht findet jetzt jemand das Problem.

Ich werde die manuelle Methode morgen testen.

MfG

1
#include <stdlib.h>
2
#include <adc.h>
3
#include <delays.h>
4
#include <p18f1220.h>
5
6
#pragma config WDT = OFF
7
8
#define __OUTPIN PORTBbits.RB0
9
10
void init (void) {
11
  OSCTUNE = 0x00;
12
13
14
  DDRB = 0x0E;
15
  DDRA = 0x03;
16
17
  OpenADC ( ADC_FOSC_RC      // Umsetzung mit dem Oszillatortakt
18
        & ADC_RIGHT_JUST   // Rechtsbündiges Ergebnis in Integer
19
        & ADC_12_TAD,
20
          ADC_CH0          // Kanal 0
21
        & ADC_INT_OFF      // Interrupts deaktivieren
22
        & ADC_VREFPLUS_EXT // Referenzspannung ist die Versorgungsspannung
23
        & ADC_VREFMINUS_EXT // Negativ aus masse..
24
    ,15  ); 
25
  Delay10TCYx(50);
26
27
  return;
28
}
29
30
31
void main (void) {
32
  
33
  int speed=0;
34
  
35
36
  // Initialisierungen durchführen:
37
  init();
38
39
40
  blink(100, 3);
41
42
43
  while (1) {
44
    
45
46
    ConvertADC();
47
    // Auf die Umsetzung warten:
48
    while(BusyADC())
49
      ;
50
    //speed = (ReadADC() >> 5);
51
    speed = ReadADC();
52
    
53
    // der eingelesene wert an dieser stelle schwankt zwischen dem eingestellten wert und
54
    // irgendwelchem müll (vermutlich null)
55
    speed = (speed >> 9);
56
    //if ((speed > 20) || (speed < 10)) {
57
    if (speed) {
58
      __OUTPIN = 1; 
59
    } else {
60
      __OUTPIN = 0;
61
    }
62
    
63
  }
64
}

von Fff T. (teichert)


Lesenswert?

Um möglichen Antworten zuvorzukommen:
blink() ist jetzt nicht mehr im Code, wird aber verwendet.
An der LED soll nur das MSB des ADU-Werts ausgegeben werden.

Danke.

von Schoasch (Gast)


Lesenswert?

Hi

Hier mal so die Fehler die mir auffallen:
1
#define __OUTPIN PORTBbits.RB0
Wie schon erwähnt... schreib nicht in die PORT-Register sondern in die 
LAT-Register!


So... ich hab mal folgendes geschrieben:
1
void init()
2
{
3
  TRISA = 0x01;  //RA0 = Input
4
   
5
  //Analogwandler Einstellungen
6
  ADCON1 = 0x01;   //RA0 = Analog Input
7
  ADCON0 = 0x00;  //Enspricht deinen einstellungen
8
  ADCON2 = 0xAF; //-------||---------------
9
10
  ADCON0 = 0x01; // Enable ADC
11
12
  Delay10TCYx(50);
13
}
14
15
int read_ADC_bool ()
16
{
17
  ADCON0bits.GO = 1; //Start ADC
18
19
  while(ADCON0bits.GO); //Wait for A/D conversion to complete
20
21
  return ADRESH>>1;
22
}

Ich hab den Code jetzt nicht ausprobiert... aber so in etwa sollte das 
funktionieren.

mfg Schoasch

von Fff T. (teichert)


Lesenswert?

Hallo,

heute habe ich mit meinem Kommilitonen alle Probleme beseitigen können.
Mit Hilfe eines Oszilloskops, konnten wir relativ schnell die Lösung des 
Fehlers finden.

Den ADU initialisieren wir jetzt manuelle. Der Fehler lag leider an 
einer ganz anderen Stelle.
Entweder war dieser ein Problem des C-Compilers oder war "hausgemacht":

Der Code
1
(ad_val & 0x0008)
soll beispielsweise Bit(3) auf "Gesetzt-Sein" prüfen und gibt ja (meine 
ich jedenfalls normalerweise) 1 zurück, sodass man diesen Rückgabewert 
einem Bit (beispielsweise einem Ausgangsbit) zuweisen kann.

-> Dem ist scheinbar gar nicht so!

Ersetzt man diesen Code jetzt durch folgendes:
1
(ad_val & 0x0008)?1:0;
kann dieser Wert problemlos einem Ausgang zugewiesen werden.

Ein Bit einem Ausgang zuweisen sieht also folgendermaßen aus:
1
PORTBbits.RB0 = (ad_val & 0x0008)?1:0;
(Weist dem Ausgang Bit(0) an PORTB das Bit(3) von ad_val zu..)

Ob der ADU nun mit der Initialisierung, die wir zunächst durch die 
Libraries vorgenommen hatten, funktioniert hätte oder nicht, sei 
dahingestellt - vermutlich schon.

Das Problem war also nur, dass die abgefragten Bits gar nicht am Ausgang 
erscheinen konnten, weil o.g. Ausdruck nicht das erwartete Ergebnis 
lieferte..

Auf den Fehler kamen wir, nachdem wir zunächst versucht hatten die Bits 
des ADU-Ergebnisses "seriell" am Ausgang auszugeben und, durch einen 
weiteren Port getriggert, auf dem Oszilloskop anzeigen zu lassen (was 
zunächst nicht gelang) und wir anschließend den Wert durch eine 
Konstante ersetzten, die ebenfalls gar nicht angezeigt wurde. Ein 
Geistesblitz konnte den Fehler beheben.

Ich hoffe, dass dieser Thread anderen über dieses Problem hinweghelfen 
kann.

Ansonsten danke ich der freundlichen Unterstützung.

von Schoasch (Gast)


Lesenswert?

Hi

Naja.. es ist schon klar, dass
1
(ad_val & 0x0008)
nicht 1 zurück gibt. Denn es gibt ja entweder 0x0000 oder 0x0008 zurück.

Ich will ja nicht pingelig sein... aber um weitere Fehler zu vermeiden 
solltest du in LAT-Register schreiben.

Denn wenn du :
1
PORTBbits.RB0 = (ad_val & 0x0008)?1:0;
2
PORTBbits.RB1 = 1;

schreibst, kann es dir passieren das dir nur RB1 gesetzt wird und RB0 
ignoriert wird. WEnn du die LAT-Register verwendest, passiert das nicht.

von Fff T. (teichert)


Lesenswert?

Ja, das fiel mir geestern Abend dann auch noch ein.

Das Programm ist fertig und funktioniert.

MfG

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.