Please help my son! 16F628A timer circuit/program

Discussion in 'Programmer's Corner' started by Tigthwad, Feb 5, 2013.

  1. Tigthwad

    Thread Starter Member

    Oct 27, 2009
    31
    1
    My 12 year old son is building a circuit to activate/deactivate a KNEX motor based on a timing circuit (on for ~55 seconds). I am trying to help him get a jump start in understanding how to do it using a 16F628A programming in C

    We have been googling a ton and trying to understand how it all works (with a 1 week deadline). We are unable to understand how to use the config settings and the code as written doesn't even turn on the LED yet! The code below is our attempt to turn on LED based on switch input.

    The end goal is a program that when powered up turns on LED1 and looks for input from SW1. Upon input from SW1 it should turn on LED2 and delay for 3 seconds while watching SW2 (for cancel). If no input from SW2 in 3 seconds then turn on the Relay for 55 seconds while also activating LED2 to indicate the program is running. After 55 seconds expires go back to watching SW1 with LED1 active.

    Currently the test circuit has:

    MCLR and VDD tied together with an 8K ohm resistor
    VDD tied to 5V input
    VSS tied to ground
    RB0 to switch to ground
    RB1 to switch to ground
    RB2 to 330ohm resistor to LED to ground
    RB3 to 330ohm resistor to LED to ground

    Please help!

    Code ( (Unknown Language)):
    1. /************************
    2. * Description: LED Test with buttons
    3. * Turn on LED for x seconds
    4. * Pin Assignments:
    5. *   RB0 = Switch 1  
    6. *    RB1 = Switch 2
    7. *    RB2 = LED1
    8. *    RB3 = LED2
    9. *    RB4 = Relay connection
    10.  **************************/
    11.  
    12.  
    13. #define _XTAL_Frec 4000000
    14. #include<xc.h>
    15.  
    16.  
    17.  
    18.  
    19. #define LED_ON      1       // LED is connected cathode to ground
    20. #define LED_OFF     0
    21.  
    22. #define RELAY_ON    1       //RELAY is connected to ground
    23. #define RELAY_OFF   0       //RELAY not connect to ground
    24.  
    25. #define BUTTON_ON   0       // Button input is low when button pressed
    26. #define BUTTON_OFF  1       // (this is how a pull-up resistor button works)
    27.  
    28. #define I_O_OUT     0       // standard TRIS definitions
    29. #define I_O_IN      1       // zero is 0ut, one is 1n
    30.  
    31. #define SW_A        RB0     // switch A is on PORTB.0
    32. #define SW_B        RB1
    33. #define SW_A_TRIS   TRISB0  // switch B is on PORTB.1
    34. #define SW_B_TRIS   TRISB1
    35.  
    36. #define LED_A       RB2     // LED A is on PORTB.2
    37. #define LED_B       RB3     // LED B is on PORTB.3
    38. #define RELAY       RB4     // RELAY is connected to ground
    39. #define LED_A_TRIS  TRISB2
    40. #define LED_B_TRIS  TRISB3
    41. #define RELAY _TRIS TRISB4
    42.  
    43. void main(void)
    44. {
    45.   SW_A_TRIS  = I_O_IN;    // set up I/O pin directions
    46.   SW_B_TRIS  = I_O_IN;
    47.   LED_A_TRIS = I_O_OUT;
    48.   LED_B_TRIS = I_O_OUT;
    49.  
    50.   // now loop forever to sense buttons
    51.   while(1)
    52.   {
    53.     if (SW_A == BUTTON_ON) // test the first switch
    54.         LED_A = LED_ON;
    55.     else
    56.       LED_A = LED_OFF;
    57.  
    58.     if (SW_B == BUTTON_ON) // test the second switch
    59.       LED_B = LED_OFF;
    60.     else
    61.       LED_B = LED_ON;
    62.  
    63.   }
    64. }
     
  2. thatoneguy

    AAC Fanatic!

    Feb 19, 2009
    6,357
    718
    My son picked up on PICAXE at a younger age, the capabilities of which are well within your parameters. They are programmed in BASIC and run fairly fast.

    Which C compiler are you using? Are you programming with a PICKit 2/3?

    For your program, do you have a 10k Resistor pulling the switch High when it isn't pressed? The PIC will only see 0V or floating (usually read as zero) if there isn't a pullup resistor. Report back if this doesn't solve the problem.

    That aside, unrelated to your exact problem, but you may run into it in the future: On ALL PICs that have ADC and comparators, they are ON at power up. You need to disable both the ADC and comparators, otherwise the analog ports will all be Inputs, even if TRIS is set correctly.

    Add the following lines to use PortA for digital I/O:
    ADCON1=0x86;
    CMCON=0x07;
     
  3. ErnieM

    AAC Fanatic!

    Apr 24, 2011
    7,386
    1,605
    Gee you have a very readable coding style. <grin>
     
  4. Tigthwad

    Thread Starter Member

    Oct 27, 2009
    31
    1
    We will add the two lines above. Unfortunately I am not very informed on this stuff and its the blind leading the blind. Hopefully his young age will allow him a better starting point!

    We are using MPLAB X, XC8 compiler and the Pickit 3 for programming.

    The 10K resistor was not part of his circuit and will be added as well for both switches.

    If I "borrowed" your code for the basis of this I thank you....it is readable even for my novice eyes and very helpful...hoping we can figure out what else we are missing!
     
    ErnieM likes this.
  5. Tigthwad

    Thread Starter Member

    Oct 27, 2009
    31
    1
    I tried adding ADCON1=0x86; but the code window indicates this is a problem (word is red underline). I added the resistors to the switch ports. Nothing happens when I apply power to the circuit at this point but I haven't reprogrammed the chip as we need to solve the ADCON1 issue.

    I tried to understand from the 16F628A datasheet how to set the __config line but I don't understand the options. Which do I need to enable/disable to allow a simple timer and LED lighting?
     
  6. thatoneguy

    AAC Fanatic!

    Feb 19, 2009
    6,357
    718
    You'll want to read the Datasheet for the 16F628A Closely. It is long, but it holds a TON if information.

    The config should disable MCLR and enable the Internal Oscillator, usually LVP (Low Voltage Programming) is disabled as well. You'll want to look at the sample files that come with the compiler for a line you can copy that has those settings in it, or find in the help system what the exact keywords are.

    The ADCON1 and CMCON only change PortA, since your I/O and LEDs are on PortB, it won't fix the issue. After looking at the datasheet, the 628A doesn't have ADC, so you can leave that line out, just disable the comparators.

    If you didn't have pullups on the switches, or the internal oscillator running, that would explain why the test circuit didn't work.
     
  7. Tigthwad

    Thread Starter Member

    Oct 27, 2009
    31
    1

    Adding:

    Code ( (Unknown Language)):
    1. #pragma config MCLRE = OFF, WDTE = OFF, CP = OFF, LVP = OFF, FOSC = INTOSCIO
    Did the trick. I wish I understood what it all meant...I get the Code Protection and Watchdog(kinda) and LVP part but I am not firm on the MCLRE and FOSC parts...especially the FOSC as I know I need that later for the delay routine.

    Now that the code works, what is the best(or easiest) way to delay for 55 seconds without losing too much time? My son is starting to get excited seeing the LEDs light up!
     
  8. thatoneguy

    AAC Fanatic!

    Feb 19, 2009
    6,357
    718
    There isn't a function for delay in the library functions. Generally, delays are created by running higher priority code. However, for your application, it seems there is a macro, found in the manual:

     
  9. Tigthwad

    Thread Starter Member

    Oct 27, 2009
    31
    1
    I am unsure how to execute a macro, unfortunately the reading I do doesn't make me feel smarter...

    This is what we have built for a delay. It allows us to pass in a time as an int (seconds * 2) and also has some options for getting out of the loop via button_b. The looptuner is used to try to get close to exact timing.

    We haven't yet included the relay switching portion but that is next.

    Code ( (Unknown Language)):
    1. void delay() {
    2.     int bigcounter = 0;
    3.     int counter = 0;
    4.     int looptuner = 19500;
    5.     for(bigcounter = 0; bigcounter < 6; bigcounter++)  //set total calue of bigcounter in seconds * 2 - This is our cancel period
    6.     {
    7.         for(counter = 0; counter < looptuner; counter++)     //approx .5 second delay
    8.             {
    9.               if (SW_B == BUTTON_ON) break;                 //if switch b is press we exit
    10.             }
    11.             //LED_B = ~LED_B;
    12.             if (SW_B == BUTTON_ON) break;                   //if switch b is press we exit
    13.             ;
    14.         for(bigcounter = 0; bigcounter < 30; bigcounter++)  //set total calue of bigcounter in seconds * 2
    15.         {
    16.             for(counter = 0; counter < looptuner; counter++)     //approx .5 second delay
    17.             {
    18.               if (SW_B == BUTTON_ON) break;                 //if switch b is press we exit
    19.             }
    20.             LED_B = ~LED_B;
    21.             if (SW_B == BUTTON_ON) break;                   //if switch b is press we exit
    22.             ;
    23.         }
    24.     }
    25. }
     
  10. thatoneguy

    AAC Fanatic!

    Feb 19, 2009
    6,357
    718
    For a 55 second time delay, I'd suggest interrupts, which will require you to read both the datasheet, the compiler help file, and there are MANY useful App Notes available from Microchip.

    As I stated earlier, using a delay() function simply wastes power.

    For an interrupt, you do the math to get the right prescaler for the clock you are using, then, when that clock counts down to zero, the interrupt() function (which you'll have to write) is called, which resets the counter, updates flags, and returns to program.


    Interrupts are a programmer's best friend, once you learn the usage.

    That way, with interrupts, the keypad scanning and display updating is done in real time. PICs run millions of operations per second, while humans can perceive about 100 visual changes per second, and input about 8 characters per second (both on the optimal case). The display update is extremely slow relative to humans, so having the interrupt check for timer, and the main loop checking input and do math, you end up with no "keyboard lag" which takes place when you are trying to change the display parameters at the same time the green light delay is being called.
     
  11. takao21203

    Distinguished Member

    Apr 28, 2012
    3,577
    463
    You don't have to use full interrupt functions (real interrupt).

    You can simply poll the timer interrupt flag which gets set anyway.

    I use this sometimes for serial port (USART), because the response is faster and it only requires one line.

    The 16F628 is comfortable it also has a 16bit timer (TIMER1).

    I don't really understand why people use these macros.

    Code ( (Unknown Language)):
    1. while(!TMR1IF);
    is all what's needed.

    And you need to reset each time:
    Code ( (Unknown Language)):
    1. TMR1IF=0;
    The TIMER1 works well in the MPLAB simulator no need to reflash each time.
     
  12. MMcLaren

    Well-Known Member

    Feb 14, 2010
    759
    116
    The XC manual does show a __delay_ms() function;

     
  13. t06afre

    AAC Fanatic!

    May 11, 2009
    5,939
    1,222
    You can use the __delay_ms(x) function in a loop. For the cancel function (SW2). You can say run a 25 msec loop 120 times and check if the SW2 is pressed. If pressed you simply using the break statement to exit from the loop. No need to over complicate things here. And it will be accurate enough. I guess if you loose a few 1/100 sec (in total) in this loop it will not count much
    How about the dad, I guess he was also some excited:D
     
  14. takao21203

    Distinguished Member

    Apr 28, 2012
    3,577
    463
    The usual solution is a 32 KHz crystal together with the TIMER1 or a RTC chip.

    It is also possible to derive it from 4 MHz, 8 MHz or the like, but that's more complicated.

    Normally if you want a 55 minutes timer, you want 55 minutes, and not 44 minutes and 50 seconds.

    You can use a calculator to see how many seconds that makes, but for simplicity sake, a seconds and minutes mechanism produces better code.

    Timers and stopwatches only become really interesting when they have a display. Then you can't use delay anyway.

    If the timer is working repeatedly day after day, and you don't use an exact timebase, it will drift slowly through the 24 hours schedule.

    The TIMER1 is not that difficult to use or to program.
     
  15. Tigthwad

    Thread Starter Member

    Oct 27, 2009
    31
    1
    Thanks for the information about interrupts. I knew from my reading that my method was not efficient. At this point we needed something that worked which we have thanks to all the help received thus far. Next we will try to understand how to change the process to be more reliable and precise by using the interrupts. For non-technical people (and 12 year olds with ADD) the datasheets can be quite daunting!

    My son is actually excited about learning programming (not just microchips) so this is a perfect project for him to understand that there are multiple ways to do things and some have distinct advantages over others. This means he needs to look for the best, not just the first, answer.

    Task list:
    Add relay to circuit and make sure it functions as intended
    find out what a prescaler is and how to compute it
    find out how an interrupt is incorporated and write them as needed
     
  16. Tigthwad

    Thread Starter Member

    Oct 27, 2009
    31
    1
    I need to do more reading as I don't understand how to work with TIMER1. The code lines you posted look simple enough but I would need to see them in context to understand what they are doing I think.


    I saw this multiple places but when I include this in the code it showed an error...I must not be including something required for it to work. It would be simpler than our loop that is based on just a counter for sure.

    If I can figure out how to make the __delay_ms(x) work in the code I will upgrade to that but for now the solution eludes me.

    I was excited mostly because I have been pulling my hair out and feeling like a moron for not being able to complete a simple "Hello World" type of program.

    Is a 32mhz crystal easier to work with than the included 4mhz in the chip? I have a 32 mhz crystal we could use if needed.

    In our case the timer is for 55 seconds only....just turning on a motor circuit and then turning it off again, all on demand so no scheduled off time required. A display would be cool but much more complex for sure.
     
  17. thatoneguy

    AAC Fanatic!

    Feb 19, 2009
    6,357
    718
    Crystals are more accurate than the internal oscillator, it depends if you want a delay of exactly 55.00 seconds (crystal) or somewhere between 54 and 56 seconds (Internal Oscillator). 4Mhz or 20Mhz crystals or oscillators require 3 parts (crystal) or one 4 pin part (oscillator) more on the PCB, close to the PIC. The faster Oscillators, 4M/20M, will give you a more accurate 55 seconds, since a 5% error at 4Mhz reduces a bit after prescaling, while the drift of a 32.768 kHz clock can be extreme if the temperature changes, resulting in RC Oscillator type timing accuracy.

    For what you are doing, it sounds like the internal Oscillator will be fine for the effect lite.
     
  18. MMcLaren

    Well-Known Member

    Feb 14, 2010
    759
    116
    When does LED1 get turned off?

    After pressing SW1 and turning on LED2 and waiting for 3 seconds, why would you need to turn on LED2 again when you activate the relay? Is this a typo?
     
  19. MMcLaren

    Well-Known Member

    Feb 14, 2010
    759
    116
    It works in my MPLAB 8.84 + XC8 environment...


    [​IMG]

    Code ( (Unknown Language)):
    1. /********************************************************************
    2.  *                                                                  *
    3.  *  Project: 12F1822 Delay Demo                                     *
    4.  *   Source: 12F1822 Delay Demo.c                                   *
    5.  *   Author: Mike McLaren, K8LH                                     *
    6.  *  (C)2013: Micro Application Consultants, All Rights Reserved     *
    7.  *     Date: 06-Feb-13                                              *
    8.  *                                                                  *
    9.  *  12F1822 Delay Demo                                              *
    10.  *                                                                  *
    11.  *                                                                  *
    12.  *      IDE: MPLAB 8.84 (tabs = 4)                                  *
    13.  *     Lang: Microchip XC8 v1.11                                    *
    14.  *                                                                  *
    15.  ********************************************************************/
    16.  
    17.    #include <xc.h>
    18.  
    19.    __CONFIG(FOSC_INTOSC & WDTE_OFF & MCLRE_OFF);
    20.    __CONFIG(LVP_OFF & PLLEN_OFF);
    21.  
    22.    #define _XTAL_FREQ 8000000
    23.  
    24.   /******************************************************************
    25.    *  function prototypes                                           *
    26.    ******************************************************************/
    27.   /******************************************************************
    28.    *  type definitions                                              *
    29.    ******************************************************************/
    30.   /******************************************************************
    31.    *  variables and constants                                       *
    32.    ******************************************************************/
    33.   /******************************************************************
    34.    *  low level drivers                                             *
    35.    ******************************************************************/
    36.   /******************************************************************
    37.    *  functions                                                     *
    38.    ******************************************************************/
    39.   /******************************************************************
    40.    *  main init                                                     *
    41.    ******************************************************************/
    42.  
    43.    void main()
    44.    { ANSELA = 0;                // make pins digital
    45.      TRISA = 1<<RA1;            // RA1 input, all others output
    46.      PORTA = 0;                 // all output latches low
    47.      OSCCON = 0b01110010;       // initialize 8-MHz INTOSC
    48.      while(!HFIOFS);            // wait until OSC stable
    49.  
    50.   /******************************************************************
    51.    *  main loop                                                     *
    52.    ******************************************************************/
    53.  
    54.      while(1)                   //
    55.      { __delay_ms(200);         //
    56.        PORTA ^= 0b00000001;     // toggle RA0 output
    57.      }                          //
    58.    }
    59.  
     
    Last edited: Feb 6, 2013
  20. t06afre

    AAC Fanatic!

    May 11, 2009
    5,939
    1,222
    Try this, it is something that your son can understand and maybe improve also ;) The other suggestions are indeed correct. But way over anything what is expected from a 12 year old boy. This may perhaps be cheating. But as I see it. If your son understand this. He has also learned something. Remember this is your sons science fair, not yours ;)
    Code ( (Unknown Language)):
    1. /************************
    2. * Description: LED Test with buttons
    3. * Turn on LED for x seconds
    4. * Pin Assignments:
    5. *   RB0 = Switch 1
    6. *    RB1 = Switch 2
    7. *    RB2 = LED1
    8. *    RB3 = LED2
    9. *    RB4 = Relay connection
    10.  **************************/
    11. #define _XTAL_FREQ 4000000
    12. #include<xc.h>
    13. #define LED_ON      1       // LED is connected cathode to ground
    14. #define LED_OFF     0
    15. #define RELAY_ON    1       //RELAY is connected to ground
    16. #define RELAY_OFF   0       //RELAY not connect to ground
    17. #define BUTTON_ON   0       // Button input is low when button pressed
    18. #define BUTTON_OFF  1       // (this is how a pull-up resistor button works)
    19. #define I_O_OUT     0       // standard TRIS definitions
    20. #define I_O_IN      1       // zero is 0ut, one is 1n
    21. #define SW_A        RB0     // switch A is on PORTB.0
    22. #define SW_B        RB1
    23. #define SW_A_TRIS   TRISB0  // switch B is on PORTB.1
    24. #define SW_B_TRIS   TRISB1
    25. #define LED_A       RB2     // LED A is on PORTB.2
    26. #define LED_B       RB3     // LED B is on PORTB.3
    27. #define RELAY       RB4     // RELAY is connected to ground
    28. #define LED_A_TRIS  TRISB2
    29. #define LED_B_TRIS  TRISB3
    30. #define RELAY TRISB4
    31. __CONFIG(FOSC_INTOSCIO & WDTE_OFF & PWRTE_ON & MCLRE_OFF & BOREN_OFF & LVP_OFF & CPD_OFF & CP_OFF);
    32. unsigned char i;
    33. unsigned char flag;
    34. void main(void)
    35. {
    36.   CMCON=0x07;
    37.   flag=0;
    38.   SW_A_TRIS  = I_O_IN;    // set up I/O pin directions
    39.   SW_B_TRIS  = I_O_IN;
    40.   LED_A_TRIS = I_O_OUT;
    41.   LED_B_TRIS = I_O_OUT;
    42.   LED_A=LED_ON;
    43.   LED_B=LED_OFF;
    44. OSCF=1;
    45. /*bit 3 OSCF: INTOSC Oscillator Frequency bit
    46. 1 = 4 MHz typical
    47. 0 = 48 kHz typical
    48. */
    49.   // now loop forever to sense buttons
    50.   while(1)
    51.   {
    52.       while(SW_A==1);
    53.       LED_B=LED_ON;
    54.       for(i=0;i<40;i++)
    55.         {
    56.           if (SW_B==0)
    57.           {
    58.               LED_B=LED_OFF;
    59.               flag=1;
    60.               break;
    61.           }
    62.           __delay_ms(75);
    63.           LED_B=!LED_B;
    64.          }
    65.        if(flag==0)
    66.        {
    67.           LED_B=LED_ON;
    68.           RELAY=RELAY_ON;
    69.           for(i=0;i<55;i++)
    70.           {
    71.               __delay_ms(1000);
    72.           }
    73.           RELAY=RELAY_OFF;            
    74.        }
    75.        LED_B=0;
    76.        flag=0;
    77.   }
    78. }//end main
     
Loading...