Searcher
25.04.2014, 21:15
Dies ist eigentlich kein besonderes Programm; eher eine Demo für das Messen des Resetpins mit dem ADC.
Weil mir bei einem kleinen 4 X 7 Segment Multiplex Projekt mit ATtiny45 und 74HC595 Schieberegistern die Pins am Tiny knapp wurden, suchte ich noch einen Anschluß für einen Taster zum Betriebsmodus umschalten.
Ein Spannungsteiler und Taster an PB5 (RESET & ADC0) bescherte mir dann den "zusätzlichen" Pin.
5V----o-----o-------------------o-------
| | |
| R1.-.510 ||100nF |
| o | | .-----||-------o
|=|> | | | || |
| o '-' | |
T | | | PB5 __ Vcc |
'-----o----)---o| |o-----'
| | -o| |o-
R2.-.10k| -o| |o-
| | o---o|__|o-
| | | GND
'-' | ATtiny45
| |
GND---------o----o----------------------
Mit den Defaulteinstellungen der Fuses ist beim ATtiny45 der PB5 Pin als Reset Pin eingestellt; das sollte auch nicht geändert werden um den Tiny weiter über ISP programmieren zu können. (CKDIV8 Fuse wurde für 8Mhz Systemtakt umgestellt)
Gleichzeitig mit der Resetfunktion funktioniert der PB5 aber auch noch als ADC0 und kann mit dem ADC gemessen werden. Das hatte ich schon mal bei einem Linienfolger ausgenutzt (https://www.roboternetz.de/community/entries/41-127-virtuelle-Fotodioden-Proof-of-Concept).
Um ein sicheres High zu gewährleisten und um keinen Reset auszulösen muß die Spannung nach Datenblatt mindestens 0,9*Vcc betragen (Bei Vcc=5V: 0,9*5V=4,5V). Der Spannungsteiler mit R1 und R2 soll das gewährleisten. Erst eine viel tiefere Spannung löst einen Reset aus.
In diesem Programm mißt der ADC die Spannung an PB5 (ADC0). Wenn PB5 nahe Vcc gemessen wird, wird auf "Taster betätigt" erkannt und zur Entprellung bzw. gegen mehrfaches Erkennen eines Tastendruckes eine Schutzzeit von ca. einer Sekunde gestartet ohne blockierend zu wirken. In dieser Zeit wird PB5 nicht mehr gemessen und es können keine weiteren Tastendrücke für diese Zeit erkannt werden. Mir reicht das völlig, um zwischen zwei verschiedenen Betriebsmodi umzuschalten.
Hier wird zwischen Anzeige des Meßwertes eines Potis an ADC3 und Meßwert am Resetpin durch Tastendruck umgeschaltet.
Für die Schutzzeitzeitnahme wird die Multiplex ISR mitgenutzt, die alle 4ms durch Timer0 aufgerufen wird. Dort wird dann die Bytevariable "Cmp0a_counter" bis zum Überlauf hochgezählt und gibt das Messen des Resetpins in der Haupschleife wieder frei.
Die Bitmuster sind natürlich abhängig von der Beschaltung der Schieberegister. Nur die wichtige HW für die ADC Messung an PB5 sind gezeichnet und die dafür wichtigen Programmteile im Code hervorgehoben.
Ob man den Resetpin in dieser Art nutzt ist bestimmt von Fall zu Fall unterschiedlich und man muß dem Datenblatt entnehmen, bei welchen µCs das überhaupt möglich ist. Meistens ist es nicht nötig und sollte wohl auch vermieden werden? Der Spannungsteiler zieht etwas Strom und könnte auch noch etwas hochohmiger gemacht werden. Bei mir hat der 510 Ohm Widerstand meinen Parallelport-Selbstbau-ISP-Programmer nicht gestört (Es fließen dann während des Programmierens, wenn Reset auf GND gezogen wird, etwa 10mA über den 510 Ohm Widerstand -man beachte auch den internen Pullup von 30k bis 60k, der parallel zu dem R1 liegt. Drücken des Tasters muß dann vermieden werden um keinen Kurzschluß zu verursachen!!!). Andere Programmer könnten empfindlicher auf den niedrigen Pullup reagieren?
$regfile = "attiny45.dat"
$crystal = 8000000
$hwstack = 32
$swstack = 32
$framesize = 32
Dim I As Byte
Dim K As Word
Dim Show As Word 'value from 0 to 9999 to be displayed
Dim Show_old As Word
Dim Digit As Byte 'currently selected digit for output to display
Dim Digit_pattern As Byte 'Segment Select Pattern for 7 Seg.
Dim Digit_sel As Byte 'Digit Select Pattern for 7 Seg
Dim Number_ar(4) As Byte 'contains four digits to be multiplexed
Dim Index As Byte 'Index for Lookup table
Dim Adc_key As Word 'Gets ADC value measured on PB5
Dim Key_pressed As Byte 'Toggles when key is actuated
Dim Poti_adc_new As Word 'variables for Poti measurement
Dim Poti_adc_old As Word 'variables for Poti measurement
Dim Poti_value As Word 'variables for Poti measurement
Dim Diff_new_old As Integer 'variables for Poti measurement
Dim Cmp0a_counter As Byte 'measure security time for key pressing
Serial_clock_pin Alias Portb.0
Config Serial_clock_pin = Output 'SHCP at 74HC595
Serial_data_pin Alias Portb.2
Config Serial_data_pin = Output 'DS at 74HC595
Config Portb.1 = Output 'STCP at 74HC595
Config Adc = Single , Prescaler = Auto , Reference = Avcc
Tccr0a = Bits(wgm01) 'CTC (OCR0A as top)
Ocr0a = 124 'for 250Hz compare interrupt
Tccr0b = Bits(cs02) 'prescale = 256 (start timer)
On Compare0a Multiplex
Enable Compare0a
Enable Interrupts
Do 'Hauptschleife
If Cmp0a_counter = 0 Then
Adc_key = Getadc(0) 'measure PB5(ADC0)
If Adc_key > 1000 Then 'If key is pressed then
Toggle Key_pressed
Cmp0a_counter = 1 'start secure timing
End If
End If
Poti_adc_new = Getadc(3) 'measure Poti setting at ADC3
Diff_new_old = Poti_adc_new - Poti_adc_old
If Abs(diff_new_old) > 3 Then 'SW-Hysterese
Poti_adc_old = Poti_adc_new
Shift Poti_adc_new , Right , 2 'remove unsave bits
Poti_value = Poti_adc_new 'result between 0 and 255
End If
'Toggle output to display between Adc value at PB5 and Poti_value by each key push
If Key_pressed > 0 Then Show = Adc_key Else Show = Poti_value
Gosub Prepare_number_for_output
Loop
End
Multiplex: 'ISR called every 4ms
If Cmp0a_counter > 0 Then Incr Cmp0a_counter 'overflow counter for security time
Incr Digit
Digit_pattern = Lookup(number_ar(digit) , Bitpattern)
Select Case Digit
Case 1 : Digit_sel = &B1000_0000
Case 2 : Digit_sel = &B0100_0000
Case 3 : Digit_sel = &B0010_0000
Case 4 : Digit_sel = &B0001_0000
Digit = 0
End Select
Shiftout Serial_data_pin , Serial_clock_pin , Digit_sel , 1 'serial out to 74HC595
Shiftout Serial_data_pin , Serial_clock_pin , Digit_pattern , 1 'serial out to 74HC595
!sbi pinb,1 'toggle PB1 / STCP at 74hc595
!sbi pinb,1 'toggle PB1 / STCP at 74hc595
Return
Prepare_number_for_output:
If Show <> Show_old Then
K = Show / 1000 'separate decimal digits from word variable into byte array
Disable Compare0a 'no output to display while modifying Number_ar()
Number_ar(1) = K 'first/leftmost digit on 4*7 Seg. Display
K = Show Mod 1000 'separate decimal digits from word variable into byte array
K = K / 100
Number_ar(2) = K
K = Show Mod 100 'separate decimal digits from word variable into byte array
K = K / 10
Number_ar(3) = K
K = Show Mod 10 'separate decimal digits from word variable into byte array
Number_ar(4) = K 'forth/rightmost digit on 4*7 Seg. Display
For I = 1 To 3
If Number_ar(i) = 0 Then Number_ar(i) = 10 Else Exit For 'replace leading zeros with indexes of blank
Next I
Enable Compare0a
Show_old = Show
End If
Return
Bitpattern:
Data &B00000011 '0
Data &B10011111 '1
Data &B00100101 '2
Data &B00001101 '3
Data &B10011001 '4
Data &B01001001 '5
Data &B01000001 '6
Data &B00011111 '7
Data &B00000001 '8
Data &B00001001 '9
Data &B11111111 'blank
Gruß
Searcher
Weil mir bei einem kleinen 4 X 7 Segment Multiplex Projekt mit ATtiny45 und 74HC595 Schieberegistern die Pins am Tiny knapp wurden, suchte ich noch einen Anschluß für einen Taster zum Betriebsmodus umschalten.
Ein Spannungsteiler und Taster an PB5 (RESET & ADC0) bescherte mir dann den "zusätzlichen" Pin.
5V----o-----o-------------------o-------
| | |
| R1.-.510 ||100nF |
| o | | .-----||-------o
|=|> | | | || |
| o '-' | |
T | | | PB5 __ Vcc |
'-----o----)---o| |o-----'
| | -o| |o-
R2.-.10k| -o| |o-
| | o---o|__|o-
| | | GND
'-' | ATtiny45
| |
GND---------o----o----------------------
Mit den Defaulteinstellungen der Fuses ist beim ATtiny45 der PB5 Pin als Reset Pin eingestellt; das sollte auch nicht geändert werden um den Tiny weiter über ISP programmieren zu können. (CKDIV8 Fuse wurde für 8Mhz Systemtakt umgestellt)
Gleichzeitig mit der Resetfunktion funktioniert der PB5 aber auch noch als ADC0 und kann mit dem ADC gemessen werden. Das hatte ich schon mal bei einem Linienfolger ausgenutzt (https://www.roboternetz.de/community/entries/41-127-virtuelle-Fotodioden-Proof-of-Concept).
Um ein sicheres High zu gewährleisten und um keinen Reset auszulösen muß die Spannung nach Datenblatt mindestens 0,9*Vcc betragen (Bei Vcc=5V: 0,9*5V=4,5V). Der Spannungsteiler mit R1 und R2 soll das gewährleisten. Erst eine viel tiefere Spannung löst einen Reset aus.
In diesem Programm mißt der ADC die Spannung an PB5 (ADC0). Wenn PB5 nahe Vcc gemessen wird, wird auf "Taster betätigt" erkannt und zur Entprellung bzw. gegen mehrfaches Erkennen eines Tastendruckes eine Schutzzeit von ca. einer Sekunde gestartet ohne blockierend zu wirken. In dieser Zeit wird PB5 nicht mehr gemessen und es können keine weiteren Tastendrücke für diese Zeit erkannt werden. Mir reicht das völlig, um zwischen zwei verschiedenen Betriebsmodi umzuschalten.
Hier wird zwischen Anzeige des Meßwertes eines Potis an ADC3 und Meßwert am Resetpin durch Tastendruck umgeschaltet.
Für die Schutzzeitzeitnahme wird die Multiplex ISR mitgenutzt, die alle 4ms durch Timer0 aufgerufen wird. Dort wird dann die Bytevariable "Cmp0a_counter" bis zum Überlauf hochgezählt und gibt das Messen des Resetpins in der Haupschleife wieder frei.
Die Bitmuster sind natürlich abhängig von der Beschaltung der Schieberegister. Nur die wichtige HW für die ADC Messung an PB5 sind gezeichnet und die dafür wichtigen Programmteile im Code hervorgehoben.
Ob man den Resetpin in dieser Art nutzt ist bestimmt von Fall zu Fall unterschiedlich und man muß dem Datenblatt entnehmen, bei welchen µCs das überhaupt möglich ist. Meistens ist es nicht nötig und sollte wohl auch vermieden werden? Der Spannungsteiler zieht etwas Strom und könnte auch noch etwas hochohmiger gemacht werden. Bei mir hat der 510 Ohm Widerstand meinen Parallelport-Selbstbau-ISP-Programmer nicht gestört (Es fließen dann während des Programmierens, wenn Reset auf GND gezogen wird, etwa 10mA über den 510 Ohm Widerstand -man beachte auch den internen Pullup von 30k bis 60k, der parallel zu dem R1 liegt. Drücken des Tasters muß dann vermieden werden um keinen Kurzschluß zu verursachen!!!). Andere Programmer könnten empfindlicher auf den niedrigen Pullup reagieren?
$regfile = "attiny45.dat"
$crystal = 8000000
$hwstack = 32
$swstack = 32
$framesize = 32
Dim I As Byte
Dim K As Word
Dim Show As Word 'value from 0 to 9999 to be displayed
Dim Show_old As Word
Dim Digit As Byte 'currently selected digit for output to display
Dim Digit_pattern As Byte 'Segment Select Pattern for 7 Seg.
Dim Digit_sel As Byte 'Digit Select Pattern for 7 Seg
Dim Number_ar(4) As Byte 'contains four digits to be multiplexed
Dim Index As Byte 'Index for Lookup table
Dim Adc_key As Word 'Gets ADC value measured on PB5
Dim Key_pressed As Byte 'Toggles when key is actuated
Dim Poti_adc_new As Word 'variables for Poti measurement
Dim Poti_adc_old As Word 'variables for Poti measurement
Dim Poti_value As Word 'variables for Poti measurement
Dim Diff_new_old As Integer 'variables for Poti measurement
Dim Cmp0a_counter As Byte 'measure security time for key pressing
Serial_clock_pin Alias Portb.0
Config Serial_clock_pin = Output 'SHCP at 74HC595
Serial_data_pin Alias Portb.2
Config Serial_data_pin = Output 'DS at 74HC595
Config Portb.1 = Output 'STCP at 74HC595
Config Adc = Single , Prescaler = Auto , Reference = Avcc
Tccr0a = Bits(wgm01) 'CTC (OCR0A as top)
Ocr0a = 124 'for 250Hz compare interrupt
Tccr0b = Bits(cs02) 'prescale = 256 (start timer)
On Compare0a Multiplex
Enable Compare0a
Enable Interrupts
Do 'Hauptschleife
If Cmp0a_counter = 0 Then
Adc_key = Getadc(0) 'measure PB5(ADC0)
If Adc_key > 1000 Then 'If key is pressed then
Toggle Key_pressed
Cmp0a_counter = 1 'start secure timing
End If
End If
Poti_adc_new = Getadc(3) 'measure Poti setting at ADC3
Diff_new_old = Poti_adc_new - Poti_adc_old
If Abs(diff_new_old) > 3 Then 'SW-Hysterese
Poti_adc_old = Poti_adc_new
Shift Poti_adc_new , Right , 2 'remove unsave bits
Poti_value = Poti_adc_new 'result between 0 and 255
End If
'Toggle output to display between Adc value at PB5 and Poti_value by each key push
If Key_pressed > 0 Then Show = Adc_key Else Show = Poti_value
Gosub Prepare_number_for_output
Loop
End
Multiplex: 'ISR called every 4ms
If Cmp0a_counter > 0 Then Incr Cmp0a_counter 'overflow counter for security time
Incr Digit
Digit_pattern = Lookup(number_ar(digit) , Bitpattern)
Select Case Digit
Case 1 : Digit_sel = &B1000_0000
Case 2 : Digit_sel = &B0100_0000
Case 3 : Digit_sel = &B0010_0000
Case 4 : Digit_sel = &B0001_0000
Digit = 0
End Select
Shiftout Serial_data_pin , Serial_clock_pin , Digit_sel , 1 'serial out to 74HC595
Shiftout Serial_data_pin , Serial_clock_pin , Digit_pattern , 1 'serial out to 74HC595
!sbi pinb,1 'toggle PB1 / STCP at 74hc595
!sbi pinb,1 'toggle PB1 / STCP at 74hc595
Return
Prepare_number_for_output:
If Show <> Show_old Then
K = Show / 1000 'separate decimal digits from word variable into byte array
Disable Compare0a 'no output to display while modifying Number_ar()
Number_ar(1) = K 'first/leftmost digit on 4*7 Seg. Display
K = Show Mod 1000 'separate decimal digits from word variable into byte array
K = K / 100
Number_ar(2) = K
K = Show Mod 100 'separate decimal digits from word variable into byte array
K = K / 10
Number_ar(3) = K
K = Show Mod 10 'separate decimal digits from word variable into byte array
Number_ar(4) = K 'forth/rightmost digit on 4*7 Seg. Display
For I = 1 To 3
If Number_ar(i) = 0 Then Number_ar(i) = 10 Else Exit For 'replace leading zeros with indexes of blank
Next I
Enable Compare0a
Show_old = Show
End If
Return
Bitpattern:
Data &B00000011 '0
Data &B10011111 '1
Data &B00100101 '2
Data &B00001101 '3
Data &B10011001 '4
Data &B01001001 '5
Data &B01000001 '6
Data &B00011111 '7
Data &B00000001 '8
Data &B00001001 '9
Data &B11111111 'blank
Gruß
Searcher