www.mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik PIC 16F872 ADC/RS232emu-Probleme


Autor: Raimund (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo an alle Hilfswilligen,

Für den Pufferspeicher unserer Heizung (Wassertank) baue ich ein 
16-Kanal-Thermometer. Der PIC 16F872 steuert einen MOS 4067 MUX/DEMUX an 
der dann das Signal eines der NTC-Sensoren zum AN0 des PIC weiterleitet.

Da der 16F872 keinen asynchrone Serielle Schnittstelle besitzt habe ich 
diese nach der Anleitung von Sprut emuliert.Da ich einen MAX232 verwende 
habe ich die Signale gegenüber der Anleitung von Sprut invertieren 
müssen.

Der MOS4067 wird korrekt angsteuert und liefert auch die korrekten 
Signale an AN0,, der MAX232 liefert laut Oszi ebenfalls saubere Signale.

Die von der RS232 zum PC gesendeten Daten sollen folgendes Format haben:
Kanalnummer(15-0),Adresh,Adresl
Beispiel: 15,131,128
          14,131,64
          13,....usw fortlaufend.

PIC Ausgänge: RB0 für die emulierte serielle Schnittstelle.
              RB1-RB5 zur Ansteuerung des 4067
PIC Eingänge: AN0 nimmt das Signal vom 4067 entgegen

Beim ADC und der emulierten seriellen Schnittstelle habe ich jedoch 
Probleme. Der PIC weigert sich äussertst beharrlich ADRESL korrekt 
auszugeben. Der Wert ist immer 127. Warum?

Die in Zeile 64 enthaltene Anweisung call Warte_s1 erzeugt bei jeder 
Anzeige eines Wertes je Kanal eine führende 0! D.h. 0, Kanalnummer, 
Adresh,Adresl(immer 127).
Auch das kann ich mir nicht erklären.

Es wäre toll, wenn sich jemand dieser Probleme annehmen würde.
  list p=16f872


  #include <P16f872.INC>




;**************************************************************
;Variablennamen vergeben
                    
Temp  Equ  0x20
cycl_1  Equ  0x21  
cycl_2  Equ  0x22
Byte  Equ  0x23
Zähler  Equ 0x24
cycl_5  Equ  0x25
cycl_3   Equ 0x26
cycl_6  Equ  0x27
xw0    Equ  0x28
xw1    Equ  0x29
out    Equ  0    ; RS-232 out ist RB0

;**************************************************************


Init
  bsf     STATUS, RP0  ; Umschalten auf Bank 1
  clrf  TRISB    ; PortB alle Ausgang
  bcf    ADCON1,0  ; Nur AN0 als Eingang,Vdd und Vss = Referenz 
  bsf    ADCON1,1  ; Nur AN0 als Eingang,Vdd und Vss = Referenz 
  bsf    ADCON1,2  ; Nur AN0 als Eingang,Vdd und Vss = Referenz 
  bsf    ADCON1,3  ; Nur AN0 als Eingang,Vdd und Vss = Referenz 
  bcf    ADCON1,7  ; Ergebnis in ADRESH und ADRESL linksbündig
  bsf    TRISA,0    ; RA0 Input
  
  bcf     STATUS, RP0  ; Zurückschalten zur Bank 0
  bcf    ADCON0,5  ; AN0 ist der Eingang
  bcf    ADCON0,4  ; AN0 ist der Eingang
  bcf    ADCON0,3  ; AN0 ist der Eingang
  bsf    ADCON0,0  ; ADC ein
  bcf    ADCON0,7  ; ADC Geschwindigkeit 1,25-5 MHz
  bsf    ADCON0,6  ; ADC Geschwindigkeit 1,25-5 MHz


Loop

  movlw D'16'
  movwf Zähler    ;Zähler 0-15 auf 16
  
Ausgabe
  
  decf  Zähler,1  ;Zähler wird um 1 vermindert
  bcf    STATUS,C
  rlf   Zähler,0  ;Alle Bits von Zähler um eine Stelle nach links verschieben nur in W
  ;movlw  B'00001110'
  movwf  PORTB    ;Zähler nach PortB
  BSF    ADCON0, 2    ; ADC starten 
spring

    btfsc  ADCON0,2  ;Ist der ADC fertig?
  GOTO    spring      ; nein, weiter warten 
            ;Ja ADC ist fertig
  ;call Warte_s1
  bcf    STATUS,C
  movlw  D'255'    ;255 nach W
  ;call  Send_RS    ;Gebe 255 an RS232 aus  //Testzahl

  movlw  D'255'    ;255 nach W
  ;call  Send_RS    ;Gebe 255 an RS232 aus  //Testzahl
  
  movlw  '_'     
  ;call  Send_RS  

  movf  Zähler,0  ;Inhalt von Zähler nach W //15-0
  ;addlw  D'42'    ;Addiere 42 zu Zähler in W  //Um im Terminalprogramm von 9 an abwärts angezeigt zu werden
  call  Send_RS    ;Ergebnis nach RS232
  
  movf  ADRESH,0    ; obere  2 Bit auslesen
  movwf  xw1      ; obere  2-Bit nach xw1
  bcf    STATUS,RP1  ; Bank 1
  bsf    STATUS,RP0  ; Bank 1
  movf  ADRESL,0  ; untere 8 Bit auslesen
  movwf  xw0      ; untere 8-Bit nach xw0
  bcf    STATUS,RP0  ; Bank 0
  bcf    STATUS,RP0  ; Bank 0
        
  movf  xw1,0    ; xw1 nach W
  call  Send_RS    ; Sende über RS232
  movf  xw0,0    ; xw0 nachW
  call  Send_RS    ; Sende über RS232
;***************************************************************
  movlw  'H'      ; es soll Hallo an RS232 gesendet werden
  ;call  Send_RS    ; Datenwort ausgeben via RS-232
  movlw  'a'  
  ;call  Send_RS  
  movlw  'l'     
  ;call  Send_RS  
  movlw  'l'    
  ;call  Send_RS        ;Zum testen 'Hallo ' ausgeben
  movlw  'o'     
  ;call  Send_RS
  movlw  ' '     
  ;call  Send_RS      
;****************************************************************
  movf  Zähler,1  ; Zähler wird nach Zähler kopiert,jetzt kann Zero-Bit getestet werden
  btfss  STATUS,Z  ; Zähler auf 0?
  goto Ausgabe    ; Nein
  goto Loop      ; Ja
  
  

;***************************************************************
;Senden des Bytes, das im Register W steht 

Send_RS        ; Ausgabe eines Bytes seriell  
  movwf  Byte    ; Byte in w
  movlw  8    ; es werden 8 Bit gesendet
  movwf   cycl_1
  bsf  PORTB, out
  call  Warte_s    ; 1 Stopbit (1)
  bcf  PORTB, out
  call   Warte_s    ; 1 Startbit (0)

Send_1  rrf  Byte, f    ; aktuelles Bit in das Carry-Flag schieben
  btfsc  STATUS, C
  bsf  PORTB, out  ; Lo wenn Bit = 1
  btfss  STATUS, C
  bcf  PORTB, out  ; Hi wenn Bit = 0
  call  Warte_s    ; 1 Bit lang warten
  decfsz  cycl_1, f  ; waren das schon 8 Bit?
  goto  Send_1    ; nein, es geht weiter
  bsf  PORTB, out  ; Byte zuende, 1 Stoppbit (1) senden
  call   Warte_s    ;
  return

;**********************************************************
;ein Bit Zeitverzoegerung mit einer Warteschleife
; Timing muß genau stimmen (5%)
;
; senden            4 MHz    10 MHz
; 2400 Bps =          69d    173d
; 9600 Bps =          16d     43d

Warte_s  movlw  D'16'    ; 9600 Bps / 4 MHz senden
  movwf  cycl_2
Warte1        ; 6 Zyklen Schleife
  nop
  nop
  nop
  decfsz  cycl_2, 1  
  goto  Warte1
  return
;**********************************************************
;Grössere Pause zum testen, zur Zeit nicht benutzt
Warte_s1  movlw  D'255'    ; 9600 Bps / 4 MHz senden
  movwf  cycl_3
Warte11        ; 6 Zyklen Schleife
  nop
  nop
  nop
  decfsz  cycl_3, 1  
  goto  Warte11
  return
  end



Autor: Severino R. (severino)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Raimund wrote:

> Da der 16F872 keinen asynchrone Serielle Schnittstelle besitzt habe ich
> diese nach der Anleitung von Sprut emuliert.

Warum nimmst Du keinen PIC mit UART, z.B. 16F873 oder '876 oder '883?
Wenn Du den Thermometer nicht in grosser Serie baust, spielt ein 
eventueller Mehrpreis (eventueller deshalb, weil uralte PICs manchmal 
teurer sind als neue, leistungsfähigere).

Autor: Raimund (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Severino,

ich habe noch von Basteleien vorher einen grösseren Posten 16F872 
herumliegen. Die möchte ich erst einmal verarbeiten.

Sollte ich das Problem nicht in den Griff kriegen werde ich deinen Rat 
beherzigen.

Ein anderer PIC würde aber meines erachtens das Problem mit ADRESL auch 
nicht lösen.

Danke

Autor: Severino R. (severino)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich denke halt, das Leben ist kompliziert genug, weshalb sollte man es 
sich noch mehr verkomplizieren?
Was kostet Dich ein PIC, und wieviel Zeit hast Du nun mit dem SortUART 
aufgewendet?

Bist Du denn sicher, dass der PIC auch wirklich das sendet, was er 
A/D-wandelt?
Oder anders gesagt: versuch doch mal, Konstanten zu senden, und schau 
was beim PC ankommt.
Am besten mal die Extremwerte, die der A/D-Wandler liefern kann.

Hast Du einen ICD2 oder einen PICkit2?
Dann könntest Du Breakpoints setzen und die Register untersuchen.

Autor: Sven Stefan (stepp64) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Du schaltest vor dem Lesen von ADRESL auf Bank1 das ist richtig.
Deine Variable xw0 liegt aber in Bank0 und du schaltest erst nach dem 
Schreiben in xw0 wieder auf Bank0. Du musst also vor dem Schreiben nach 
xw0 die Bank wieder umschalten.

Sven

Autor: Raimund (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Der Pic sendet den ADRESH-Teil des 10 Bit-Ergebnisses einwandfrei und 
reproduzierbar an den PC, nur den ADRESL nicht. Als Konstante habe ich 
auch schon 'Hallo' und andere spannende Sachen tadellos übertragen 
können.

Wie gesagt wenn es auch mit Hilfe nicht klappt dann werde ich mir neue 
bzw. auch modernere PICs zulegen.

Ich schreibe die Programme mit dem MPLAB und brenne sie mit dem 
USB-Brenner von Sprut.

Autor: Sven Stefan (stepp64) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Bin ich jetzt gemeint? Ich denke nicht....

Aber trotzdem noch mal zum Verständnis:
  movf  ADRESH,0    ; obere  2 Bit auslesen
  movwf  xw1      ; obere  2-Bit nach xw1
  bcf    STATUS,RP1  ; Bank 1
  bsf    STATUS,RP0  ; Bank 1
  movf  ADRESL,0  ; untere 8 Bit auslesen
  movwf  xw0      ; untere 8-Bit nach xw0  <---- DA IST NOCH BANK1 AKTIV!!!
  bcf    STATUS,RP0  ; Bank 0
  bcf    STATUS,RP0  ; Bank 0

Bei der speicherung nach xw0 ist noch Bank1 aktiv! Dein Wert landet also 
nicht auf Adresse 0x28, sondern auf Adresse 0xA8. Den Wert den du dann 
später ausliest liegt aber in Bank0 da du ja vorher dahin umgeschaltet 
hast. Du musst es also so machen:
  movf  ADRESH,0    ; obere  2 Bit auslesen
  movwf  xw1      ; obere  2-Bit nach xw1
  bcf    STATUS,RP1  ; Bank 1
  bsf    STATUS,RP0  ; Bank 1
  movf  ADRESL,0  ; untere 8 Bit auslesen
  bcf    STATUS,RP0  ; Bank 0
  bcf    STATUS,RP0  ; Bank 0
  movwf  xw0      ; untere 8-Bit nach xw0

und dann klapts auch mit der Nachbarin ;-)

Sven

Autor: Severino R. (severino)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Sven Stefan wrote:
> Du schaltest vor dem Lesen von ADRESL auf Bank1 das ist richtig.
> Deine Variable xw0 liegt aber in Bank0 und du schaltest erst nach dem
> Schreiben in xw0 wieder auf Bank0. Du musst also vor dem Schreiben nach
> xw0 die Bank wieder umschalten.
>
> Sven

Hast Recht!

Autor: Raimund (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Sven,

dein Tipp hats gebracht. Vielen Dank. Ich hätte noch Stunden hier 
zugebracht bis mir eigefallen wäre dass für Variablen die Speicherbänke 
ja auch gelten.

ADRESL wird jetzt korrekt übertragen!

Nochmals Dank

Gruss

Raimund

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.