Electronics > Beginners

Need help with my first µC project

(1/5) > >>

david77:
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:


--- Code: ---$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
--- End code ---

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

djsb:
Can you set breakpoints and put watches on the variables that you use to check that they are behaving as you expect?
Have you tried simplifying your program and checking each subroutine one at a time. You could build in some kind of test into the program that uses the LED's as an output (in place of print/printf statements and a serial terminal).

David.

david77:
 :-X
Uh, well, the most obvious I didn't see. Ok, thanks David.
I let the display show my Seccount variable and it turned out I didn't put that back to zero when
pressing stop... So the µC never got to the line decreasing my Mincounter.

Now I can ask you guys about another thing that puzzles me. How the hell do I debounce the
switches properly? I want the +1 key to add 1 to the counter each time I press it.
At the moment it's got a mind of it's own...

Do I poll it in the main loop or do I poll it using a Timer0 interrupt every few ms? And if so, how many ms
apart? Or should I use the DEBOUNCE command?
Or should I just whack in some old fashioned hardware debouncing (couple of R's, a C and a 7414)?

So many questions... But I already start to like the µC :).
Some years ago I did a kitchen timer in "discrete" TTL logic...what a pain!

PeterG:
David,
    i normally de-bounce with a "Delayms 2" or similar command to handle the button bounce. A small cap across the button also helps.

Regards

Peter

ThoWaBu:

I think Delay isn´t really a debouncing...

I very short :

In fact of switch prellen there are short "spikes", but you want only count on a minimum KeyPressing Time.

This could be 50ms or something -- it depends on the User interface and how bad the switch is.

So I do the Follow and it works _very_ well :

On switch state Released set your TimeCounter to 0.
On switch state Pressed increase your Counter ervery Timebase.
(Timer interrupt)

If the Counter overruns your Time-Limit (i.e. 50ms) your Key is Pressed.
Don´t let your counter overrun.

You can switch between several Time-Limits to detect long and short pressed Buttons.
(Maybe some overkill)

Navigation

[0] Message Index

[#] Next page

There was an error while thanking
Thanking...
Go to full version