Programming to Delay for 6 hours

Discussion in 'Embedded Systems and Microcontrollers' started by freddarkomf, Jun 22, 2012.

  1. freddarkomf

    Thread Starter New Member

    Jun 14, 2012
    9
    0
    Hi all,
    I am a newbie in electronic, please somebody assist me to write a program using c++ to pull PIN1 high(5V) for 6 hours and pull PIN2 low(0V) 6 hour, then in the next cycle (after 6 hours) pull PIN1 low for 6 hours and pull PIN2 high for 6 hours. That's , it should alternate every 6 hours. Am using atmega 32 microcontroller.
    Thank you.
     
  2. colinb

    Active Member

    Jun 15, 2011
    351
    35
    Hi freddarkomf,

    Welcome to the world of microcontroller programming and electronics. It's an exciting place.

    For your ATmega32 question, I assume you have selected particular port pin assignments, for instance, PA1 and PA2 (port A, pins 1 and 2). First make sure you understand the DDRx (in this example, DDRA for port A) register, the Data Direction Register in which the bits set to '1' are outputs and '0' bits are inputs. Then you can write to the PORTA register to set the pin values. See tutorials on AVR general purpose I/O from Maxembedded and Protostack.

    As for getting the timing right: Are you using the gcc/avr-libc toolchain (WINAVR or AVR-GCC? If so, I can help. Define the F_CPU macro as the system clock frequency of your AVR MCU in Hertz. ("#define F_CPU 1000000UL" for 1 MHz). Look at the avr-libc documentation for the delay routines for more. The built-in _delay_ms() function can only delay for a short time, so you can define a function like this to delay for any number of seconds:

    Code ( (Unknown Language)):
    1.  
    2. // Interface - can put in header file
    3. void delay_sec(long sec);
    4. void delay_6_hours(void);
    5.  
    6. // Implementation - put in .c file
    7.  
    8. #define F_CPU 1000000UL  // 1 MHz -- NOTE!! MUST SET TO MATCH AVR FUSES
    9. #include <util/delay.h>
    10.  
    11. void delay_sec(long sec)
    12. {
    13.     while (sec > 0)
    14.     {
    15.         _delay_ms(1000);
    16.         sec -= 1;
    17.     }
    18. }
    19.  
    20. enum { seconds_per_hour = 60 * 60 };
    21.  
    22. void delay_6_hours(void)
    23. {
    24.     delay_sec(6 * seconds_per_hour);
    25. }
    26.  
    So the delay_6_hours() function will delay for 6 hours before returning. Just build your main program loop as appropriate, something like this (untested, pseudocode):
    Code ( (Unknown Language)):
    1.  
    2. // Initialization
    3. DDRA |= _BV(PIN2) | _BV(PIN1);  // Set PA2, PA1 as outputs.
    4.  
    5. while (1)                   // Loop forever.
    6. {
    7.     PORTA &= ~_BV(PIN2);    // PA2 = low.
    8.     PORTA |= _BV(PIN1);     // PA1 = high.
    9.     delay_6_hours();        // Wait for 6 hours.
    10.     PORTA &= ~_BV(PIN1);    // PA1 = low.
    11.     PORTA |= _BV(PIN2);     // PA2 = high.
    12.     delay_6_hours();        // Wait for 6 hours.
    13. }
    14.  
    Happy hacking!
     
  3. freddarkomf

    Thread Starter New Member

    Jun 14, 2012
    9
    0
    Thanks all am going to try it and get back.
     
  4. freddarkomf

    Thread Starter New Member

    Jun 14, 2012
    9
    0
    I tried this code with my WinAVR and it gives me error (warning: implicit declaration of function '_delay_6hours') and (undefined reference to `_delay_6hours'),please can somebody help me figure out what is wrong with the _delay_6hours() code

    this is the code

    #include<avr/io.h>
    #include<util/delay.h>
    #define F_CPU 1000000
    void deley_sec (long sec);
    void delay_6_hours (void);
    int main(void)
    {
    DDRD |=_BV(4);
    while(1)
    {
    PORTD |=_BV(4);
    _delay_6hours ();
    PORTD &=~_BV(4);

    }

    }


    #define F_CPU 1000000 = I must set to mach AVR Fuse, I dont understand this please;
    I have read from the internet and I understand its also a memory type, I hope am right.
    But I don't fully understand it, please somebody help me...

    What is Fuse (guess its not electrical circuit protective device) ?
    How do I know my Fuse from my data sheet?
    How do I check my Fuse?
    How do I set my fuse, if I have to set it?
    am using Atmega 32 AVR microcontroller
     
  5. nerdegutta

    Moderator

    Dec 15, 2009
    2,517
    785
    I don't know much about ATMega but ... you have

    Code ( (Unknown Language)):
    1.     void delay_6_hours (void);
    and
    Code ( (Unknown Language)):
    1. _delay_6hours ();
    I think there is a writing error... same with the

    Code ( (Unknown Language)):
    1. void deley_sec (long sec);
    It's a good practice to have the chips datasheet on your desk while programming...
     
  6. freddarkomf

    Thread Starter New Member

    Jun 14, 2012
    9
    0
    so what is wrong with my code please ?
     
  7. colinb

    Active Member

    Jun 15, 2011
    351
    35
    As nerdegutta implied, you have a typo in the call to delay_6_hours(), you put one underscore in the wrong place.

    Also, more fundametally, you have the declaration (also called a function prototype) in your source file before main, but you don't define the delay_6_hours() function body.

    Here is a C source file you can actually compile and run as-is to start with:

    EDIT --- This is broken, see my comment two replies below about adding a second delay call.

    Code ( (Unknown Language)):
    1. // Compile with optimizations enabled for the _delay_ms() function
    2. // to work properly. E.g.:
    3. // avr-gcc -mmcu=atmega328p -Os -o delay6hr.elf delay6hr.c
    4.  
    5. #define F_CPU 1000000UL  // 1 MHz -- NOTE!! MUST SET TO MATCH AVR FUSES
    6.  
    7. #include <avr/io.h>
    8. #include <util/delay.h>
    9.  
    10. // Private function declarations
    11. void delay_sec(long sec);
    12. void delay_6_hours(void);
    13.  
    14. // Main program
    15.  
    16. int main(void)
    17. {
    18.     DDRD |=_BV(4);
    19.     while(1)
    20.     {
    21.         PORTD |= _BV(4);
    22.         delay_6_hours();
    23.         PORTD &= ~_BV(4);
    24.  
    25.     }
    26. }
    27.  
    28. // Private function definitions
    29.  
    30. void delay_sec(long sec)
    31. {
    32.     while (sec > 0)
    33.     {
    34.         _delay_ms(1000);
    35.         sec -= 1;
    36.     }
    37. }
    38.  
    39. enum { seconds_per_hour = 60 * 60 };
    40.  
    41. void delay_6_hours(void)
    42. {
    43.     delay_sec(6 * seconds_per_hour);
    44. }
    45.  
     
    Last edited: Aug 13, 2012
  8. Wendy

    Moderator

    Mar 24, 2008
    20,766
    2,536
    Welcome to AAC!

    I've moved this thread to a more appropriate forum where it might get more help. Good luck.
     
  9. colinb

    Active Member

    Jun 15, 2011
    351
    35
    Oops! I left in an error from your code. You must add a second delay to the beginning or end of the while(1) {...} loop, or after the existing delay completes, the MCU will set the output LOW and immediately set it HIGH again about 3 microseconds later. Change the while(1) block of code to make the main() function like this:
    Code ( (Unknown Language)):
    1. int main(void)
    2. {
    3.     DDRD |=_BV(4);
    4.     while(1)
    5.     {
    6.         PORTD |= _BV(4);
    7.         delay_6_hours();
    8.         PORTD &= ~_BV(4);
    9.         delay_6_hours();
    10.     }
    11. }
    12.  
     
  10. freddarkomf

    Thread Starter New Member

    Jun 14, 2012
    9
    0
    hi all,
    Thanks very much, I kept on trying until I had it right, thanks especially Colinb, Nerdegutta and Bill Marsden.

    My next problem is I have two programs 6HOURS DELAY and LED on at port A when when signal is applied to port B, how do I combine the two programs so that my micro controller can perform the two actions for me... T his are the programs.

    6HOURS DELAY

    #include<avr/io.h>
    #include<util/delay.h>
    #define F_CPU 1000000
    void deley_sec (long sec);
    void delay_6_hours (void);
    int main(void)
    {
    DDRD |=_BV(4);
    while(1)
    {
    PORTD |=_BV(4);
    void delay_6hours (long sec);
    PORTD &=~_BV(4);

    }

    }


    LED ON

    #include <avr/io.h>
    int main(void)
    {
    DDRB = 0xF8;
    PORTB = 0xFF;
    DDRA = 0xF0;

    while(1)
    {
    PORTA = PINB;
    }
    }

    Thank you in advance;
     
  11. colinb

    Active Member

    Jun 15, 2011
    351
    35
    Now you need a better method of handling timing rather than the "busy-wait" or "blocking delay" that the delay_6_hours() function provides.

    What you need is a time counter that keeps track of time, or at least relative time since the last event. Then your main program can loop forever and do the assignment of PINB to PORTA, check if it's time to toggle pin PD4 (and toggle it if the 6 hours timer has elapsed), then repeat the while loop forever.

    A good way to count the 6 hours time is to use a timer peripheral to trigger an interrupt every second, then in the interrupt service routine (ISR) that is triggered, you increment or decrement some global seconds counter variable.

    I'll point you to some information on interrupts and the AVR timer peripheral, so hopefully you can learn about it. If you study AVR interrupt handling and the timer peripherals, then come back and we can discuss how you might implement this.


    Take a look at timers and interrupts, and see if you can get some example code working to demonstrate it working yourself.
     
  12. freddarkomf

    Thread Starter New Member

    Jun 14, 2012
    9
    0
    Hi all,

    Please somebody help me, I have microcontroller with the inscription ATMEGA32 16PU 1130, what is the meaning of the 16PU and 1130?
    I want to set my clock fuse am not using external resonator, is the 16PU the clock speed ?
    Please somebody help me as am confuse ?
     
  13. colinb

    Active Member

    Jun 15, 2011
    351
    35
    OK, it's better if you post a totally separate question like this in its own new thread, not "hijacking" your own other thread for it. But I will answer your question by first referring you to the ATmega32 Data Sheet page 332, "Ordering Information", where the Atmel part numbers are explained:
    [​IMG]

    The ATmega32-16PU is the version with 16-MHz maximum speed rating, and the PU is the package type. The "40P6" is shown a couple of pages later and is a 40-lead DIP.

    The "1130" part of the marking is the manufacture date code. It means it was made in the 30th week of 2011.
     
  14. freddarkomf

    Thread Starter New Member

    Jun 14, 2012
    9
    0
    Thank you very much, you men have been very very helpful. Greetings from Ghana.
     
Loading...