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.

[PIC] mikroc interrupt Service Routine and how to change the value of global variable

Status
Not open for further replies.

Vaisakhan Ku

Junior Member level 1
Joined
Jan 19, 2014
Messages
16
Helped
0
Reputation
0
Reaction score
0
Trophy points
1
Activity points
259
Hi all,
Am in a dead confusion, how can I update the value of global variables declared as extern variables in the main function inside the ISR. Am using Mikroc for PIC. consistently i failed to update the value of these variables. I tested and verified that the interrupts are working fine as per the logic designed, but I cant get the values of global variables that gets changed in the ISR. Pls guide me if any came across similar situation, or please suggest any books or website were I can find some more information. :-|:-:)-:)?::?:
 

how can I update the value of global variables declared as extern variables in the main function inside the ISR.

Any variable should be define outside of the main function. Post your code.
 


Code C - [expand]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
extern int *Ref_high,*CC_ON,*Ref_count_need,*Count_Avail,*Count,*Ref_count,*New_count,*Old_count,*Diff;
  extern char *temp;
  
  #include "Final_header.h"
  char Int_to_Char(int)
  void calculate()
 
  //char Int_to_Char(int);
 
  // Lcd pinout settings
  sbit LCD_D4 at RC0_bit;
  sbit LCD_D5 at RC1_bit;
  sbit LCD_D6 at RC2_bit;
  sbit LCD_D7 at RC3_bit;
  sbit LCD_RS at RC4_bit;
  sbit LCD_EN at RC5_bit;
 
  // Pin direction
  sbit LCD_D4_Direction at TRISC0_bit;
  sbit LCD_D5_Direction at TRISC1_bit;
  sbit LCD_D6_Direction at TRISC2_bit;
  sbit LCD_D7_Direction at TRISC3_bit;
  sbit LCD_RS_Direction at TRISC4_bit;
  sbit LCD_EN_Direction at TRISC5_bit;
 
  
  void initialize(void)
    {
      ANSEL=ANSELH=0;    //all inputs are digital
      OPTION_Reg =0xa0;  //0b11100000  Enabled: RBPU:disabled,INTEDG:rising,T0CS:Ra4 pin,PSA:Timer,PS2:0,PS1:0,PS0:0
      INTCON =0xa8;   //0b10111000 enabled: GIE:Disabled,PEIE:Disabled,T0IE:Enabled,INTE:Enabled,RBIE:enabled,T0IF:Cleared,INTF:Cleared,RBIF:Cleared
      trisb=0xff;
      trisa=0x10;
      IOCB.b1=0;
      IOCB.b2=1;
      IOCB.b3=0;
      IOCB.b4=0;
      IOCB.b5=0;
      trisd=0; 
      portd=0x00000000;
      lcd_init();
    }
    
  interrupt()
    {
      if(INTCON.RBIF)
        {
 
 
          if(PORTB.B2==1)
            {
              CC_ON=1;
              *Ref_count_need=1;
              IOCB.B1=1;
              IOCB.B3=1;
              IOCB.B4=1;
              IOCB.B5=1;
              
              if(PORTB.B1==1)
                {
                  *Ref_High=1;
 
                }
              if(PORTB.B1==0)
                {
                  portd.B3=1;
                  *Ref_High=0;
                }
 
              goto Exit_to_main;
            }
 
           if(PORTB.B3==1)
             {
               CC_ON=0;
               *Count_Avail=0;
               IOCB.B1=0;
               IOCB.B3=0;
               IOCB.B4=0;
               IOCB.B5=0;
               goto Exit_to_main;
             }
 
           if(PORTB.B1==1)
             {
              if(*Ref_high && *Ref_count_need)
                 {
                   *Ref_high=0;
 
                 }
               tmr0=0;
               
               goto Exit_to_main;
             }
 
           if(PORTB.B1==0)
             {
               if(*Ref_High==1)
                 {
                   *Ref_Count_Need=1;
                   goto Exit_to_main;
                 }
               if(*Ref_High==0)
                 {
                   if(*Ref_Count_need==1)
                     {
                       Ref_Count_Need=0;
                       Ref_Count=tmr0;
                       New_Count=tmr0;
                       Count_Avail=1;
                       goto Exit_to_main;
                     }
                   if(*Ref_Count_need==0)
                     {
                       *Old_Count=*New_count;
                       *New_Count=tmr0;
                       *Count_Avail=1;
                       goto Exit_to_main;
                     }
                 }
             }
          INTCON.RBIF=0;
        }
      Exit_to_main:;
    }
 
    void Int_to_Char(int *temp_int)
    {
      char *temp_char;
      inttostr(*temp_int,*temp_char);
      *temp=*temp_char;
      ltrim(*temp);
      //return(*temp_char);
    }
 
 
  void calculate()
    {
      char Display_Val;
      if(Count_Avail==0)
        {
          goto exit_from_calc;
        }
      diff=Ref_count-New_Count;
      Count_Avail=0;
      if(diff>0)
        {
          if(Diff==0)
            {
              goto exit_from_calc;
            }
          Lcd_Out(1,1,"Count is High  ");
          Lcd_Out(2,1,"Ref:");
          Display_val=int_to_char(Ref_count);
          Lcd_Out_cp(Display_val);
          Lcd_Out(2,10,"New:");
          Display_val=int_to_char(New_Count);
          Lcd_Out_cp(Display_val);
          goto exit_from_calc;
        }
      if(diff<0)
        {
          Lcd_Out(1,1,"Count is Low   ");
          Lcd_Out(2,1,"Ref:");
          Display_val=int_to_char(Ref_count);
          Lcd_Out_cp(Display_val);
          Lcd_Out(2,10,"New:");
          Display_val=int_to_char(New_Count);
          Lcd_Out_cp(Display_val);
          goto exit_from_calc;
        }
      exit_from_calc:;
    }
 
 
 
 
  void main()
    {
      initialize();
      /*Lcd_Out(1,6,"CC Turning ON");
      Lcd_Out(2,1,"Welcomne to Cruice Control");
      Delay_ms(750);
      Lcd_Cmd(_lcd_clear);*/
      Lcd_out(1,1,"Initializing....");
      Delay_ms(50);
      Lcd_Cmd(_lcd_clear);
      while(1)
        {
          /*if(CC_ON==1)
            {*/
              //calculate();
 
              lcd_cmd(_lcd_clear);
              Lcd_out(1,1,"CC_ON:");
              *cc_on=12345;
              Int_to_Char(&cc_on);
              Lcd_out_cp(temp);
              Lcd_out_cp("  Ref_high:");
              Lcd_chr_cp(temp);
              Lcd_out_cp("   Ref_count_need:");
              Lcd_out_cp(Ref_count_need);
              Lcd_out(2,1,"   Count_Avail:");
              Lcd_out_cp(Count_Avail);
              delay_ms(100);
              //change_pwm();
           // }
        }
    }

 
Last edited by a moderator:

I tried to state the variable as volatile in a diffrent programm to see if it works!, but I could not get it working. can any one guide me on this matter?
 

Why your are declaring variables as extern? Extern variables are used only if your using multiple source files. But you doesn't seem to be using multiple source files. Interrupt service routine should be:
Code:
void interrupt(){
...
}

you can use break keyword if you want to exit. I don't know the reason why you have declared all the variables as pointers. I think you don't need to declare those as pointers. I can't understand your application. By looking at the code that's what I got to say.
 

I have been trying to count the number of pulses reaches at the Tmr0 pin on the PIC. for that these are the conditions, the counter count whrn the portb.b2 is high, and its done through IOCB interrupt on portb b2 going on low to high. the counter will skip the counting if the counting is activated while the portb.b2 is already high, and will starts on the next high going pulse. and this count is assigned to variable Ref_count during the first high pulse on the portb.b2 and all subsequent counts are assigned to new_count and then compared to see if these are high or low compared to the initial count Ref_count. I can get to the conditions and I checked and found that the interrupts are working fine, but I cant assign the variables with different values inside the ISR. I tried to implement many methods, like declaring the variables in header file and using pointers and passing the values to functions by reference to avoid any local visibility issues between the functions. But none worked fine for me, also, i tried to declare the variable as volatile too, but it didnt worked for me. So if any one can guide me to use Global variables inside the ISR, and what are the declarations that I have to make so that I will be able to change the variables inside the ISR. My compiler is MikroC for PIC.
 

As stated - use the volatile directive if the same variable is used inside and anywhere outside an ISR. It warns the compiler that the variable may change without notice (in the ISR so the time may be unpredictable) so it codes defensively to prevent a situation where it could change in mid-calculation.

You didn't mention you only had one source file before, as ADGAN points out, the reason you would use 'extern' is to tell the compiler that the variable or function isn't in this code at all but is declared in another source file as part of the project. For example if you put 'MyPrintFunction' in 'printer.c' you could use it in 'MyProgram.c' if you used 'extern' to tell it to look elsewhere in the project source files. Without it, you would get a 'function not found' error.

Although it isn't against the rules, I would also look to remove the 'goto' instructions from your program. They can easily lead you into trouble, especially if you edit the code later and forget exactly where they lead to. For example, you could 'goto' a place in the program that was in another function and cause it to return to the wrong place, or you could 'goto' a place that is conditionally compiled and isn't present at all in some version of the program.

Brian.
 
i could not understand that fully, so can you please explain what you mean by correcting a simple program that I written in similar fashion.
The program will display 2 different message after pressing the button at portb.b1, which is detected by the IOBC.b1 to get to the ISR and ISR prints the code on to the LCD. I have declared the variable char m[], in a header file and attached to the main program. also i have re declared the variables before using in main function. Here are the codes, pls try to change the code the way that you were explaining to me so that i can understand.
also i have attached the Proteus Design and the HEX file generated from MikroC.

------Header file----

Code C - [expand]
1
2
3
4
volatile char *y;
  volatile int a,b;
  volatile char m[20];
  volatile char x;




------main Program----



Code C - [expand]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
#include "cruice_header.h"
  
  volatile extern char *y;
  volatile extern int a,b;
  volatile extern char m[20];
  volatile extern char x;
  
  
  // Lcd pinout settings
  sbit LCD_D4 at RC0_bit;
  sbit LCD_D5 at RC1_bit;
  sbit LCD_D6 at RC2_bit;
  sbit LCD_D7 at RC3_bit;
  sbit LCD_RS at RC4_bit;
  sbit LCD_EN at RC5_bit;
 
  // Pin direction
  sbit LCD_D4_Direction at TRISC0_bit;
  sbit LCD_D5_Direction at TRISC1_bit;
  sbit LCD_D6_Direction at TRISC2_bit;
  sbit LCD_D7_Direction at TRISC3_bit;
  sbit LCD_RS_Direction at TRISC4_bit;
  sbit LCD_EN_Direction at TRISC5_bit;
 
  void initialize()
    {
      ANSEL=ANSELH=0;    //all inputs are digital
      OPTION_Reg =0xa0;  //0b11100000  Enabled: RBPU:disabled,INTEDG:rising,T0CS:Ra4 pin,PSA:Timer,PS2:0,PS1:0,PS0:0
      INTCON =0xa8;   //0b10111000 enabled: GIE:Disabled,PEIE:Disabled,T0IE:Enabled,INTE:Enabled,RBIE:enabled,T0IF:Cleared,INTF:Cleared,RBIF:Cleared
      trisb=0xff;
      trisa=0x10;
      IOCB.b1=1;
      IOCB.b2=0;
      IOCB.b3=0;
      IOCB.b4=0;
      IOCB.b5=0;
      trisd=0;
      Lcd_init();
 
    }
 
 
  interrupt()
    {
      if(intcon.rbif==1)
        {
          if(portb.b1==1)
            {
              lcd_out(1,1,"inside Interrupt");
              lcd_out(2,1,"M:-");
              lcd_out_cp(m);
              delay_ms(250);
              lcd_cmd(_lcd_clear);
              m[20]="M value has changed";
              lcd_out(1,1,"Contents of M changed");
              lcd_out(2,1,"M:-");
              lcd_out_cp(m);
            
            }
 
         INTCON.rbif=0;
        }
    }
 
  void main()
    {
      initialize();
      m[20]="assigned from main";
 
      while(1)
        {
 
        }**broken link removed**[ATTACH]101277._xfImport[/ATTACH]
    }

 
Last edited by a moderator:

I cannot use DSN files but I can't understand why you are declaring variables as 'extern'.

This is how it works:
1. If you have ONE 'C' file, you put type/size declarations in it. Globals go outside the main() function, locals go inside main() or other functions.
2. If you have MORE THAN ONE 'C' file you put the type/size declaration in one of them and also declare it as 'extern' in other 'C' files that use the same variable.

When the compiler runs, it takes each of the C files and compiles them, then it 'links' them to make the final program (the .hex file). The idea behind using 'extern' is it tells the compiler to look in the other 'C' files in the project and use the variable it finds there instead of flagging an error because it doesn't know its type or name. It lets different 'C' files share the same variable.

I think you are confusing the '.h' file with a '.c' file. A header (also known as an 'include' file) is simply dropped into place in the program by the #include directive and it is all treated as a single text file. If you declare variables in a .h file and include it in the .c file, the declaration will appear twice, once as the real declaration and again saying it is outside this .c file.

If you only have one source file, put the declarations at the top, before the main() code and do not put them in the .h file at all. Only variables used both inside and outside the ISR need to be 'volatile'.

Brian.
 
Regarding your Proteus file, you have to connect the 1st pin to 5V via a 10K resistor, connect a crystal oscillator with caps. Also to supply power use the power option under terminal mode.
 

Hi all, thanks for the information regarding the header and extra files in the main c program, that indeed removed some of the confusions. But Even after implementing the suggested changes in the program,i could not get the value assigned to the char variable m[] and get it printed. I am attaching the code pls point out if there is any mistakes !????.
I have attached the output if the Preteus simulator using he Hex code of this code.
Pls suggest!!!!????
Troubleshooting pic 2.jpgTroubleshooting pic 1.jpg
Code:
  volatile char *y;
  volatile int a,b;
  volatile char m[20];
  volatile char x;
  
  
  // Lcd pinout settings
  sbit LCD_D4 at RC0_bit;
  sbit LCD_D5 at RC1_bit;
  sbit LCD_D6 at RC2_bit;
  sbit LCD_D7 at RC3_bit;
  sbit LCD_RS at RC4_bit;
  sbit LCD_EN at RC5_bit;

  // Pin direction
  sbit LCD_D4_Direction at TRISC0_bit;
  sbit LCD_D5_Direction at TRISC1_bit;
  sbit LCD_D6_Direction at TRISC2_bit;
  sbit LCD_D7_Direction at TRISC3_bit;
  sbit LCD_RS_Direction at TRISC4_bit;
  sbit LCD_EN_Direction at TRISC5_bit;

  void initialize()
    {
      ANSEL=ANSELH=0;    //all inputs are digital
      OPTION_Reg =0xa0;  //0b11100000  Enabled: RBPU:disabled,INTEDG:rising,T0CS:Ra4 pin,PSA:Timer,PS2:0,PS1:0,PS0:0
      INTCON =0xa8;   //0b10111000 enabled: GIE:Disabled,PEIE:Disabled,T0IE:Enabled,INTE:Enabled,RBIE:enabled,T0IF:Cleared,INTF:Cleared,RBIF:Cleared
      trisb=0xff;
      trisa=0x10;
      IOCB.b1=1;
      IOCB.b2=0;
      IOCB.b3=0;
      IOCB.b4=0;
      IOCB.b5=0;
      trisd=0;
      Lcd_init();

    }


  interrupt()
    {
      if(intcon.rbif==1)
        {
          if(portb.b1==1)
            {
              lcd_out(1,1,"inside Interrupt");
              lcd_out(2,1,"M:-");
              lcd_out_cp(m);
              delay_ms(150);
              lcd_cmd(_lcd_clear);
              m[20]="M value has changed";
              lcd_out(1,1,"Contents M changed");
              lcd_out(2,1,"M:-");
              lcd_out_cp(m[20]);

            }

         INTCON.rbif=0;
        }
    }

  void main()
    {
      initialize();
      m[20]="assigned from main";

      while(1)
        {

        }
    }
 

m[20] is a single memory location, that's why you can't fit a string of characters into it.

When you use "voltatile char m[20];" you are reserving 20 locations of memory to hold 'char' sized data. In a 16F887 that means 20 bytes of 8 bits. Each of those locations is addressed by the index number in the brackets so m[20] is referring to 20 locations after the start of where 'm' is located (m[0]).

I think what you intend to do is load the string into the 'm' character array so "inside Interupt" is stored as:
m[0] contains 'i',
m[1] contains 'n',
m[2] contains 's',
m[3] contains 'i',
.
.
m[14] contains 'p',
m[15] contains 't'

You can try doing that with *m = "inside Interrupt" but some compilers will barf at that. A better solution is 'sprintf(m,"inside Interrupt")' which should work in all compilers.
Incidentally, when you declare a text string, always make sure there is at least one extra storage space available because 'C' terminates strings by adding a binary zero at their ends and it needs space to save it. Also, as these strings never change there is no need to declare than as volatile, in fact you can save some program space by saving the strings as 'const char' then using the name of the string in the program instead of the string itself.

Brian.
 
yes, that indeed helped me. and I found i found this particular para from the manual and then am clear why the variable m wasn't changing."A character constant is one or more characters enclosed in single quotes, such as 'A', '+', or '\n'. In the mikroC PRO for PIC, single-character constants are of the unsigned int type. Multi-character constants are referred to as string constants or string literals. For more information refer to String Constants."

I tried to use, strcpy function and it did worked for me. and if you can tell me the logic for a new problem that i have now, it may also be a small problem like what we had now. so pls look at the code that i pasted. Here I have declared int a,b,e as volatile and i initialized a=123 , b=345 e=0. and while I press the button at the port B the value of int e changes and the changed value gets reflected on to the lcd so that we can see, but Im getting a continuous e=0. and its not getting updated. what could be causing this?

Code:
  # define LCD_PRINT(r,c,val) { inttostr(val,temp1); ltrim(temp1);Lcd_Out(r,c,temp1);}
  
  volatile int a,b,e;
  volatile char temp1[7];


  // Lcd pinout settings
  sbit LCD_D4 at RC0_bit;
  sbit LCD_D5 at RC1_bit;
  sbit LCD_D6 at RC2_bit;
  sbit LCD_D7 at RC3_bit;
  sbit LCD_RS at RC4_bit;
  sbit LCD_EN at RC5_bit;

  // Pin direction
  sbit LCD_D4_Direction at TRISC0_bit;
  sbit LCD_D5_Direction at TRISC1_bit;
  sbit LCD_D6_Direction at TRISC2_bit;
  sbit LCD_D7_Direction at TRISC3_bit;
  sbit LCD_RS_Direction at TRISC4_bit;
  sbit LCD_EN_Direction at TRISC5_bit;


  void initialize()
    {
      ANSEL=ANSELH=0;    //all inputs are digital
      OPTION_Reg =0xa0;  //0b11100000  Enabled: RBPU:disabled,INTEDG:rising,T0CS:Ra4 pin,PSA:Timer,PS2:0,PS1:0,PS0:0
      INTCON =0xa8;   //0b10111000 enabled: GIE:Disabled,PEIE:Disabled,T0IE:Enabled,INTE:Enabled,RBIE:enabled,T0IF:Cleared,INTF:Cleared,RBIF:Cleared
      trisb=0xff;
      trisa=0x10;
      IOCB.b1=1;
      IOCB.b2=0;
      IOCB.b3=0;
      IOCB.b4=0;
      IOCB.b5=0;
      trisd=0;
      Lcd_init();

    }


  interrupt()
    {
      if(intcon.rbif==1)
        {
          e=890;
          INTCON.rbif=0;
        }
    }

  void main()
    {
      initialize();
      a=123;
      b=345;
      e=0;
      while(1)
        {
          lcd_cmd(_lcd_cursor_off);
          LCD_PRINT(1,1,a);
          LCD_PRINT(2,1,b);
          LCD_PRINT(2,8,e);
        }
    }
 

You haven't turned the global interrupt bit on!
After 'Lcd_init();' add another line 'INTCON.GIE = 1;'

Don't change the previous INTCON line, it is better to set the individual enable bits first then turn GIE on right at the end. A word of warning, the interrupt bits are set in INTCON regardless of whether the GIE is turned on or not. No interrupts are generated if GIE = 0 but the bits themselves are still active. You might find you get an unexpected interrupt as you enable GIE. If it causes problems, simply reset the interrupt bits immediately before turning GIE on.

Brian.
 

Hi Brian,
indeed i have turned on the GIE. coz i have declared INTCON=0xa8. and I have checked the interrupt are working or not.and when i checked the value of the changing variable ie e=0-->890, it is happening, but its inside the ISR only and its not visible to outside main function, also the other variable can be seen inside the ISR with the initialized value. i feel It seems a scope and visibility issue but don't know how to get around this. I cant find any specific details about this. If you come across this issue pls guide me.
 

Sorry, I read the comment on the INTCON line where you said it was disabled. Incidentally, the hex value and binary in the comment are different. I would still advise you turn GIE on later though and not at the same time as the other enable bits.

I'm not sure why it isn't working but I suspect it is something to do with the nested #define of your LCD_PRINT statement. I gave up using MikroC because of it's bugs and lack of debugging facilities so I can't try it to be absolutely sure. My guess is that the pre-proccesor isn't carrying the 'temp1' value from one statement of the #define to the next properly.

Try writing LCD_PRINT as a function instead of a macro and see if that works. It shouldn't be difficult and it may use less memory. I can't check it but this might work:

Code:
void LCD_PRINT(char Row, char Col, unsigned int Value)
{
LCD_Out(Row, Column, ltrim(inttostr(Value)));
}

Brian.
 

Problem Solved: mikroc interrupt Service Routine and how to change the value of global variable
reason: char variables cant be assigned values with "=" operator, but for that we have to use strcpy function.
and the LCD_OUT function was showing always zero during the conversion from int to str was coz of the size of the target string. The size has to be minimum array of 7. ex: temp[7], and this has to be initialized. only then the inttostr function and LCD_OUT function work without error.

This is not there in the manual, but worked hard in the net and talked to Mikroc team to find out.
But thanks all for the support!!!!! and sorry for the delay in posting this....
 

Status
Not open for further replies.

Similar threads

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top