Taster am ADC-Port ohne ADC-Auswertung

Was wenn – wie im augenblicklich in der Neuplanung befindlichen Antennentuner – der ADC für Messaufgaben genutzt wird und sich die Frage stellt, was man mit den restlichen ADC-Pins anfangen kann?

Situation: ADC0 und ADC1 haben Analog-Messaufgaben, hier im Antennentuner die Vorlauf- und Rücklauf-Spannung für SWR und HF-Power zu messen. Alle anderen Ports sind belegt. Es stehen nur noch ADC2 bis ADC7 eines ATmega16 zur Verfügung. An die sollen 6 Taster angeschlossen werden.

Die erste Lösung wie im vorherigen Kapitel "Taster am ADC mit ADC-Auswertung" beschrieben blieb unbefriedigend wegen der langen Reaktionszeit auf Tastenbetätigungen bei der Verwendung von "GetADC". Der direkte Zugriff auf die ADC-Register brachte eine deutliche Verbesserung. Kann man neben den echten ADC-Auswertungen, hier an ADC0 und ADC1, die restlichen ADC-Pins für reine Schalteranwendungen nutzen? Man kann, auch wenn irgendein AVR-Guru im Web davon abrät.

Eingesetzt wurde die vorher beschriebene "Dannegger-Methode" mit Timer-Interrupts, und es ging tatsächlich, ohne die Messungen an ADC0 und ADC1 zu stören. Hier die Codeschnipsel aus dem an anderer Stelle beschriebenen Controller zum  Antennentuner zur Kombination ADC-Messung und Tasterauswertung an einem ATmega16, ADC und weitere 4 Tastern an PortA als Test:

'Configure ADC  ---------------------------------------------------------------
Config ADC = Single , Prescaler = Auto , Reference = AVCC

'Configure PortA (Key port, 6 keys @ Port A.2 ... A.7) -------------------------
'PA.0 & PA.1 are ADC-Pins ADC0 & ADC1 measuring voltages (real ADC function)
'4 test keys @ Port A.2...A.5 (key0, key1, key2, Key3)
DDRA = &B00000000                                 'PortA = Input (=ADC-Port)
PortA = &B11111100                                'activate Pullup 2...7, not 0, 1!
Key_port Alias PinA                               'Input-Port Keys
Const Key0 = 2                                    'Key0 @ PINA.2
Const Key1 = 3                                    'Key1 @ PINA.3
Const Key2 = 4                                    'Key2 @ PINA.4
Const Key3 = 5                                    'Key3 @ PINA.5

'Configure Timer0-Interrupt for Keys (Timer0 = 8bit, 2^8=256 counts) ----------
'Overflow time: Overflow-Counts * Prescale / crystal frequency
'= 255 * 1024 / 16.000.000 = 16,3 msec = ~ 61 Hz (crystal 16 MHz)
'Possible Prescales: 8, 64, 256, 1024, here 1024
Config Timer0 = Timer , Prescale = 1024
Const Presettimer0 = 56                           'Initialize Timer0 (shorten time, >0)
On Timer0 Timer0_isr                              'On Overflow go to Timer0_isr

Da ADC0 und ADC1 (PA.0 und PA.1 am ATmega16) Messaufgaben haben, stehen die ADC-Ports ab ADC2 (PA.2) anderweitig zur Verfügung. Mit "PortA = &B11111100" werden also die Pullups für PA.2 bis PA.7 eingeschaltet. Damit können bis zu 6 Taster von PA.2 bis PA.7 nach Masse geschaltet werden.

Der Rest geht wie oben unter 'Die "Dannegger-Methode" mit Timer-Interrupts' beschrieben, also Initialisierung der Taster-Variablen, Timer-Konfigurierung, Timer- und Interrupt-Start und Timer0_isr-Routine. Die Timer0_isr wertet den gesamten Key_port (=PortA) aus, also auch die als ADC0 und ADC1 fungierenden PA.0 und PA.1. Daher werden die Taster Key0, Key1 usw. ab 2 hochgezählt, oben z.B. mit "Const Key0 = 2", womit PA.2 angesprochen wird.

Die Abfrage der Taster geht dann genau so wie mit der Dannegger-Methode, z.B.

Do

   'Do something else

   'Disable/enable timer0 may be omitted, test it. Omitted here.
   If bytKey_state <> bytKey_save Then            'Any key was pressed
      'Disable timer0                              'Stop Timer0 for display
      'Check Key Key0 --------------
      If bytKey_press.Key0 = 1 Then               'key0 is pressed
         Call ClearLCDLine(2 , 16)
         LCD "Key 0"
      End If
      'Check Key Key1 --------------
      If bytKey_press.Key1 = 1 Then               'key1 is pressed
         Call ClearLCDLine(2 , 16)
         LCD "Key 1"
      End If

      'Check the other keys...

      bytKey_press = 0                            'reset Key_press
      'Enable Timer0                               'Restart Timer0
   End If
Loop

Die ADC-Funktionalität für die ADC-Ports A.0 und A.1 kann mit "GetADC" oder variabler und mit besserem Zeitverhalten, aber mit mehr zu schreibendem Code, über die ADC-Register realisiert werden, wie es in 'ADC mal ohne BASCOM-"GetADC"' beschrieben ist.

Der Vollständigkeit halber noch die Sub ClearLCDLine, nichts Tiefsinniges:

Sub ClearLCDLine(byVal bytRow As Byte , byVal bytChars As Byte)
'Clear LCD bytChars characters in line bytRow
   Locate bytRow , 1
   LCD SPC(bytChars)
   Locate bytRow , 1
End Sub

Also - geht doch: PA0 und PA1 arbeiten als ADC0 und ADC1 und messen Gleichspannungen, währenddessen die restlichen Pins des ADC-Port A auf Tastendruck reagieren. Und das so flott und sicher wie oben mit der "Dannegger-Methode" beschrieben.

Gemischte Input-/Output-Funktionen an Port A

Sollen die Ports PA.2 bis PA.7 ganz oder teilweise als Output-Ports dienen, lässt sich das mit dem Data Direction Register DDRA für den Port A entsprechend einstellen, z.B.

DDRA = &B11000000                                 'Port A.0...A.5 = Input, A.6, A.7 = Output
PortA = &B00111100                                'activate Pullup 2...5, not 0, 1, 6, 7!

Die Ports A.0 bis A.5 sind Input-Ports, A.0 und A.1 als ADC, A.2...A.5 als Digitaleingänge. Für letztere werden die Pullup-Widerstände nach +5V aktiviert. Die Ports A.5, A.6 sind Output-Ports, z.B. zur Ansteuerung von Funktionsanzeigen mit LED.