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


von Raimund (Gast)


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.
1
  list p=16f872
2
3
4
  #include <P16f872.INC>
5
6
7
8
9
;**************************************************************
10
;Variablennamen vergeben
11
                    
12
Temp  Equ  0x20
13
cycl_1  Equ  0x21  
14
cycl_2  Equ  0x22
15
Byte  Equ  0x23
16
Zähler  Equ 0x24
17
cycl_5  Equ  0x25
18
cycl_3   Equ 0x26
19
cycl_6  Equ  0x27
20
xw0    Equ  0x28
21
xw1    Equ  0x29
22
out    Equ  0    ; RS-232 out ist RB0
23
24
;**************************************************************
25
26
27
Init
28
  bsf     STATUS, RP0  ; Umschalten auf Bank 1
29
  clrf  TRISB    ; PortB alle Ausgang
30
  bcf    ADCON1,0  ; Nur AN0 als Eingang,Vdd und Vss = Referenz 
31
  bsf    ADCON1,1  ; Nur AN0 als Eingang,Vdd und Vss = Referenz 
32
  bsf    ADCON1,2  ; Nur AN0 als Eingang,Vdd und Vss = Referenz 
33
  bsf    ADCON1,3  ; Nur AN0 als Eingang,Vdd und Vss = Referenz 
34
  bcf    ADCON1,7  ; Ergebnis in ADRESH und ADRESL linksbündig
35
  bsf    TRISA,0    ; RA0 Input
36
  
37
  bcf     STATUS, RP0  ; Zurückschalten zur Bank 0
38
  bcf    ADCON0,5  ; AN0 ist der Eingang
39
  bcf    ADCON0,4  ; AN0 ist der Eingang
40
  bcf    ADCON0,3  ; AN0 ist der Eingang
41
  bsf    ADCON0,0  ; ADC ein
42
  bcf    ADCON0,7  ; ADC Geschwindigkeit 1,25-5 MHz
43
  bsf    ADCON0,6  ; ADC Geschwindigkeit 1,25-5 MHz
44
45
46
Loop
47
48
  movlw D'16'
49
  movwf Zähler    ;Zähler 0-15 auf 16
50
  
51
Ausgabe
52
  
53
  decf  Zähler,1  ;Zähler wird um 1 vermindert
54
  bcf    STATUS,C
55
  rlf   Zähler,0  ;Alle Bits von Zähler um eine Stelle nach links verschieben nur in W
56
  ;movlw  B'00001110'
57
  movwf  PORTB    ;Zähler nach PortB
58
  BSF    ADCON0, 2    ; ADC starten 
59
spring
60
61
    btfsc  ADCON0,2  ;Ist der ADC fertig?
62
  GOTO    spring      ; nein, weiter warten 
63
            ;Ja ADC ist fertig
64
  ;call Warte_s1
65
  bcf    STATUS,C
66
  movlw  D'255'    ;255 nach W
67
  ;call  Send_RS    ;Gebe 255 an RS232 aus  //Testzahl
68
69
  movlw  D'255'    ;255 nach W
70
  ;call  Send_RS    ;Gebe 255 an RS232 aus  //Testzahl
71
  
72
  movlw  '_'     
73
  ;call  Send_RS  
74
75
  movf  Zähler,0  ;Inhalt von Zähler nach W //15-0
76
  ;addlw  D'42'    ;Addiere 42 zu Zähler in W  //Um im Terminalprogramm von 9 an abwärts angezeigt zu werden
77
  call  Send_RS    ;Ergebnis nach RS232
78
  
79
  movf  ADRESH,0    ; obere  2 Bit auslesen
80
  movwf  xw1      ; obere  2-Bit nach xw1
81
  bcf    STATUS,RP1  ; Bank 1
82
  bsf    STATUS,RP0  ; Bank 1
83
  movf  ADRESL,0  ; untere 8 Bit auslesen
84
  movwf  xw0      ; untere 8-Bit nach xw0
85
  bcf    STATUS,RP0  ; Bank 0
86
  bcf    STATUS,RP0  ; Bank 0
87
        
88
  movf  xw1,0    ; xw1 nach W
89
  call  Send_RS    ; Sende über RS232
90
  movf  xw0,0    ; xw0 nachW
91
  call  Send_RS    ; Sende über RS232
92
;***************************************************************
93
  movlw  'H'      ; es soll Hallo an RS232 gesendet werden
94
  ;call  Send_RS    ; Datenwort ausgeben via RS-232
95
  movlw  'a'  
96
  ;call  Send_RS  
97
  movlw  'l'     
98
  ;call  Send_RS  
99
  movlw  'l'    
100
  ;call  Send_RS        ;Zum testen 'Hallo ' ausgeben
101
  movlw  'o'     
102
  ;call  Send_RS
103
  movlw  ' '     
104
  ;call  Send_RS      
105
;****************************************************************
106
  movf  Zähler,1  ; Zähler wird nach Zähler kopiert,jetzt kann Zero-Bit getestet werden
107
  btfss  STATUS,Z  ; Zähler auf 0?
108
  goto Ausgabe    ; Nein
109
  goto Loop      ; Ja
110
  
111
  
112
113
;***************************************************************
114
;Senden des Bytes, das im Register W steht 
115
116
Send_RS        ; Ausgabe eines Bytes seriell  
117
  movwf  Byte    ; Byte in w
118
  movlw  8    ; es werden 8 Bit gesendet
119
  movwf   cycl_1
120
  bsf  PORTB, out
121
  call  Warte_s    ; 1 Stopbit (1)
122
  bcf  PORTB, out
123
  call   Warte_s    ; 1 Startbit (0)
124
125
Send_1  rrf  Byte, f    ; aktuelles Bit in das Carry-Flag schieben
126
  btfsc  STATUS, C
127
  bsf  PORTB, out  ; Lo wenn Bit = 1
128
  btfss  STATUS, C
129
  bcf  PORTB, out  ; Hi wenn Bit = 0
130
  call  Warte_s    ; 1 Bit lang warten
131
  decfsz  cycl_1, f  ; waren das schon 8 Bit?
132
  goto  Send_1    ; nein, es geht weiter
133
  bsf  PORTB, out  ; Byte zuende, 1 Stoppbit (1) senden
134
  call   Warte_s    ;
135
  return
136
137
;**********************************************************
138
;ein Bit Zeitverzoegerung mit einer Warteschleife
139
; Timing muß genau stimmen (5%)
140
;
141
; senden            4 MHz    10 MHz
142
; 2400 Bps =          69d    173d
143
; 9600 Bps =          16d     43d
144
145
Warte_s  movlw  D'16'    ; 9600 Bps / 4 MHz senden
146
  movwf  cycl_2
147
Warte1        ; 6 Zyklen Schleife
148
  nop
149
  nop
150
  nop
151
  decfsz  cycl_2, 1  
152
  goto  Warte1
153
  return
154
;**********************************************************
155
;Grössere Pause zum testen, zur Zeit nicht benutzt
156
Warte_s1  movlw  D'255'    ; 9600 Bps / 4 MHz senden
157
  movwf  cycl_3
158
Warte11        ; 6 Zyklen Schleife
159
  nop
160
  nop
161
  nop
162
  decfsz  cycl_3, 1  
163
  goto  Warte11
164
  return
165
  end

von Severino R. (severino)


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).

von Raimund (Gast)


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

von Severino R. (severino)


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.

von Sven S. (stepp64) Benutzerseite


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

von Raimund (Gast)


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.

von Sven S. (stepp64) Benutzerseite


Lesenswert?

Bin ich jetzt gemeint? Ich denke nicht....

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

und dann klapts auch mit der Nachbarin ;-)

Sven

von Severino R. (severino)


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!

von Raimund (Gast)


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

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.