Help Me With MiKroC Code

Discussion in 'Embedded Systems and Microcontrollers' started by kirayamato_143, Oct 23, 2011.

  1. kirayamato_143

    Thread Starter Member

    Jan 23, 2011
    59
    0
    HI can anybody help me understand some of this code which i dont get,, i qouted the part which for me needs explanation, but im still in the process of understanding all of this its for our project,,please help me

    Code ( (Unknown Language)):
    1.  
    2. /*
    3.  * Project name: Programmable Digital Timer
    4.  * Copyright:
    5.      (c) Rajendra Bhatt, 2010.
    6.      MCU:             PIC16F628A
    7.      Oscillator:      XT, 4.0 MHz
    8. */
    9.  
    10. // LCD module connections
    11.  sbit LCD_RS at RA0_bit;
    12.  sbit LCD_EN at RA1_bit;
    13.  sbit LCD_D4 at RB4_bit;
    14.  sbit LCD_D5 at RB5_bit;
    15.  sbit LCD_D6 at RB6_bit;
    16.  sbit LCD_D7 at RB7_bit;
    17.  sbit LCD_RS_Direction at TRISA0_bit;
    18.  sbit LCD_EN_Direction at TRISA1_bit;
    19.  sbit LCD_D4_Direction at TRISB4_bit;
    20.  sbit LCD_D5_Direction at TRISB5_bit;
    21.  sbit LCD_D6_Direction at TRISB6_bit;
    22.  sbit LCD_D7_Direction at TRISB7_bit;
    23. // End LCD module connections
    24.  
    25.  sbit MODE at RA2_bit;
    26.  sbit SELECT at RA3_bit;
    27.  sbit ENTER at RA4_bit;
    28.  sbit START at RB0_bit;
    29.  sbit RelaySW at RB3_bit;
    30.  
    31. // Define Messages
    32.  char MSG1[] = "Device is ";
    33.  char MSG2[] = "OFF";
    34.  char MSG3[] = "ON ";
    35.  char MSG4[] = "HH:MM";
    36.  
    37.  unsigned short HHMM_Pos[] = {6, 7, 8, 9, 10};
    38.  unsigned short ON_Time[] = {0, 0, 10, 0, 0}; // 10 + 48 is :
    39.  unsigned short OFF_Time[] = {0, 0, 10, 0, 0};
    40.  
    41.  unsigned short Mode_Select = 0 ; // 0:ON, 1:OFF
    42.  unsigned short i, j, k, Timer_On, Get_Input, Cur_Pos, Cur_On;
    43.  unsigned short temp, refresh, Num, HalfSec, Blink, ChangeMin=0;
    44.  unsigned short OFF_HH, OFF_MM, ON_HH, ON_MM;
    45.  
    46.  void Disp_First_Row(){
    47.   Lcd_Out(1,1, MSG1);
    48.   if (RelaySW == 0) Lcd_Out(1,11, MSG2);
    49.   if (RelaySW == 1) Lcd_Out(1,11, MSG3);
    50.  }
    51.  
    52.  void Disp_Char(unsigned short col, unsigned short chr){
    53.   Lcd_Chr(2, col, chr+48);
    54.  }
    55.  
    56. " void Disp_Time(){
    57.  
    58.    for(i=0; i<5; i++){
    59.       if(!Mode_Select){
    60.        Lcd_Out(2,1, MSG2);
    61.        Disp_Char(HHMM_Pos[i],OFF_Time[i]);
    62.       }
    63.       if(Mode_Select){
    64.        Lcd_Out(2,1, MSG3);
    65.        Disp_Char(HHMM_Pos[i],ON_Time[i]);
    66.  "     }
    67.    }
    68.  }
    69.  
    70.  void play_sound(){
    71.   Sound_Play(2500, 500);
    72.  }
    73.  
    74.  void debounce(){
    75.   Delay_ms(250);
    76.  }
    77.  
    78.  void cursor_left(){
    79.    for(j=0; j<5; j++){
    80.       Lcd_Cmd(_LCD_MOVE_CURSOR_LEFT);
    81.    }
    82.  }
    83.  
    84.  void disable_timer(){
    85.   INTCON = 0x00;
    86.   RelaySW = 0;
    87.   INTCON.T0IF = 0;
    88.   Timer_On = 0;
    89.   Blink = 0xff;
    90.   Mode_Select = 0;
    91.   Disp_First_Row();
    92.   Disp_Time();
    93.   play_sound();
    94.  }
    95.  
    96.  
    97.  void interrupt() {
    98.   Num ++;           // Interrupt causes Num to be incremented by 1
    99.   if(Num == 9) {
    100.    HalfSec ++;      // Increase sec
    101.    Num = 0;
    102.    Blink = ~Blink;
    103.    if (HalfSec == 120){
    104.     HalfSec = 0;
    105.     ChangeMin = 1;
    106.    }
    107.   }
    108.   TMR0 = 39;        // TMR0 returns to its initial value
    109.   INTCON.T0IF = 0;  // Bit T0IF is cleared so that the interrupt could reoccur
    110. }
    111.  
    112. void main() {
    113.   CMCON = 7;           // Disable Comparators
    114.   TRISA = 0b00111100;
    115.   TRISB = 0b00000001;
    116.   Sound_Init(&PORTB,2); // Initialize Buzzer o/p pin
    117.   RelaySW = 0;
    118.   Timer_On = 0;
    119.   Get_Input = 0;
    120.   Cur_Pos = 0;
    121.   Cur_On = 0;
    122.   refresh = 0;
    123.   Num = 0;
    124.   HalfSec = 0;
    125.  
    126.   Lcd_Init();                // Initialize LCD
    127.   Lcd_Cmd(_LCD_CLEAR);       // Clear display
    128.   Lcd_Cmd(_LCD_CURSOR_OFF);  // Cursor off
    129.   Lcd_Out(1,1, "Copyright @");
    130.   Lcd_Out(2,1, "Embedded-Lab.com");
    131.   i=0;
    132.   while(i<4){
    133.    debounce();
    134.    i ++;
    135.   }
    136.   Lcd_Cmd(_LCD_CLEAR);
    137.   Disp_First_Row();
    138.   Lcd_Out(2,4,"-");
    139.   Lcd_Out(2,12, MSG4);
    140.   Disp_Time();
    141.  
    142.   do {
    143.    if(!MODE && !Timer_On){
    144.     debounce();
    145.     if(!Get_Input){
    146.      Mode_Select = ~Mode_Select;
    147.      Disp_Time();
    148.     }
    149.     if(Get_Input){
    150.      if(!Mode_Select){
    151.       OFF_time[Cur_Pos] = OFF_time[Cur_Pos]+1;
    152.       temp = OFF_time[Cur_Pos];
    153.       switch (Cur_Pos){
    154.        case 0: if(temp > 9) OFF_time[Cur_Pos]=0;
    155.                break;
    156.        case 1: if(temp > 9) OFF_time[Cur_Pos]=0;
    157.                break;
    158.        case 3: if(temp > 5) OFF_time[Cur_Pos]=0;
    159.                break;
    160.        case 4: if(temp > 9) OFF_time[Cur_Pos]=0;
    161.                break;
    162.       }
    163.       Disp_Char(6+Cur_Pos, OFF_time[Cur_Pos]);
    164.  
    165.      }
    166.  
    167.      if(Mode_Select){
    168.       ON_time[Cur_Pos] ++;
    169.       temp = ON_time[Cur_Pos];
    170.       switch(Cur_Pos){
    171.  
    172.        case 0: if(temp > 9) ON_time[Cur_Pos]=0;
    173.                break;
    174.        case 1: if(temp > 9) ON_time[Cur_Pos]=0;
    175.                break;
    176.        case 3: if(temp > 5) ON_time[Cur_Pos]=0;
    177.                break;
    178.        case 4: if(temp > 9) ON_time[Cur_Pos]=0;
    179.                break;
    180.       }
    181.       Disp_Char(6+Cur_Pos, ON_time[Cur_Pos]);
    182.      }
    183.      Lcd_Cmd(_LCD_MOVE_CURSOR_LEFT);
    184.     }
    185.    }   // END if(!MODE)
    186.  
    187.    if(!SELECT && !Timer_On){
    188.      debounce();
    189.      Get_Input = 1;
    190.  
    191.      if(Cur_On) {
    192.        Cur_Pos ++;
    193.        if (Cur_Pos == 2) {
    194.          Lcd_Cmd(_LCD_MOVE_CURSOR_RIGHT);
    195.          Cur_Pos ++;
    196.        }
    197.        if(Cur_Pos > 4) {
    198.          Lcd_Cmd(_LCD_MOVE_CURSOR_RIGHT);
    199.          Cur_Pos = 0;
    200.          cursor_left();
    201.        }
    202.        else Lcd_Cmd(_LCD_MOVE_CURSOR_RIGHT);
    203.      }
    204.  
    205.      if(!Cur_On) {
    206.        Cur_On = 1;
    207.        cursor_left();
    208.        Lcd_Cmd(_LCD_UNDERLINE_ON);
    209.      }
    210.    }
    211.  
    212.    if(!ENTER && Get_Input){
    213.     debounce();
    214.     Get_Input = 0;
    215.     Cur_On = 0;
    216.     Cur_Pos = 0;
    217.     Disp_Time();
    218.     Lcd_Cmd(_LCD_CURSOR_OFF);  // Cursor off
    219.    }
    220.  
    221.    if (!START && !Get_Input){
    222.     debounce();
    223.     switch(Timer_On){
    224.     case 0: play_sound();
    225.             Timer_On = 1;
    226.             OPTION_REG = 0x07; // Prescaler (1:256) is assigned to the timer TMR0
    227.             TMR0 = 39;          // Timer T0 counts from 39 to 255
    228.             INTCON = 0xA0;     // Enable interrupt TMR0 and Global Interrupts
    229.             INTCON.T0IF = 0;
    230.             Mode_Select = 0;
    231.             Blink = 0;
    232.             Disp_Time();
    233.             break;
    234.     case 1: disable_timer();
    235.             break;
    236.     }
    237.    }
    238.  
    239.    if(Timer_On){
    240.     OFF_HH = OFF_Time[0]*10 + OFF_Time[1];
    241.     OFF_MM = OFF_Time[3]*10 + OFF_Time[4];
    242.     ON_HH = ON_Time[0]*10 + ON_Time[1];
    243.     ON_MM = ON_Time[3]*10 + ON_Time[4];
    244.     switch(Blink){
    245.      case 0: Lcd_Chr(2,8,' ');
    246.              break;
    247.      case 255: Lcd_Chr(2,8,':');
    248.              break;
    249.     }
    250.  
    251.     if(!OFF_HH && !OFF_MM &&!RelaySW){
    252.      if(ON_HH || ON_MM){
    253.       RelaySW = 1;
    254.       Mode_Select = 0xff;
    255.       Disp_First_Row();
    256.       Disp_Time();
    257.       play_sound();
    258.      }
    259.      else {
    260.       disable_timer();
    261.      }
    262.     }
    263.  
    264.     if(!ON_HH && !ON_MM && RelaySW){
    265.      disable_timer();
    266.      play_sound();
    267.     }
    268.  
    269.     if(ChangeMin) {
    270.      switch(Mode_Select){
    271.       case 0: if(OFF_MM == 0 && OFF_HH>0){
    272.                OFF_MM = 59;
    273.                OFF_HH -- ;
    274.               }
    275.               else if (OFF_MM >>0) OFF_MM --;
    276.               OFF_Time[0] = OFF_HH/10;
    277.               OFF_Time[1] = OFF_HH%10;
    278.               OFF_Time[3] = OFF_MM/10;
    279.               OFF_Time[4] = OFF_MM%10;
    280.               break;
    281.  
    282.       case 255: if(ON_MM == 0 && ON_HH>0){
    283.                ON_MM = 59;
    284.                ON_HH -- ;
    285.               }
    286.               else if(ON_MM >> 0) ON_MM --;
    287.               ON_Time[0] = ON_HH/10;
    288.               ON_Time[1] = ON_HH%10;
    289.               ON_Time[3] = ON_MM/10;
    290.               ON_Time[4] = ON_MM%10;
    291.               break;
    292.      }
    293.      ChangeMin = 0;
    294.      Disp_Time();
    295.     }
    296.  
    297.    }
    298.  
    299.  
    300.   }while(1);
    301.  }
    302.  
    303. [/i][/i][/i][/i]
     
    Last edited by a moderator: Oct 23, 2011
  2. kirayamato_143

    Thread Starter Member

    Jan 23, 2011
    59
    0
    I mean this part
     
  3. THE_RB

    AAC Fanatic!

    Feb 11, 2008
    5,435
    1,305
    What's the part you don't get?

    The for() loop displays 5 characters to the LCD. That could be like "HH:MM" which is 5 characters.

    Depending on mode_select it displays a different message (MSG2 or MSG3). It also changes between displaying the ON time or OFF time.
     
    kirayamato_143 likes this.
  4. kirayamato_143

    Thread Starter Member

    Jan 23, 2011
    59
    0
    if
    i=1
    Mode_select=1
    what will this output and where will it be displayed
    Disp_Char(HHMM_Pos,OFF_Time);

    i dont get the meaning of this arrays
    unsigned short HHMM_Pos[] = {6, 7, 8, 9, 10};
    unsigned short ON_Time[] = {0, 0, 10, 0, 0}; // 10 + 48 is :
    unsigned short OFF_Time[] = {0, 0, 10, 0, 0};
     
  5. THE_RB

    AAC Fanatic!

    Feb 11, 2008
    5,435
    1,305
    The function disp_char() is shown in your code;
    Code ( (Unknown Language)):
    1.  
    2. void Disp_Char(unsigned short col, unsigned short chr){
    3.   Lcd_Chr(2, col, chr+48);
    4.  }
    5.  
    It accepts 2 arguments; column position and character

    So,
    Disp_Char(HHMM_Pos,OFF_Time);

    gets the column position from HHMM_Pos[] and the character to display from OFF_Time[]
     
    kirayamato_143 likes this.
  6. kirayamato_143

    Thread Starter Member

    Jan 23, 2011
    59
    0
    oh i see,, thanks
    can you help me know where this number came from
    i dont know why it should be like this i got the codes here http://embedded-lab.com/blog/?p=1378
    unsigned short HHMM_Pos[] = {6, 7, 8, 9, 10};
    unsigned short ON_Time[] = {0, 0, 10, 0, 0}; // 10 + 48 is :
    unsigned short OFF_Time[] = {0, 0, 10, 0, 0};
     
  7. thatoneguy

    AAC Fanatic!

    Feb 19, 2009
    6,357
    718
    Looking at the inputs at the top of the code, it appears to be a settable timer with display.

    The code is a good example of "why comments are good", but the variable names make it readable enough.

    unsigned short HHMM_Pos[] = {6, 7, 8, 9, 10};

    Means display HH:MM at roughly the center positions of a 16 character LCD, is that line you were asking about?

    The other arrays are simply default values before the user presses any buttons. From the "Usage" section of the article above:


     
  8. kirayamato_143

    Thread Starter Member

    Jan 23, 2011
    59
    0
    You say the other arrays are default values, does it means that it has just to be declared or else the program wont work? sorry i didnt get it why it has to be like that , you may forward me to some site if there is a similar example or please help me lighten up,,but i understand the HH:MM tnx,
     
  9. thatoneguy

    AAC Fanatic!

    Feb 19, 2009
    6,357
    718
    He is setting the default time to 00:00 at the same time as declaring the variable, it saves lines, and helps make the code a bit more readable.

    If you look at the display function, it goes to the position, then displays the value of the on array, which are zeroes to start until adjusted later in the program.

    Have you compiled the program and gotten it to work in the simulator? You can change the numbers and see how it changes the displayed values.
     
    kirayamato_143 likes this.
  10. kirayamato_143

    Thread Starter Member

    Jan 23, 2011
    59
    0
    thanks sir your advice really works now i'm stuck in understanding this code.. please help
    void interrupt() {
    Num ++; // Interrupt causes Num to be incremented by 1
    if(Num == 9) {
    HalfSec ++; // Increase sec
    Num = 0;
    Blink = ~Blink;
    if (HalfSec == 120){
    HalfSec = 0;
    ChangeMin = 1;
    }
    }
    TMR0 = 39; // TMR0 returns to its initial value
    INTCON.T0IF = 0; // Bit T0IF is cleared so that the interrupt could reoccur
    }
     
  11. thatoneguy

    AAC Fanatic!

    Feb 19, 2009
    6,357
    718
    He set Timer 0 up to interrupt often, so to get accurate time, he loads a "pre-count" of 39 in (interrupt occurs when timer counts to 255), The prescaler for Timer0 was set to divide the clock down to interrupt roughly every half second, and the preloading of 39 in the Timer0 counter fine tunes that to be very close to 1/2 second.

    If the interrupt has been called (from Timer 0 overlow) 9 times, 1/2 second has elapsed, so he increments it, resets the Num counter to zero, and toggles the state of the Blink output, so that something blinks on for 1 second, off for 1 second, probably the ":" in HH:MM
    He then tests if Num (half seconds) = 120, if so, that means 60 full seconds have elapsed. If so he sets the variable ChangeMin to 1 to alert the main loop test of the ChangeMin variable that the minute needs to be incremented, and zeros the counters used to determine minutes.
    Finally, he re-enables Timer Interrupts, they are automatically disabled when the interrupt occurs by setting the flag, to re-enable the Timer 0 interrupt, the flag bit for timer 0 needs to be cleared.

    Setting flags like ChangeMin to 1 in is very common for interrupt routines. Unless the project is extremely straightforward, you never want to use a delay or long function inside the interrupt code, unless you really know exactly what you are doing.

    Since timer0 interrupts are disabled when the interrupt routine is entered, and they are the only interrupt enabled from initialization code is Timer0, a few interrupts would be missed while processing a few millisecond delay, for example.

    Interrupts are the best tool to ensure things happen when you want them to, and to alert the code of just about anything (UART data received, button pressed, CCP even occured, etc). Interrupts eliminate running in an endless loop with a bunch of delays between polling the conditions you are looking for.

    The downside to interrupts on the 16F series is there is only one interrupt routine, so if you are using more than one interrupt source, say 2 timers and the UART, you need to test which event triggered the interrupt and process it QUICKLY. This typically means setting a flag that is checked in the main loop, which still runs extremely fast, plenty of speed in the main loop to fully service/debounce button presses, UART, etc. A good example is the ChangeMin flag in the interrupt routine above.

    The general idea is that the interrupt is serviced re-enabled as fast as possible due to the multiple sources of interrupts. This is the situation where tight code in the interrupt routine really matters. For the example above, some dawdling could be forgiven, but at the risk of losing a few half seconds.

    The PIC18 series allows for prioritized interrupts (high and low priority), but that only means that a high priority interrupt can interrupt the low priority interrupt. This is useful if time critical code must be done inside the high priority interrupt routine, say to respond to Ethernet or USB, and the low priority interrupt is changing PWM duty cycle or "not as critical but important" task. Though most hobbyist PIC18 programs use only the single interrupt for simplicity, and a bit of compatibility to port the code to a PIC16 device.

    Let me know if all of that makes sense to you. It appears I got a little verbose, as I am unaware of your level of knowledge.
     
    Last edited: Nov 9, 2011
Loading...