Ok, yesterday I was bored and got the idea to try and get into micorcontrollers again.
I decided on a small project that I've had in mind quite some time now:
A electronic kitchentimer. That shouldn't be too hard to realise.
What I want:
- max. count time: 99 min.
- operation with three buttons: Start/Stop, +1 min., +10 min.
The timer should be able to count from 99 minutes to zero. As display I want to use two 7-segment
diplays. I want to drive them using two BCD-to-7-segment drivers (74LS249) , so I only need 8
I/O ports.
Further I need three I/O's for my buttons, one I/O for a blinking LED to signal the timer is running and
one I/O to activate some sort of buzzer thingy. So 13 I/O lines are enough.
I decided to use an AtMega8L, simply because I had some around and I have a small breadboard for
ATMegas.
I elected BASCOM-AVR to be my language of choice, the reason being: I know BASIC and not much else.
I haven't got a circuit diagram to show you, but it is all rather simple: ATMega8, 2x74LS49, displays and
some buttons and LED's.
And here's my code so far:
$regfile = "m8def.dat" ' specify the used micro
$crystal = 4000000 ' used crystal frequency
$hwstack = 100 ' default use 32 for the hardware stack
$swstack = 100 ' default use 10 for the SW stack
$framesize = 100 ' default use 40 for the frame space
Config Portd = Output
Config Portc = Output
Config Portd.2 = Input 'definiert Portd als Output
Config Portb = Input
Declare Sub Bcdout(byval Mincount As Integer )
Dim Digit1 As Integer , Digit2 As Integer
Dim Mincount As Integer , Seccount As Integer
Dim Sdisplay As String * 2 , Sdigit1 As String * 1 , Sdigit2 As String * 2
Dim Stopped As Integer , Preset As Integer
Let Mincount = 0 'Anzeige auf "00" setzen beim einschalte
Let Seccount = 0 'Sekundenzähler auf 0 setzen
Let Stopped = 1 ' Stopped: 0 = Run / 1 = Stop
'bei PowerUp soll Zähler stehen
'Config Timer0 = Timer , Prescale = 64
'Enable Timer0
'On Timer0 Isr_pollkeys
Config Timer1 = Timer , Prescale = 256 'Konfiguriere Timer1
Enable Timer1
On Timer1 Isr_von_timer1 'verzweige bei Timer1 ueberlauf zu Isr_von_Timer1
Timer1 = 49910 'Timer auf 49910 setzen (15625 counts = 1sec.)
'4000000/256=15625 == 1 sec.
Config Int0 = Falling 'Konfiguriere INT0 für Start/Stop Taste
Enable Int0
On Int0 Isr_resettaste 'Sprung bei INT0 Start/Stop Taste
Enable Interrupts 'Interrupts aktivieren
Do 'Hauptprogramm
If Stopped = 1 Then
Portc.4 = 1
Bcdout Mincount
If Pinb.0 = 0 Then Gosub Inkrement1
Elseif Stopped = 0 Then
Portc.4 = 0
If Seccount = 60 Then
Let Seccount = 0
Bcdout Mincount
If Mincount <> 0 Then
Let Mincount = Mincount - 1
Elseif Mincount = 0 Then
Let Stopped = 1
Let Mincount = 0
Let Portc.1 = 1
Waitms 500
Let Portc.1 = 0
End If
End If
End If
Loop
End
Inkrement1:
If Stopped = 1 Then Let Mincount = Mincount + 1
If Mincount >= 99 Then Let Mincount = 0
Return
Isr_von_timer1: 'ISR von Timer1
Timer1 = 49910 'Timer1 soll wieder von 49910 wegzõhlen
Let Seccount = Seccount + 1
Toggle Portc.0
Return
Isr_resettaste: 'Reagiert auf Start/Stop Taste
If Stopped = 1 And Mincount > 0 Then 'Wenn Stopped=1 und Min-counter > 0 ==STARTTASTE
Let Stopped = 0 'setze Stopped = 0, so dass Zähler laufen kann
Elseif Stopped = 0 Then 'Wenn Stopped = 0 (Zähler läuft) ==STOP/RESET TASTE
Let Stopped = 1
Let Mincount = 0 'Minutenzähler zurücksetzen
End If
Return
Isr_pollkeys:
'If Pinb.0 = 0 Then Gosub Inkrement1
'Debounce Pinb.0 , 0 , Inkrement1 , Sub
Return
Sub Bcdout(byval Mincount) 'SUB gibt BCD Kodiert die Anzeige aus
Sdisplay = Str(mincount) 'Hier wird Minutenzähler (Integer) in String
If Len(sdisplay) = 1 Then Let Sdisplay = "0" + Sdisplay 'gewandelt, zerlegt, wieder in INT gewandelt
Sdigit1 = Left(sdisplay , 1) ' und einzeln an die CASE Anweisungen gegeben.
Sdigit2 = Right(sdisplay , 1) 'wenn nötig wird eine fuehrende Null angefuegt
Digit1 = Val(sdigit1)
Digit2 = Val(sdigit2)
Select Case Digit1
Case 1
Portd.0 = 0
Portc.3 = 0
Portc.2 = 0
Portd.3 = 1
Case 2
Portd.0 = 0
Portc.3 = 0
Portc.2 = 1
Portd.3 = 0
Case 3
Portd.0 = 0
Portc.3 = 0
Portc.2 = 1
Portd.3 = 1
Case 4
Portd.0 = 0
Portc.3 = 1
Portc.2 = 0
Portd.3 = 0
Case 5
Portd.0 = 0
Portc.3 = 1
Portc.2 = 0
Portd.3 = 1
Case 6
Portd.0 = 0
Portc.3 = 1
Portc.2 = 1
Portd.3 = 0
Case 7
Portd.0 = 0
Portc.3 = 1
Portc.2 = 1
Portd.3 = 1
Case 8
Portd.0 = 1
Portc.3 = 0
Portc.2 = 0
Portd.3 = 0
Case 9
Portd.0 = 1
Portc.3 = 0
Portc.2 = 0
Portd.3 = 1
Case 0
Portd.0 = 0
Portc.3 = 0
Portc.2 = 0
Portd.3 = 0
End Select
Select Case Digit2
Case 1
Portd.4 = 0
Portd.5 = 0
Portd.6 = 0
Portd.7 = 1
Case 2
Portd.4 = 0
Portd.5 = 0
Portd.6 = 1
Portd.7 = 0
Case 3
Portd.4 = 0
Portd.5 = 0
Portd.6 = 1
Portd.7 = 1
Case 4
Portd.4 = 0
Portd.5 = 1
Portd.6 = 0
Portd.7 = 0
Case 5
Portd.4 = 0
Portd.5 = 1
Portd.6 = 0
Portd.7 = 1
Case 6
Portd.4 = 0
Portd.5 = 1
Portd.6 = 1
Portd.7 = 0
Case 7
Portd.4 = 0
Portd.5 = 1
Portd.6 = 1
Portd.7 = 1
Case 8
Portd.4 = 1
Portd.5 = 0
Portd.6 = 0
Portd.7 = 0
Case 9
Portd.4 = 1
Portd.5 = 0
Portd.6 = 0
Portd.7 = 1
Case 0
Portd.4 = 0
Portd.5 = 0
Portd.6 = 0
Portd.7 = 0
End Select
End Sub
Sorry, the commentary is in German but I reckon it's quite self explaining
PORTC.0: Blinking light, toggles every second
PORTC.4: Is high when counter stopped / low when running. Just for testing
PORTD.0/2 PORTC.1/2 & PORTD.4...7: Output for 2 digits BCD code to 74LS249's
PORTC.1: The output for the buzzy thing.
PIND2/INT0: Start/stop key
PINB.0: Increase 1 min. key
Variables:
Mincount: counter get increased by pressing +1, decreases when timer runs
Seccount: counts the seconds. Gets increased by Timer1 interrupt
Stopped: flag, indicates if counter is running (=0) or stopped (=1)
My problem so far is as follows:
When I compile the program with a pre-set Mincount (maybe 10) then everything works fine.
At this stage I do not read PINB.0.
The counter powers up with "10" on the display. I press "Start" and it counts down to "00", PORTC.1
gets high for a bit and then the thing stops, sets the Stopped flag to 1, the display back to "00".
If, however I add code to read PINB.0 it all goes wrong. The counter increases when the key is pressed
as it should, when I press "Start" the Stopped flag changes, but the counter doesn't count!
It just sits at whatever value I keyed into Mincount.
I tried just polling the key in the main loop (also using DEBOUNCE) and I tried using Timer0 interrupt
to poll the key outside the main loop (the code is there -> Isr_pollkeys:).
The blinking LED on PORTC.0 keeps on blinking, so the Timer1 interrupt seems to work, I guess.
I realise this should be a very simple project, thus I thought I might be able to do it. It is however
my first "real" own µC project, I'm quite a noob here.
Maybe the pro's would choose other hardware or another way to realise it, or choose ASM or C as
language but this is the way I chose to tackle it and I think I can't be that far off. There is probably
something quite obvious I overlook or am not aware of.
Oh, and guys: No BASIC bashing please! I really like that language and I know what the "real" programmers
think of it
.
So a little nudge in the right direction would be appreciated!
David