Continue to Site

Welcome to EDAboard.com

Welcome to our site! EDAboard.com is an international Electronics Discussion Forum focused on EDA software, circuits, schematics, books, theory, papers, asic, pld, 8051, DSP, Network, RF, Analog Design, PCB, Service Manuals... and a whole lot more! To participate you need to register. Registration is free. Click here to register now.

Create Mode function in PIC Microcontroller

Status
Not open for further replies.

alpha91

Full Member level 3
Joined
Sep 23, 2011
Messages
168
Helped
1
Reputation
2
Reaction score
2
Trophy points
1,298
Activity points
2,625
Hi all, I am creating a system that allow LED to light up in few different mode.
microcontroller = 16F628A
compiler = MikroC

my PIC microcontroller also connected to 16x2 LCD to display current mode.

This program currently have a problem that everytime i changed the mode with INT, the result only reflect after one full cycle. Is there anyway to make it change right after i pressed the INT button?
I tried to use reset so that it can scan the condition (set in EEPROM in this case) but i fail to compile the asm code.

my code is as below:

Code:
 // Mode change for LED
 // LED output at B3
 // INT button at B0

 int mode1;
 int modecount;
 signed int i = 0;

sbit LCD_RS at RA0_bit;
sbit LCD_EN at RA1_bit;
sbit LCD_D4 at RB4_bit;
sbit LCD_D5 at RB5_bit;
sbit LCD_D6 at RB6_bit;
sbit LCD_D7 at RB7_bit;
sbit LCD_RS_Direction at TRISA0_bit;
sbit LCD_EN_Direction at TRISA1_bit;
sbit LCD_D4_Direction at TRISB4_bit;
sbit LCD_D5_Direction at TRISB5_bit;
sbit LCD_D6_Direction at TRISB6_bit;
sbit LCD_D7_Direction at TRISB7_bit;
 
 
 
 char message1[] = "Mode 1";
 char message2[] = "Mode 2";
 char message3[] = "Mode 3";
 char message4[] = "Unicorn Banshee HG";



 
void main()
{

     CMCON = 0x07;
     TRISA = 0; // To configure PORTC as output port
     TRISB = 0x01;
     OPTION_REG.INTEDG = 1; // Set Rising Edge Trigger for INT
     INTCON.GIE = 1; // Enable The Global Interrupt
     INTCON.INTE = 1; // Enable INT

     PWM1_Init(5000);            // Initialize PWM frequency
     PWM1_Set_Duty(127);
     PWM1_Start();
     mode1 = 0x00;

     Lcd_Init();        // Initialize LCD
     Lcd_Cmd(_LCD_CLEAR);               // Clear display
     Lcd_Cmd(_LCD_CURSOR_OFF);  // OFF cursor
     Lcd_Cmd(0x01);               // Clear display
     Lcd_Cmd(0x03); //cursor home


     while(1)
         // Loop:
          {

              if( eeprom_read(0) == 0x01) // Mode2

              {
                  Lcd_out(1,1,message4);
                  Lcd_out(2,1,message2);
                  for(i = 0; i < 256; i += 250)
                   {
                   PWM1_Set_Duty(i);

                   Delay_ms(200);
                   }
                   for(i = 250; i >= 0; i -= 250)
                   {
                   PWM1_Set_Duty(i);
                   Delay_ms(200);
                   }
              }

              else if (eeprom_read(0) == 0x02)     // Mode 3

              {
                   Lcd_out(1,1,message4);
                  Lcd_out(2,1,message3);
                   for(i = 0; i < 256; i += 5)
                   {
                   PWM1_Set_Duty(i);

                   Delay_ms(140);
                   }
                   for(i = 253; i >= 0; i -= 5)
                   {
                   PWM1_Set_Duty(i);
                   Delay_ms(120);
                   }
              }
              else if (eeprom_read(0) == 0x03)     // Mode 4

              {
                   PORTB.F1 = 1;
                   delay_ms(500);
                   PORTB.F1 = 0;
                   delay_ms(500);
              }

              else // Default mode1
              {
              Lcd_out(1,1,message4);
              Lcd_out(2,1,message1);
              mode1 = 0x00;
              for(i = 0; i < 256; i += 250)
                   {
                   PWM1_Set_Duty(i);

                   Delay_ms(1000);
                   }
                   for(i = 250; i >= 0; i -= 250)
                   {
                   PWM1_Set_Duty(i);
                   Delay_ms(1000);
                   }

              }
          }
  }

  void interrupt() //  ISR
       {
           INTCON.INTF=0;
           // mode1 +1;

           modecount = 0x01;
           mode1 = mode1 + modecount;
           eeprom_write(0,mode1);
           //goto Loop;
           // asm 
           //  {
           //    reset;
           //   }

           delay_ms(50);

           
           }
 
Last edited by a moderator:

Timer interrupts have to be used for modes. If large delays are executing then even if you use INTx pin to detect mode change then it will only get applied after the Delay_ms(1000) gets executed. You can use while() which tests for mode and you can change mode in TNTx interrupt. If mode changes then program execution comes out of the loop and enters next valid mode loop.
 
Timer interrupts have to be used for modes. If large delays are executing then even if you use INTx pin to detect mode change then it will only get applied after the Delay_ms(1000) gets executed. You can use while() which tests for mode and you can change mode in TNTx interrupt. If mode changes then program execution comes out of the loop and enters next valid mode loop.

Hi, thanks for reply.
TNTx is timer interrupt?
I actually learned the basic of timer interrupt before but in this case i wondering how should i do it because timer interrupt duration is set with the TMR1H and TMR1L.
I though make a "reset" function at interrupt actully. which when i trigger the interrupt to change state, the PIC is reset and scan the condition again. but i implement the ASM code:

asm{

reset;

}

The MikroC compiler comes out an error which cant recognize the reset function.
 

Sorry, it is not TNTx. It is INTx only. In INTx interrupt change the modes and use while() loops with condition to test modes. One loop for one mode. Still if Delays inside while loops are executing then mode test will be done after delay executes.
 
Hi,

I don´t see a debounce function in your code. Do you have hardware debounce.
You need one of both.

****
Only a couple of modes are defined. EEPROM_Value 0x01, 0x02, 0x03, all others are processed as MODE0.

Why don´t you limit the EEPROM value to 0x01 to 0x03?
for example: If mode1 = 4 then mode1 = 1 (pseudocode)

Klaus
 
Sorry, it is not TNTx. It is INTx only. In INTx interrupt change the modes and use while() loops with condition to test modes. One loop for one mode. Still if Delays inside while loops are executing then mode test will be done after delay executes.

ok. but if that is the case how should i set the interrupt timer TMR1H and TMR1L?
actually i did one project before is using timer interrupt to select which LED to blink. and TMR1H and TMR1L is the duration of blink.
but i am not sure how to implement it in this case.

Hi,

I don´t see a debounce function in your code. Do you have hardware debounce.
You need one of both.

****
Only a couple of modes are defined. EEPROM_Value 0x01, 0x02, 0x03, all others are processed as MODE0.

Why don´t you limit the EEPROM value to 0x01 to 0x03?
for example: If mode1 = 4 then mode1 = 1 (pseudocode)

Klaus

Hi. Thank you very much for reminding the debounce. I will add into my code.

for the EEPROM value limitation, do you mean i set an "if" condition in the interrupt function as your example?
 

Hi,

Yes, in the interrupt function.

Btw: is the interrupt level_triggered or edge_triggered?

*******
An idea:
Maybe you could set up a timer to time out every 20ms (or any other useful value)
Make the main loop to run according this value.
Instead of using busy delay routines you can just count loops.
Then you don't need a debounce function.
Example for a 1 s blink: use a counter set it to 24 and decrement it every run. When zero: toggle LED and set it to 24.

This enables you to do a lot of things at virtually the same time.
It's more PLC style with a fixed timing.

Klaus
 
Hi,

Yes, in the interrupt function.

Btw: is the interrupt level_triggered or edge_triggered?

*******
An idea:
Maybe you could set up a timer to time out every 20ms (or any other useful value)
Make the main loop to run according this value.
Instead of using busy delay routines you can just count loops.
Then you don't need a debounce function.
Example for a 1 s blink: use a counter set it to 24 and decrement it every run. When zero: toggle LED and set it to 24.

This enables you to do a lot of things at virtually the same time.
It's more PLC style with a fixed timing.

Klaus


Hi.
I am how sure whether it is level triggered or state triggered. May I know how can i check this?

And i had modified one of the condition as below:

Code:
if( eeprom_read(0) == 0x01) // Mode2
              {
              Lcd_out(1,1,message4);
              Lcd_out(2,1,message2);
                  for( k=0; k < 10; k++ )
                  {
                   for(i = 0; i < 256; i += 250)
                   {
                   PWM1_Set_Duty(i);

                   Delay_ms(100);
                   }
                   }
                   for (k >= 10; k < 20; k++)
                   {
                      for(i = 250; i >= 0; i -= 250)
                   {
                   PWM1_Set_Duty(i);
                   Delay_ms(100);
                   }
                   }
                   for ( k >= 20; k <21; k = 0)
                   {
                   return;
                   }
              }

is it you suggest something like this?
This code still have one problem which is after several times of blinking. It stop, and I can't change the mode anymore.
 
Last edited by a moderator:

Hi.
I am how sure whether it is level triggered or state triggered. May I know how can i check this?

INTEDG_bit value or INTEDGx_bit value.
 
Last edited by a moderator:
Hi,

It seems you posted the wrong code....at least it has nothing to do with my recommendations.

Klaus
 
INTEDG_bit value or INTEDGx_bit value.

Sorry, i dont know how to check this. Can you guide me? i am still beginner in PIC programming.


is it you suggest something like this?
This code still have one problem which is after several times of blinking. It stop, and I can't change the mode anymore.[/QUOTE]

Hi,

It seems you posted the wrong code....at least it has nothing to do with my recommendations.

Klaus

Hi, this is one of the mode. I didnt post the whole code.
I thought you were saying that breakdown the long delay into shorter then using counter to count the repeat times.
I think i misunderstand then.

What if everytime after interrupt i reset the PIC? will it works? since i use EEPROM to record the mode value.
 

Hi,


An idea:
Maybe you could set up a timer to time out every 20ms (or any other useful value)
--> I don´t see this in your code.

Make the main loop to run according this value.
--> I don´t see this in your code.
At the beginnin of the main loop you need to wait for the timer event.
It shouldn´t be a problem to wait until the timer flag is set. Then clear the flag and run the main routine


Instead of using busy delay routines you can just count loops.
--> You still use busy waits.
Don´t use delay_ms at all - it just consumes processing power and it can´t do anything else druing this time.


Klaus
 

An idea:
Maybe you could set up a timer to time out every 20ms (or any other useful value)
--> I don´t see this in your code.

Make the main loop to run according this value.
--> I don´t see this in your code.
At the beginnin of the main loop you need to wait for the timer event.
It shouldn´t be a problem to wait until the timer flag is set. Then clear the flag and run the main routine


Instead of using busy delay routines you can just count loops.
--> You still use busy waits.
Don´t use delay_ms at all - it just consumes processing power and it can´t do anything else druing this time.

oh. I though i using the 100ms is what you mean in the first conditions.
sorry, i have no idea on how to make a main loop to time out. Do you mean using interrupt timer?
 
Last edited:

Hi,

Do you mean using interrupt timer?

As already said:
set up a timer to time out every 20ms
It just sets a flag when timed out.
No need to generate an interrupt --> No need or an ISR.

I´m not familiar with PICs, therefore I don´t know the name of the flag. But the function is similar in almost all microcontrollers.


Klaus
 
  • Like
Reactions: alpha91

    V

    Points: 2
    Helpful Answer Positive Rating

    alpha91

    Points: 2
    Helpful Answer Positive Rating
Hi,



As already said:

It just sets a flag when timed out.
No need to generate an interrupt --> No need or an ISR.

I´m not familiar with PICs, therefore I don´t know the name of the flag. But the function is similar in almost all microcontrollers.


Klaus

Alright. Thanks a lot.
I try to find out how should i set the timer then.
Thank you.
 

Status
Not open for further replies.

Similar threads

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top