To show stopwatch timing on LCD

Discussion in 'Embedded Systems and Microcontrollers' started by PicUser, Jun 15, 2011.

  1. PicUser

    Thread Starter New Member

    Jun 15, 2011
    5
    0
    Hi, i am a newbie in programming.

    I am working to start a timer0 and show it's timing on LCD. I would like to make the timing like a stopwatch.

    Please help me :( I have tried to write out and troubleshoot the coding for the past few days. Yet i got no result from it.

    The LCD is working out fine (i have tried working only on the LCD).

    Please advise me on my errors. Thank you so much.

    These are my coding:

    #include <p18f4620.h>
    #include <stdio.h>
    #include <delays.h>
    #include <init_testing.h>
    #include <timers.h>
    #include <init_timers.h>
    #pragma config LVP = OFF, PWRT = ON, WDT = OFF
    #pragma config PBADEN = OFF
    #pragma config DEBUG = OFF

    void delay_ms(unsigned int);
    void delay_20us(unsigned int);
    void functionSet(void);
    void entryMode(void);
    void displayOn(void);
    void displayClear(void);
    void sendChar(char c);
    void enable (void);
    void sendString(far rom char *str);
    void moveTo2nd(void);

    unsigned long int tick_count, hour2, minute2, second2, milisecond2;
    unsigned long int rec_hour, rec_minute, rec_second, rec_milisecond;
    unsigned char hour, minute, second, milisecond;
    char outchar; // character to send to the LCD
    char int_2_char (unsigned char int1);

    void main(void)
    {
    tick_count, hour2, minute2, second2, milisecond2 = 0;
    rec_hour, rec_minute, rec_second, rec_milisecond = 0;
    milisecond = 99;
    second = 60;
    minute = 60;
    hour = 10;

    // init timer0
    RCONbits.IPEN = 1; // Enable Priority Features
    INTCON2bits.TMR0IP = 1; // TMR0 Overflow Interrupt Priority bit = HIGH
    INTCONbits.TMR0IF = 0; // Clear timer0 interrupt flag
    INTCONbits.GIE = 1; // Enable global interrupt
    INTCONbits.PEIE = 0; // disables all low priority peripheral interrupts
    INTCONbits.TMR0IE = 1; // Enables the TMR0 overflow interrupt


    // init LCD
    TRISD = 0; // define Port D as output
    displayClear();
    Delay10TCYx(200); // delay for 200us
    functionSet();
    entryMode();
    displayOn();

    while(1);

    }

    #pragma code
    #pragma interrupt T0ISR // Timer0 -- interrupt service routine
    void T0ISR(void)
    {
    INTCONbits.GIE = 0; // disable global interrupt
    INTCONbits.TMR0IF = 0; // Clear timer0 interrupt flag
    INTCONbits.TMR0IE = 0; // Disables the TMR0 overflow interrupt

    for(tick_count = 0; tick_count<milisecond; tick_count++) //count til 98
    {
    milisecond2++;
    rec_milisecond = milisecond2; // recorded

    if (rec_milisecond >= 99) // 1second is up
    {
    tick_count = 0; // reset
    milisecond2 = 0;
    for(tick_count = 0; tick_count<second; tick_count++) //count til 59
    {
    second2++;
    rec_second = second2; // recorded

    if (rec_second >= 59) // 1minute is up
    {
    tick_count = 0; // reset
    second2 = 0;

    for(tick_count = 0; tick_count<minute; tick_count++) // count til 59
    {
    minute2++;
    rec_minute = minute2; //recorded

    if (rec_minute >= 59) // 1hour is up
    {
    tick_count = 0; // reset
    minute2 = 0;

    for(tick_count = 0; tick_count<hour; tick_count++) // count til 9
    {
    hour2++;
    rec_hour = hour2; // recorded
    if (rec_hour >= 9)
    {
    tick_count = 0; // reset
    hour2 = 0;
    }
    }

    }
    }
    }
    }
    }

    // send "time = mm:ss" to LCD display
    sendString(" Lap 1");
    moveTo2nd();
    sendChar('T');
    sendChar('i');
    sendChar('m');
    sendChar('e');
    sendChar(' ');
    sendChar('=');
    sendChar(' ');

    outchar = int_2_char (rec_minute);
    sendChar(outchar);
    sendChar(':');
    outchar = int_2_char (rec_second);
    sendChar(outchar);
    sendChar('.');
    outchar = int_2_char (rec_milisecond);
    sendChar(outchar);
    }

    return;
    }

    // function to convert unsigned char to char (for display)
    char int_2_char (unsigned char int1)
    {
    char char1;
    switch (int1)
    {
    case 0 : char1 = '0' ; break;
    case 1 : char1 = '1' ; break;
    case 2 : char1 = '2' ; break;
    case 3 : char1 = '3' ; break;
    case 4 : char1 = '4' ; break;
    case 5 : char1 = '5' ; break;
    case 6 : char1 = '6' ; break;
    case 7 : char1 = '7' ; break;
    case 8 : char1 = '8' ; break;
    case 9 : char1 = '9' ; break;
    default : char1 = '?' ;
    }
    return(char1);
    }

    void functionSet(void) // 0010 1010 - 4 bit mode, 2 lines, 5 X 8.
    {
    RS= 0;
    DB7 = 0; // Upper nibbles
    DB6 = 0;
    DB5 = 1;
    DB4 = 0;
    enable();
    Delay10TCYx(200);
    enable();
    DB7 = 1; // Lower nibbles
    enable();
    Delay10TCYx(200);
    }
    void enable(void)
    {
    E = 1;
    Delay10TCYx(1);
    E = 0;
    }
    void entryMode(void) //0000 0110, increment with no shift
    {
    RS = 0;
    DB7 = 0; // Upper nibbles
    DB6 = 0;
    DB5 = 0;
    DB4 = 0;
    enable();
    DB6 = 1; // Lower nibbles
    DB5 = 1;
    enable();
    Delay10TCYx(80);
    }
    void displayOn(void) // display on, cursor off, blink off
    {
    RS = 0;
    DB7 = 0; // Upper nibbles
    DB6 = 0;
    DB5 = 0;
    DB4 = 0;
    enable();
    DB7 = 1; // Lower nibbles
    DB6 = 1;
    DB5 = 0;
    DB4 = 0;
    enable();
    Delay10TCYx(80);
    }
    void displayClear(void) // display clear
    {
    RS = 0;
    DB7 = 0; // Upper nibbles
    DB6 = 0;
    DB5 = 0;
    DB4 = 0;
    enable();
    DB7 = 0; // Lower nibbles
    DB6 = 0;
    DB5 = 0;
    DB4 = 1;
    enable();
    Delay10TCYx(80);
    }
    void sendString(far rom char *str)
    {
    int index = 0;
    while (str[index] != '\0')
    {
    sendChar(str[index]);
    index++;
    }
    }
    void sendChar(char c) // send character to LCD
    {
    RS = 1;
    DB7 = (c >> 7) & 1;
    DB6 = (c >> 6) & 1;
    DB5 = (c >> 5) & 1;
    DB4 = (c >> 4) & 1;
    enable();
    DB7 = (c >> 3) & 1;
    DB6 = (c >> 2) & 1;
    DB5 = (c >> 1) & 1;
    DB4 = (c & 1);
    enable();
    Delay10TCYx(80);
    }
    void moveTo2nd(void) //1100 0000 - move cursor to 2nd line
    {
    RS = 0;
    DB7 = 1; // Upper nibbles
    DB6 = 1;
    DB5 = 0;
    DB4 = 0;
    enable();
    DB7 = 0; // Lowr nibbles
    DB6 = 0;
    enable();
    Delay10TCYx(80);
    }
     
  2. DumboFixer

    Active Member

    Feb 10, 2009
    219
    34
    Your biggest mistake is that there's far too much code in your interrupt routine. The interrrupt handler needs to be very short - use it to increment a counter and to reset the interrupt ready for the next one.

    The sending of data to the LCD should definately not be done in the ISR.

    When including code for the form you should use the CODE tag (#)
     
  3. PicUser

    Thread Starter New Member

    Jun 15, 2011
    5
    0
    Hi DumboFixer, thanks for your reply. I will do that amendment.
    May i ask if my counting algorithm is correct?
    I would like to count every 98ms = 1s, every 59s will be 1 minute.

    Please advise.

    Thanks
     
  4. PicUser

    Thread Starter New Member

    Jun 15, 2011
    5
    0
    I am able to show something on the LCD :) but the LCD shows
    " Lap 1"
    " Time = ?:?.?"

    It is not counting, i do not think it has been to the ISR.
    I have set the timer0 to prescale 1:2 and using 16bits. If i did not calculate wrongly, it should go to ISR every 131.07ms ??

    Code ( (Unknown Language)):
    1.  
    2. void main(void)
    3. {
    4.  
    5.  // init timer0
    6.  
    7.  T0CON = 0x10000000;       // timer0 on, Prescale 1:2
    8.  RCONbits.IPEN = 1;              // Enable Priority Features
    9.  INTCON2bits.TMR0IP = 1;         // TMR0 Overflow Interrupt Priority bit = HIGH
    10.     INTCONbits.TMR0IF = 0;          // Clear timer0 interrupt flag
    11.     INTCONbits.GIE = 1;             // Enable global interrupt
    12.     INTCONbits.PEIE = 0;            // disables all low priority peripheral interrupts
    13.     INTCONbits.TMR0IE = 1;          // Enables the TMR0 overflow interrupt
    14.  
    15.  
    16.  // init LCD
    17.  TRISD = 0;      // define Port D as output  
    18.  displayClear();  
    19.  Delay10TCYx(200);    // delay for 200us
    20.  functionSet();
    21.    entryMode();
    22.  displayOn();
    23.  
    24.  while(1)
    25.  {
    26.   // send "time = mm:ss" to LCD display
    27.   sendString("   Lap 1");
    28.     moveTo2nd();
    29.   sendString("   Time = ");
    30.   outchar = int_2_char (rec_minute);
    31.   sendChar(outchar);
    32.   sendChar(':');
    33.   outchar = int_2_char (rec_second);
    34.   sendChar(outchar);
    35.   sendChar('.');
    36.   outchar = int_2_char (rec_milisecond);
    37.   sendChar(outchar);
    38.  }
    39.  
    40. }
    41.  
    42. #pragma code
    43. #pragma interrupt T0ISR        // Timer0 -- interrupt service routine
    44. void T0ISR(void)
    45. {
    46.      
    47.  INTCONbits.GIE = 0;             // disable global interrupt    
    48.     INTCONbits.TMR0IF = 0;          // Clear timer0 interrupt flag  
    49.     INTCONbits.TMR0IE = 0;          // Disables the TMR0 overflow interrupt
    50.  milisecond = 99;
    51.  second = 60;
    52.  minute = 60;
    53.  
    54.  
    55.   for(milisecond_count = 0; milisecond_count<milisecond; milisecond_count++)   //count til 98
    56.   {  
    57.      rec_milisecond = milisecond_count;    
    58.  
    59.    if (rec_milisecond >= 99)      // 1second is up
    60.    {
    61.     milisecond_count = 0;             // reset
    62.  
    63.     for(second_count = 0; second_count<second; second_count++)  //count til 59
    64.      {
    65.         rec_second = second_count;    // recorded
    66.  
    67.      if (rec_second >= 59)          // 1minute is up
    68.          {
    69.       second_count = 0;                // reset
    70.            
    71.       for(minute_count = 0; minute_count<minute; minute_count++)  // count til 59
    72.        {
    73.              rec_minute = minute;    //recorded
    74.        
    75.        if (rec_minute >= 59)          // 1hour is up
    76.            {
    77.         minute_count = 0;                // reset
    78.              
    79.           }
    80.       }
    81.      }
    82.     }
    83.  
    84.          
    85.   }
    86.  }
    87.  
    88. }
    89.  
     
  5. PicUser

    Thread Starter New Member

    Jun 15, 2011
    5
    0
    Hi, i have did something on to my code.
    This time the lcd flickered in a fast speed which i was not able to determine what it was showing and then it stopped at this result "0:000:000:000"

    Can someone please advise what is my mistake?
    And what is the solution to it?
    I am going to be nuts.........
    Please advise :(

    Code ( (Unknown Language)):
    1.  
    2. #include <p18f4620.h>
    3. #include <stdio.h>
    4. #include <delays.h>
    5. #include <init_testing.h>
    6. #include <timers.h>
    7. #include <init_timers.h>
    8.  
    9. #pragma config LVP = OFF, PWRT = ON, WDT = OFF
    10. #pragma config PBADEN = OFF
    11. #pragma config DEBUG = OFF
    12. #define pulse 16036
    13.  
    14. void delay_ms(unsigned int);
    15. void functionSet(void);
    16. void entryMode(void);
    17. void displayOn(void);
    18. void displayClear(void);
    19. void sendChar(char c);
    20. void enable (void);
    21. void sendString(far rom char *str);
    22. void moveTo2nd(void);
    23. void timer_init(void);
    24.  
    25. unsigned char minute, second;
    26. unsigned int milisecond;
    27. char outchar; //    character to send to the LCD
    28. char int_2_char (unsigned char int1);
    29.  
    30. void main(void)
    31. {
    32.  int i;
    33.  
    34.  timer_init();
    35.  milisecond = 0;
    36.  second = 0;
    37.  minute = 0;
    38.  
    39.  // init LCD
    40.  TRISD = 0;      // define Port D as output  
    41.  displayClear();  
    42.  Delay10TCYx(200);    // delay for 200us
    43.  functionSet();
    44.    entryMode();
    45.  displayOn();
    46.  
    47.  // send "time = mm:ss" to LCD display
    48.  sendString("   Lap 1");
    49.    moveTo2nd();
    50.  sendString("Time =     ");
    51.  
    52.  for(;;)
    53.  {
    54.    
    55.   outchar = int_2_char (minute);
    56.   sendChar(outchar);
    57.  
    58.   sendChar(':');
    59.  
    60.   outchar = int_2_char (second);
    61.   sendChar(outchar);
    62.  
    63.   sendChar('.');
    64.  
    65.   outchar = int_2_char (milisecond);
    66.    sendChar(outchar);
    67.  }
    68.  
    69. }
    70.  
    71. #pragma code
    72. #pragma interrupt T0ISR        // Timer0 -- interrupt service routine
    73. void T0ISR(void)
    74. {
    75.  if(INTCONbits.TMR0IF==1)
    76.  {      
    77.      INTCONbits.TMR0IF = 0;          // Clear timer0 interrupt flag  
    78.   milisecond++;
    79.   if(milisecond>=pulse)   // count til 98ms
    80.   {
    81.    milisecond = 0;
    82.    second++;
    83.   }
    84.   if(second>=60)     // count til 59s
    85.   {
    86.    second = 0;
    87.    minute++;
    88.   }
    89.  
    90.   }  
    91. }
    92.  
    93. void timer_init(void)
    94. {
    95.  OpenTimer0( TIMER_INT_OFF &
    96.     T0_16BIT &
    97.     T0_SOURCE_INT &
    98.     T0_PS_1_2 );
    99.  
    100.  RCONbits.IPEN = 1;              // Enable Priority Features
    101.  INTCON2bits.TMR0IP = 1;         // TMR0 Overflow Interrupt Priority bit = HIGH
    102.  INTCONbits.TMR0IF = 0;          // Clear timer0 interrupt flag
    103.  INTCONbits.GIE = 1;             // Enable global interrupt
    104.  INTCONbits.PEIE = 1;            // Enables all low priority peripheral interrupts
    105.  INTCONbits.TMR0IE = 1;          // Enables the TMR0 overflow interrupt
    106.  TMR0L = 0;
    107.  TMR0H = 0;
    108. }
    109.  
    110.  
    111. // function to convert unsigned char to char (for display)
    112. char int_2_char (unsigned char int1)
    113. {
    114.  char char1;
    115.  switch (int1)
    116.  {
    117.  case 0 : char1 = '0' ; break;
    118.  case 1 : char1 = '1' ; break;
    119.  case 2 : char1 = '2' ; break;
    120.  case 3 : char1 = '3' ; break;
    121.  case 4 : char1 = '4' ; break;
    122.  case 5 : char1 = '5' ; break;
    123.  case 6 : char1 = '6' ; break;
    124.  case 7 : char1 = '7' ; break;
    125.  case 8 : char1 = '8' ; break;
    126.  case 9 : char1 = '9' ; break;
    127.   default : char1 = '?' ;
    128.  }
    129.  return(char1);
    130. }
    131.  
    132. void functionSet(void)   // 0010 1010 - 4 bit mode, 2 lines, 5 X 8.
    133. {
    134.   RS= 0;
    135.   DB7 = 0;      // Upper nibbles
    136.   DB6 = 0;
    137.   DB5 = 1;
    138.   DB4 = 0;
    139.   enable();
    140.   Delay10TCYx(200);
    141.   enable();
    142.   DB7 = 1;      // Lower nibbles
    143.   enable();
    144.   Delay10TCYx(200);
    145. }
    146.  
    147. void enable(void)
    148. {
    149.   E = 1;
    150.   Delay10TCYx(1);
    151.   E = 0;
    152. }
    153.  
    154. void entryMode(void)    //0000 0110, increment with no shift
    155. {
    156.   RS = 0;
    157.   DB7 = 0;      // Upper nibbles
    158.   DB6 = 0;
    159.   DB5 = 0;
    160.   DB4 = 0;
    161.   enable();
    162.   DB6 = 1;      // Lower nibbles
    163.   DB5 = 1;
    164.   enable();
    165.   Delay10TCYx(80);
    166. }
    167.  
    168. void displayOn(void)      // display on, cursor off, blink off
    169. {
    170.   RS = 0;
    171.   DB7 = 0;      // Upper nibbles
    172.   DB6 = 0;
    173.   DB5 = 0;
    174.   DB4 = 0;
    175.   enable();
    176.   DB7 = 1;      // Lower nibbles
    177.   DB6 = 1;
    178.   DB5 = 0;
    179.   DB4 = 0;
    180.   enable();
    181.   Delay10TCYx(80);
    182. }
    183.  
    184. void displayClear(void)      // display clear
    185. {
    186.   RS = 0;
    187.   DB7 = 0;      // Upper nibbles
    188.   DB6 = 0;
    189.   DB5 = 0;
    190.   DB4 = 0;
    191.   enable();
    192.   DB7 = 0;      // Lower nibbles
    193.   DB6 = 0;
    194.   DB5 = 0;
    195.   DB4 = 1;
    196.   enable();
    197.   Delay10TCYx(80);
    198. }
    199.  
    200. void sendString(far rom char *str)
    201. {
    202.   int index = 0;
    203.   while (str[index] != '\0')
    204.   {
    205.      sendChar(str[index]);
    206.      index++;
    207.   }
    208. }
    209.  
    210. void sendChar(char c)                // send character to LCD
    211. {
    212.   RS = 1;
    213.   DB7 = (c >> 7) & 1;
    214.   DB6 = (c >> 6) & 1;
    215.   DB5 = (c >> 5) & 1;
    216.   DB4 = (c >> 4) & 1;
    217.   enable();
    218.   DB7 = (c >> 3) & 1;
    219.   DB6 = (c >> 2) & 1;
    220.   DB5 = (c >> 1) & 1;
    221.   DB4 = (c & 1);
    222.   enable();
    223.   Delay10TCYx(80);
    224. }
    225.  
    226. void moveTo2nd(void)       //1100 0000 - move cursor to 2nd line
    227. {
    228.   RS =  0;
    229.   DB7 = 1;      // Upper nibbles
    230.   DB6 = 1;
    231.   DB5 = 0;
    232.   DB4 = 0;
    233.   enable();
    234.   DB7 = 0;      // Lowr nibbles
    235.   DB6 = 0;
    236.   enable();
    237.    Delay10TCYx(80);
    238. }
    239.  
    240. void delay_ms(unsigned int duration) // delay in miliseconds for 4.0MHZ crystal
    241. {
    242.  unsigned int i;
    243.  for(;duration!=0;duration--)
    244.  {
    245.   for(i=0;i<=50;i++)
    246.   {
    247.    _asm
    248.     nop
    249.     nop
    250.     nop
    251.    _endasm
    252.   }
    253.   _asm
    254.    nop
    255.    nop
    256.   _endasm
    257.  }
    258. }
    259.  
    260.  
     
  6. PicUser

    Thread Starter New Member

    Jun 15, 2011
    5
    0
    Can someone please please advise if the method of calculation is correct.

    As i would need 98ms to become 1 second, so the number of ticks which i need is (98*1000) / 2 = 49000 ticks
    then timer0 is able to support 16 bits so 2 power of 16bits is 65536.

    use 65536 - 49000 = 16536 ticks

    I will use 16536 ticks as my 98ms.

    I found this calculation method from 1 of PIC tutorial.
     
  7. THE_RB

    AAC Fanatic!

    Feb 11, 2008
    5,435
    1,305
    I think your basic method os very flawed and you should use a different method!

    If you use a 10MHz xtal in PLL mode that means your PIC 18F timers will run at 10 MIPS.

    So each timer "tick" is 0.1uS.

    Then use TMR2 prescaled 4:1 with a PR2 value of (250-1) so your TMR2 interrupt will occur at exactly 1000 ticks, which is ALWAYS at exactly 100uS (or 0.1mS).

    Then in your interrupt you can just add 0.1mS to a counter every interrupt, and use that counter to generate all the times exactly.
     
Loading...