NerdKits - electronics education for a digital generation

You are not logged in. [log in]

NEW: Learning electronics? Ask your questions on the new Electronics Questions & Answers site hosted by CircuitLab.

Project Help and Ideas » Nerdy Stopwatch / Kitchen Timer

May 08, 2011
by SpaceGhost
SpaceGhost's Avatar

I've done some modifications to the realtimeclock1 project with some stuff found on the web and some other stuff that I added, that I would like to share.

With this realtimeclock project accumulated time in seconds & 1/100 seconds is still displayed on line one of the LCD, as in the original program. On line two the accumulated time is also shown, in H:M:S format. Line three shows a user settable timer value, also in H:M:S format. Line four displays information pertaining to the presets. The program I have put together has a six button interface.

Pushbutton PC5 has three functions - pushing the PC5 button once after the device's initial powerup starts the timer. Pressing Pushbutton PC5 again (2nd press) stops timer and holds the acummulated time on the LCD (hrs:min:sec). Pressing Pushbutton PC5 again (3rd press) resets the accumulated time to 0:0:0. Pushing Pushbutton PC5 again then restarts the timer.

Timer's user settable "alarm" functions: Pressing Pushbutton PC4 once causes the LCD to display "0 H", twice displays "0 M", and third time displays "0 S". While in either the Hour, Minute or Seconds modes, pressing Pushbutton PC3 will increment the timer value. Pressing Pushbutton PC2 decreases the timer value. Note: Hour value will not count below 0. Minute and seconds values will not count below 0 or above 59 (>59 loops back to 0, <0 loops to 59).

Then, by pressing Pushbutton PC4 a fourth time (or, by just pressing Pushbutton PC5) the set alarm time will be displayed. Pressing Pushbutton PC5 will start the timer. When timer reaches the user set time, the "alarm" LED (PC0) will light.

The timer keeps timing until Pushbutton PC5 is pressed again (holding the accumulated time), and the alarm LED stays lit until Pushbutton PC5 is pressed again, thus resetting the accumulated time to 0:0:0. The timer may be restarted with the same alarm time entered. Pressing Pushbutton PB1 resets the alarm time to 0:0:0, except when using a preset.

Pushbutton PB2 selects the presets. My program has two - "Preset 1" (10 min.) and "Preset 2" (30 min.). But a person could of course alter the code to whatever they want the presets to be, and I believe some extra presets could be even be added to the program if desired (memory space allowing).

Default setting on power up is "Presets off". Preset status is displayed on LCD line four. When using either preset you get a "30 second warning" (PB5 LED lights), before the "alarm" (PC0) LED is triggered. "WARNING" is also displayed on LCD line four during the 30 second "warning" time period. As you will notice in the code, line four also displays other stuff when using presets.

An alarm time does not have to be set to just run the timer - without an alarm time entered, the project will operate like a stop watch. Pressing PC5 Pushbutton starts the clock; pressing PC5 pushbutton again stops the clock at the elaspsed time; pressing PC5 pushbutton again resets the elapsed time to 0:0:0 and ready to begin timing again.

So here we have it - a nerdy stopwatch/kitchen timer! This project was a lot of fun to work on - it's really great to finally have a little free time to play with my toys. :-)

/////////////
//             A Nerdy Stopwatch/Kitchen Timer
// clock01
//            (settable alarm/timer w/ presets)
////////////

// modification of
//
// realtimeclock1.c
// for NerdKits with ATmega168
// mrobbins@mit.edu

#define F_CPU 14745600

#include <stdio.h>
#include <stdlib.h>

#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/pgmspace.h>
#include <inttypes.h>

#include "../libnerdkits/delay.h"
#include "../libnerdkits/lcd.h"
#include "../libnerdkits/uart.h"

// PIN DEFINITIONS:

void realtimeclock_setup() {
  // setup Timer0:
  // CTC (Clear Timer on Compare Match mode)
  // TOP set by OCR0A register
  TCCR0A |= (1<<WGM01);
  // clocked from CLK/1024
  // which is 14745600/1024, or 14400 increments per second
  TCCR0B |= (1<<CS02) | (1<<CS00);
  // set TOP to 143
  // because it counts 0, 1, 2, ... 142, 143, 0, 1, 2 ...
  // so 0 through 143 equals 144 events
  OCR0A = 143;
  // enable interrupt on compare event
  // (14400 / 144 = 100 per second)
  TIMSK0 |= (1<<OCIE0A);
}

// the_time will store the elapsed time
// in hundredths of a second.
// (100 = 1 second)
// 
// note that this will overflow in approximately 248 days!
//
// This variable is marked "volatile" because it is modified
// by an interrupt handler.  Without the "volatile" marking,
// the compiler might just assume that it doesn't change in 
// the flow of any given function (if the compiler doesn't
// see any code in that function modifying it -- sounds 
// reasonable, normally!).
//
// But with "volatile", it will always read it from memory 
// instead of making that assumption.
volatile int32_t the_time;

SIGNAL(SIG_OUTPUT_COMPARE0A) {
  // when Timer0 gets to its Output Compare value,
  // one one-hundredth of a second has elapsed (0.01 seconds).
  the_time++;
}

int main() {
  realtimeclock_setup();

  // init lcd
  lcd_init();
  FILE lcd_stream = FDEV_SETUP_STREAM(lcd_putchar, 0, _FDEV_SETUP_WRITE);
  lcd_home();

// outputs -

  DDRC |= (1<<PC0);   // pin 23 sourcing output for ALARM LED

  DDRB |= (1<<PB5);   // pin 19 sourcing output for WARNING LED

// inputs -

  DDRC &= ~(1<<PC5); // pin 28 pushbutton (sink input) START/STOP/RESET (on_off)

  DDRC &= ~(1<<PC4); // pin 27 pushbutton (sink input) SET

  DDRC &= ~(1<<PC3); // pin 26 pushbutton (sink input) UP

  DDRC &= ~(1<<PC2); // pin 25 pushbutton (sink input) DOWN

  DDRB &= ~(1<<PB2); // pin 16 - switch for presets

  DDRB &= ~(1<<PB1); // pin 15 - reset alarm time

  PORTC |= (1<<PC5); // internal pull up resistors pin 28 - 25
  PORTC |= (1<<PC4);
  PORTC |= (1<<PC3);
  PORTC |= (1<<PC2);
  PORTB |= (1<<PB2);
  PORTB |= (1<<PB1);

// declare variables to represent pushbutton inputs

uint8_t on_off;
uint8_t j;

uint8_t set;
uint8_t up;
uint8_t dn;

int8_t a;
int8_t b;
int8_t c;
int8_t e;

uint8_t pre;
int8_t g;

uint16_t hr, mmmin, sec, h, m, s;
uint32_t val, sm;

uint8_t reset;

a = 0;
b = 0;
c = 0;
e = 0;

g = 0;

val = 0;
hr = 0;
sm = 0;
mmmin = 0;
sec = 0;
h = 0;
m = 0;
s = 0;
the_time = 0;

j=0; // start with timer OFF

while(1) {

   if (j == 0) {

   PORTC &= ~(1<<PC0);  // output OFF

   sm = 0;
   the_time = 0;

   lcd_line_one();
   fprintf_P(&lcd_stream, PSTR("            0.00 sec"));

   lcd_line_two();
   fprintf_P(&lcd_stream, PSTR("0:0:0 H:M:S   "));
}

//////////////////////////////////////////////// timing function

   on_off = (PINC & (1<<PC5)) >> PC5;

   if (on_off == 0) {

        j = j + 1;      //if button pressed, increase count by one
        if (j >= 3 )    //three button states - 0, 1 & 2
        j = 0;           //count loops back to j = 0 after j = 2
        delay_ms(500);   // switch delay
    }

   if (j == 1) { //// begin timing operation

   a = 0;

   sei();

   val = sec + (60 * mmmin) + (3600 * hr);

   sm = val + (int32_t) the_time/100;

   lcd_line_one();

   fprintf_P(&lcd_stream, PSTR("%16.2f sec"), (double) the_time / 100.0);

   lcd_line_two();

   h = (uint16_t) sm/3600;
   m = (uint16_t) ((sm % 3600)/60);
   s = sm % 60;

   fprintf_P(&lcd_stream, PSTR("%d:%d:%d H:M:S "), h, m, s);
}

    if ((j == 0) && (g > 0)) {

    lcd_line_four();
    fprintf_P(&lcd_stream, PSTR("   Preset %d        "), g);
}

    else if (g == 0) {

    lcd_line_four();
    fprintf_P(&lcd_stream, PSTR("   Presets off      "), g);
}

///////////////////////////////////////////////////////////

///////////////////////////////////////////////preset functions

  pre = (PINB & (1<<PB2)) >> PB2;

   if (pre == 0) {

        g = g + 1;      //if button pressed, increment switch
        if (g >= 3 )    //set 2 as highest allowed count, and if f is greater than 2,
        g = 0;           //count loops back to zero
        delay_ms(500);   // switch delay

        lcd_line_four();
        fprintf_P(&lcd_stream, PSTR("   Preset %d        "), g);
    }

   if ((g == 0) && (!a == 2)) {

        c = 0;

        lcd_line_four();
        fprintf_P(&lcd_stream, PSTR("   Presets off      "), g);
    }

   if (g == 1) {

        c = 10;
    }

   if (g == 2) {

        c = 30;
    }

////// preset 1 (10 min)

 if ((m == 9) && (s >= 30) && (g == 1)) { // 30 second WARNING

  PORTB |= (1<<PB5); // WARNING output ON

        lcd_line_four();
        fprintf_P(&lcd_stream, PSTR("     WARNING        "));
}

 if ((m >= 10) && (g == 1) && (j == 1)) { // ALARM set for 10 minutes (preset 1)

  PORTC |= (1<<PC0); // ALARM output ON

        lcd_line_four();
        fprintf_P(&lcd_stream, PSTR(" Preset %d TIMED OUT"), g);
}

 else {

  PORTB &= ~(1<<PB5);  // output OFF
}

//////////////////////////////////////////////////

////// preset 2 (30 min)

if ((m == 29) && (s >= 30) && (g == 2)) { // 30 second WARNING

  PORTB |= (1<<PB5); // WARNING output ON

        lcd_line_four();
        fprintf_P(&lcd_stream, PSTR("     WARNING        "));
}

if ((m >= 30) && (g == 2) && (j == 1)) { // ALARM set for 30 minutes (preset 2)

  PORTC |= (1<<PC0); // ALARM output ON

        lcd_line_four();
        fprintf_P(&lcd_stream, PSTR(" Preset %d TIMED OUT"), g);
}

 else {

  PORTB &= ~(1<<PB5);  // output OFF
}

///////////////////////////////////end preset functions

///////////////////////////////////////////// set hours or minutes or seconds

       set = (PINC & (1<<PC4)) >> PC4;
        up = (PINC & (1<<PC3)) >> PC3;  
        dn = (PINC & (1<<PC2)) >> PC2;

   if (set == 0) {

        a = a + 1;      //if button pressed, increase count by one
        if (a >= 4)    //set 3 as highest allowed count, and if a is greater than 3,
        a = 0;           //count loops back to zero
        delay_ms(500);   // switch delay
    }

///////////////////////////// set hours

        if (a == 1) {
        lcd_line_three(); //  or, use lcd_goto_position(2, 0);
        fprintf_P(&lcd_stream, PSTR("%d H         "), b);       
    }

        if ((a == 1) && (up == 0)) {  // set HOUR

        b = b + 1;      //if button pressed, increase count by one
        delay_ms(300);   // switch delay

        lcd_line_three();

        fprintf_P(&lcd_stream, PSTR("%d H          "), b);

    }

        if ((a == 1) && (dn == 0)) {  // set HOUR

        b = b - 1;      //if button pressed, decrease count by one
        if (b < 0)
        b = 0;
        delay_ms(300);   // switch delay

        lcd_line_three();

        fprintf_P(&lcd_stream, PSTR("%d H          "), b);      
    }

///////////////////////////// set minutes

        if (a == 2) {

        lcd_line_three();
        fprintf_P(&lcd_stream, PSTR("%d M          "), c);      
    }

        if ((a == 2) && (up == 0)) {  // set MINUTES

        c = c + 1;      //if button pressed, increase count by one
        if (c > 59)  //set 59 as highest allowed count and, if c is > than 59,
        c = 0;       //count loops back to zero         
        delay_ms(300);   // switch delay

        lcd_line_three();
        fprintf_P(&lcd_stream, PSTR("%d M          "), c);      
    }

        if ((a == 2) && (dn == 0)) {  // set MINUTES

        c = c - 1;      //if button pressed, decrease count by one
        if (c < 0)
        c = 59;
        delay_ms(300);   // switch delay

        lcd_line_three();
        fprintf_P(&lcd_stream, PSTR("%d M          "), c);
    }

///////////////////////////// set seconds

        if (a == 3) {

        lcd_line_three();
        fprintf_P(&lcd_stream, PSTR("%d S          "), e);      
    }

        if ((a == 3) && (up == 0)) {  // set SECONDS

        e = e + 1;      //if button pressed, increase count by one
        if (e > 59)  //set 59 as highest allowed count and, if e is > than 59,
        e = 0;       //count loops back to zero         
        delay_ms(300);   // switch delay

        lcd_line_three();
        fprintf_P(&lcd_stream, PSTR("%d S          "), e);
    }

        if ((a == 3) && (dn == 0)) {  // set SECONDS

        e = e - 1;      //if button pressed, decrease count by one
        if (e < 0)
        e = 59;
        delay_ms(300);   // switch delay

        lcd_line_three();
        fprintf_P(&lcd_stream, PSTR("%d S          "), e);
    }

        if (a == 0) {

        lcd_line_three();
        fprintf_P(&lcd_stream, PSTR("%d:%d:%d alarm    "), b, c, e);
    }

////////////////////////////////////////////////

//////////////////////////////////////// alarm function v

if ((h >= b) && (m >= c) && (s >= e)) {

  PORTC |= (1<<PC0); /// ALARM output ON

  if (j == 0)

  PORTC &= ~(1<<PC0); // output OFF  
}

if ((a == 0) && (b == 0) && (c == 0) && (e == 0) && (h >= b) && (m >= c) && (s >= e)){

/// ^ above line keeps ALARM output off if H:M:S = 0:0:0 & alarm = 0:0:0

  PORTC &= ~(1<<PC0);  // output OFF 
}

////////////////////////////////////////

/////////////////////////////////// reset alarm time to 0

reset = (PINB & (1<<PB1)) >> PB1;

   if (reset == 0) {

   b = 0;
   c = 0;
   e = 0;
}

}

  return 0;
}

As always, I welcome any criticism of the code I've posted. I believe there are probably simpler/more efficient ways to do some of the things that I've done. That where I really appreciate suggestions and comments (I feel that I might have a "Rube Goldberg" way of doing things sometimes). And I still consider the code a work in progress. There are a few things I am thinking about adding, or modifying...

Perhaps with a little more work on it this project could be worthy of posting on the new Library's Projects page. (Awsome job btw, to all of you guys that made the Library happen - loving it!!)

Dave

May 08, 2011
by Ralphxyz
Ralphxyz's Avatar

Thanks SpaceGhost, I would definitely post this as a Project in the Library.

I will definitely use a modified version on the I2C Real Time Clock Alarm setup.

I should be able to use your logic for the button press operations.

Thanks again for sharing.

Ralph

June 23, 2011
by Ralphxyz
Ralphxyz's Avatar

Hey Spaceghost you still around?

I am having some problems running your stopwatch.

First thing line one on LCD is always 0.00 sec it never increments.

Hope to hear from you.

Ralph

June 23, 2011
by SpaceGhost
SpaceGhost's Avatar

Hello Ralph, I just seen your post while browsing around before bedtime.

I haven't worked on that project in a while, and I do recall that I had some minor improvements in mind for the preset functions. But I'm pretty sure that the seconds/100th seconds incremented on line one for me, at least when I last ran the code.

This is a project that I had planned to revisit and build into something more permanent even, someday...

It kind of fell by the wayside when I started working on some other things - mainly just some fancy switching programs and such... Just stuff I wanted to file away for later use.

Now that I've kind of ran out of other ideas to work on at the moment, I think it would be fun to jump back into this project again for a while.

Yeah, I'd like to work on this with you Ralph. I'm still on here a lot, I just haven't posted anything in a while.

Lines 173 - 206 might be where your problem could be...

Does the rest of the code pretty much work as I had described?

I will load my program as soon as I get home from work tomorrow afternoon. Post your code, and we can compare. Reloading the program for myself will also refresh in my mind the things that I still want to work on for that project. If we are really lucky, maybe some of the other guys might offer us some input. Could be a lot of fun, definitely a cool way to start the weekend!

Dave

June 24, 2011
by Ralphxyz
Ralphxyz's Avatar

Hi SpaceGhost glad to see you still around.

I have not modified your code from above.

The PC5 button does not appear to work correctly. I tried the other buttons some work as expected others I am not sure.

I was putting together a BUTTONS library and wanted to incorporate your routine for value input.

I also want to compare how you did value input with how Rick did it in his DS3232 I2C Real Time clock project.

I remember I was really impressed with Rick's implementation functionally.

Plus I could use a stopwatch and an alarm clock.

So to start I do not seem to have any clock running. No seconds on line one or H:M:S on line two.

I have tried running the Nerdkit's RTC project but I 'am not getting any LCD output from that either.

That has worked in the past so I am also looking into that.

I'll test each button and put together a work sheet to work off.

Ralph

June 24, 2011
by Ralphxyz
Ralphxyz's Avatar

Here is my Button test:

Presets OFF

PC5 
no changes when pressed nothing
if held down line three and line four disappear and display flashes
PB1 not tested nothing to do

PC4 
first press  line three changes to 0 H                              check
second press line three changes to 0 M                              check
third press  line three changes to 0 S                              check
forth press  line three changes to 0:0:0 alarm                      check

PC3 PC4 has made selection
first press increments 1 if held down continues to increment        check
holding the button down increments to 127 then LCD switches         Not As Noted
to -128 and decrements down to 0 then 
starts back up at 1. When in negative numbes if PC2 is hit 
returns to 0

PC2 
first press decrements H:M:S by one continues to decrement to 0

PC4
forth press (after setting time) 0:0:10 alarm                       check

PC5 
Start timer press                                                   fails

Presets

PB2
first press   line four turns to Preset 1 line three turns to 0:10:0 alarm      check
second press  line four turns to Preset 2 line three turns to 0:30:0 alarm      check
third press   line four turns to Presets off line three remains as last set     check

Everything beside PC5 and having a clock appears to be working.

Ralph

June 24, 2011
by SpaceGhost
SpaceGhost's Avatar

I just loaded the code above to my MCU.

I copied and pasted the above code as a whole new program, to be sure that I hadn't accidentally posted another version of that program that was incomplete or otherwise wasn't ready to be posted.

On power up, I have "0.00 sec" displayed on the right hand side of line one.

On line two, "0:0:0 H:M:S" is displayed.

On line three, "0:0:0 alarm" is displayed.

"Presets off" is displayed on line four.

Pushing and releasing, once, a small tactile normally-open push button switch momentarily tying PC5 (pin 28) to the negative supply rail of my breadboard starts the timer timing on my circuit...

Line one is counting off accumulative seconds and one/one-hundreds of seconds.

Line two is displaying seconds and minutes also. I have not ran the timer long enough to accumulate hours yet, of course.

Hmm, it's odd that it's working for me, but not for you...

Have you tried a different push button on PC5? Maybe your's isn't making contact?

Or maybe it's making contact but not opening the circuit upon release (contacts stuck closed)? I tried holding the push button down on my circuit and not releasing it - my 0.00 display on line one blinks "0.55" and "0.00" alternately with a closed circuit, and did not increment. I held the switch closed while I powered up the circuit too, and had the same result.

That's all that I can think of right now, besides the ol' standard advice of "check your wiring." One side of the switch should be to ground, the other to pin 28 of course. Maybe try another couple pieces of wire for your switch connections - I've actually had that work when I've tried troubleshooting a circuit that didn't want to behave right.

I'd sure like to see you get this to work. Has anyone else tried the code, or have any suggestions?

June 24, 2011
by SpaceGhost
SpaceGhost's Avatar

Very strange.. It seems that your push button is having an effect, at least when it's held closed. But, when I hold down my PB5 push button the line one display "flashes" too, but I believe that it may be flashing differently than yours'. Line three and four does not disappear on my display though.

When I press the button on PB4 after a normal power up, line three cycles through "0 H", then "0 M", then "0 S", and then back to "0:0:0 alarm" if I do not use PB3 to increment a time variable of PB2 to de-increment it.

I am able to increment or de-increment H, M, or S when in the program mode with PB3 and PB4 respectively. And if I set a variable (or variables), it appears in its intended place or places after the fourth button push. Pushing PB1 "resets" the "alarm" display to "0:0:0" for me.

I hadn't checked to see what the upper limit would be for hours... I did try to make the code so hours don't go negative (I think). I did set the minute and second upper limits to 59 and then return to 0, I believe... None of the presets should go to negative numbers, they don't for me.

Sounds like most of what you got is working but PC5 is causing a problem?

Hmmm...

June 24, 2011
by SpaceGhost
SpaceGhost's Avatar

OOPS!! I made some errors in what I was trying to say in my previous post --

I meant to say PC5 in the first paragraph.

I meant to say PC4 in the second paragraph.

I meant to say PC3 and PC2 respectively in the third paragraph!!!

Sorry about that!

June 24, 2011
by Ralphxyz
Ralphxyz's Avatar

Darn, I figured you had published good code. I tested the PC5 switch and it is good.

I also tested my wiring with my continuity tester and it is good.

I am still not getting any seconds. That is my first goal, to figure why I can not get the seconds to show.

You say [quote] "On power up, I have "0.00 sec" displayed on the right hand side of line one." [/quote].

Does the seconds increment or do they stay 0.00"

Ralph

June 24, 2011
by SpaceGhost
SpaceGhost's Avatar

The seconds stay at 0.00 upon power up, until I push PC5 once.. Then the timer begins timing (incrementing).

June 24, 2011
by SpaceGhost
SpaceGhost's Avatar

I looked at your Button Test again -

Presets OFF

PC5
no changes when pressed nothing
if held down line three and line four disappear and display flashes

All you (should) need to do to start the timer is press the PC5 button once. It should not be held down.

Maybe your switch has a lot of bounce? If the MCU is seeing a push of the button as two quick pushes it would be like immediately halting the count. If the MCU is seeing the push of the button as three pulses, it would reset the count.

You might try a lighter push on the button, or a couple pushes on the button... Or you may need to modify the delay on line #170 to work with your particular button...

June 24, 2011
by SpaceGhost
SpaceGhost's Avatar

Has anyone else tried this code? Surely I could not be the only person that this code will work for...

June 25, 2011
by Ralphxyz
Ralphxyz's Avatar

This is so irritating, but as might be noted typical for me, I often can not run other people's code.

I switched buttons with the one from PC4, which works for PC4 but there is no difference.

Now if I press PC4 and make a entry say 2 hours and then press PC5 I am returned to the opening screen.

0: 0: 0 alarm

The hour setting is not saved but obviously PC5 is making contact and effecting the program.

Pressing PC5 is the same as hitting a reset button.


I tried adding a debug message to line 186:

fprintf_P(&lcd_stream, PSTR("j is %d %16.2f sec"),j, (double) the_time / 100.0);

j is never printed on the LCD.

I just have to learn how to use a AVR-gcc debugger.

Ralph

June 25, 2011
by SpaceGhost
SpaceGhost's Avatar

Quote:

"Now if I press PC4 and make a entry say 2 hours and then press PC5 I am returned to the opening screen."

That is odd too... When I press push button PC4, make an entry for hours, then press push button PC5, my timer starts timing.

Line three displays the number of hours set - "1:0:0 alarm", for example.

Pushing PC5 push button again causes my display to stop, holding the accumulated time on the display. Pushing PC5 again (third time) Causes the accumulated time to reset to "0.00 sec", and "0:0:0 H:M:S".

The amount of time entered on line three, the "alarm" time remains the same, unless I press the PB1 push button to reset the alarm time to 0.

At least that's how it's working for me.

June 25, 2011
by SpaceGhost
SpaceGhost's Avatar

I have just made a minor change to the original code, to prevent while cycling through the presets having the 30 minute preset remain when returning to the "Presets off" mode.

After line #222, in the "if (pre == 0)" loop I added:

if (g == 0)  // new

    b = 0;
    c = 0;
    e = 0;

That was just something I had been meaning to fix. Unfortunately I don't think that it would have an effect on your problem, Ralph..

June 25, 2011
by Noter
Noter's Avatar

Hey Ralph, maybe you have a bad row on your breadboard and the switch is not making contact with the mcu pin?

June 25, 2011
by SpaceGhost
SpaceGhost's Avatar

I just now changed lines #233 to #241 to:

   if (g == 1) {

        a = 0;
        b = 0;
        c = 10;
        e = 0;
    }

   if (g == 2) {

        a = 0;
        b = 0;
        c = 30;
        e = 0;
    }

To prevent hour and seconds values being held when changing to a preset.

June 25, 2011
by SpaceGhost
SpaceGhost's Avatar

Hi Noter, yeah I considered that also, except though at this point it seems that his button may be making contact, but for some reason the button closure is not having the expected effect...

In Ralph's button test, he had noted -

Presets OFF

PC5
no changes when pressed nothing
if held down line three and line four disappear and display flashes

Then, after swapping switches Ralph said -

"Now if I press PC4 and make a entry say 2 hours and then press PC5 I am returned to the opening screen.

0: 0: 0 alarm

The hour setting is not saved but obviously PC5 is making contact and effecting the program.

Pressing PC5 is the same as hitting a reset button."

Just curious Ralph, what type of buttons are you using?

June 25, 2011
by Noter
Noter's Avatar

Ok, I gave it a try (only PC5) and it works for me but to get a clean compile I had to change line 63 from

SIGNAL(SIG_OUTPUT_COMPARE0A) {

to

SIGNAL(TIMER0_COMPA_vect) {

The only difference may be that I am on a 328P vs a 168. I had the same results as Ralph until I made that change.

June 25, 2011
by Noter
Noter's Avatar

Actually, I don't see SIG_OUTPUT_COMPARE0A in the atmega168 include file either. What mcu are you using SpaceGhost?

June 25, 2011
by SpaceGhost
SpaceGhost's Avatar

I'm using an atmega 168, that I bought from the Nerd Kits guys. It is an extra, not the one that came with my kit.

The code that I posted is modified from the realtimeclock1 project that I got from this site. Here is the original, unmodified program that I started with -

// realtimeclock1.c
// for NerdKits with ATmega168
// mrobbins@mit.edu

#define F_CPU 14745600

#include <stdio.h>
#include <stdlib.h>

#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/pgmspace.h>
#include <inttypes.h>

#include "../libnerdkits/delay.h"
#include "../libnerdkits/lcd.h"
#include "../libnerdkits/uart.h"

// PIN DEFINITIONS:

void realtimeclock_setup() {
  // setup Timer0:
  // CTC (Clear Timer on Compare Match mode)
  // TOP set by OCR0A register
  TCCR0A |= (1<<WGM01);
  // clocked from CLK/1024
  // which is 14745600/1024, or 14400 increments per second
  TCCR0B |= (1<<CS02) | (1<<CS00);
  // set TOP to 143
  // because it counts 0, 1, 2, ... 142, 143, 0, 1, 2 ...
  // so 0 through 143 equals 144 events
  OCR0A = 143;
  // enable interrupt on compare event
  // (14400 / 144 = 100 per second)
  TIMSK0 |= (1<<OCIE0A);
}

// the_time will store the elapsed time
// in hundredths of a second.
// (100 = 1 second)
// 
// note that this will overflow in approximately 248 days!
//
// This variable is marked "volatile" because it is modified
// by an interrupt handler.  Without the "volatile" marking,
// the compiler might just assume that it doesn't change in 
// the flow of any given function (if the compiler doesn't
// see any code in that function modifying it -- sounds 
// reasonable, normally!).
//
// But with "volatile", it will always read it from memory 
// instead of making that assumption.
volatile int32_t the_time;

SIGNAL(SIG_OUTPUT_COMPARE0A) {
  // when Timer0 gets to its Output Compare value,
  // one one-hundredth of a second has elapsed (0.01 seconds).
  the_time++;
}

int main() {
  realtimeclock_setup();

  // init lcd
  lcd_init();
  FILE lcd_stream = FDEV_SETUP_STREAM(lcd_putchar, 0, _FDEV_SETUP_WRITE);
  lcd_home();

  // init serial port
  uart_init();
  FILE uart_stream = FDEV_SETUP_STREAM(uart_putchar, uart_getchar, _FDEV_SETUP_RW);
  stdin = stdout = &uart_stream;

  // turn on interrupt handler
  sei();

  while(1) {
    lcd_home();
    fprintf_P(&lcd_stream, PSTR("%16.2f sec"), (double) the_time / 100.0);
  }

  return 0;
}

SIGNAL(SIG_OUTPUT_COMPARE0A) was part of the original code. That original code had worked for me also - if it hadn't, I wouldn't have even had began trying to modify it.

The original code only (to the best of my recollection) timed in seconds/one-one hundreds seconds (line one on the LCD), and the timer began immediately on power up.

Which include file should I look in to see if SIGNAL(SIG_OUTPUT_COMPARE0A) is in it? I confess that I really don't understand this issue. Especially, why you had to make that modification, and I didn't?

June 25, 2011
by Noter
Noter's Avatar

The interrupt vectors are defined in avr includes iom168p.h or iom328p.h. On my PC the include files are located in the C:WinAVR-20100110avrincludeavr directory. Could it be a winavr version difference?

June 25, 2011
by Noter
Noter's Avatar

oops - forgot to double thos backslashes ...

E:\WinAVR-20100110\avr\include\avr

June 25, 2011
by Noter
Noter's Avatar

Yep, that's it, version difference. I guess the old names dropped out somewher along the way.

Take a look at this link - http://www.nongnu.org/avr-libc/user-manual/groupavrinterrupts.html ...


Choosing the vector: Interrupt vector names

There are currently two different styles present for naming the vectors. One form uses names starting with SIG_, followed by a relatively verbose but arbitrarily chosen name describing the interrupt vector. This has been the only available style in avr-libc up to version 1.2.x.

Starting with avr-libc version 1.4.0, a second style of interrupt vector names has been added, where a short phrase for the vector description is followed by _vect. The short phrase matches the vector name as described in the datasheet of the respective device (and in Atmel's XML files), with spaces replaced by an underscore and other non-alphanumeric characters dropped. Using the suffix _vect is intented to improve portability to other C compilers available for the AVR that use a similar naming convention.

June 25, 2011
by SpaceGhost
SpaceGhost's Avatar

Here's what is in my iom168p.h file:

/* Copyright (c) 2007 Atmel Corporation
   All rights reserved.

   Redistribution and use in source and binary forms, with or without
   modification, are permitted provided that the following conditions are met:

   * Redistributions of source code must retain the above copyright
     notice, this list of conditions and the following disclaimer.

   * Redistributions in binary form must reproduce the above copyright
     notice, this list of conditions and the following disclaimer in
     the documentation and/or other materials provided with the
     distribution.

   * Neither the name of the copyright holders nor the names of
     contributors may be used to endorse or promote products derived
     from this software without specific prior written permission.

  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  POSSIBILITY OF SUCH DAMAGE. 
*/

/* $Id: iom168p.h,v 1.3.2.12 2009/02/11 18:05:27 arcanum Exp $ */

/* avr/iom168p.h - definitions for ATmega168P. */

/* This file should only be included from <avr/io.h>, never directly. */

#ifndef _AVR_IO_H_
#  error "Include <avr/io.h> instead of this file."
#endif

#ifndef _AVR_IOXXX_H_
#  define _AVR_IOXXX_H_ "iom168p.h"
#else
#  error "Attempt to include more than one <avr/ioXXX.h> file."
#endif

#ifndef _AVR_IOM168P_H_
#define _AVR_IOM168P_H_ 1

/* Registers and associated bit numbers */

#define PINB _SFR_IO8(0x03)
#define PINB0 0
#define PINB1 1
#define PINB2 2
#define PINB3 3
#define PINB4 4
#define PINB5 5
#define PINB6 6
#define PINB7 7

#define DDRB _SFR_IO8(0x04)
#define DDB0 0
#define DDB1 1
#define DDB2 2
#define DDB3 3
#define DDB4 4
#define DDB5 5
#define DDB6 6
#define DDB7 7

#define PORTB _SFR_IO8(0x05)
#define PORTB0 0
#define PORTB1 1
#define PORTB2 2
#define PORTB3 3
#define PORTB4 4
#define PORTB5 5
#define PORTB6 6
#define PORTB7 7

#define PINC _SFR_IO8(0x06)
#define PINC0 0
#define PINC1 1
#define PINC2 2
#define PINC3 3
#define PINC4 4
#define PINC5 5
#define PINC6 6

#define DDRC _SFR_IO8(0x07)
#define DDC0 0
#define DDC1 1
#define DDC2 2
#define DDC3 3
#define DDC4 4
#define DDC5 5
#define DDC6 6

#define PORTC _SFR_IO8(0x08)
#define PORTC0 0
#define PORTC1 1
#define PORTC2 2
#define PORTC3 3
#define PORTC4 4
#define PORTC5 5
#define PORTC6 6

#define PIND _SFR_IO8(0x09)
#define PIND0 0
#define PIND1 1
#define PIND2 2
#define PIND3 3
#define PIND4 4
#define PIND5 5
#define PIND6 6
#define PIND7 7

#define DDRD _SFR_IO8(0x0A)
#define DDD0 0
#define DDD1 1
#define DDD2 2
#define DDD3 3
#define DDD4 4
#define DDD5 5
#define DDD6 6
#define DDD7 7

#define PORTD _SFR_IO8(0x0B)
#define PORTD0 0
#define PORTD1 1
#define PORTD2 2
#define PORTD3 3
#define PORTD4 4
#define PORTD5 5
#define PORTD6 6
#define PORTD7 7

#define TIFR0 _SFR_IO8(0x15)
#define TOV0 0
#define OCF0A 1
#define OCF0B 2

#define TIFR1 _SFR_IO8(0x16)
#define TOV1 0
#define OCF1A 1
#define OCF1B 2
#define ICF1 5

#define TIFR2 _SFR_IO8(0x17)
#define TOV2 0
#define OCF2A 1
#define OCF2B 2

#define PCIFR _SFR_IO8(0x1B)
#define PCIF0 0
#define PCIF1 1
#define PCIF2 2

#define EIFR _SFR_IO8(0x1C)
#define INTF0 0
#define INTF1 1

#define EIMSK _SFR_IO8(0x1D)
#define INT0 0
#define INT1 1

#define GPIOR0 _SFR_IO8(0x1E)
#define GPIOR00 0
#define GPIOR01 1
#define GPIOR02 2
#define GPIOR03 3
#define GPIOR04 4
#define GPIOR05 5
#define GPIOR06 6
#define GPIOR07 7

#define EECR _SFR_IO8(0x1F)
#define EERE 0
#define EEPE 1
#define EEMPE 2
#define EERIE 3
#define EEPM0 4
#define EEPM1 5

#define EEDR _SFR_IO8(0x20)
#define EEDR0 0
#define EEDR1 1
#define EEDR2 2
#define EEDR3 3
#define EEDR4 4
#define EEDR5 5
#define EEDR6 6
#define EEDR7 7

#define EEAR _SFR_IO16(0x21)

#define EEARL _SFR_IO8(0x21)
#define EEAR0 0
#define EEAR1 1
#define EEAR2 2
#define EEAR3 3
#define EEAR4 4
#define EEAR5 5
#define EEAR6 6
#define EEAR7 7

#define EEARH _SFR_IO8(0x22)
#define EEAR8 0

#define EEPROM_REG_LOCATIONS 1F2021

#define GTCCR _SFR_IO8(0x23)
#define PSRSYNC 0
#define PSRASY 1
#define TSM 7

#define TCCR0A _SFR_IO8(0x24)
#define WGM00 0
#define WGM01 1
#define COM0B0 4
#define COM0B1 5
#define COM0A0 6
#define COM0A1 7

#define TCCR0B _SFR_IO8(0x25)
#define CS00 0
#define CS01 1
#define CS02 2
#define WGM02 3
#define FOC0B 6
#define FOC0A 7

#define TCNT0 _SFR_IO8(0x26)
#define TCNT0_0 0
#define TCNT0_1 1
#define TCNT0_2 2
#define TCNT0_3 3
#define TCNT0_4 4
#define TCNT0_5 5
#define TCNT0_6 6
#define TCNT0_7 7

#define OCR0A _SFR_IO8(0x27)
#define OCR0A_0 0
#define OCR0A_1 1
#define OCR0A_2 2
#define OCR0A_3 3
#define OCR0A_4 4
#define OCR0A_5 5
#define OCR0A_6 6
#define OCR0A_7 7

#define OCR0B _SFR_IO8(0x28)
#define OCR0B_0 0
#define OCR0B_1 1
#define OCR0B_2 2
#define OCR0B_3 3
#define OCR0B_4 4
#define OCR0B_5 5
#define OCR0B_6 6
#define OCR0B_7 7

#define GPIOR1 _SFR_IO8(0x2A)
#define GPIOR10 0
#define GPIOR11 1
#define GPIOR12 2
#define GPIOR13 3
#define GPIOR14 4
#define GPIOR15 5
#define GPIOR16 6
#define GPIOR17 7

#define GPIOR2 _SFR_IO8(0x2B)
#define GPIOR20 0
#define GPIOR21 1
#define GPIOR22 2
#define GPIOR23 3
#define GPIOR24 4
#define GPIOR25 5
#define GPIOR26 6
#define GPIOR27 7

#define SPCR _SFR_IO8(0x2C)
#define SPR0 0
#define SPR1 1
#define CPHA 2
#define CPOL 3
#define MSTR 4
#define DORD 5
#define SPE 6
#define SPIE 7

#define SPSR _SFR_IO8(0x2D)
#define SPI2X 0
#define WCOL 6
#define SPIF 7

#define SPDR _SFR_IO8(0x2E)
#define SPDR0 0
#define SPDR1 1
#define SPDR2 2
#define SPDR3 3
#define SPDR4 4
#define SPDR5 5
#define SPDR6 6
#define SPDR7 7

#define ACSR _SFR_IO8(0x30)
#define ACIS0 0
#define ACIS1 1
#define ACIC 2
#define ACIE 3
#define ACI 4
#define ACO 5
#define ACBG 6
#define ACD 7

#define SMCR _SFR_IO8(0x33)
#define SE 0
#define SM0 1
#define SM1 2
#define SM2 3

#define MCUSR _SFR_IO8(0x34)
#define PORF 0
#define EXTRF 1
#define BORF 2
#define WDRF 3

#define MCUCR _SFR_IO8(0x35)
#define IVCE 0 
#define IVSEL 1
#define PUD 4
#define BODSE 5
#define BODS 6

#define SPMCSR _SFR_IO8(0x37)
#define SELFPRGEN 0
#define PGERS 1
#define PGWRT 2
#define BLBSET 3
#define RWWSRE 4
#define RWWSB 6
#define SPMIE 7

#define WDTCSR _SFR_MEM8(0x60)
#define WDP0 0
#define WDP1 1
#define WDP2 2
#define WDE 3
#define WDCE 4
#define WDP3 5
#define WDIE 6
#define WDIF 7

#define CLKPR _SFR_MEM8(0x61)
#define CLKPS0 0
#define CLKPS1 1
#define CLKPS2 2
#define CLKPS3 3
#define CLKPCE 7

#define PRR _SFR_MEM8(0x64)
#define PRADC 0
#define PRUSART0 1
#define PRSPI 2
#define PRTIM1 3
#define PRTIM0 5
#define PRTIM2 6
#define PRTWI 7

#define OSCCAL _SFR_MEM8(0x66)
#define CAL0 0
#define CAL1 1
#define CAL2 2
#define CAL3 3
#define CAL4 4
#define CAL5 5
#define CAL6 6
#define CAL7 7

#define PCICR _SFR_MEM8(0x68)
#define PCIE0 0
#define PCIE1 1
#define PCIE2 2

#define EICRA _SFR_MEM8(0x69)
#define ISC00 0
#define ISC01 1
#define ISC10 2
#define ISC11 3

#define PCMSK0 _SFR_MEM8(0x6B)
#define PCINT0 0
#define PCINT1 1
#define PCINT2 2
#define PCINT3 3
#define PCINT4 4
#define PCINT5 5
#define PCINT6 6
#define PCINT7 7

#define PCMSK1 _SFR_MEM8(0x6C)
#define PCINT8 0
#define PCINT9 1
#define PCINT10 2
#define PCINT11 3
#define PCINT12 4
#define PCINT13 5
#define PCINT14 6

#define PCMSK2 _SFR_MEM8(0x6D)
#define PCINT16 0
#define PCINT17 1
#define PCINT18 2
#define PCINT19 3
#define PCINT20 4
#define PCINT21 5
#define PCINT22 6
#define PCINT23 7

#define TIMSK0 _SFR_MEM8(0x6E)
#define TOIE0 0
#define OCIE0A 1
#define OCIE0B 2

#define TIMSK1 _SFR_MEM8(0x6F)
#define TOIE1 0
#define OCIE1A 1
#define OCIE1B 2
#define ICIE1 5

#define TIMSK2 _SFR_MEM8(0x70)
#define TOIE2 0
#define OCIE2A 1
#define OCIE2B 2

#ifndef __ASSEMBLER__
#define ADC     _SFR_MEM16(0x78)
#endif
#define ADCW    _SFR_MEM16(0x78)

#define ADCL _SFR_MEM8(0x78)
#define ADCL0 0
#define ADCL1 1
#define ADCL2 2
#define ADCL3 3
#define ADCL4 4
#define ADCL5 5
#define ADCL6 6
#define ADCL7 7

#define ADCH _SFR_MEM8(0x79)
#define ADCH0 0
#define ADCH1 1
#define ADCH2 2
#define ADCH3 3
#define ADCH4 4
#define ADCH5 5
#define ADCH6 6
#define ADCH7 7

#define ADCSRA _SFR_MEM8(0x7A)
#define ADPS0 0
#define ADPS1 1
#define ADPS2 2
#define ADIE 3
#define ADIF 4
#define ADATE 5
#define ADSC 6
#define ADEN 7

#define ADCSRB _SFR_MEM8(0x7B)
#define ADTS0 0
#define ADTS1 1
#define ADTS2 2
#define ACME 6

#define ADMUX _SFR_MEM8(0x7C)
#define MUX0 0
#define MUX1 1
#define MUX2 2
#define MUX3 3
#define ADLAR 5
#define REFS0 6
#define REFS1 7

#define DIDR0 _SFR_MEM8(0x7E)
#define ADC0D 0
#define ADC1D 1
#define ADC2D 2
#define ADC3D 3
#define ADC4D 4
#define ADC5D 5

#define DIDR1 _SFR_MEM8(0x7F)
#define AIN0D 0
#define AIN1D 1

#define TCCR1A _SFR_MEM8(0x80)
#define WGM10 0
#define WGM11 1
#define COM1B0 4
#define COM1B1 5
#define COM1A0 6
#define COM1A1 7

#define TCCR1B _SFR_MEM8(0x81)
#define CS10 0
#define CS11 1
#define CS12 2
#define WGM12 3
#define WGM13 4
#define ICES1 6
#define ICNC1 7

#define TCCR1C _SFR_MEM8(0x82)
#define FOC1B 6
#define FOC1A 7

#define TCNT1 _SFR_MEM16(0x84)

#define TCNT1L _SFR_MEM8(0x84)
#define TCNT1L0 0
#define TCNT1L1 1
#define TCNT1L2 2
#define TCNT1L3 3
#define TCNT1L4 4
#define TCNT1L5 5
#define TCNT1L6 6
#define TCNT1L7 7

#define TCNT1H _SFR_MEM8(0x85)
#define TCNT1H0 0
#define TCNT1H1 1
#define TCNT1H2 2
#define TCNT1H3 3
#define TCNT1H4 4
#define TCNT1H5 5
#define TCNT1H6 6
#define TCNT1H7 7

#define ICR1 _SFR_MEM16(0x86)

#define ICR1L _SFR_MEM8(0x86)
#define ICR1L0 0
#define ICR1L1 1
#define ICR1L2 2
#define ICR1L3 3
#define ICR1L4 4
#define ICR1L5 5
#define ICR1L6 6
#define ICR1L7 7

#define ICR1H _SFR_MEM8(0x87)
#define ICR1H0 0
#define ICR1H1 1
#define ICR1H2 2
#define ICR1H3 3
#define ICR1H4 4
#define ICR1H5 5
#define ICR1H6 6
#define ICR1H7 7

#define OCR1A _SFR_MEM16(0x88)

#define OCR1AL _SFR_MEM8(0x88)
#define OCR1AL0 0
#define OCR1AL1 1
#define OCR1AL2 2
#define OCR1AL3 3
#define OCR1AL4 4
#define OCR1AL5 5
#define OCR1AL6 6
#define OCR1AL7 7

#define OCR1AH _SFR_MEM8(0x89)
#define OCR1AH0 0
#define OCR1AH1 1
#define OCR1AH2 2
#define OCR1AH3 3
#define OCR1AH4 4
#define OCR1AH5 5
#define OCR1AH6 6
#define OCR1AH7 7

#define OCR1B _SFR_MEM16(0x8A)

#define OCR1BL _SFR_MEM8(0x8A)
#define OCR1BL0 0
#define OCR1BL1 1
#define OCR1BL2 2
#define OCR1BL3 3
#define OCR1BL4 4
#define OCR1BL5 5
#define OCR1BL6 6
#define OCR1BL7 7

#define OCR1BH _SFR_MEM8(0x8B)
#define OCR1BH0 0
#define OCR1BH1 1
#define OCR1BH2 2
#define OCR1BH3 3
#define OCR1BH4 4
#define OCR1BH5 5
#define OCR1BH6 6
#define OCR1BH7 7

#define TCCR2A _SFR_MEM8(0xB0)
#define WGM20 0
#define WGM21 1
#define COM2B0 4
#define COM2B1 5
#define COM2A0 6
#define COM2A1 7

#define TCCR2B _SFR_MEM8(0xB1)
#define CS20 0
#define CS21 1
#define CS22 2
#define WGM22 3
#define FOC2B 6
#define FOC2A 7

#define TCNT2 _SFR_MEM8(0xB2)
#define TCNT2_0 0
#define TCNT2_1 1
#define TCNT2_2 2
#define TCNT2_3 3
#define TCNT2_4 4
#define TCNT2_5 5
#define TCNT2_6 6
#define TCNT2_7 7

#define OCR2A _SFR_MEM8(0xB3)
#define OCR2_0 0
#define OCR2_1 1
#define OCR2_2 2
#define OCR2_3 3
#define OCR2_4 4
#define OCR2_5 5
#define OCR2_6 6
#define OCR2_7 7

#define OCR2B _SFR_MEM8(0xB4)
#define OCR2_0 0
#define OCR2_1 1
#define OCR2_2 2
#define OCR2_3 3
#define OCR2_4 4
#define OCR2_5 5
#define OCR2_6 6
#define OCR2_7 7

#define ASSR _SFR_MEM8(0xB6)
#define TCR2BUB 0
#define TCR2AUB 1
#define OCR2BUB 2
#define OCR2AUB 3
#define TCN2UB 4
#define AS2 5
#define EXCLK 6

#define TWBR _SFR_MEM8(0xB8)
#define TWBR0 0
#define TWBR1 1
#define TWBR2 2
#define TWBR3 3
#define TWBR4 4
#define TWBR5 5
#define TWBR6 6
#define TWBR7 7

#define TWSR _SFR_MEM8(0xB9)
#define TWPS0 0
#define TWPS1 1
#define TWS3 3
#define TWS4 4
#define TWS5 5
#define TWS6 6
#define TWS7 7

#define TWAR _SFR_MEM8(0xBA)
#define TWGCE 0
#define TWA0 1
#define TWA1 2
#define TWA2 3
#define TWA3 4
#define TWA4 5
#define TWA5 6
#define TWA6 7

#define TWDR _SFR_MEM8(0xBB)
#define TWD0 0
#define TWD1 1
#define TWD2 2
#define TWD3 3
#define TWD4 4
#define TWD5 5
#define TWD6 6
#define TWD7 7

#define TWCR _SFR_MEM8(0xBC)
#define TWIE 0
#define TWEN 2
#define TWWC 3
#define TWSTO 4
#define TWSTA 5
#define TWEA 6
#define TWINT 7

#define TWAMR _SFR_MEM8(0xBD)
#define TWAM0 0
#define TWAM1 1
#define TWAM2 2
#define TWAM3 3
#define TWAM4 4
#define TWAM5 5
#define TWAM6 6

#define UCSR0A _SFR_MEM8(0xC0)
#define MPCM0 0
#define U2X0 1
#define UPE0 2
#define DOR0 3
#define FE0 4
#define UDRE0 5
#define TXC0 6
#define RXC0 7

#define UCSR0B _SFR_MEM8(0xC1)
#define TXB80 0
#define RXB80 1
#define UCSZ02 2
#define TXEN0 3
#define RXEN0 4
#define UDRIE0 5
#define TXCIE0 6
#define RXCIE0 7

#define UCSR0C _SFR_MEM8(0xC2)
#define UCPOL0 0
#define UCSZ00 1
#define UCPHA0 1
#define UCSZ01 2
#define UDORD0 2
#define USBS0 3
#define UPM00 4
#define UPM01 5
#define UMSEL00 6
#define UMSEL01 7

#define UBRR0 _SFR_MEM16(0xC4)

#define UBRR0L _SFR_MEM8(0xC4)
#define UBRR0_0 0
#define UBRR0_1 1
#define UBRR0_2 2
#define UBRR0_3 3
#define UBRR0_4 4
#define UBRR0_5 5
#define UBRR0_6 6
#define UBRR0_7 7

#define UBRR0H _SFR_MEM8(0xC5)
#define UBRR0_8 0
#define UBRR0_9 1
#define UBRR0_10 2
#define UBRR0_11 3

#define UDR0 _SFR_MEM8(0xC6)
#define UDR0_0 0
#define UDR0_1 1
#define UDR0_2 2
#define UDR0_3 3
#define UDR0_4 4
#define UDR0_5 5
#define UDR0_6 6
#define UDR0_7 7

/* Interrupt Vectors */
/* Interrupt Vector 0 is the reset vector. */
#define INT0_vect         _VECTOR(1)   /* External Interrupt Request 0 */
#define INT1_vect         _VECTOR(2)   /* External Interrupt Request 1 */
#define PCINT0_vect       _VECTOR(3)   /* Pin Change Interrupt Request 0 */
#define PCINT1_vect       _VECTOR(4)   /* Pin Change Interrupt Request 0 */
#define PCINT2_vect       _VECTOR(5)   /* Pin Change Interrupt Request 1 */
#define WDT_vect          _VECTOR(6)   /* Watchdog Time-out Interrupt */
#define TIMER2_COMPA_vect _VECTOR(7)   /* Timer/Counter2 Compare Match A */
#define TIMER2_COMPB_vect _VECTOR(8)   /* Timer/Counter2 Compare Match A */
#define TIMER2_OVF_vect   _VECTOR(9)   /* Timer/Counter2 Overflow */
#define TIMER1_CAPT_vect  _VECTOR(10)  /* Timer/Counter1 Capture Event */
#define TIMER1_COMPA_vect _VECTOR(11)  /* Timer/Counter1 Compare Match A */
#define TIMER1_COMPB_vect _VECTOR(12)  /* Timer/Counter1 Compare Match B */ 
#define TIMER1_OVF_vect   _VECTOR(13)  /* Timer/Counter1 Overflow */
#define TIMER0_COMPA_vect _VECTOR(14)  /* TimerCounter0 Compare Match A */
#define TIMER0_COMPB_vect _VECTOR(15)  /* TimerCounter0 Compare Match B */
#define TIMER0_OVF_vect   _VECTOR(16)  /* Timer/Couner0 Overflow */
#define SPI_STC_vect      _VECTOR(17)  /* SPI Serial Transfer Complete */
#define USART_RX_vect     _VECTOR(18)  /* USART Rx Complete */
#define USART_UDRE_vect   _VECTOR(19)  /* USART, Data Register Empty */
#define USART_TX_vect     _VECTOR(20)  /* USART Tx Complete */
#define ADC_vect          _VECTOR(21)  /* ADC Conversion Complete */
#define EE_READY_vect     _VECTOR(22)  /* EEPROM Ready */
#define ANALOG_COMP_vect  _VECTOR(23)  /* Analog Comparator */
#define TWI_vect          _VECTOR(24)  /* Two-wire Serial Interface */
#define SPM_READY_vect    _VECTOR(25)  /* Store Program Memory Read */

#define _VECTORS_SIZE (26 * 4)

/* Constants */
#define SPM_PAGESIZE 128
#define RAMEND       0x4FF     /* Last On-Chip SRAM Location */
#define XRAMSIZE     0
#define XRAMEND      RAMEND
#define E2END        0x1FF
#define E2PAGESIZE   4
#define FLASHEND     0x3FFF

/* Fuses */
#define FUSE_MEMORY_SIZE 3

/* Low Fuse Byte */
#define FUSE_CKSEL0 (unsigned char)~_BV(0)  /* Select Clock Source */
#define FUSE_CKSEL1 (unsigned char)~_BV(1)  /* Select Clock Source */
#define FUSE_CKSEL2 (unsigned char)~_BV(2)  /* Select Clock Source */
#define FUSE_CKSEL3 (unsigned char)~_BV(3)  /* Select Clock Source */
#define FUSE_SUT0   (unsigned char)~_BV(4)  /* Select start-up time */
#define FUSE_SUT1   (unsigned char)~_BV(5)  /* Select start-up time */
#define FUSE_CKOUT  (unsigned char)~_BV(6)  /* Clock output */
#define FUSE_CKDIV8 (unsigned char)~_BV(7) /* Divide clock by 8 */
#define LFUSE_DEFAULT (FUSE_CKSEL0 & FUSE_CKSEL2 & FUSE_CKSEL3 & FUSE_SUT0 & FUSE_CKDIV8)

/* High Fuse Byte */
#define FUSE_BODLEVEL0 (unsigned char)~_BV(0)  /* Brown-out Detector trigger level */
#define FUSE_BODLEVEL1 (unsigned char)~_BV(1)  /* Brown-out Detector trigger level */
#define FUSE_BODLEVEL2 (unsigned char)~_BV(2)  /* Brown-out Detector trigger level */
#define FUSE_EESAVE    (unsigned char)~_BV(3)  /* EEPROM memory is preserved through chip erase */
#define FUSE_WDTON     (unsigned char)~_BV(4)  /* Watchdog Timer Always On */
#define FUSE_SPIEN     (unsigned char)~_BV(5)  /* Enable Serial programming and Data Downloading */
#define FUSE_DWEN      (unsigned char)~_BV(6)  /* debugWIRE Enable */
#define FUSE_RSTDISBL  (unsigned char)~_BV(7)  /* External reset disable */
#define HFUSE_DEFAULT (FUSE_SPIEN)

/* Extended Fuse Byte */
#define FUSE_BOOTRST (unsigned char)~_BV(0)
#define FUSE_BOOTSZ0 (unsigned char)~_BV(1)
#define FUSE_BOOTSZ1 (unsigned char)~_BV(2)
#define EFUSE_DEFAULT (FUSE_BOOTSZ0 & FUSE_BOOTSZ1)

/* Lock Bits */
#define __LOCK_BITS_EXIST
#define __BOOT_LOCK_BITS_0_EXIST
#define __BOOT_LOCK_BITS_1_EXIST

/* Signature */
#define SIGNATURE_0 0x1E
#define SIGNATURE_1 0x94
#define SIGNATURE_2 0x0B

#endif  /* _AVR_IOM168P_H_ */
June 25, 2011
by SpaceGhost
SpaceGhost's Avatar

Okay, so your fix should help Ralph?

(sorry about that last huge post!)

June 25, 2011
by Noter
Noter's Avatar

That's interesting, I don't see the old definition in your include file either. I wonder where your compile is getting it from. Maybe something in your makefile, would you post it so we can have a look.

Yes, I think Ralph likely has the same issue and the fix should get him going too.

June 25, 2011
by SpaceGhost
SpaceGhost's Avatar

Here's the Makefile:

GCCFLAGS=-g -Os -Wall -mmcu=atmega168 
LINKFLAGS=-Wl,-u,vfprintf -lprintf_flt -Wl,-u,vfscanf -lscanf_flt -lm
AVRDUDEFLAGS=-c avr109 -p m168 -b 115200 -P COM5
LINKOBJECTS=../libnerdkits/delay.o ../libnerdkits/lcd.o ../libnerdkits/uart.o

all:    realtimeclock1-upload

realtimeclock1.hex: realtimeclock1.c
    make -C ../libnerdkits
    avr-gcc ${GCCFLAGS} ${LINKFLAGS} -o realtimeclock1.o realtimeclock1.c ${LINKOBJECTS}
    avr-objcopy -j .text -O ihex realtimeclock1.o realtimeclock1.hex

realtimeclock1.ass: realtimeclock1.hex
    avr-objdump -S -d realtimeclock1.o > realtimeclock1.ass

realtimeclock1-upload:  realtimeclock1.hex
    avrdude ${AVRDUDEFLAGS} -U flash:w:realtimeclock1.hex:a
June 25, 2011
by SpaceGhost
SpaceGhost's Avatar

I have to be way from my computer for a while.. I will check back here in a few hours.

Dave

June 25, 2011
by Noter
Noter's Avatar

If you were to change -mmcu=atmega168 to -mmcu=atmega168p or -mmcu=atmega328p, the include files identified above are used and you'll get the warning that SIG_OUTPUT_COMPARE0A is not defined. I'm not sure what is happengin with -mmcu=atmega168 because I can't find where it defines SIG_OUTPUT_COMPARE0A but it works. Using -mmcu=atmega168a works too but then you can't go back to using -mmcu=atmega168 without always getting an error saying the device is not defined. So there is something a little wierd going on with -mmcu=atmega168 vs the others.

I don't think it is a version difference after all, just different 168/168a vector definitions (even though I can't find them) compared to the 168p and 328p.

Anyway, I think Ralph is using a 328p and his problem will be resolved by using the new interrupt vector name TIMER0_COMPA_vect.

June 25, 2011
by Ralphxyz
Ralphxyz's Avatar

Woooweee!! Thanks Paul that did it!!

Now that is a good reference for the next time things are almost working.

When things are acting goofy check the vector: Interrupt vector names!!

Dave thank you for your time and your code.

I think I'll add a GOOFY topic to the Nerdkit library so there is a documented reference!!

Ralph

June 25, 2011
by Noter
Noter's Avatar

The compiler was giving a warning saying SIG_OUTPUT_COMPARE0A was not defined. It probably slipped by you because the hex was still generated and loaded on the chip. A good rule of thumb is to always check for compiler warnings and fix them whenever things are not working as expected.

June 25, 2011
by Ralphxyz
Ralphxyz's Avatar

Just at the last did I see that warning. I tried switching to a ATmega168p and the compile stopped short then I saw the warning.

You had published the fix. I probable would have ignored the warning because the .hex loaded.

I am sure I have had other projects fail for this exact same reason, like I said at the beginning I have a history of not being able to run other peoples code I'll bet for some of them this was the same reason.

Thanks again,

Ralph

June 25, 2011
by SpaceGhost
SpaceGhost's Avatar

Just for the heck of it, I tried the substitution also. The code seems to work, either way for me!

Ralph, so glad that you got the code working. It was certainly a puzzler for a while! We both learned something here today.

Noter, thanks so much for taking a look. I was hoping that someone like yourself would step in.. It just wasn't making any sense why the code would work for me and not Ralph, with all the checking and re-checking he had to do.

Since the code works either way for me, but only works using SIGNAL(TIMER0_COMPA_vect) as the vector: Interrupt vector name for you guys, I'm guessing that Noter's version would be more "universal"? I'm going to save my current copy of the code with this change.

June 25, 2011
by SpaceGhost
SpaceGhost's Avatar

Here's my newest version of the code, with some other minor fixes -

/////////////
//             A Nerdy Stopwatch/Kitchen Timer
// clock01
//            (settable alarm/timer w/ presets)
////////////

// modification of
//
// realtimeclock1.c
// for NerdKits with ATmega168
// mrobbins@mit.edu

#define F_CPU 14745600

#include <stdio.h>
#include <stdlib.h>

#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/pgmspace.h>
#include <inttypes.h>

#include "../libnerdkits/delay.h"
#include "../libnerdkits/lcd.h"
#include "../libnerdkits/uart.h"

// PIN DEFINITIONS:

void realtimeclock_setup() {
  // setup Timer0:
  // CTC (Clear Timer on Compare Match mode)
  // TOP set by OCR0A register
  TCCR0A |= (1<<WGM01);
  // clocked from CLK/1024
  // which is 14745600/1024, or 14400 increments per second
  TCCR0B |= (1<<CS02) | (1<<CS00);
  // set TOP to 143
  // because it counts 0, 1, 2, ... 142, 143, 0, 1, 2 ...
  // so 0 through 143 equals 144 events
  OCR0A = 143;
  // enable interrupt on compare event
  // (14400 / 144 = 100 per second)
  TIMSK0 |= (1<<OCIE0A);
}

// the_time will store the elapsed time
// in hundredths of a second.
// (100 = 1 second)
//
// note that this will overflow in approximately 248 days!
//
// This variable is marked "volatile" because it is modified
// by an interrupt handler.  Without the "volatile" marking,
// the compiler might just assume that it doesn't change in
// the flow of any given function (if the compiler doesn't
// see any code in that function modifying it -- sounds
// reasonable, normally!).
//
// But with "volatile", it will always read it from memory
// instead of making that assumption.
volatile int32_t the_time;

SIGNAL(TIMER0_COMPA_vect) {
  // when Timer0 gets to its Output Compare value,
  // one one-hundredth of a second has elapsed (0.01 seconds).
  the_time++;
}

int main() {
  realtimeclock_setup();

  // init lcd
  lcd_init();
  FILE lcd_stream = FDEV_SETUP_STREAM(lcd_putchar, 0, _FDEV_SETUP_WRITE);
  lcd_home();

// outputs -

  DDRC |= (1<<PC0);   // pin 23 sourcing output for ALARM LED

  DDRB |= (1<<PB5);   // pin 19 sourcing output for WARNING LED

// inputs -

  DDRC &= ~(1<<PC5); // pin 28 pushbutton (sink input) START/STOP/RESET (on_off)

  DDRC &= ~(1<<PC4); // pin 27 pushbutton (sink input) SET

  DDRC &= ~(1<<PC3); // pin 26 pushbutton (sink input) UP

  DDRC &= ~(1<<PC2); // pin 25 pushbutton (sink input) DOWN

  DDRB &= ~(1<<PB2); // pin 16 - switch for presets

  DDRB &= ~(1<<PB1); // pin 15 - reset alarm time

  PORTC |= (1<<PC5); // internal pull up resistors pins 28 - 25
  PORTC |= (1<<PC4);
  PORTC |= (1<<PC3);
  PORTC |= (1<<PC2);
  PORTB |= (1<<PB2);
  PORTB |= (1<<PB1);

// declare variables to represent pushbutton inputs

uint8_t on_off;
uint8_t j;

uint8_t set;
uint8_t up;
uint8_t dn;

int8_t a;
int8_t b;
int8_t c;
int8_t e;

uint8_t pre;
int8_t g;

uint16_t hr, mmmin, sec, h, m, s;
uint32_t val, sm;

uint8_t reset;

a = 0;
b = 0;
c = 0;
e = 0;

g = 0;

val = 0;
hr = 0;
sm = 0;
mmmin = 0;
sec = 0;
h = 0;
m = 0;
s = 0;
the_time = 0;

j=0; // start with timer OFF

while(1) {

   if (j == 0) {

   PORTC &= ~(1<<PC0);  // output OFF

   sm = 0;
   the_time = 0;

   lcd_line_one();
   fprintf_P(&lcd_stream, PSTR("            0.00 sec"));

   lcd_line_two();
   fprintf_P(&lcd_stream, PSTR("0:0:0 H:M:S   "));
}

//////////////////////////////////////////////// timing function

   on_off = (PINC & (1<<PC5)) >> PC5;

   if (on_off == 0) {

        j = j + 1;      //if button pressed, increase count by one
        if (j >= 3 )    //three button states - 0, 1 & 2
        j = 0;           //count loops back to j = 0 after j = 2
        delay_ms(500);   // switch delay
    }

   if (j == 1) { //// begin timing operation

   a = 0;

   sei();

   val = sec + (60 * mmmin) + (3600 * hr);

   sm = val + (int32_t) the_time/100;

   lcd_line_one();

   fprintf_P(&lcd_stream, PSTR("%16.2f sec"), (double) the_time / 100.0);

   lcd_line_two();

   h = (uint16_t) sm/3600;
   m = (uint16_t) ((sm % 3600)/60);
   s = sm % 60;

   fprintf_P(&lcd_stream, PSTR("%d:%d:%d H:M:S "), h, m, s);
}

    if ((j == 0) && (g > 0)) {

    lcd_line_four();
    fprintf_P(&lcd_stream, PSTR("   Preset %d        "), g);
}

    else if (g == 0) {

    lcd_line_four();
    fprintf_P(&lcd_stream, PSTR("   Presets off      "), g);
}

///////////////////////////////////////////////////////////

///////////////////////////////////////////////preset functions

  pre = (PINB & (1<<PB2)) >> PB2;

   if (pre == 0) {

        g = g + 1;      //if button pressed, increment switch
        if (g >= 3 )    //set 2 as highest allowed count, and if g is greater than 3,
        g = 0;           //count loops back to zero
        delay_ms(500);   // switch delay

        lcd_line_four();
        fprintf_P(&lcd_stream, PSTR("   Preset %d        "), g);

        if (g == 0)  // new

        b = 0;
        c = 0;
        e = 0;      
    }

   if ((g == 0) && (!a == 2)) {

        c = 0;

        lcd_line_four();
        fprintf_P(&lcd_stream, PSTR("   Presets off      "), g);
    }

   if (g == 1) {

        a = 0;
        b = 0;
        c = 10;
        e = 0;
    }

   if (g == 2) {

        a = 0;
        b = 0;
        c = 30;
        e = 0;
    }

////// preset 1 (10 min)

 if ((m == 9) && (s >= 30) && (g == 1)) { // 30 second WARNING

  PORTB |= (1<<PB5); // WARNING output ON

        lcd_line_four();
        fprintf_P(&lcd_stream, PSTR("     WARNING        "));
}

 if ((m >= 10) && (g == 1) && (j == 1)) { // ALARM set for 10 minutes (preset 1)

  PORTC |= (1<<PC0); // ALARM output ON

        lcd_line_four();
        fprintf_P(&lcd_stream, PSTR(" Preset %d TIMED OUT"), g);
}

 else {

  PORTB &= ~(1<<PB5);  // output OFF
}

//////////////////////////////////////////////////

////// preset 2 (30 min)

if ((m == 29) && (s >= 30) && (g == 2)) { // 30 second WARNING

  PORTB |= (1<<PB5); // WARNING output ON

        lcd_line_four();
        fprintf_P(&lcd_stream, PSTR("     WARNING        "));
}

if ((m >= 30) && (g == 2) && (j == 1)) { // ALARM set for 30 minutes (preset 2)

  PORTC |= (1<<PC0); // ALARM output ON

        lcd_line_four();
        fprintf_P(&lcd_stream, PSTR(" Preset %d TIMED OUT"), g);
}

 else {

  PORTB &= ~(1<<PB5);  // output OFF
}

///////////////////////////////////end preset functions

///////////////////////////////////////////// set hours or minutes or seconds

       set = (PINC & (1<<PC4)) >> PC4;
        up = (PINC & (1<<PC3)) >> PC3; 
        dn = (PINC & (1<<PC2)) >> PC2;

   if (set == 0) {

        a = a + 1;      //if button pressed, increase count by one
        if (a >= 4)    //set 3 as highest allowed count, and if a is greater than 3,
        a = 0;           //count loops back to zero
        delay_ms(500);   // switch delay
    }

///////////////////////////// set hours

        if (a == 1) {
        lcd_line_three(); //  or, use lcd_goto_position(2, 0);
        fprintf_P(&lcd_stream, PSTR("%d H         "), b);      
    }

        if ((a == 1) && (up == 0)) {  // set HOUR

        b = b + 1;      //if button pressed, increase count by one
        delay_ms(300);   // switch delay

        lcd_line_three();

        fprintf_P(&lcd_stream, PSTR("%d H          "), b);

    }

        if ((a == 1) && (dn == 0)) {  // set HOUR

        b = b - 1;      //if button pressed, decrease count by one
        if (b < 0)
        b = 0;
        delay_ms(300);   // switch delay

        lcd_line_three();

        fprintf_P(&lcd_stream, PSTR("%d H          "), b);     
    }

///////////////////////////// set minutes

        if (a == 2) {

        lcd_line_three();
        fprintf_P(&lcd_stream, PSTR("%d M          "), c);     
    }

        if ((a == 2) && (up == 0)) {  // set MINUTES

        c = c + 1;      //if button pressed, increase count by one
        if (c > 59)  //set 59 as highest allowed count and, if c is > than 59,
        c = 0;       //count loops back to zero        
        delay_ms(300);   // switch delay

        lcd_line_three();
        fprintf_P(&lcd_stream, PSTR("%d M          "), c);     
    }

        if ((a == 2) && (dn == 0)) {  // set MINUTES

        c = c - 1;      //if button pressed, decrease count by one
        if (c < 0)
        c = 59;
        delay_ms(300);   // switch delay

        lcd_line_three();
        fprintf_P(&lcd_stream, PSTR("%d M          "), c);
    }

///////////////////////////// set seconds

        if (a == 3) {

        lcd_line_three();
        fprintf_P(&lcd_stream, PSTR("%d S          "), e);     
    }

        if ((a == 3) && (up == 0)) {  // set SECONDS

        e = e + 1;      //if button pressed, increase count by one
        if (e > 59)  //set 59 as highest allowed count and, if e is > than 59,
        e = 0;       //count loops back to zero        
        delay_ms(300);   // switch delay

        lcd_line_three();
        fprintf_P(&lcd_stream, PSTR("%d S          "), e);
    }

        if ((a == 3) && (dn == 0)) {  // set SECONDS

        e = e - 1;      //if button pressed, decrease count by one
        if (e < 0)
        e = 59;
        delay_ms(300);   // switch delay

        lcd_line_three();
        fprintf_P(&lcd_stream, PSTR("%d S          "), e);
    }

        if (a == 0) {

        lcd_line_three();
        fprintf_P(&lcd_stream, PSTR("%d:%d:%d alarm    "), b, c, e);
    }

////////////////////////////////////////////////

//////////////////////////////////////// alarm function v

if ((h >= b) && (m >= c) && (s >= e)) {

  PORTC |= (1<<PC0); /// ALARM output ON

  if (j == 0)

  PORTC &= ~(1<<PC0); // output OFF 
}

if ((a == 0) && (b == 0) && (c == 0) && (e == 0) && (h >= b) && (m >= c) && (s >= e)){

/// ^ above line keeps ALARM output off if H:M:S = 0:0:0 & alarm = 0:0:0

  PORTC &= ~(1<<PC0);  // output OFF
}

////////////////////////////////////////

/////////////////////////////////// reset alarm time to 0

reset = (PINB & (1<<PB1)) >> PB1;

   if (reset == 0) {

   b = 0;
   c = 0;
   e = 0;
}

}

  return 0;
}
June 25, 2011
by Ralphxyz
Ralphxyz's Avatar

Thanks Dave works like a charm.

Ralph

June 26, 2011
by Rick_S
Rick_S's Avatar

One other thing, you may want to replace

SIGNAL(TIMER0_COMPA_vect)

With

ISR(TIMER0_COMPA_vect)

The SIGNAL syntax has been depreciated ( LINK ) and replace by ISR. I believe that is also why the vector name changed. The reason SIGNAL still works is that interrupt.h still handles both but may not in the future.

Here is a snipped from interrupt.h.

/** \def SIGNAL(vector)
\ingroup avr_interrupts

\code #include <avr/interrupt.h> \endcode

Introduces an interrupt handler function that runs with global interrupts
initially disabled.

This is the same as the ISR macro without optional attributes.
\deprecated Do not use SIGNAL() in new code. Use ISR() instead.

Good catch Noter, I often forget to look at interrupts in older code even though I know avr-libc made those changes.

Rick

June 26, 2011
by Noter
Noter's Avatar

What I can't figure out is where the old SIG_OUTPUT_COMPARE0A is defined for mmcu atmega168. There are no definitions for interrupt vectors in iom168.h ... maybe gcc provides some baseline defaults?

June 26, 2011
by Rick_S
Rick_S's Avatar

It's in iomx8.h. That is a generic include for ATmega48, ATmega88 and ATmega168 and is included at the top of iom168.h.

Rick

June 26, 2011
by Noter
Noter's Avatar

Thanks Rick. I have missed that at least 3 times. :-)

June 27, 2011
by Ralphxyz
Ralphxyz's Avatar

Now let me illustrate why I get so confused (which is actually pretty easy, but this I find interesting).

While trying to get Daves code to run I knew it was based on the Nerdkit RTC project.

I knew I had had that project running in the past so I went and found my RTC folders and found

RTC168
RTC328
RTC328p

Since I was using a ATmega328, as Paul suspected, I tried loading the realtimeclock.c file from the RTC328 folder.

This failed to run.

Well I went and did other things and came back and loaded the realtimclock.c file from the RTC328p folder.

This time it ran.

I use a narrow 15 line Terminal window so I do not see any warnings unless I am looking specifically for them.

In looking at the code to see why this ran but Daves didn't I saw the:

SIGNAL(SIG_OUTPUT_COMPARE0A) 
{

This ran fine on my ATmega328

After reading Paul's explanation and running Dave's newest code I thought I had better see what was going on.

Why was I able to use SIGNAL(SIG_OUTPUT_COMPARE0A) with my ATmega328?

Then I noticed in Dave's newest code that he didn't have:

 #include "../libnerdkits/io_328p.h"

Obviously, as Dave was writing for a ATmega168 he would not include that.

Well it turns out that if one does not include the io_328p.h call you can use the old interrupt naming convention with a ATmega328.

The reason the RTC328p code ran was because I had commented out the io_328p.h include.

Of course the reason the RTC328 code failed to run was because it had the io_328p.h include.

Geesch once again cursed by that "ATTENTION TO DETAILS" devil.

Ralph

Post a Reply

Please log in to post a reply.

Did you know that interrupts can be used to trigger pieces of code when events happen? Learn more...