PIC18F4520 state when ADC reaches certain value

Discussion in 'Embedded Systems and Microcontrollers' started by LewisMF, Jun 11, 2015.

  1. LewisMF

    Thread Starter Member

    Nov 15, 2014
    63
    2
    Good morning everyone,

    I am trying to program a PIC18F4520 so that when one of the ADC readings (CH0 or CH1) reach a certain threshold the PIC will go in to an 'alarm state' and will continue in that state until the device is reset by the MCLR pin.

    At the moment, when the ADC reaches the threshold it will go in to the 'alarm state' but when the ADC value changes it will go back to normal condition and what I want is for it to "Latch" and stay in the 'alarm state' until reset, as explained above.

    How could I implement this?

    Thanks in advanced for any given help.

    /***************************************************************************************************/

    PS: I am using C language in C18 compiler :)
     
  2. DickCappels

    Moderator

    Aug 21, 2008
    2,651
    632
    It sounds like what you want is the controller to stop and wait fro the rest rather than to continue testing the ADC inputs.

    A simple way to do that is with an infinite loop.

    #include<stdio.h>
    void main()
    while (1)
    {
    // you code here
    }
     
  3. LewisMF

    Thread Starter Member

    Nov 15, 2014
    63
    2
    Hi DickCappels,

    Thank you for your interest on helping me with this.

    I already have an infinite loop, therefore the PIC is constantly reading the ADC channels 0 and 1.

    What I need is if one of those ADC channels go over a certain threshold, the PIC carries out a certain function and stays in that state until reset.

    Even know it is in that 'alarm state' I need the ADC channels to still be converting and checking for any other possible states but for the PIC to remain in the 'alarm state'.

    I hope I explained myself correctly.
     
  4. DickCappels

    Moderator

    Aug 21, 2008
    2,651
    632
    Then you might want to modify your code so that it stops checking the ADC channel whose threshold has already been crossed.

    There are probably more elegant ways around this but I would use flags (bits somewhere or write a values to a variable that was set to zero right after reset) and set the flag once a threshold is crossed and using that flag skip the ADC measurement for that channel the next time through the loop. There would be a separate flag and test for each ADC channel that is handled that way.
     
  5. LewisMF

    Thread Starter Member

    Nov 15, 2014
    63
    2
    I have tried this already but the problem is that I need the ADC to keep converting while in the 'alarm state' because I need to keep measuring the line in case on of the sensors on the ADC are shorted or the line has been open.

    Any ideas?
     
  6. ericgibbs

    AAC Fanatic!

    Jan 29, 2010
    2,503
    380
    If I follow your requirement correctly.?
    Have you considered just setting an Alarm flag bit when the ADC value exceeds the set level and only clearing the flag on a MCLR reset.?
    If flag is Set then remain in Alarm state but keep sampling the ADC's.

    E
     
  7. DickCappels

    Moderator

    Aug 21, 2008
    2,651
    632
    @LewisMF, you received the same advice in two posts. There seems to be a useful idea here...
     
  8. djsfantasi

    AAC Fanatic!

    Apr 11, 2010
    2,802
    832
    Once the threshold has been reached on a channel, you state you want a function to be performed and the program to stay "latched" in that state. Talking about the function, will it be performed one time only when the threshold is exceeded, or repeat until MCLR is activated?

    This can be done in logic with two Boolean variables (or flags). One to indicate when the threshold had been exceeded and a second to indicate that this is the first time the threshold was exceeded. I'll supply some code examples when I am on a computer.
     
  9. LewisMF

    Thread Starter Member

    Nov 15, 2014
    63
    2
    Hi djsfantasi,

    That is correct, the function will be repeated until MCLR is activated.

    Code examples would be great, thankyou. I will be waiting for them :)

    Thank you for your help.
     
  10. DickCappels

    Moderator

    Aug 21, 2008
    2,651
    632
    Please post your existing code. It is far easier to recommend changes if we can see what needs to be changed.
     
  11. LewisMF

    Thread Starter Member

    Nov 15, 2014
    63
    2
    Hi Ericgibbs,

    I do not really understand your solution, would it be possible for you to post some kind of pseudo-code to help understand it.

    Thank you for you help :)
     
  12. ericgibbs

    AAC Fanatic!

    Jan 29, 2010
    2,503
    380
    hi L,
    I do not use C for programming.
    A simple flow path would be something like this.
    At power on, Clear the Alm Flag ;ensure its 0
    Test the ADC value within your timed loop.
    If the ADC => Alarm value, then Set AlmFlg =1 ; this is the Alarm state.

    Within your timed ADC read loop, check to see if the AlmFlg is 0 or 1 and take the appropriate path option within your program.

    The AlmFlg can be a single Bit within an Alarm Status Byte, the other Bits within the Byte could be used to latch other flag states

    E
     
  13. LewisMF

    Thread Starter Member

    Nov 15, 2014
    63
    2
    As requested, here is my code...

    Code (Text):
    1. /*Libraries*/
    2. #include <stdio.h>
    3. #include <stdlib.h>
    4. #include <delays.h>
    5. #include <adc.h>
    6. #include <my_lcd.h>
    7. #include <p18f4520.h>
    8.  
    9. /*Fuses*/
    10. #pragma config OSC = HS,FCMEN = OFF,IESO = OFF
    11. #pragma config PWRT = ON,BOREN = OFF,BORV = 0
    12. #pragma config WDT = OFF,WDTPS = 32768
    13. #pragma config MCLRE = ON,LPT1OSC = OFF,PBADEN = OFF,CCP2MX = PORTC
    14. #pragma config STVREN = OFF,LVP = OFF,XINST = OFF,DEBUG = OFF
    15. #pragma config CP0 = OFF,CP1 = OFF,CP2 = OFF, CP3 = OFF
    16. #pragma config CPB = OFF,CPD = OFF
    17. #pragma config WRT0 = OFF,WRT1 = OFF,WRT2 = OFF
    18. #pragma config WRTB = OFF,WRTC = ON,WRTD = OFF
    19. #pragma config EBTR0 = OFF,EBTR1 = OFF,EBTR2 = OFF
    20. #pragma config EBTRB = OFF
    21.  
    22. /*Pin definitions*/
    23. #define GREEN_LED LATCbits.LATC0
    24. #define RED_LED LATCbits.LATC1
    25. #define YELLOW_LED LATCbits.LATC2
    26. #define BUZZER_PIN LATCbits.LATC3
    27. #define FAULT_RELAY_PIN LATCbits.LATC6
    28. #define FIRE_RELAY_PIN LATCbits.LATC7
    29.  
    30. /*Variable declarations*/
    31. unsigned int adc_result;
    32. unsigned char config1, config2, portconfig;
    33. unsigned int i, x=0;
    34.  
    35. /*Program Functions*/
    36. void state_alarm(void)      //Function for alarm state
    37. {
    38.  
    39.      while(BusyXLCD());                 //Wait while LCD is busy
    40.      clear_lcd();                       //Clear LCD
    41.      putrsXLCD("ALARM ON ZONE1!!");     //Output string to LCD
    42.  
    43.      RED_LED=1;            //Red LED is ON
    44.      GREEN_LED=0;          //Green LED is OFF
    45.      YELLOW_LED=0;           //Yellow LED is OFF
    46.  
    47.      BUZZER_PIN=1;          //Buzzer ON
    48.  
    49.      FIRE_RELAY_PIN=1;     //Fire relay is activated
    50.      FAULT_RELAY_PIN=0;    //Fault relay is inactive
    51.  
    52.      Delay10KTCYx(250);
    53. }
    54.  
    55. void state_normal(void)     //Function for normal state
    56. {
    57.      while(BusyXLCD());                  //Wait while LCD is busy
    58.      WriteCmdXLCD(0x80);                 //Go to LCD position 0x80
    59.      putrsXLCD("CONVENTIONAL FCP");      //Output string to LCD
    60.      while(BusyXLCD());                  //Wait while LCD is busy
    61.      WriteCmdXLCD(0xC5);                 //Go to LCD position 0xC0
    62.      putrsXLCD("*STAND-BY*");            //Output string to LCD
    63.  
    64.      RED_LED=0;      //Red LED is ON
    65.      GREEN_LED=1;    //Green LED is OFF
    66.      YELLOW_LED=0;   //Yellow LED is OFF
    67.  
    68.      BUZZER_PIN=0;   //Buzzer ON
    69.  
    70.      FIRE_RELAY_PIN=0;     //Fire relay is activated
    71.      FAULT_RELAY_PIN=0;    //Fault relay is inactive
    72.  
    73.      Delay10KTCYx(250);
    74. }
    75.  
    76. void state_opencircuit(void)    //Function for open circuit
    77. {
    78.  
    79.     while(BusyXLCD());                //Wait while LCD is busy
    80.     WriteCmdXLCD(0x80);               //Go to LCD position 0x80
    81.     putrsXLCD("*OPEN CIRCUIT!*");     //Output string to LCD
    82.    
    83.     RED_LED=0;      //Red LED is OFF
    84.     GREEN_LED=0;    //Green LED is OFF
    85.     YELLOW_LED=1;   //Yellow LED is ON
    86.  
    87.     FIRE_RELAY_PIN=0;     //Fire relay is inactive
    88.     FAULT_RELAY_PIN=1;    //Fault relay is activated
    89.  
    90.     BUZZER_PIN=1;       //Buzzer ON
    91.     Delay10KTCYx(250);  //Wait 500mS
    92.     BUZZER_PIN=0;       //Buzzer OFF
    93.     Delay10KTCYx(250);  //Wait 500mS
    94. }
    95.  
    96. void state_shortcircuit(void)   //Function for short circuit
    97. {
    98.     while(BusyXLCD());                 //Wait while LCD is busy
    99.     WriteCmdXLCD(0x80);                //Go to LCD position 0x80
    100.     putrsXLCD("*SHORT CIRCUIT!*");     //Escribir mensaje en LCD
    101.  
    102.     RED_LED=0;      //Red LED is OFF
    103.     GREEN_LED=0;    //Green LED is OFF
    104.     YELLOW_LED=1;   //Yellow LED is ON
    105.  
    106.     FIRE_RELAY_PIN=0;    //Fire relay is inactive
    107.     FAULT_RELAY_PIN=1;   //Fault relay is activated
    108.  
    109.     BUZZER_PIN=1;        //Buzzer ON
    110.     Delay10KTCYx(250);   //Wait 500mS
    111.     BUZZER_PIN=0;        //Buzzer OFF 500mS.
    112.     Delay10KTCYx(250);   //Wait 500mS
    113. }
    114.  
    115. void initialize_LCD(void)   //LCD Initialization code
    116. {
    117.     OpenXLCD(FOUR_BIT & LINES_5X7);        //Four bit mode and 5x7 lines
    118.     while(BusyXLCD());                     //Wait while LCD is busy
    119.     WriteCmdXLCD(CURSOR_OFF & BLINK_OFF);  //Cursor OFF
    120. }
    121.  
    122. /*MAIN PROGRAM*/
    123. void main(void)
    124. {
    125.     ADCON1=0x0E;    //ADC_CH0 as analog input
    126.     TRISC=0x00;     //PORTC as digital outputs
    127.  
    128.     Delay10KTCYx(255);
    129.    
    130.     initialize_LCD();   //Initialize LCD
    131.  
    132.     INTCONbits.GIE=0;   //Disable all interrupts
    133.  
    134.     config1 = ADC_FOSC_16 & ADC_RIGHT_JUST & ADC_16_TAD ;
    135.     config2 = ADC_CH0 & ADC_INT_OFF & ADC_VREFPLUS_VDD & ADC_VREFMINUS_VSS ;
    136.     portconfig = ADC_1ANA;
    137.  
    138.     while(1)
    139.     {
    140.          OpenADC(config1,config2,portconfig);   //Open the ADC converter
    141.          ConvertADC();                          //Start converting
    142.          while(BusyADC());                      //Wait while ADC is converting
    143.          adc_result = ReadADC();                //Read the ADC result and store it in variable
    144.          CloseADC();                            //Close the ADC
    145.  
    146.             if(adc_result<=388 && adc_result>=0.20) //ADC result for alarm condition, line current aprox. 25mA
    147.             {
    148.                      state_alarm();    //Execute the function 'state_alarm'
    149.             }
    150.  
    151.              else if(adc_result>388 && adc_result<583) //ADC result for normal condition, line current < 25mA
    152.                 {
    153.                      state_normal();    //Execute the function 'state_normal'
    154.                 }
    155.  
    156.              else if (adc_result>=583)   //ADC result for open circuit, line current = 0mA
    157.                 {
    158.                      state_opencircuit();    //Execute the function 'state_opencircuit'
    159.                 }
    160.  
    161.              else if(adc_result<0.20)     //ADC result for short-circuit, line current > 100mA
    162.                 {
    163.                      state_shortcircuit();    //Execute the function 'state_shortcircuit'
    164.                 }
    165.         }
    166. }
    If you have any questions regarding the code, please do not hesitate to ask.
     
  14. djsfantasi

    AAC Fanatic!

    Apr 11, 2010
    2,802
    832
    ...And as promised, here is my example. Note how I defined boolean variables to represent the various states. Then, when deciding whether or not to call your "function", I test for
    Has this channel gone over the threshold and has it not done so before?
    I.e., this is the first time I have seen the threshold exceeded. Given your example, I am confident that you can understand the example and modify it to your requirement,
    Code (Text):
    1. // pseudo-code
    2.  
    3. byte inputValue=0; // size dependent on what the ADC returns
    4. boolean ch0ThresholdExceeded=false;
    5. boolean ch0TriggeredBefore  =false;
    6.  
    7. #define Threshold 128
    8.  
    9. void yourFunction(byte myValue) {
    10.   // code to do whatever you need
    11. }
    12.  
    13. void main() {
    14.  
    15.   while (-1) {
    16.      inputValue=readADC(0); // read from the ADC
    17.      ch0ThresholdExceeded= (inputValue >= Threshold); // has the threshold
    18.                                                       // been exceeded?
    19.     if (ch0ThresholdExceeded & ! ch0TriggeredBefore) {
    20.       yourFunction(inputValue); // only call function the first time
    21.       ch0TriggeredBefore=true; // set the flag to prevent repeated execution
    22.                                 // of the function
    23.     }
    24.     // a similar block of code would be used for channel 1
    25.   }
    26. }
    27.  
     
  15. DickCappels

    Moderator

    Aug 21, 2008
    2,651
    632
    From my less-than-perfect understanding of what you want to accomplish, you want to prevent this test from being made after the alarm condition has been entered, correct?

    else if(adc_result>388 && adc_result<583) //ADC result for normal condition, line current < 25mA
    {
    state_normal(); //Execute the function 'state_normal'
    }
     
  16. LewisMF

    Thread Starter Member

    Nov 15, 2014
    63
    2
    Hi DickCappels,

    Yes I want to prevent the state_normal(); function from being entered when the PIC's ADC reaches the alarm threshold and keep the PIC in the state_alarm(); function.

    But at the same time, I need the ADC to keep converting in case a short circuit or an open circuit occurs (the other two states)
     
  17. LewisMF

    Thread Starter Member

    Nov 15, 2014
    63
    2
    Hi djsfantasi,

    Thank you for the pseudo-code.

    I am going to test it in my program and I will get back to you :)
     
  18. LewisMF

    Thread Starter Member

    Nov 15, 2014
    63
    2
    Hi djsfantasi,

    I have been trying to implement this in C18 using standard C but there are no built in boolean values.

    Is there any way I can implement this using variables? Or any other way to do it?

    Thanks in advanced for your help! :)
     
  19. djsfantasi

    AAC Fanatic!

    Apr 11, 2010
    2,802
    832
    Use variables of type int. Use variables to define false as 0 and true as -1.
     
  20. LewisMF

    Thread Starter Member

    Nov 15, 2014
    63
    2
    I have just tested the code as you explained and it works, the function does not repeat itself but there is a problem...

    When the alarm threshold is crossed, the PIC executes the state_alarm(); function and stays there as long as the ADC value is over the threshold, the moment the ADC's value goes below the threshold again, the PIC goes back to execute the state_normal(); function.

    So basically I am in the same situation as before...

    What I need is for the PIC to stay in the state_alarm(); function until reset, independent of the ADC's value but at the same time, still sample the ADC in case of short or open circuit on the line.

    Here is the new code:

    Code (Text):
    1. /*Libraries*/
    2. #include <stdio.h>
    3. #include <stdlib.h>
    4. #include <delays.h>
    5. #include <adc.h>
    6. #include <my_lcd.h>
    7. #include <p18f4520.h>
    8.  
    9. /*Fuses*/
    10. #pragma config OSC = HS,FCMEN = OFF,IESO = OFF
    11. #pragma config PWRT = ON,BOREN = OFF,BORV = 0
    12. #pragma config WDT = OFF,WDTPS = 32768
    13. #pragma config MCLRE = ON,LPT1OSC = OFF,PBADEN = OFF,CCP2MX = PORTC
    14. #pragma config STVREN = OFF,LVP = OFF,XINST = OFF,DEBUG = OFF
    15. #pragma config CP0 = OFF,CP1 = OFF,CP2 = OFF, CP3 = OFF
    16. #pragma config CPB = OFF,CPD = OFF
    17. #pragma config WRT0 = OFF,WRT1 = OFF,WRT2 = OFF
    18. #pragma config WRTB = OFF,WRTC = ON,WRTD = OFF
    19. #pragma config EBTR0 = OFF,EBTR1 = OFF,EBTR2 = OFF
    20. #pragma config EBTRB = OFF
    21.  
    22. /*Pin definitions*/
    23. #define GREEN_LED LATCbits.LATC0
    24. #define RED_LED LATCbits.LATC1
    25. #define YELLOW_LED LATCbits.LATC2
    26. #define BUZZER_PIN LATCbits.LATC3
    27. #define FAULT_RELAY_PIN LATCbits.LATC6
    28. #define FIRE_RELAY_PIN LATCbits.LATC7
    29.  
    30. /*Variable declarations*/
    31. unsigned int adc_result;
    32. unsigned char config1, config2, portconfig;
    33. unsigned int exceeded=0, triggered=0;       //Exceeded and triggered variable for ADC channel 0
    34.  
    35. /*Program Functions*/
    36. void state_alarm(void)      //Function for alarm state
    37. {
    38.  
    39.      while(BusyXLCD());     //Wait while LCD is busy
    40.      clear_lcd();           //Clear LCD
    41.      putrsXLCD("ALARM ON ZONE1!!");     //Output string to LCD
    42.  
    43.      RED_LED=1;      //Red LED is ON
    44.      GREEN_LED=0;    //Green LED is OFF
    45.      YELLOW_LED=0;   //Yellow LED is OFF
    46.  
    47.      BUZZER_PIN=1;   //Buzzer ON
    48.  
    49.      FIRE_RELAY_PIN=1;     //Fire relay is activated
    50.      FAULT_RELAY_PIN=0;    //Fault relay is inactive
    51.  
    52.      Delay10KTCYx(250);
    53. }
    54.  
    55. void state_normal(void)     //Function for normal state
    56. {
    57.      while(BusyXLCD());                  //Wait while LCD is busy
    58.      WriteCmdXLCD(0x80);                 //Go to LCD position 0x80
    59.      putrsXLCD("CONVENTIONAL FCP");      //Output string to LCD
    60.      while(BusyXLCD());                  //Wait while LCD is busy
    61.      WriteCmdXLCD(0xC3);                 //Go to LCD position 0xC0
    62.      putrsXLCD("*STAND-BY*");            //Output string to LCD
    63.  
    64.      RED_LED=0;      //Red LED is ON
    65.      GREEN_LED=1;    //Green LED is OFF
    66.      YELLOW_LED=0;   //Yellow LED is OFF
    67.  
    68.      BUZZER_PIN=0;   //Buzzer ON
    69.  
    70.      FIRE_RELAY_PIN=0;     //Fire relay is activated
    71.      FAULT_RELAY_PIN=0;    //Fault relay is inactive
    72.  
    73.      Delay10KTCYx(250);
    74. }
    75.  
    76. void state_opencircuit(void)    //Function for open circuit
    77. {
    78.     clear_lcd();                      //Clear the LCD
    79.  
    80.     while(BusyXLCD());                //Wait while LCD is busy
    81.     WriteCmdXLCD(0x80);               //Go to LCD position 0x80
    82.     putrsXLCD("*OPEN CIRCUIT!*");     //Output string to LCD
    83.    
    84.     RED_LED=0;      //Red LED is OFF
    85.     GREEN_LED=0;    //Green LED is OFF
    86.     YELLOW_LED=1;   //Yellow LED is ON
    87.  
    88.     FIRE_RELAY_PIN=0;     //Fire relay is inactive
    89.     FAULT_RELAY_PIN=1;    //Fault relay is activated
    90.  
    91.     BUZZER_PIN=1;       //Buzzer ON
    92.     Delay10KTCYx(250);  //Wait 500mS
    93.     BUZZER_PIN=0;       //Buzzer OFF
    94.     Delay10KTCYx(250);  //Wait 500mS
    95. }
    96.  
    97. void state_shortcircuit(void)   //Function for short circuit
    98. {
    99.     clear_lcd();                       //Clear the LCD
    100.  
    101.     while(BusyXLCD());                 //Wait while LCD is busy
    102.     WriteCmdXLCD(0x80);                //Go to LCD position 0x80
    103.     putrsXLCD("*SHORT CIRCUIT!*");     //Escribir mensaje en LCD
    104.  
    105.     RED_LED=0;      //Red LED is OFF
    106.     GREEN_LED=0;    //Green LED is OFF
    107.     YELLOW_LED=1;   //Yellow LED is ON
    108.  
    109.     FIRE_RELAY_PIN=0;    //Fire relay is inactive
    110.     FAULT_RELAY_PIN=1;   //Fault relay is activated
    111.  
    112.     BUZZER_PIN=1;        //Buzzer ON
    113.     Delay10KTCYx(250);   //Wait 500mS
    114.     BUZZER_PIN=0;        //Buzzer OFF 500mS.
    115.     Delay10KTCYx(250);   //Wait 500mS
    116. }
    117.  
    118. void initialize_LCD(void)   //LCD Initialization code
    119. {
    120.     OpenXLCD(FOUR_BIT & LINES_5X7);        //Four bit mode and 5x7 lines
    121.     while(BusyXLCD());                     //Wait while LCD is busy
    122.     WriteCmdXLCD(CURSOR_OFF & BLINK_OFF);  //Cursor OFF
    123. }
    124.  
    125. /*MAIN PROGRAM*/
    126. void main(void)
    127. {
    128.     ADCON1=0x0E;    //ADC_CH0 as analog input
    129.     TRISC=0x00;     //PORTC as digital outputs
    130.  
    131.     Delay10KTCYx(255);
    132.    
    133.     initialize_LCD();   //Initialize LCD
    134.  
    135.     INTCONbits.GIE=0; //Disable all interrupts
    136.  
    137.     config1 = ADC_FOSC_16 & ADC_RIGHT_JUST & ADC_16_TAD ;
    138.     config2 = ADC_CH0 & ADC_INT_OFF & ADC_VREFPLUS_VDD & ADC_VREFMINUS_VSS ;
    139.     portconfig = ADC_1ANA;
    140.  
    141.     while(1)
    142.     {
    143.          OpenADC(config1,config2,portconfig);   //Open the ADC converter
    144.          ConvertADC();                          //Start converting
    145.          while(BusyADC());                      //Wait while ADC is converting
    146.          adc_result = ReadADC();                //Read the ADC result and store it in variable
    147.          CloseADC();                            //Close the ADC
    148.  
    149.             if(adc_result<=295 && adc_result>=0.20) //ADC result for alarm condition, line current aprox. 25mA
    150.             {
    151.                 exceeded = 1;     //Set threshold exceeded flag to 1
    152.                
    153.                 if(exceeded != triggered)   //If exceeded is != to trigger...
    154.                 {
    155.                      state_alarm();     //Execute function state_alarm();
    156.                      triggered = 1;     //Set triggered flag to 1 so the function is not repeated
    157.                 }
    158.             }
    159.  
    160.              else if(adc_result>295 && adc_result<531) //ADC result for normal condition, line current < 25mA
    161.                 {
    162.                      state_normal();
    163.                 }
    164.  
    165.              else if (adc_result>=531)   //ADC result for open circuit, line current = 0mA
    166.                 {
    167.                      state_opencircuit();
    168.                 }
    169.  
    170.              else if(adc_result<0.20)     //ADC result for short-circuit, line current > 100mA
    171.                 {
    172.                      state_shortcircuit();
    173.                 }
    174.         }
    175. }
    As you can see, in the main function, the first check that is carried out is the alarm threshold check, which is the part of most interest.

    :)
     
Loading...