Forum: Mikrocontroller und Digitale Elektronik Analog Digital Converter kleines Problem (PIC)


von Anton P. (tonei)


Angehängte Dateien:

Lesenswert?

Hallo miteinander!

Ich habe gerade einen ADC mit dem Programm MPLAB programmert (Code ist 
im Anhang) und wollte das Programm so gestalten, dass sich die 8 LED's 
am Microcontroller von Links nach rechts je nach Spannunsgbeaufschlagung 
einschalten d.h.; bei 0 VOlt soll keine LED leuchten und bei 5 Volt 
sollen alle LED's leuchten.

Mein Problem ist jedoch, dass die LED's willkürlich zu leuchten 
beginnen.

Der Programmiercode ist als PDF- Documetn angehängt.
Der Microcontroller ist ebenfalls als PDf angehängt.

Ich bitte euch darum vielleicht einen kurzen Blick darüber zu werfen und 
mir eventuell den/ die Fehler zu nennen.

Ich bedanke mich schonmal im Vorraus!


MFG Tonei!

von Bastler² (Gast)


Lesenswert?

Du hast den fremden ASM-Code nicht wirklich verstanden, gell? Sonst 
wüsstest du, dass dir die LEDs die oberen 8bit des A/D-Wandlers im 
Binärformat anzeigen. Also, Code umschreiben, so dass jede LED ab einem 
gewissen Wert leuchtet und fertig ist deine Aussteuerungsanzeige.

von Chris B. (dekatz)


Lesenswert?

Wobei DIE Schaltung in der Praxis ohnehin nicht laufen würde - der 
16F877 hat keinen Internen Oszillator und ich sehe dort nirgends eine 
Taktquelle ;-)

von Michi (Gast)


Lesenswert?

Chris B. schrieb:
> und ich sehe dort nirgends eine
> Taktquelle ;-)

OSI, Pin 16

von Ingo S. (schicki)


Angehängte Dateien:

Lesenswert?

Hallo,

ich habe Dir ein paar Beispiele beiglegt. Ich vermute das die 
Ausrichtung im ADRESH nicht korrekt ist oder in der Config etwas nicht 
stimmt.

Viele Grüße
Ingo

von Bastler² (Gast)


Lesenswert?

Die Antwort ist 54. Zumindest ist das die Zeile die für das nicht 
erwünschte Verhalten sorgt ;)

von Ingo S. (schicki)


Lesenswert?

So wie es aussieht, ist es das sprut Beipiel aus dem Internet. Die 
laufen eigentlich bei mir (an einem Echtsystem).

Grüße
Ingo

von Karl H. (kbuchegg)


Lesenswert?

sagt er ja, dass es läuft.
Aber es löst nicht seine Aufgabe.

Anton. überleg mal.
Vom ADC kriegst du 256 verschiedene Zahlen. Je nach Spannung. Du hast 
aber nur 8 LED. Es ist daher völlig unlogisch das ADC Ergebnis einfach 
so auf die LED zu legen. Das kann nicht das realisieren, was du dir 
vorstellst.

von Ingo S. (schicki)


Lesenswert?

in einem meiner Projekte ist eine Balkenanzeige drin. Mit dem dürfte es 
Anton hinkriegen.

von Chris B. (dekatz)


Lesenswert?

Michi schrieb:
> Chris B. schrieb:
>> und ich sehe dort nirgends eine
>> Taktquelle ;-)
>
> OSI, Pin 16

Der Pin heisst T1OSI und ist der Eingang für den TIMER1-Oszillator.

von Chris B. (dekatz)


Lesenswert?

Und vor allem sollte mal PORTA auch als ANALOGEINGANG definiert 
werden..a la Datenblatt:
BCF STATUS, RP0 ;
BCF STATUS, RP1 ; Bank0
CLRF PORTA      ; Initialize PORTA by clearing output data latches
BSF STATUS, RP0 ; Select Bank 1
MOVLW 0x06      ; Configure all pins
MOVWF ADCON1    ; as digital inputs
MOVLW 0x..      ; (1)
MOVWF TRISA     ;

(1)Hier setzt du deinen Wert entsprechend der Funktionen der einzeln 
Pins ein.

von Anton P. (tonei)


Angehängte Dateien:

Lesenswert?

Hallo Leute

Vielen Dank für die tatkräftige Unterstützung jedoch habe ich es immer 
noch nicht geschafft mein Programm zum Laufen zu bringen.

Habe jetzt noch sowas ähnliches im Internet gefunden und mit dem 
vorherigen Programmen etwas vermischt. Jedoch zeigt es mir immer noch 
Errors an und es funktioniert nicht.
Vielleicht könnt ihr nochmals einen Blick drüber werfen.

Würde mich sehr freuen!

MFG ANTON

von Chris B. (dekatz)


Lesenswert?

Anton P. schrieb:
> Habe jetzt noch sowas ähnliches im Internet gefunden und mit dem
> vorherigen Programmen etwas vermischt. Jedoch zeigt es mir immer noch
> Errors an und es funktioniert nicht.

Ja in der Tat und es ist auch kaum Verwunderlich.
Wenn der Zielcontroller ein PIC16F877 sein soll, dann hat der eben kein 
VRCON Register wie auch kein CMCON Register.

Dieses "Zusammenkopierte" aus diversen Quellen (eigene Initialisierung, 
ein Fragment aus der AN700 von MICROCHIP und die "AD-Wandlung" mit nicht 
vorhandenem Comperator) durchblicke ich (ohne maximalen Zeitaufwand) 
ehrlich gesagt nicht.

Vielleicht solltest du beim ursprünglichen Programm mit dem AD-Wandler 
weitermachen, wenn du dort die Ports (besonders PORTA) richtig 
konfigurierst bist du dem Ziel wesentlich näher als mit dieser 
"Variante".

Oder einfach mit einer blinkenden LED beginnen.....

von Ottmar K. (wil1)


Lesenswert?

Hallo Anton,
wenn Du anstatt des PDF-Files Deinen Code als ASM-File anghängt hättest, 
dann könnte man den Code
1. besser lesen
2. MPLAB mal drüber laufen lassen und die Fehler korrigieren...

mfG Ottmar

von Anton P. (tonei)


Angehängte Dateien:

Lesenswert?

Ottmar K. schrieb:
> Hallo Anton,
> wenn Du anstatt des PDF-Files Deinen Code als ASM-File anghängt hättest,
> dann könnte man den Code
> 1. besser lesen
> 2. MPLAB mal drüber laufen lassen und die Fehler korrigieren...
>
> mfG Ottmar

Hallo Ottmar!

Danke für deinen Hinweis habe jetzt im Anhang das ASM- File angehängt 
und bitte darum dieses mal anzusehen und eventuell die Fehler 
auszubessern.

Nochmal zur gewollten Funktion:

Je nach Spannungswert an der Spannungsquelle sollen die 8 LED's 
leuchten.
D.h.: Bei 0V keine LED und bei 5V alle LDS.

Microcontroller PIC 16F877

DANKE
MFG ANTON

von Spess53 (Gast)


Lesenswert?

Hi

>Nochmal zur gewollten Funktion:

>Je nach Spannungswert an der Spannungsquelle sollen die 8 LED's
>leuchten.
>D.h.: Bei 0V keine LED und bei 5V alle LDS.

Dann reduziere den ADC-Wert auf die obersten 3 Bit und schiebe Einsen 
entsprechen dieses Werte von rechts in ein mit Null initialisiertes 
Register.

Wie das in PIC-Assembler aussieht weiß ich nicht.

MfG Spess

von Ingo S. (schicki)


Angehängte Dateien:

Lesenswert?

Hallo Anton,

anbei ist nochmals ein Beispiel von mir. Ich denke das ist ganz genau 
das was Du benötigst.

Bei A/D-Wert 0 leuchtet keine LED - bei A/D-Wert 255 leuchten alle. Die 
Taktfrequenz beträgt 20 Mhz. Bei andere Frequent solltest du dies im 
Quelltext und in der Erholungspause des AD-Wandlers beachten.

Solltest Du die oberen drei Bits noch benötigen, solltest du das 
Programm anpassen in dem Du mit ADRESL und ADRESH arbeitest.

LG
Ingo

von Ingo S. (schicki)


Lesenswert?

Hallo Anton,

hier wäre die Hardware zu meinem Beispiel;

Hauptplatine mit PIC16F877:
http://www.schwabenplan.com/downloads/d00100.pdf

Analoge Zusatzplatine:
http://www.schwabenplan.com/downloads/d00300.pdf

Digitale Balkenanzeige:
http://www.schwabenplan.com/downloads/d00800.pdf

Allgemeine Infos:
http://www.schwabenplan.com/allgemeines.htm

Grüße
Ingo

von Anton P. (tonei)


Lesenswert?

Hallo Ingo!!

Vielen vielen Dank für deine Unterstützung. Mein Programm funktioniert 
jetzt wie gewollt und ohne Fehler. Bin sehr dankbar für dieses Forum und 
hoffe, dass auch ich einmal helfen kann.

Nochmals vielen Dank!

MFG ANTON

von Ingo S. (schicki)


Lesenswert?

Hallo Anton,

sehr gerne. nur ganz kurz eine Frage. Warum programmierst Du in 
Assembler? Für den PIC16F877 gibt es doch auch ganz gute C-Compiler. Ich 
verwende den CC5X. Für diese Anwendung würde auch die kostenlose Version 
ausreichen. Der CCS oder der HITEC ist auch net schlecht.

Viele Grüße
Ingo

von Anton P. (tonei)


Lesenswert?

Hallo Ingo

Ich habe zwar schon einiges an Erfahrung mit C jedoch wollte ich 
verstehen was mit den einzelnen Bits so passiert und auch mal in 
Assembler hineinschnuppern. ;)

von Ingo S. (schicki)


Lesenswert?

ok, das macht Sinn.

Der Umstieg von Assembler in C ist einfach. Aber von C zum Assembler ist 
es ein wenig komplexer. Ist hal ein schmaller Assembler Syntax gegenüber 
dem 8051.

von Anton P. (tonei)


Lesenswert?

Ja der Umstieg von C zu Assembler ist in der Tat schwirig bin fast 
verzweifelt. Werde aber jetzt aus Neugier mal den C- Compiler testen um 
zu sehen wie das so funktioniert.

Kann man da so programmieren wie in C++ nur das die Variablen Eingänge 
bzw. Ausgänge sind?

von Ingo S. (schicki)


Angehängte Dateien:

Lesenswert?

Hier wäre ein Beispiel für den CC5X. Da gab es mal eine suer seite zu. 
Gibts leider nicht mehr.

Ich kenn mich bei c++ nicht so gut aus. Es ist kein Full ANSI C aber der 
taugt was.

Ich habe sehr viele Beispiele zu:

PIC16F877 in C (CC5X) und Assembler
PIC18F452 für den C18 von Microchip
PIC18F97J60 für den C18 von Microchip

von Anton P. (tonei)


Lesenswert?

Hallo Leute

Noch eine Frage:
Warum braucht der ADC eine gewisse Zeit um sich erholen zu  können?

MFG ANTON

von Ingo S. (schicki)


Lesenswert?

Hallo Anton,

ja die benörigts Du. Du kannst die genau benötigte Zeit im Datenbalatt 
berechnen. Bei 20 MHz verwende ich in der Regel 20 - 25 ms.

Im Prozzesor ist ein Multiplexer verbaut. den kannst Du ja über die 
Config-Register steuern. Damit unter anderem ein prellen nicht vorkommt 
wird wird dies zwingend benötigt.

LG
Ingo

von Anton P. (tonei)


Lesenswert?

Hallo Ingo

Kann ich die LED's auch ohne eines vorher definierten Wertes (z.B.: 
MOVLW D'96') zum leuchten bringen? D.h.: Nur mit dem Signal das ich aus 
dem ADC bekomme??

MFG ANTON

von Ingo S. (schicki)


Lesenswert?

Hallo Anton,

vom Prinzip her schon. Die Pins müssen als Ausgang definiert sein.

Du musst dann nur folgendes tun...
MOVLW D'96' // Hier ladest Du den Dezimalwert 96 in den Akku
MOVWF PORTB // Nun musst du diesen Wert vom Akku an z.B. wie hier an 
PORTB schrieben...


Grüße
Ingo

von Anton P. (tonei)


Lesenswert?

Ja aber dann habe ich doch wieder den Dezimalwert 96 in meinem Programm 
oder?

von Chris B. (dekatz)


Lesenswert?

Anton P. schrieb:
> Hallo Ingo
>
> Kann ich die LED's auch ohne eines vorher definierten Wertes (z.B.:
> MOVLW D'96') zum leuchten bringen? D.h.: Nur mit dem Signal das ich aus
> dem ADC bekomme??
>
> MFG ANTON

Dafür am besten den AD-Wandler so konfigurieren das das Ergebniss "Left 
justified" ist (ADCON1.ADFM = 0).
Wenn dann der AD-Wandler fertig ist (ADCON0.GDO_DONE = 0) hast die die 
höherwertigsten Bits vom 10-Bit-Ergebniss in ADRESH (damit bekommst du 
auch den vollen ADC-Wertebereich angezeigt, nur eben mit 8 Bit 
Auflösung). Ausgabe dann mit:
BANKSEL ADRESH
MOVF    ADRESH,W
BANKSEL PORTB
MOVWF   PORTB

von Anton P. (tonei)


Angehängte Dateien:

Lesenswert?

Hallo Chris!

Wie wende ich das bei meinem Programm an da ich nirgends die Befehle 
BANKSEL und dergleichen habe??

MFG ANTON

von Chris B. (dekatz)


Lesenswert?

Anton P. schrieb:
> Wie wende ich das bei meinem Programm an da ich nirgends die Befehle
> BANKSEL und dergleichen habe??

BANKSEL ist kein Controllerbefehl sondern eine Assembleranweisung 
genaugenommen ein MACRO.
BANKSEL erstzt dir z.B. "bsf STATUS,RP0" etc.
Du brauchst nicht mehr im Datenblatt nachsehen in welcher Bank sich das 
Register befindet.
Und es gibt PIC die haben mehr als 2 BÄNKE, also gibt es da auch ein RP0 
u. RP1 und damit eine neue Fehlerquelle welche man mit BANKSEL vermeiden 
kann.

von Anton P. (tonei)


Angehängte Dateien:

Lesenswert?

Hallo Leute!!

Habe noch eine Frage:

Möchte noch auf eine andere Art den ADC programmieren.
Möchte je nach Spannungswert an der Spannungsquelle de LED's nach 
einander leuchten lassen.
Nur habe ich das Problem: das mit meinem Programm(im Anhang) die LED's 
willkürlich zu leuchten beginnen.

Hoffe ihr könnt mir noch einmal helfen!

MFG ANTON

von Ottmar K. (wil1)


Lesenswert?

Hallo Anton
Ich hoffe Dir ist klar wie das ADC-Ergebnis ausgegeben wird und wie 
grunsätzliche vorzugehen ist.

Egal welche Vref Du im CVRCON CONTROL REGISTER ausgewählt hast, der ADC 
gibt bei Uinput ADC = Vref, stets dieses Ergebnis aus.
ADRESH = b'00000011', ADRESL = b'11111111' = 1023 oder 0x 03FF
bei geringerer Spannung eben einen niedrigeren Wert als 1023. Das 
Ergebnis ist binär, besteht also aus einer Folge von Einsern und Nullen.

Es ist dann Sache des Anwenders durch geeignete Umrechnung von 
ADRESH,ADRESL den wirklichen Spannungswert zu berechnen.

Solange Du versuchst ADRESH oder ADRESL direkt, also bit für bit in den 
PORTB zu kopieren:

; Wert nach PortB schreiben
  movfw    ADRESH       ; obere 8 Bit auslesen
  movwf    PORTB        ; obere 8-Bit nach PortB

erhältst Du stets die Binärzahl des ADC-Ergebnisses. Das kann durchaus 
z.B. in ADRESH b'00000000' oder in ADRESL b'10101001' sein. In ADRESH 
werden maximal nur die Bits 0 und 1 gesetzt!! Bit 2-7 bleiben 
ungenutzt!!

Eine Balkenanzeige ist nur dann sinnvoll zu realisieren, wenn das 
maximale Ergebnis des ADC = Maximal 1024 (0 - 1023) - eben wegen der 8 
bits von PORTB - durch 8 geteilt wird und in 128er-Stufen  (1024/8=128) 
eine LED zu- bzw. eingeschaltet wird.

Im Prinzip brauchst Du nur ADRESH,ADRESL durch 127 (0-127) zu teilen. 
Das kann z.B. durch einfache Subtraktion geschehen, wobei die Anzahl der 
Subtraktionen ohne negatives Ergebnis letztlich die Anzahl der zu 
schaltenden Bits ergibt (5 Subtraktionen - Balkenanzeige PORTB,Bit 0-4 
EIN, Einzelanzeige nur PORTB,4 EIN).

Tip:
Schau Dir mal bei 
[http://www.sprut.de/electronic/pic/programm/adclcd/adclcd.html] das 
Programmbeispiel zur 16-Bit-Subtraktion an.

mfG Ottmar

von Anton P. (tonei)


Lesenswert?

Hallo!

Das Problem ist, dass ich es so nicht machen darf.
Mir wurde gesagt das ich am Ausgang das minderwertigste Bit definieren 
muss und dann aufsteigend nur wie soll das gehen ohne den LEDs 
Dezimalzahlen zuzuordnen??

BITTE um Hilfe

MFG ANTON

von Ottmar K. (wil1)


Angehängte Dateien:

Lesenswert?

Hallo Anton,
habe ich Dich jetzt richtig verstanden?
Du willst nur das Low-Byte des ADC-Ergebnisses  "ADRESL" für die Balken- 
bzw. Einzelanzeige verwenden? Ja nun, das ist aber recht simpel zu 
lösen!
Hier ein Beispiel zur Balkenanzeige, die Verwirklichung einer 
Einzelanzeige wird Dir da bestimmt leicht fallen.

Prinzip:
Du frägst einfach beginnend mit dem MSB die Bits 7 - 0 von ADRESL ab und 
setzt dann entsprechend am LED-PORT die Bits absteigend vom höchsten 
gesetzten Bit.

Vergiss nicht ein genügend langes Delay zu verwenden um den Balken nicht 
zu sehr zappeln zu lassen. Es ist klar, dass die Anzeige nicht dem real 
gemessenen Spannungswert folgt sondern in Sprüngen von 2^0 - 2^7.

Soll es ein Einzelanzeige sein - die Lösung fällt Dir bestimmt rasch 
ein.
Schau Dir mal dazu beiliegenden Codeschnipsel an. Das geht bestimmt noch
eleganter, aber so ist es wohl am verständlichsten.

mfG Ottmar

von Chris B. (dekatz)


Lesenswert?

Oder die Kurzversion davon:

In "var_adc" steht der Wert aus der ADC-Wandlung!
1
    movlw  b'11111111'     ;"vollen" Balken als Startwert
2
    movwf  var_balken
3
    movlw  .8              ;über alle 8 Bit(1)
4
    movwf  counter
5
;das Höchstwertige Bit wird ins CARRY geschoben. Ist dieses 1, ist der
6
;"Balken" fertig. Wenn nicht wird wird der Balken um 1 Stelle nach 
7
;RECHTS geschoben, d.h. das CARRY wird an die Höchstwertige Stelle des 
8
;Balken geschoben und das das CARRY praktischerweise "0" ist, braucht 
9
;man es auch praktischerweise nicht explizit zu Löschen ;-)
10
loop1
11
    rlf     var_adc,F       
12
    bc      Balken_fertig
13
    rrf     var_balken
14
    decfsz  counter
15
    goto    loop1
16
Balken_fertig
17
    movf    var_balken,W
18
    movwf   PORTB
19
usw......

(1) will man das Flackern des niederwertigsten Bits verhindern, dann 
schiebt man nur 7 Mal und es bleibt Bit0 immer auf "1".

von Chris B. (dekatz)


Lesenswert?

Wenn tatsächlich eine Dekadische Anzeige verlangt ist und die 
Balkenlänge ein binäres Vielfaches ist (also 2,4,8,16... Segmente), dann 
ist das auch keine Hexerei.
In "var_adc" steht der Wert aus der ADC-Wandlung, in "var_balken" wird 
die Anzeige gebastelt.
Anzeigeintervalle gehen von 0...31,32....64 usw., also zuerst den 
ADC-Wert durch 32 dividieren:
1
    rrf  var_adc,F
2
    rrf  var_adc,F
3
    rrf  var_adc,F
4
    rrf  var_adc,F
5
    rrf  var_adc,F
dann die 3 uns interessierenden Bit isolieren
1
    movlw  b'00000111'
2
    andwf  var_adc,W
3
    movwf  counter
ergibt eine Wert von 0...7, wir haben aber 8 Segmente also:
1
    incf  counter,F
und alle Segmente löschen
1
    clrf  var_balken
jetzt von RECHTS solange "1" reinschieben bis Zähler auf 0
1
loop  
2
    rlf  var_balken,F  ;bereits gesetze Segmente
3
    bsf  var_balken,0  ;PLUS das äusserts RECHTE
4
    decfsz  counter,F
5
    goto  loop
fertig und anzeigen
1
    movf  var_balken,W
2
    movwf  PORTB
3
......
Zumindest am Simulator läuft es wie es soll....;-)

Wenn man natürlich eine Anzeige mit z.B. 17 Segementen möchte, dann wird 
das etwas aufwändiger.....

von Anton P. (tonei)


Angehängte Dateien:

Lesenswert?

Hallo Leute

Vielen Dank für eure Unterstützung!

Habe jetzt noch eine letze Frage:

Möchte bei der SChaltung (im Anhang) bei den rechten 8 LEDS die 
niederwertigste (untersten) Bits ausgeben  ausgeben und bei den rechten 
8 LEDs die höherwertigen Bits(obersten) ausgeben.
Das Board ist als Word- Dokument angehängt,da mein pdf creator leider 
nicht mehr funktioniert.

Das Problem ist jetzt, das er links und rechts das gleiche ausgibt.

Hoffe ihr könnt mir helfen!

MFG ANTON

von Chris B. (dekatz)


Lesenswert?

Dann solltest du das machen was dir hier schon geraten wurde: konsequent 
BANKSEL verwenden - denn ADRESH und ADRESL liegen in unterschiedlichen 
Speicherbänken!!!

Zuerst Zugriff auf ADCON0, dann liest du ADRESL. Dummerweise liegt in 
der Bank von ADCON0 auf der Adresse ADRESH - also gibts du ADRESH auf 
PortB aus. Und dann - diesmal korrekterweise - ADRESH nochmals, aber auf 
PortD!

von Anton P. (tonei)


Lesenswert?

Hallo!

Ich bin schon fast am verzweifeln und bekomme mein Programm nicht zum 
laufen! :(

Ich weis, dass dies keine Webside ist um Aufgaben erfüllen zu lassen, 
doch ich bitte darum das mir vielleicht jemand dieses Programm etwas 
überarbeitet. BITTE

MFG ANTON

von Chris B. (dekatz)


Lesenswert?

Hast du endlich die entsprechenden BANKSEL bei deine SFR-Zugriffen 
eingefügt?
Und im Listing vom 11. gibt es keine Configurationseinstellung!

von Anton P. (tonei)


Lesenswert?

Hallo!
Habe ich schon versucht doch es geht leider immer noch nicht!

mfg ANTON

von Chris B. (dekatz)


Lesenswert?

Dann Poste doch mal das aktuelle!! Programm - vom Herumraten kommt nix 
raus.

von Anton P. (tonei)


Lesenswert?

Hallo!

Könntest du mir eventuell (wenn vorhanden) ein Beispiel mit BAKSEL 
schicken da ich nicht genau weiß was damit gemeint ist??

MFG ANTON

von Ottmar K. (wil1)


Angehängte Dateien:

Lesenswert?

Hallo Anton,
Du weißt dass die Register beim PIC auf verschiedene Speicherbänke 
verteilt sind. Nur wenn Du dem Assembler mitteilst wo diese Register zu 
finden sind, können die entsprechenden Codebefehle ausgeführt werden.

Wird z.B. TRISA "beschrieben" ohne dass zur Bank 1 umgeschaltet wird, 
geht dieser Befehl ins Leere. Dies gilt auch für ADRESH bzw. ADRESL, 
jedes dieser beiden Register befindet sich in einer anderen Bank.

Z.B. befindet sich beim PIC16F877 PORTA in Bank 0. TRISA in Bank 1. 
Diese erreichst Du so:

bcf STATUS, RP0   ;umschalten auf Speicherbank 0
bsf STATUS, RP1   ; "
clrf PORTA        ;Wert um RA7:0 auf logisch 0 zu setzen

jetzt zum Datenrichtungsregister TRISA, welches sich in Bank 1 befindet

BSF STATUS, RP0  ;umschalten zu Bank (Bit RP1 bleibt unverändert)
movlw 0xFF       ;Wert um RA7:0 als Eingänge zu schalten
movwf TRISA      ;Wert in Datenrichtungsregister kopieren

bcf STATUS, RP0 ; und nun wieder zurück zu Bank0

BANKSEL
Der Assembler kennt sogenannte "Preprozessorbefehle" wie z.B. "banksel". 
Schau dazu mal hier nach: 
[http://www.sprut.de/electronic/pic/assemble/pseudo.html] sobald ein 
solcher "Pseudo-Befehl" im Assemblercode auftaucht, wird der 
entsprechende Assemblercode zum Bankwechsel ohne Dein Zutun iin das 
Programm (nicht in das ASM-File!) eingefügt:

"banksel PORTA"
Nach "RUN" in MPLAB-Sim, bzw. "MAKE" oder "Build all" im Menü "Projekt" 
kannst Du im Menü "View - Programm-Memory" aber sehen, dass MPLAB 
selbstständig diesen Code anstelle von "banksel PORTA" eingetragen hat:
BCF 0x3, 0x5   ;=BCF Registeradresse, Bitnummer -> bcf STATUS, RP0
BCF 0x3, 0x6   ;= "   "                "        -> bcf STATUS, RP1

CLRF 0x5       ;=CLRF Registeradresse -> CLRF PORTA

Wie Du siehst ist es viel einfach einfach "banksel <Registerlabel>" zu 
schreiben, als zwei Codezeilen zu schreiben. Im letzteren Fall musst Du 
genau wissen in welcher Bank sich das Register befindet, mit "banksel" 
aber nicht, weil das ja Dein Assemblerprogramm für Dich weiß.

Natürlich ist es Blödsinn einfach vor jedes Register "banksel" zu 
verwenden. Dazu schaut man immer wieder im Datenblatt im Abschnitt 
"Memory Organization", Tabelle "PIC16F876A/877A REGISTER FILE MAP" nach. 
Dort sind die einzelnen Bänke mit den darin enthaltenen Register 
übersichtlich aufgeführt.
So lernt man die Hardware des PIC kennen und das Programmieren wird 
zusehends leichter und auf jeden Fall machst Du mit "banksel" keinen 
Fehler bei der Auswahl der Bank für das/die nachfolgend verwendeten 
Register.

Ich habe mal Dein Balkenprogramm kurz überdacht und dazu meine Version 
geschrieben und nur "banksel" zum Bankwechsel vewendet. Du musst aber 
daran denken, dass mit den unteren 8 Bit ADRESL lediglich der Bereich 0 
- ca. 1,246Volt dargestellt werden kann. Darüber kommen Bit 0 und 1 von 
ADRESH ins Spiel.
Schau es Dir mal an, vielleicht hilft Dir das weiter.

Noch ein Tip: Wenn Du ein Programm schreibst, nimm das Datenblatt und 
gehe dort Schritt für Schritt durch die Beschreibung der Register. Spare 
NIEMALS mit Kommentaren zu JEDER Codezeile. Es ist nicht sinnvoll so zu 
kommentieren:

bsf PORTB,RB1       ;bit 1 Setze RB1 = 1
             besser:
                    ;bit1=1 LED an RB1 einschalten
also keinen Befehlscode erläutern, sonder das was der Befehlscode 
bewirkt!

Na ja, kommt Zeit kommt Rat!
noch viel Spass mit den PICs!

mfG Ottmar

von Anton P. (tonei)


Lesenswert?

Hallo Ottmar!

Vielen Dank für dein Programm und die ausfühliche Beschreibung!

Kann ich das bei deinem Programm so verstehen, das wenn man auf 5 Volt 
ist alle LEDs leuchtn und wenn man die Spannung auf 4,35Volt veringert 
die niederwertigsten Bits (LEDS) aufhören zu leuchten?? Und warum 
leuchten bei einem Wert von 3.75Volt und 0 Volt wieder alle LEDS???

Kann ich mir das jetzt so vorstellen, dass einfach der Wert vom ADC 
ausgegeben wird ohne jede Ordnung und die LEDs die als erstes nicht 
leuchten die niederwertigsten Bits(LEDS) sind??

MFG ANTON

von Chris B. (dekatz)


Lesenswert?

So wie ich das sehe ist da ein kleiner Bug in dem Programm:
Definiert wird mit ADCON0.ADFM = 1 eine Rechtsbündige Ausgabe, also
ADRESH:ADRESL = xxxxxx11 11111111 (Maximalwert).
Bei der ADC-Wandlung wird ADRESH in tempADC1 und ADRESL in TempADC0 
gespeichert.
Der Erzeugung des BALKEN wird aber tempADC0 verwendet! also wiederholt 
sich der Wertbereich von 00000000....11111111 insgesamt 4x.
Richtig wäre:
ADCON0.ADFM = 0 -> Linksbündige Ausgabe, also
ADRESH:ADRESL = 11111111 11xxxxxx (Maximalwert).
Und die in der Routine "LED_Bargraph" wird tempADC1 zur Erzeugung des 
Balken verwendet.

Natürlich sind bei 3,75V alle LED wieder aus: 5V /4 = 1,25V (5V - 1,25V 
= 3,75V) und das ist genau der Wert der mit Rechtsbündiger Ausgabe mit 8 
Bit in ADRESL darstellbar ist....

von Ottmar K. (wil1)


Lesenswert?

Hallo Anton,
Chris B. hat natürlich recht. Bei der linksbündigen Ausgabe werden die 
höherwertigen Bits berücksichtigt und die letzten Bits (0 und 1) fallen 
unter den Tisch.

Ich habe das übersehen (könnte ja auch sagen: wollte wissen ob Du es 
bemerkst :-). In meinem Programm wird tatsächlich über 1,246V nur noch 
Unsinn im Balken angezeigt, während bei der linksbündigen Ausgabe ab 5V 
abwärts bis auf 1,251 als letzter Balken angezeigt wird. Ein kleiner 
Unterschied aber mit spürbarer Wirkung!

Zum ADC: Der ADC kann die Vref, in diesem Fall die Betriebsspannung des 
PIC in 1023 einzelne Stufen auflösen. Im Abschnitt "Init" wurde Vdd 
(+5V) als +Referenzspannung und Vdd (GND, Masse, OV) als Vss- gewählt. 
Dies Werte stehen durch die Konfiguration von ADCON0/ADCON1 intern zur 
Verfügung.

Die Auflösung des ADC beträgt 10bit, also dezimal 1023. Somit ist die 
geringste messbare Spannung am ADCD 5000mV/1023 = 4,8875.... mV.

ADRESL hat 8 Bit, kann also von den 1023 Steps lediglich 256 (0 - 255) 
darstellen. ADRESH verfügt über lediglich 2 Bits, aber diese sind 
höherwertig als die Bits in ADRESL.

Hier die RECHTSbündige Ausgabe:
ADC-Wert
   255  ADRESH b'00000000', ADRESL = b'11111111'
 +   1
   256  ADRESH b'00000001', ADRESL = b'00000000'
  +255
   511  ADRESH b'00000001', ADRESL = b'11111111'
    +1
   512  ADRESH b'00000010', ADRESL = b'00000000'
  +255
   767  ADRESH b'00000010', ADRESL = b'11111111'
  +  1
   768  ADRESH b'00000011', ADRESL = b'00000000'
  +255
  1023 ADRESH b'00000011',  ADRESL = b'11111111'
LINKSbündig formatiert sieht das Ergebnis aber so aus:
 1023  ADRESH b'11111111',  ADRESL = b'11000000'

Im diesem Fall orientiert sich die Balkenanzeige voll und ganz an ADRESH 
und zeigt lediglich die letzten Bits 0 und 1 von ADRESL (rechtsbündig) 
nicht an. Somit umfasst Deine Balkenanzeige in diesem Fall

ADRESH  b'10000000'  = 256 * 4.8875mV = 1251mv
                                        bis
ADRESH  b'11111111' = 1023 * 4.8875mV = 5000mV

Also ist es günstiger die Variable tmpADC1 (Kopie von ADRESH) zur 
Erzeugung Deiner Balkenanzeige zu verwenden.

Wenn Du die Balkenanzeige drauf hast, wird es -so meine ich- Zeit, dass 
Du dran gehst die Spannung als Volt oder mV im LCD auszugeben!

mfG Ottmar

von Ottmar K. (wil1)


Lesenswert?

Ottmar K. schrieb:
> Somit umfasst Deine Balkenanzeige in diesem Fall
>
> ADRESH  b'10000000'  = 256 * 4.8875mV = 1251mv
>                                         bis
> ADRESH  b'11111111' = 1023 * 4.8875mV = 5000mV

Da habe ich einen Krampf dargestellt (typischer Schnellschuss)! Am 
Ergebnis des ADC hat sich natürlich trotz der linksbündigen Ausgabe 
nichts geändert! Die Balkenanzeige zeigt daher nur im Bereich ab ca. 
19,5mV - 2502mV eine Veränderung der ADC-Spannung an.

Für die hier besprochene Balkenanzeige ist ja nur maßgeblich, dass das 
höchste Bit gesetzt ist, die niedrigeren Bits fallen bei dieser 
Auswertung unter den Tisch.

Die niedrigste angezeigte Spannung ist (Segment wechselt von Aus<->Ein):
ADRESH = 00000000,ADRESL = 00000100 = dez. 4, 4x(5V/1023)=0,0195V
linksbündig:
ADRESH = 00000100,ADRESL = 00000000
Spannungsänderungen unter diesem Wert werden nicht angezeigt (Balken 
vollständig aus).

Die höchste angezeigte Spannung ist:
ADRESH = 00000010,ADRESL = 00000000  = dez. 512, 512x(5V/1023)=2,502V.
linksbündig:
ADRESH = 10000000,ADRESL = 00000000
Spannungsänderungen über diesem Wert werden nicht angezeigt (Balken 
vollständig ein)

mfG Ottmar

von Anton P. (tonei)


Lesenswert?

Hallo Leute!

Es tut mir leid aber ich verstehe den Fehler leider nicht was ihr da 
meint mit der linksbündigen  und rechtsbündigen Ausgabe.

Gibt es nicht eine einfacher Variante des ADC die Leds zum leuchten zu 
bringen ohne Balkenanzeige oder der gleichen nur die Ausgabe des ADC mit 
Beachtung der niederwertigsten Bits--> bei 5 Volt leuchten alle LEDs und 
ab 4,5V oder so hören die niederwertigsten /höchstwertigsten Bits (LEDs) 
auf zum leuchten??

Ich bitte ein letztes Mal um Hilfe und entschuldige mich das ich solche 
Fragen stelle, die für euch wahrscheinlich als "dumm" gelten.

MFG ANTON

von Chris B. (dekatz)


Lesenswert?

Wurde eigentlich genau erklärt was man rechtsbündig / linksbündig 
versteht, aber ganz einfach:

1.Ersetze im Programm von Ottmar K. die Zeile
...bsf    ADCON1,ADFM    ;b7=1 A/D-Ergebnis rechts ausgerichtet...
durch
...bcf    ADCON1,ADFM    ;b7=0 A/D-Ergebnis links ausgerichtet...

2. Ersetze nach dem label LED_loop die zeile mit
....rlf    tmpADC0,f  ;ADC-Wert linksschieben...
durch
....rlf    tmpADC1,f  ;ADC-Wert linksschieben

Dann sollte das Program genau das tun was es soll!

(einige Kommentare bei der ADC-Wandlung selbst passen natürlich nicht 
mehr ganz, aber das hat ja mit der Funktionsfähigkeit nix zu tun).

In Assembler geht es eben nur in kleinsten Schritten und offen gesagt 
macht es keine Sinn hier herumzuoptimieren und irgendeine x-beliebige 
andere Anzeige zu erzeugen. Du solltest dieses Programm VERSTEHEN, dann 
kannst du jederzeit andere Anzeigevarianten "basteln".

von Ottmar K. (wil1)


Lesenswert?

@Chris
OK, LCD muss ja noch nicht sein, aber ich hätte es vorgezogen vor dem 
ADC die LCD-Ausgabe kennenzulernen.

@ Anton
Anton P. schrieb:
> Es tut mir leid aber ich verstehe den Fehler leider nicht was ihr da
> meint mit der linksbündigen  und rechtsbündigen Ausgabe.

Nochmals rechts-/linksbündig
|  ADRESH, ADRESL |
|00000011,11111111|RECHTSbündig
|11111111,11000000|LINKSbündig

Ich hatte doch mein funktionierendes Programm 
[Beitrag "Re: Analog Digital Converter kleines Problem (PIC)"]
als Anlage beigefügt. Es mag nicht der Stern am Programmhimmel sein, 
aber es funktioniert. Das solltest Du daher auch ausprobieren, wenn 
nicht in den Chip gebrannt, dann doch zumindest mit dem Simulator 
MPLAB-SIM. Dann wirst Du auch sehen, was die links/rechtsbündige Ausgabe 
in ADRESH, ADRESL bewirkt.

Gehe den Code Zeile für Zeile, anhand des Kommentars UND dem Datenblatt 
durch, damit Du die Zusammenhänge verstehen kannst.

Chris hat klar mitgeteilt was zu ändern ist um die höherwertigen Bits 
auszugeben, wodurch ein erweiterter Spannungsbereich zwischen ca. 5 und 
1,25V angezeigt werden kann.

Falls Du mit MPLAB-SIM nicht klarkommen solltest, stelle dazu Deine 
Fragen, hier ein paar Links dazu:
{http://www.fernando-heitor.de/index.php/downloads/Dokumente/MPLAB-Tutorial/] 
(MPLAB-Tutorial in deutsch herunterladen)
[http://www.microchip.com/stellent/idcplg?IdcService=SS_GET_PAGE&nodeId=2123&param=en022520] 
(englisch)

mfG Ottmar

von Anton P. (tonei)


Lesenswert?

Hallo!

Ich möchte nur den Wert des ADC auf die LEDs übertragen ohne 
Balkenanzeige oder irgendsowas.

Könnt ihr mir noch einmal helfen habe morgen meine Arbeit darüber und 
bekomme es nicht in den Griff!!

BITTE !!!

MFG ANTON

von Ottmar K. (wil1)


Lesenswert?

Hallo Anton,

ich versteh Dich nicht! Du hast einen funktionierenden Code erhalten. 
Wenn  PORTC zur Ausgabe verwendet werden soll, tauscht Du eben PORTB 
gegen PORTC im Code. Es ist doch egal ob man die LEDs am Ausgang als 
Balkenanzeige oder "Einzel-LEDs" oder sonst wie bezeichnet.

Mehr als bisher gibt es zu diesem Thema ergänzend nichts mehr zu sagen.

mfG Ottmar

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.