PIC Microcontroller Non-Blocking Delay Implementation

Home Forums Microcontrollers PIC Microcontroller PIC Microcontroller Non-Blocking Delay Implementation

Tagged: ,

Viewing 8 posts - 1 through 8 (of 8 total)
  • Author
    Posts
  • #12100
    emufambirwi
    Participant

    I am doing a project which requires that I turn on and off two LED’s independently from a computer using serial port communication. I send a character like ‘A’ via the serial port and turn on one LED for say 1 minute and send another character like ‘B’ and turn on another LED for 2 minutes. My problem is that when using Timer0 of pic 18F87k22, I can’t implement the 1 minute and 2 minute delays independently. When I turn on the one LED the other one doesn’t respond and vice versa. I am simulating using Proteus and my code is is in MikroC as shown below:

    char uart_rd;
    char cnt;
    
    void interrupt () 
    {
      if (TMR0IF_bit) 
      {
         cnt++;                 // increment counters
         TMR0IF_bit = 0;        // clear TMR0IF
    
         TMR0L = 0xDC;             // set TMR0 for aproximetly 1 sec
         TMR0H = 0x0B;
      }
    }
    
    void one_min_delay () 
    {
      TRISB  = 0;              // PORTB is output
      TMR0H = 0x0B;
      TMR0L = 0xDC;               // Timer0 initial value
    
      T0CON = 0x84;            // Set TMR0 to 8bit mode and prescaler to 256
      GIE_bit = 1;             // Enable global interrupt
      TMR0IE_bit = 1;          // Enable Timer0 interrupt
    
      cnt = 0;                 // Initialize cnt
    
      do 
      {
        if (cnt >= 60) 
        {
          LATB = 0x00;      // turnoff PORTB LEDs
          cnt = 0;             // Reset cnt
        }
      }while(1);
    }
    
    void two_min_delay () 
    {
      TRISB  = 0;              // PORTB is output
      TMR0H = 0x0B;
      TMR0L = 0xDC;               // Timer0 initial value
      T0CON = 0x84;            // Set TMR0 to 8bit mode and prescaler to 256
      GIE_bit = 1;             // Enable global interrupt
      TMR0IE_bit = 1;          // Enable Timer0 interrupt
    
      cnt = 0;                 // Initialize cnt
    
      do 
      {
        if (cnt >= 120) 
        {
          LATB = 0x00;      // turnoff PORTB LEDs
          cnt = 0;             // Reset cnt
        }
      }while(1);
    }
    
    void main() 
    {
      UART1_Init(9600);               // Initialize UART module at 9600 bps
      Delay_ms(100);                  // Wait for UART module to stabilize
      TRISB = 0x00;
    
      while (1) 
      {
        if (UART1_Data_Ready()) 
        {     // If data is received,
          uart_rd = UART1_Read();
        }
    
        if (uart_rd=='A')   
        {
          LATB = 0x01;
          one_min_delay();
        }
        else if (uart_rd == 'B')   
        {
          PORTB = 0x02;
          two_min_delay ();
        }
        uart_rd ='\0';
      }
    }
    
    #12102
    Ligo George
    Keymaster

    My logic will be by using 2 variables.

    1. Increment each variable after a fixed delay or timer overflow if the corresponding LED is ON.
    2. Check each variable for the limit.
    3. If the limit is reached, turn OFF the corresponding LED and reset the variable to zero.
    #12103
    emufambirwi
    Participant

    Thanks for the reply. I hope I get you well. The number of variables is the same as the number of LED’s to be controlled. Let me change my code and try that and I will give you feedback.

    Another question is: Is there any other way to do this without the use of interrupts?

     

    #12105
    emufambirwi
    Participant

    This is how I have changed my code and the result is still the same :

    char uart_rd;
    char cnt, cnt1;
    
    void interrupt ()
    {
      if (TMR0IF_bit)
      {
        cnt++;                 // increment counters
        cnt1++;
        TMR0IF_bit = 0;        // clear TMR0IF
        TMR0L = 0xDC;             // set TMR0 for aproximetly 1 sec
        TMR0H = 0x0B;
      }
    }
    
    void one_min_delay ()
    {
      TRISB  = 0;              // PORTB is output
      TMR0H = 0x0B;
      TMR0L = 0xDC;               // Timer0 initial value
    
      T0CON = 0x84;            // Set TMR0 to 8bit mode and prescaler to 256
      GIE_bit = 1;             // Enable global interrupt
      TMR0IE_bit = 1;          // Enable Timer0 interrupt
    
      cnt = 0;                 // Initialize cnt
    
      do
      {
        if (cnt >= 60)
        {
          LATB = 0x00;      // turnoff PORTB LEDs
          cnt = 0;             // Reset cnt
        }
      }while(1);
    }
    
    void two_min_delay ()
    {
      TRISB  = 0;              // PORTB is output
      TMR0H = 0x0B;
      TMR0L = 0xDC;               // Timer0 initial value
      T0CON = 0x84;            // Set TMR0 to 8bit mode and prescaler to 256
      GIE_bit = 1;             // Enable global interrupt
      TMR0IE_bit = 1;          // Enable Timer0 interrupt
    
      cnt1 = 0;                 // Initialize cnt1
    
      do
      {
        if (cnt1 >= 120)
        {
          LATB = 0x00;      // turnoff PORTB LEDs
          cnt1 = 0;             // Reset cnt
        }
      }while(1);
    }
    
    void main()
    {
      UART1_Init(9600);               // Initialize UART module at 9600 bps
      Delay_ms(100);                  // Wait for UART module to stabilize
      TRISB = 0x00;
    
      while (1)
      {
        if (UART1_Data_Ready())
        {     // If data is received,
          uart_rd = UART1_Read();
        }
    
        if (uart_rd=='A')
        {
          LATB = 0x01;
          one_min_delay();
        }
        else if (uart_rd == 'B')
        {
          PORTB = 0x02;
          two_min_delay ();
        }
        uart_rd ='\0';
      }
    }
    
    #12108
    Ligo George
    Keymaster

    Sorry, I don’t understand your code. You have 3 infinite loops in your program. One in main loop, one in 1 min delay loop and other in 2 min delay loop.

    You can try like this :

    void main()
    {
      unsigned int a, b;
      UART1_Init(9600);               // Initialize UART module at 9600 bps
      Delay_ms(100);                  // Wait for UART module to stabilize
      TRISB = 0x00;
    
      while (1)
      {
        if (UART1_Data_Ready())
        {     // If data is received,
          uart_rd = UART1_Read();
        }
    
        if (uart_rd=='A')
        {
          LATB = 0x01;
          a = 100;
        }
        else if (uart_rd == 'B')
        {
          LATB = 0x02;
          b = 200;
        }
        uart_rd ='\0';
        
        if(a > 0)
        {
           Delay_ms(1);
           a--;
        }
        else
          LATB = 0;
        
       if(b > 0)
       {
         Delay_ms(1);
         b--;
       }
       else
         LATB = 0;
      }
    }
    #12109
    emufambirwi
    Participant

    Thanks Mr George, now I can control the LED’s independently but they are forever ON. Let me see if I can do something about the timing

     

    #12110
    emufambirwi
    Participant

    Sorry, my mistake, I had left some } in the code. But 1st LED blinks fast

    #12111
    Ligo George
    Keymaster

    You can adjust the delay by changing the 100 and 200 constants assigned to a and b respectively.

Viewing 8 posts - 1 through 8 (of 8 total)
  • You must be logged in to reply to this topic.
>