Hallo!
Im letzten Beitrag habe ich den Analog/Digital-Converter angesprochen. Das heutige Thema hat zwar auch mit dem Stichwort "Analog" zu tun, aber nicht mit der Messung einer Spannung, sondern mit dem Vergleich zweier Spannungen. Der Analog-Comparator (AC) vergleicht zwei Spannungen miteinander. Ist die Spannung am Pin AIN0 (PD6) höher als die Spannung am Pin AIN1 (PD7), dann gibt der Analog-Comparator HIGH zurück. Ist die Spannung am Pin AIN0 kleiner als die Spannung am Pin AIN1, dann gibt der Analog-Comparator LOW zurück.
Das kann man nutzten, um z.B. Pegelstände über ein Potentiometer einzustellen, welche beim Über- oder Unterschreiten angezeigt werden sollen. Oder um einen Pegel immer unter einem anderen Pegel zu halten. Z.B. zur Ansteuerung einer Wasserpumpe, die nur dann Wasser in einen Auffangbehälter pumpt, wenn noch genug Platz im Auffangbehälter ist.
An welchem Pin (AIN0 oder AIN1) die Referenzspannung angelegt wird ist egal. Die Spannung darf aber, wie üblich, nicht höher als VCC sein. Statt einer externen Referenzspannung kann eine interne 1,30 Volt (min: 1,15 V; max: 1,40 V) Bandgap-Referenzspannung verwendet werden. Diese interne Referenzspannung wird intern an AIN0 angelegt. Der Pin PD6 wird dadurch für andere Anwendungen frei.
Analog Comparator Block Diagram (ATmega8 Datenblatt; Kapitel "Analog Comparator")
Der AC ist ständig eingeschaltet (aktiv) und muss nicht explizit gestartet werden. Man kann ihn mit STOP AC
ausschalten und mit START AC
wieder einschalten.
Das ist kein Befehl, sondern die Abkürzung für Analog Comparator Control and Status Register - Analog Comparator Output. Dieses Bit zeigt den Zustand des AC an und kann jederzeit abgefragt werden.
Die Hilfe zu diesem Bit findest du im ATmega8-Datenblatt im Kapitel "Analog Comparator".
Beispiel:
$regfile = "m8def.dat"
Led1 Alias Portb.0
Config Led1 = Output
Do
Led1 = ACSR.ACO
Loop
End
Dieses Minimalbeispiel setzt voraus, dass an PB0 eine LED angeschlossen ist. Bei meinem Test sind an den Pins AIN1 und AIN0 jeweils ein 25k Poti als Spannungsteiler (zwischen VCC und GND) angeschlossen. Liegt an AIN0 eine höhere Spannung als an AIN1, dann leuchtet die LED. Wie man sieht, muss der AC nicht gestartet werden. Der AC ist ständig aktiv -- außer man schaltet ihn explizit aus (mit STOP AC
).
Der AC kann auch einen Interrupt auslösen. Der AC-Interrupt (ACI) kann bei LOW-HIGH-Flanke (RISING), bei HIGH-LOW-Flanke (FALLING) und bei Zustandsänderung (TOGGLE) ausgelöst werden. Dieses Verhalten kann man mit dem Befehl CONFIG ACI
einstellen.
Die Hilfe zu diesem Befehl findest du hier: http://avrhelp.mcselec.com/index.html?config_aci.htm
Beispiel:
$regfile = "m8def.dat"
Led1 Alias Portb.0
Config Led1 = Output
Led2 Alias Portb.1
Config Led2 = Output
Config Aci = On , Trigger = Toggle
On Aci On_aci
Enable Aci
Enable Interrupts
Do
Led1 = ACSR.ACO
Loop
End
On_aci:
Led2 = Not ACSR.ACO
Return
Dieses Beispiel setzt zusätzlich zum vorherigen Beispiel noch eine LED an PB1 voraus. Wenn man sich mit dem Testaufbau ein wenig spielt, dann fällt auf, dass die erste LED nach dem Start des Programms sofort entweder ein oder aus ist (je nach Poti-Einstellung). Die zweite LED wird erst dann ein- oder ausgeschaltet, wenn der Schwellwert durch Drehen an einem der Potis über- oder unterschritten wird. Der Interrupt wird also nur beim "Toggeln" ausgelöst.
Setzt man das Bit ACSR.ACBG
Analog Comparator Bandgap Select, dann wird intern an AIN0 eine 1,30 Volt (min: 1,15 V; max: 1,40 V) Bandgap-Referenzspannung angelegt. Der Pin PD6 wird damit frei.
Beispiel:
$regfile = "m8def.dat"
Led1 Alias Portb.0
Config Led1 = Output
ACSR.ACBG = 1 ' Interne Bandgap-Referenzspannung verwenden
Do
Led1 = ACSR.ACO
Loop
End
Der AC kann nicht nur mit den Pins AIN0 und AIN1 arbeiten. Statt AIN1 kann man den vom Analog/Digital-Converter (ADC) bekannten Multiplexer verwenden. Natürlich nur, wenn dieser nicht bereits vom ADC verwendet wird. Damit hat man für den Analog-Comparator die Pins ADC0 bis ADC5 (bei SMD-Bausteinen auch ADC6 und ADC7) zur Verfügung. Da es (laut Roland Walter) nach dem Umschalten des Multiplexers bis zu 750 ns dauern kann, bis der AC mit der Messung fertig ist, muss man diese 750 ns warten bevor man das Bit ACSR.ACO auswertet. Wenn der ATmega8 mit 8 Mhz läuft, dann dauert ein Tick 125 ns (1 sec / 8000000 Ticks = 0,000000125). Um den µC 750 ns warten zu lassen braucht es sechs Ticks. Diese kann man am Einfachsten mit !NOP
verbraten. Im Datenblatt finde ich nur den Hinweis auf 1 bis 2 Ticks, aber lieber ein paar Ticks zu viel als zu wenig warten. ;-)
Ich verwende im Beispiel das erste Mal den MACRO
-Befehl. Damit kann man sich Schreibarbeit sparen und öfter wiederkehrende Befehle zusammenfassen. Bascom ersetzt beim Kompilieren des Programms den Makro-Aufruf durch den Inhalt des Makros. Ein Makro ist schneller als GOTO oder GOSUB und braucht weniger Laufzeitressourcen, aber es wird kein Flash-Speicherplatz gespart.
Beispiel:
$regfile = "m8def.dat"
$crystal = 8000000
Led1 Alias Portb.0
Config Led1 = Output
Led2 Alias Portb.1
Config Led2 = Output
ACSR.ACBG = 1 'Bandgap-Referenzspannung einschalten
SFIOR.ACME = 1 'Multiplexer einschalten
'Makro, welches bei 8 Mhz 750 ns wartet
Macro Wait750ns
!NOP '125 ns
!NOP '125 ns
!NOP '125 ns
!NOP '125 ns
!NOP '125 ns
!NOP '125 ns
End Macro
Do
ADMUX = 0 'nach ADC0 umschalten
Wait750ns 'warten
Led1 = ACSR.ACO
ADMUX = 1 'nach ADC1 umschalten
Wait750ns 'warten
Led2 = ACSR.ACO
Loop
End
In diesem Beispiel wird je eine LED an PB0 und PB1 erwartet. Die in den vorherigen Beispielen angesprochenen Potis befinden sich für dieses Beispiel an den Pins ADC0 (PC0) und ADC1 (PC1).
Viel Spaß beim Ausprobieren. :-)
lg Gerold :-)
Den zugehörigen Original-Beitrag findest du im Loetstelle-Forum.
Ich programmiere Progressive Web Applications, Mobile Apps, Desktop-Programme und noch vieles mehr. Falls es dich interessiert, findest du mehr Informationen darüber auf meiner Business-Website.