AD-Referenz in Bascom umschalten          

Hexfile disassemblieren, eigene AD-Funktion                 
Elektronik-Labor   Projekte   AVR 

 

Im Mega32 ist jede Menge Platz für neue Ideen. So könnte man z.B. ganz spezielle Messprogramme in Bascom entwickeln. In diesem Zusammenhang habe ich nach einer Möglichkeit gesucht, die Referenz des AD-Wandlers im laufenden Betrieb umzuschalten. Dazu muss der Ref-Anschluss des Controllers frei bleiben. Nur ein 100-nF-Kondensator gegen Masse ist zu empfehlen. Das Umschalten per Software ist anscheinend nicht so einfach wie man denken könnte. Der erste Versuch ging etwa so, womit auf die interne Referenz von 2,56 V umgeschaltet werden sollte:  

If Einstellung2 then Config Adc = Single , Prescaler = 32 , Reference = Internal

Keine Reaktion. Anscheinend ist die ursprüngliche Config-Anweisung für den Compiler bindend und kann zur Laufzeit nicht mehr korrigiert werden. Wie ging das noch mit dem Umschalten? Das Datenblatt zum Mega32 sagt: Alles steht im Register ADMUX, der Kanal, und auch die verwendete Referenz. Die Einstellungen zur Referenz belegen die oberen beiden Bits: 11 bedeutet interne Referenz, 01 bedeutet AVCC. Also sollte man doch einfach dieses Register verändern können:

If Einstellung2 then  Admux = 192  

Die Hoffnung war, dass Bascom Admux liest, den gewünschten AD-Kanal in den unteren Bits einfügt und wieder zurückschreibt. Ging aber leider auch nicht. Mit konstanter Boshaftigkeit wurde immer nur die Einstellung aus der ursprünglichen Config-Anweisung genommen. Wie das überhaupt geht, mit dem AD-Wandler, das zeigt ein Assemblerprogramm aus dem Lernpaket Mikrocontroller für den Tiny13:


;ADC3.asm, AD-Wandler mit Referenz 1,1 V

.include "tn13def.inc"

.def A = r16
.def B = r17
.def Delay = r18
.def Count = r19

;Port B
.equ TXD = 1
.equ RXD = 2


rjmp Anfang
Anfang:
sbi ddrb,TXD ;Datenrichtung TXD
rcall AdcInit
Schleife:
rcall RdCOM
rcall RdADC
rcall WrCOM
rjmp Schleife

AdcInit:
ldi A,3 ;Clock / 4
out ADCSRA,A
sbi ADCSRA,ADEN ;AD einschalten
ret

RdADC:
out ADMUX,A
sbi ADMUX,ADLAR ;Left adjust
sbi ADMUX,REFS0 ;1,1 V Referenz
sbi ADCSRA,ADSC ;Wandlung starten
ADrdy:
sbic ADCSRA,ADSC
rjmp ADrdy
sbi ADCSRA,ADSC
ADrdyb:
sbic ADCSRA,ADSC
rjmp ADrdyb
in A,ADCH
ret


Die spannende Frage ist nun, was läuft da in Bascom anders, und was kann man dagegen tun? Man muss dem Compiler einmal genauer auf die Finger schauen, indem das Ergebnis in Assembler analysiert wird. Das geht mithilfe des AVR Studio 4. Beim Kompilieren soll Bascom ein OBJ-File erzeugen.


Hier ein extra kurzes Basic-Programm, das helfen soll, der Sache auf den Grund zu gehen:

$regfile = "m32def.dat"
Dim Dd As Word
Config Adc = Single , Prescaler = 32 , Reference = Internal
Start Adc

Do
Dd = Getadc(3)
Loop

Beim Kompilieren erzeugt Bascom neben dem Hexfile und anderen Dateien auch das OBJ-File. Dieses kann man nun in das AVR Studio laden. Es wird automatisch ein AVR-Projekt erstellt und der Simulator gestartet. Vorher wird man noch gefragt, welcher Chip gemeint ist.




Im Simulator kann man dem Programm mit allen möglichen Mitteln auf die Finger schauen. Zum Beispiel mit dem Disassembler. 




Hier ist das Ergebnis des Disassemblers. Die entscheidende Stelle ist markiert und zusätzlich kommentiert. Die für die Referenz zuständigen Bits im ADMUX-Register (Adresse 0x07)  werden als Konstanten eingefügt, so wie der Compiler sie aus der Config-Anweisung gelesen hat. Zur Laufzeit ist da leider nichts mehr zu ändern.

--- Test2.bas ------------------------------------------------------------------------------------

5: Config Adc = Single , Prescaler = 32 , Reference = Internal
+0000003D: E085 LDI R24,0x05 Load immediate
+0000003E: B986 OUT 0x06,R24 Out to I/O location
5: Config Adc = Single , Prescaler = 32 , Reference = Internal
+0000003F: EC80 LDI R24,0xC0 Load immediate
+00000040: B987 OUT 0x07,R24 Out to I/O location
6: Start Adc
+00000041: 9A37 SBI 0x06,7 Set bit in I/O register
10: Dd = Getadc(3)
+00000042: EC83 LDI R24,0xC3 Load immediate
+00000043: 6C80 ORI R24,0xC0 Logical OR with immediate , 1100 000 fest vorgegeben
10: Dd = Getadc(3)
+00000044: B987 OUT 0x07,R24 Out to I/O location , ins ADMUX-Register
+00000045: 940E0056 CALL 0x00000056 Call subroutine
+00000047: E6A0 LDI R26,0x60 Load immediate
10: Dd = Getadc(3)
+00000048: E0B0 LDI R27,0x00 Load immediate
+00000049: 938D ST X+,R24 Store indirect and postincrement
10: Dd = Getadc(3)
+0000004A: 939C ST X,R25 Store indirect
12: Loop
+0000004B: 940C0042 JMP 0x00000042 Jump
12: Loop
+0000004D: 9731 SBIW R30,0x01 Subtract immediate from word
+0000004E: F7F1 BRNE PC-0x01 Branch if not equal
12: Loop
+0000004F: 9508 RET Subroutine return
+00000050: 9468 SET Set T in SREG
12: Loop
+00000051: F862 BLD R6,2 Bit load from T to register
+00000052: 9508 RET Subroutine return
12: Loop
+00000053: 94E8 CLT Clear T in SREG
+00000054: F862 BLD R6,2 Bit load from T to register
12: Loop
+00000055: 9508 RET Subroutine return
+00000056: 9A36 SBI 0x06,6 Set bit in I/O register
12: Loop
+00000057: 9936 SBIC 0x06,6 Skip if bit in I/O register cleared
+00000058: CFFE RJMP PC-0x0001 Relative jump
12: Loop
+00000059: 9A36 SBI 0x06,6 Set bit in I/O register
+0000005A: 9936 SBIC 0x06,6 Skip if bit in I/O register cleared
12: Loop
+0000005B: CFFE RJMP PC-0x0001 Relative jump
+0000005C: B184 IN R24,0x04 In from I/O location
12: Loop
+0000005D: B195 IN R25,0x05 In from I/O location
+0000005E: 9508 RET Subroutine return

Das Ergebnis ist klar: Mit den Standard-Befehlen kann man die Referenz nicht umschalten! Also muss eine eigene Funktion her. Das ist gar nicht so schwierig, denn man kann ja einiges abschreiben, z.B. dass Bascom den AD-Wandler gleich zweimal hintereinander startet. Hier ist eine mögliche Lösung, bei der die Referenzeinstellung zusammen mit dem Kanal übergeben wird:

$regfile = "m32def.dat"
$hwstack = 32
$swstack = 64
$framesize = 64

$baud = 19200
$crystal = 11059200
Dim Dd As Word
Dim Ref As Byte

Declare Function Ad(byval C As Byte) As Word


Config Adc = Single , Prescaler = 32 , Reference = Avcc
Start Adc

Ref = 192 'Ref 2,56 V
Do
Dd = Ad(7)
Print Dd

Waitms 500
Loop


Function Ad(byval C As Byte) As Word
Local Dl As Byte
Local Dh As Byte
Local Dd3 As Word
C = C + Ref
Admux = C
Adcsr.6 = 1
Do
Loop Until Adcsr.6 = 0
Adcsr.6 = 1
Do
Loop Until Adcsr.6 = 0
Dl = Adcl
Dh = Adch
Dd3 = 256 * Dh
Dd3 = Dd3 + Dl
Ad = Dd3
End Function



Elektronik-Labor   Projekte   AVR