Arduino as cycle timer with LCD?

Discussion in 'The Projects Forum' started by GRNDPNDR, Apr 6, 2015.

  1. GRNDPNDR

    Thread Starter Member

    Mar 1, 2012
    435
    7
    I've got a "small" project I'd like to start working on, but before I do I thought I would check with some more knowledgeable people to see if and how it could be done.

    I'm in need of a cycle timer and I wanted to do the job with an arduino and an LCD.

    The cycle timer part is easy enough, I already have some code that should work, but I'm not a programmer and I wanted something a little more "fancy".

    I want to get an LCD display for the Arduino and be able to change the cycle times on the fly without having to reupload more code and essentially stopping the system while that's happening.

    Being that I'm an Arduino n00b, I'm hoping some of you kind folk could assist me with this project.... OR point me to a similar off the shelf cycle timer with an LCD display, as I haven't been able to locate one yet.
     
  2. elec_mech

    Senior Member

    Nov 12, 2008
    1,513
    193
    I'm not sure what a cycle timer is or what you're looking for exactly. If you're asking how to add an LCD to an Arduino with a minimum of programming and wiring, then I'd suggest a 1-wire serial LCD. Sparkfun sells a bunch here. eBay sells several varieties, but I'd avoid those as most are really I2C or SPI port expanders and still require a lot of programming to make work.
     
  3. GRNDPNDR

    Thread Starter Member

    Mar 1, 2012
    435
    7
    I guess I should have specified what a cycle timer is instead of assuming everyone knows. It's a small timer that will activate a relay for a set amount of time and leave it off for a set amount of time.... so like 10 secs on, 3 minutes off.
    http://www.amazon.com/CanaKit-UK670CY-Cyclic-Digital-Assembled/dp/B005UTBUDC

    I bought this to play around with, http://www.dfrobot.com/index.php?route=product/product&path=35_124&product_id=51

    so I'd like to slap that onto my arduino and program a cycle timer that will let me use the lcd shield to set on and off times without having to change the code, reupload and test the timing that way.
     
  4. elec_mech

    Senior Member

    Nov 12, 2008
    1,513
    193
    Okay, I think I understand now. So you've written a cycle timer code, but the only way to change and run it is by manually changing and uploading the code each time, correct? So you want to use the LCD shield and buttons to set the time, and start/stop the timer. Is this correct?

    I don't have much Arduino experience, but I've programmed microcontrollers for years, so I think I can help until someone smarter comes along. :)

    Can you post the cycle timer code you have thus far? Much easier to work with existing code than make it up from scratch.

    Also, let us know how you'd like this to work along with the timing range, for example:
    • Max time is 99 minutes, 59 seconds (can be anything really since the LCD can show up to 32 characters)
    • Button A is used to set minutes (count up from 0 to 99 then back to zero)
    • Button B is used to set seconds (count up from 0 to 99 then back to zero)
    • Button C is used to start the timer
    • Button D is used to stop the timer
    • Button E is used to reset the timer to zero
    Alternately, you could use buttons A-D to set each digit (button A - minutes tens place, button B - minutes ones place, etc.), then use the last button to start and stop the timer. To reset to zero, you could hold the start/stop button down for 2 seconds or more. Just some options.
     
  5. GRNDPNDR

    Thread Starter Member

    Mar 1, 2012
    435
    7
    100% ... except I didn't write the code, I found it online from someone who did a similar project and posted the code to use.

    I've had to clean my workspace as it got to be quite disastrous this last year, so I haven't had a chance to even test the code to see if it works.
    I've also put up a project on freelancer and have someone who has apparently already written the code, but I need to talk to him a bit more before I award that project.

    His timer is 0-999 secs. no separate minute or second adjustment, and I kind of like that idea now that you mentioned it, but the buttons I have on the shield are; Select, left, right, up, down, and reset, so I don't know if it could be done the way you suggest by having button A set minutes, button B set seconds, etc.... also the reset button is to reset the arduino, I don't think it can be used to reset the digits. I don't really know for sure because I haven't really explored the Arduinos capabilities and this is the first time I've actually had a use for it.
     
  6. elec_mech

    Senior Member

    Nov 12, 2008
    1,513
    193
    It's up to you. I think you can do this yourself, but I understand if you prefer to pay someone to do it for you. If you're going to pay someone however, I suggest you have them write the code to do exactly what you want. If they're just offering to sell you some code they've written that counts from 000 to 999 on an LCD, I'm pretty sure you can find a similar example online for free. This is what makes the Arduino so popular - there are tons of free codes already written for all kinds of projects. The trick is finding something similar to what you want to do and modifying it. C is not my forte, but with an example, I can reverse-engineer it. If you can post the code you found (or a link to it), that may be enough for me to work from.

    Keep in mind those are simply labels - up does not mean that button has to be up, etc. You'll tell the Arduino what you want each button to do. Select could be programmed to mean Start, right could programmed to mean Reset (the counter, not the Arduino), etc. Might be easier to print tiny labels that say what you want each button to do and tape them over the existing labels for ease of understanding.

    I didn't realize the board had a sixth dedicated reset button, but I didn't mean that specific button would be used for reset. The product page says there are five buttons available for use, so I just labeled them randomly A-E to better describe what you want to do.
     
  7. GRNDPNDR

    Thread Starter Member

    Mar 1, 2012
    435
    7
    His code pretty much does what I need for now, and my brief search didn't turn up anything I wanted to bother with but I didn't search very throughly.
    Here is his demonstration..

    Ya I figured the buttons could be programmed to do whatever I needed, but the product page is slightly different from what I have, I think mine is a slightly newer model? it has that 6th reset button and is lacking 3 rows of pins on the right side. Other than that it should be the same product.

    Here's the code I dug up online for a basic cycle timer that doesn't include the LCD shield. But for $50 I think I might just modify the guys code from freelancer.

    Code (Text):
    1.  
    2. unsigned char relayPin[12] = {4,5,6,7};//Remainining pins: (22,23,24,25,26,27,28,29}; // Define the led's pin
    3.  
    4. //initializes the function: Zone
    5. void Zone(unsigned long on, unsigned long off, int i);
    6.  
    7.  
    8. int mode[4]={LOW,LOW,LOW,LOW}; //Initilizes mode array to LOW (OFF) Mode
    9. unsigned long previousMillis[5]={0,0,0,0,0}; //initilizes previousMillis array
    10. //Conversions
    11. unsigned long Sec = 1000UL;
    12. unsigned long Min = 60000UL;
    13. //unsigned long Hour=60*Min;
    14.  
    15. //unsigned long daytime=43200000UL;
    16.  
    17. void setup()
    18. {
    19. //Initilizes the Pins as OUTPUT going through the for loop.
    20. int i;
    21. for(i = 0; i < 4; i++)
    22. {
    23. pinMode(relayPin[i],OUTPUT);
    24. digitalWrite(relayPin[i],mode[i]);
    25. }
    26. }
    27.  
    28. void loop(){
    29. //Zone(3*Min,15*Min,0);
    30. //Zone(6000UL,900000UL,1);
    31. Zone(4000UL,900000UL,2);
    32. }
    33.  
    34. /*
    35. Zone:
    36. Recieves: On time, Off time, and Pin Number(0-4)
    37. Note: millis() function calls time since arduino has been on, in milliseconds (ms)
    38. psuedocode:
    39. if (millis) - previlousMillis[i] is greater than (Off Time) and mode is equal to LOW
    40. then set previousMillis[i] to (millis), set pin mode to HIGH(ON),
    41. then it does it again for the ON time
    42. */
    43. void Zone(unsigned long on, unsigned long off, int i){
    44. if (millis() - previousMillis[i]>= off && mode[i]==LOW){
    45. previousMillis[i]=millis();
    46. mode[i]=HIGH;
    47. digitalWrite(relayPin[i],mode[i]);
    48. }
    49. if (millis()-previousMillis[i]>= on && mode[i] == HIGH){
    50. previousMillis[i]=millis();
    51. mode[i]=LOW;
    52. digitalWrite(relayPin[i],mode[i]);
    53. }
    54. }
    55.  
     
  8. GRNDPNDR

    Thread Starter Member

    Mar 1, 2012
    435
    7
    Here is the code from the guy I hired. I'm actually very happy with this and he's making a couple of changes to make it "perfect"

    I'm just not sure how to connect my relay because Pin 13 is used by the shield.... so I can change the pin I'm just not sure which pins I can use.

    Code (Text):
    1.  
    2. //Sample using LiquidCrystal library
    3. #include <LiquidCrystal.h>
    4. // select the pins used on the LCD panel
    5. LiquidCrystal lcd(8, 9, 4, 5, 6, 7);
    6.  
    7. // define some values used by the panel and buttons
    8. int lcd_key  = 0;
    9. int adc_key_in  = 0;
    10. #define btnRIGHT  0
    11. #define btnUP  1
    12. #define btnDOWN  2
    13. #define btnLEFT  3
    14. #define btnSELECT 4
    15. #define btnNONE  5
    16.  
    17. // define relay pin
    18. int RelayPin = 13;
    19.  
    20. int page = 1;
    21. boolean repeat = false;
    22. int on_time[] = {0,0,0,0};
    23. float on_time_value = 0;
    24. int off_time[] = {0,0,0,0};
    25. float off_time_value = 0;
    26. boolean hold = false;
    27. int cur_x = 15;
    28. int cur_y = 0;
    29. boolean toggle = 0;
    30. float count = 0;
    31.  
    32.  
    33. // read the buttons
    34. int read_LCD_buttons()
    35. {
    36. adc_key_in = analogRead(0);  // read the value from the sensor
    37. // my buttons when read are centered at these valies: 0, 144, 329, 504, 741
    38. // we add approx 50 to those values and check to see if we are close
    39. if (adc_key_in > 1000) return btnNONE; // We make this the 1st option for speed reasons since it will be the most likely result
    40. /*
    41. // For V1.1 us this threshold
    42. if (adc_key_in < 50)  return btnRIGHT;
    43. if (adc_key_in < 250)  return btnUP;
    44. if (adc_key_in < 450)  return btnDOWN;
    45. if (adc_key_in < 650)  return btnLEFT;
    46. if (adc_key_in < 850)  return btnSELECT;
    47. */
    48. // For V1.0 comment the other threshold and use the one below:
    49.  
    50. if (adc_key_in < 50)  return btnRIGHT;
    51. if (adc_key_in < 195)  return btnUP;
    52. if (adc_key_in < 380)  return btnDOWN;
    53. if (adc_key_in < 555)  return btnLEFT;
    54. if (adc_key_in < 790)  return btnSELECT;  
    55.  
    56.  
    57.  
    58. return btnNONE;  // when all others fail, return this...
    59. }
    60.  
    61. void setup()
    62. {
    63.   lcd.begin(16, 2);  // start the library
    64.   display_page(page);
    65.   pinMode(RelayPin, OUTPUT);
    66.   digitalWrite(RelayPin, LOW);
    67.  
    68. }
    69. void loop()
    70. {
    71. lcd_key = read_LCD_buttons();  // read the buttons
    72.  
    73. switch (lcd_key)  // depending on which button was pushed, we perform an action
    74. {
    75.   case btnRIGHT:
    76.   {
    77.   if (!hold)
    78.   {
    79.   if (page == 2)
    80.   {
    81.   cur_x++;
    82.   if (cur_x == 14)
    83.   {
    84.   cur_x = 15;
    85.   }
    86.   if (cur_x > 15)
    87.   {
    88.   if (cur_y == 0)
    89.   {
    90.   cur_y = 1;
    91.   }
    92.   else
    93.   {
    94.   cur_y = 0;
    95.   }  
    96.   cur_x = 11;
    97.   }
    98.   lcd.setCursor(cur_x,cur_y);
    99.   }
    100.   hold = true;
    101.   }
    102.   break;
    103.   }
    104.   case btnLEFT:
    105.   {
    106.   if (!hold)
    107.   {
    108.   if (page == 2)
    109.   {
    110.   cur_x--;
    111.   if (cur_x == 14)
    112.   {
    113.   cur_x = 13;
    114.   }
    115.   if (cur_x < 11)
    116.   {
    117.   if (cur_y == 0)
    118.   {
    119.   cur_y = 1;
    120.   }
    121.   else
    122.   {
    123.   cur_y = 0;
    124.   }
    125.   cur_x = 15;
    126.   }
    127.   lcd.setCursor(cur_x,cur_y);
    128.   }
    129.   hold = true;
    130.   }  
    131.  
    132.   break;
    133.   }
    134.   case btnUP:
    135.   {
    136.   if (!hold)
    137.   {
    138.   if (page == 2)
    139.   {
    140.   if (cur_y == 0) //on time
    141.   {
    142.   if (cur_x == 15)
    143.   {
    144.   if (on_time[3] == 0)
    145.   {
    146.   on_time[3] = 5;
    147.   }
    148.   else
    149.   {
    150.   on_time[3] = 0;
    151.   }  
    152.   }
    153.   else
    154.   {
    155.   on_time[cur_x-11]++;
    156.   if (on_time[cur_x-11] > 9)
    157.   {
    158.   on_time[cur_x-11] = 0;
    159.   }
    160.   }
    161.   }
    162.   else //off time
    163.   {
    164.   if (cur_x == 15)
    165.   {
    166.   if (off_time[3] == 0)
    167.   {
    168.   off_time[3] = 5;
    169.   }
    170.   else
    171.   {
    172.   off_time[3] = 0;
    173.   }  
    174.   }
    175.   else
    176.   {
    177.   off_time[cur_x-11]++;
    178.   if (off_time[cur_x-11] > 9)
    179.   {
    180.   off_time[cur_x-11] = 0;
    181.   }
    182.   }
    183.   }
    184.   display_page(2);
    185.   }
    186.   hold = true;
    187.   }
    188.   break;
    189.   }
    190.   case btnDOWN:
    191.   {
    192.   if (!hold)
    193.   {
    194.   if (page == 2)
    195.   {
    196.   if (cur_y == 0) //on time
    197.   {
    198.   if (cur_x == 15)
    199.   {
    200.   if (on_time[3] == 0)
    201.   {
    202.   on_time[3] = 5;
    203.   }
    204.   else
    205.   {
    206.   on_time[3] = 0;
    207.   }  
    208.   }
    209.   else
    210.   {
    211.   on_time[cur_x-11]--;
    212.   if (on_time[cur_x-11] < 0)
    213.   {
    214.   on_time[cur_x-11] = 9;
    215.   }
    216.   }
    217.   }
    218.   else //off time
    219.   {
    220.   if (cur_x == 15)
    221.   {
    222.   if (off_time[3] == 0)
    223.   {
    224.   off_time[3] = 5;
    225.   }
    226.   else
    227.   {
    228.   off_time[3] = 0;
    229.   }  
    230.   }
    231.   else
    232.   {
    233.   off_time[cur_x-11]--;
    234.   if (off_time[cur_x-11] < 0)
    235.   {
    236.   off_time[cur_x-11] = 9;
    237.   }
    238.   }
    239.   }
    240.   display_page(2);
    241.   }
    242.   hold = true;
    243.   }
    244.   break;
    245.   }
    246.   case btnSELECT:
    247.   {
    248.   if (!hold)
    249.   {
    250.   if (page == 1)
    251.   {
    252.   repeat = false;
    253.   page = 2;
    254.   lcd.clear();
    255.   }
    256.   else if (page == 2)
    257.   {
    258.   page = 3;
    259.   on_time_value = on_time[0]*100+on_time[1]*10+on_time[2]+on_time[3]*0.1;
    260.   off_time_value = off_time[0]*100+off_time[1]*10+off_time[2]+off_time[3]*0.1;
    261.   toggle = 0;
    262.   count = 0;
    263.   //set timer1 interrupt at 1Hz
    264.   TCCR1A = 0;// set entire TCCR1A register to 0
    265.   TCCR1B = 0;// same for TCCR1B
    266.   TCNT1  = 0;//initialize counter value to 0
    267.   // set compare match register for 2hz increments
    268.   OCR1A = 7812;// = (16*10^6) / (2*1024) - 1 (must be <65536)
    269.   // turn on CTC mode
    270.   TCCR1B |= (1 << WGM12);
    271.   // Set CS10 and CS12 bits for 1024 prescaler
    272.   TCCR1B |= (1 << CS12) | (1 << CS10);
    273.   // enable timer compare interrupt
    274.   TIMSK1 |= (1 << OCIE1A);
    275.   interrupts(); // enable all interrupts
    276.  
    277.   lcd.clear();
    278.   }
    279.   else if (page == 3)
    280.   {
    281.   page = 2;
    282.   digitalWrite(RelayPin,LOW);
    283.   noInterrupts(); // disable all interrupts
    284.  
    285.   lcd.clear();
    286.   }
    287.   display_page(page);
    288.   hold = true;
    289.   }
    290.   break;
    291.   }
    292.   case btnNONE:
    293.   {
    294.   hold = false;
    295.   break;
    296.   }
    297.  
    298. }
    299.  
    300. }
    301.  
    302. void display_page(int page)
    303. {
    304.   switch (page)  // depending on which button was pushed, we perform an action
    305.   {
    306.   case 1: //welcome screen
    307.   {
    308.   lcd.setCursor(0,0);
    309.   lcd.print("  Arduino  ");
    310.   lcd.setCursor(0,1);
    311.   lcd.print("  Cycle Timer  ");
    312.   repeat = true;
    313.   break;
    314.   }
    315.   case 2: //setting
    316.   {
    317.   lcd.setCursor(0,0);
    318.   lcd.print("On Time  ");
    319.   lcd.print(on_time[0]);
    320.   lcd.print(on_time[1]);
    321.   lcd.print(on_time[2]);
    322.   lcd.print(".");
    323.   lcd.print(on_time[3]);
    324.   lcd.setCursor(0,1);
    325.   lcd.print("Off Time  ");
    326.   lcd.print(off_time[0]);
    327.   lcd.print(off_time[1]);
    328.   lcd.print(off_time[2]);
    329.   lcd.print(".");
    330.   lcd.print(off_time[3]);
    331.   lcd.setCursor(cur_x,cur_y);
    332.   lcd.cursor();
    333.   lcd.blink();
    334.   repeat = true;
    335.   break;
    336.   }
    337.   case 3:  //run
    338.   {
    339.   lcd.noCursor();
    340.   lcd.noBlink();
    341.   lcd.setCursor(0,0);
    342.   if (toggle == false)
    343.   {
    344.   lcd.print(" ");
    345.   lcd.print("On=");
    346.   lcd.print(on_time_value,1);
    347.   lcd.print("  ");
    348.   }
    349.   else
    350.   {
    351.   lcd.print("*");
    352.   lcd.print("On=");
    353.   lcd.print("[");
    354.   lcd.print(count,1);
    355.   lcd.print("]  ");
    356.   }
    357.  
    358.   lcd.setCursor(0,1);
    359.   if (toggle == false)
    360.   {
    361.   lcd.print("*");
    362.   lcd.print("Off=");
    363.   lcd.print("[");
    364.   lcd.print(count,1);
    365.   lcd.print("]  ");
    366.   }
    367.   else
    368.   {
    369.   lcd.print(" ");
    370.   lcd.print("Off=");
    371.   lcd.print(off_time_value,1);
    372.   lcd.print("  ");
    373.   }
    374.  
    375.   break;  
    376.   }  
    377.   }
    378. }
    379.  
    380. ISR(TIMER1_COMPA_vect)
    381. {
    382.   if (toggle) // On
    383.   {
    384.   if (count >= on_time_value)
    385.   {
    386.   digitalWrite(RelayPin,LOW);
    387.   toggle = 0;
    388.   count = 0;
    389.   }
    390.   }
    391.   else // Off
    392.   {
    393.   if (count >= off_time_value)
    394.   {
    395.   digitalWrite(RelayPin,HIGH);
    396.   toggle = 1;
    397.   count = 0;
    398.   }
    399.   }
    400.   count = count + 0.5;
    401.   display_page(3);
    402. }
    403.  
     
  9. GRNDPNDR

    Thread Starter Member

    Mar 1, 2012
    435
    7
    I've got revised code now that changes a few things.
    1.) the timer now starts as soon as it's powered on instead of showing a welcome screen. In case of a power failure it will resume operation when power is restored without anyone having to reset the time.
    2.) when changing the time up it will set the next column to 1 when you reach 9 in the previous column.
    3.) when setting the time it will start with the ON cycle instead of starting with the OFF cycle.

    I'm very very happy with the work done. The guy was extremely professional and proficient, he was able to make the needed changes within a few mins and the timer works perfectly so far as I can see right now.

    This phase of the project is done at least. It would have taken me months to achieve this. $50 and it was done overnight :)
     
  10. elec_mech

    Senior Member

    Nov 12, 2008
    1,513
    193
    Cool beans, glad to hear he's customizing it to suit your needs.

    Might want to ask the other guy since he has a better idea which pins are being used and which free ones would work best. If you could put together a quick schematic of the connections thus far (even a cellphone picture of a napkin sketch), I can help further.

    What kind of relay is it? Is the coil voltage rated for 5VDC? Be sure to add a diode across the coils to help prevent back EMF from damaging the Arduino pin.
     
  11. GRNDPNDR

    Thread Starter Member

    Mar 1, 2012
    435
    7
    my bad, the pin isn't in use exactly, but the header on the bottom of the shield is plugged into it so I can't attach anything to it.... this shield is a little weird that way, I think I have the previous version which doesn't have sensor pins and doesn't have any headers on top of the shield.

    I think what I'll have to do is buy a different 3 pin header and a 5 pin header so I can utilize the pins I need to drive the relay.

    The relay I have right now I think is 5v coils, it's a little relay breakout board with a delay on relay, I'm just using this for testing and to play with.

    I will need to get a similar one, but without a delay. I'm only switching 24v
     
    Last edited: Apr 7, 2015
  12. GRNDPNDR

    Thread Starter Member

    Mar 1, 2012
    435
    7
    nevermind,thanks to the wiki I found out that there is a spot for those digital pins, I just need to solder a header onto it.
     
  13. txpenguin

    New Member

    Aug 24, 2015
    1
    0
    GRNDPNDR any chance you could provide the revised code? I'm very new to Arduino and am attempting a similar project for an Aquaponic garden. I'd really like to compare the two versions for educational purposes/sanity check.

    Much appreciated!
     
Loading...