Analog and interrupt

Discussion in 'Embedded Systems and Microcontrollers' started by FroceMaster, Mar 1, 2015.

  1. FroceMaster

    Thread Starter Member

    Jan 28, 2012
    400
    4
    Hi
    Have this Little project
    at AN1 i have a V. controlled by a LDR and a resistor.

    When the lights outside be to bright the PIC should do something, and when it's to dark it should do another thing.

    Can the analog reading be triggering an interrupt, or do the code has to run over and check the voltage every run. ?
    Here is my code. Chip is 16F1509
    Code (Text):
    1. #include <htc.h>
    2. #include <stdio.h>
    3. #include <stdlib.h>
    4. #include "lcd.h"
    5. #include <string.h>
    6. __CONFIG (CLKOUTEN_OFF & FCMEN_ON & IESO_OFF & BOREN_OFF & CP_OFF & MCLRE_OFF & PWRTE_ON & WDTE_OFF & FOSC_INTOSC);//XT
    7. __CONFIG (LVP_ON & LPBOR_OFF & BOREN_ON & STVREN_ON & WRT_OFF);
    8. #define _XTAL_FREQ 4000000
    9. #define FOSC 4000000L
    10. volatile signed int light;
    11. volatile bit on;
    12. //global defs
    13.  
    14.   union
    15. {
    16. unsigned int res;
    17. char bytes[2];
    18. }
    19. ADC;
    20. char ADC_num[6];
    21. float lightintens;
    22.  
    23. static void interrupt isr(void)   // Here is interrupt function - the name is unimportant.
    24. {
    25.     //no interrupt yet.
    26. }// end interrupt
    27.  
    28.  
    29.    
    30. void setup(void)
    31. {    
    32. IRCF3=1;//16MHz clock speed
    33. IRCF2=1;
    34. IRCF1=1;
    35. IRCF0=1;
    36. //REGISTER 5-1: OSCCON: OSCILLATOR CONTROL REGISTER
    37. // bit 6-3 IRCF<3:0>: Internal Oscillator Frequency Select bits
    38. //1111 = 16MHz
    39. //1110 = 8MHz
    40. //1101 = 4MHz
    41. //1100 = 2MHz
    42. //1011 = 1MHz
    43. //1010 = 500 kHz(1)
    44. //1001 = 250 kHz(1)
    45. //1000 = 125 kHz(1)
    46. //0111 = 500 kHz (default upon Reset)
    47. //0110 = 250 kHz
    48. //0101 = 125 kHz
    49. //0100 = 62.5 kHz
    50. //001x = 31.25 kHz
    51. //000x = 31kHz LF
    52. //Port analog / digital
    53. TRISA=0; //all port ud.
    54. TRISA1=1; //set a1 in
    55. TRISB=0; // out
    56. //TRISC=0b11111000;//RC0-RC2 out,RC3-RC7 in,
    57. TRISC=0b00000000;// all other out.
    58. GIE = 0;  // Global interrupt disable just in case
    59. //ANSELA = 0b00000001;  // Set PORT AN0 to analog input AN1 to AN7 digital I/O
    60. ANSELA=0; // set alle digital.
    61. ANSA1=1; //analog
    62. ANSELB=0;
    63. ANSELC=0;//turn off all analog functions
    64.  
    65.  
    66. ///ADCON0=0b00000000;   // select right justify result. ADC port channel 0
    67.  
    68. //adcon1
    69. ADFM=1;    //right justified
    70. //ADCS=100; // fosc/4
    71. ADPREF0=1;
    72. ADPREF1=0;
    73. //ADPREF=00; //vref+ = vdd
    74. TRIGSEL0=0;
    75. TRIGSEL1=0;
    76. TRIGSEL2=0;
    77. TRIGSEL3=0;
    78. CHS0=1;  //an1
    79. CHS1=0;
    80. CHS2=0;
    81. CHS3=0;
    82. CHS4=0; // AN1  analog kanal  intern kanal
    83.  
    84. //timer1 settings
    85. TMR1CS1=1; //CLOCK SOURCE S-ELECTIONS
    86. TMR1CS0=0;
    87. //11 =Timer1 clock source is Capacitive Sensing Oscillator (CAPOSC)
    88. //10 =Timer1 clock source is pin or oscillator:
    89. //If T1OSCEN = 0:
    90. //External clock from T1CKI pin (on the rising edge)
    91. //If T1OSCEN = 1:
    92. //Crystal oscillator on SOSCI/SOSCO pins
    93. //01 =Timer1 clock source is system clock (FOSC)
    94. //00 =Timer1 clock source is instruction clock (FOSC/4)
    95. T1CKPS1=0; // <1:0>: Timer1 Input Clock Prescale Select bits
    96. T1CKPS0=0;
    97. //11 = 1:8 Prescale value
    98. //10 = 1:4 Prescale value
    99. //01 = 1:2 Prescale value
    100. //00 = 1:1 Prescale value
    101. T1OSCEN=1;//LP Oscillator Enable Control bit
    102. //1 = Dedicated Timer1 oscillator circuit enabled
    103. //0 = Dedicated Timer1 oscillator circuit disabled
    104. nT1SYNC=1; //: Timer1 Synchronization Control bit
    105. TMR1ON=0;//: Timer1 On bit
    106. TMR1H = 0x81;     // preset for timer1 MSB register
    107. TMR1L = 0x00;     // preset for timer1 LSB register
    108. TMR1GE=0; // gate for timer1 disable.
    109. //T1GCON: TIMER1 GATE CONTROL REGISTER
    110. //bit 7 TMR1GE: Timer1 Gate Enable bit
    111. //If TMR1ON = 0:
    112. //This bit is ignored
    113. //If TMR1ON = 1:
    114. //1 = Timer1 counting is controlled by the Timer1 gate function
    115. //0 = Timer1 counts regardless of Timer1 gate function
    116.   //Timer1 Interrupt prepare
    117.    TMR1IE=1;// PIE1 register
    118.    PEIE=1; //INTCON register
    119.     //PIR1=0; // Clear all bits PERIPHERAL INTERRUPT REQUEST REGISTER 1
    120.  
    121.    //todo now in order to generate interrupt GEI=1 and TMR1ON=1
    122.  
    123. //timer0 settings.
    124. TMR0IE=0; //use timer0 interrupt register.  ÆNDRET
    125. TMR0CS=0; // bruger tæller,
    126. TMR0SE=0; // lav til høj tælning.
    127. IOCIE=0; // enable interrupt on change  ÆNDRET
    128. PSA=1; //not assign prescaler.
    129. //other misc settings
    130. } //end setup
    131.  
    132.  
    133. void house_on (void)
    134. {
    135. RC0=1;
    136. __delay_ms(5);
    137. RC0=0;
    138. RC1=1;
    139. __delay_ms(5);
    140. RC1=0;
    141. RC2=1;
    142. __delay_ms(5);
    143. RC2=0;
    144. RC3=1;
    145. __delay_ms(5);
    146. RC3=0;
    147. RC4=1;
    148. __delay_ms(5);
    149. RC4=0;
    150. RC5=1;
    151. __delay_ms(5);
    152. RC5=0;
    153. RC6=1;
    154. __delay_ms(5);
    155. RC6=0;
    156. RC7=1;
    157. __delay_ms(5);
    158. RC7=0;
    159.   }
    160.  
    161. void lights_on (void)    //to dark or light.
    162. {
    163.    
    164.                 utoa(ADC_num, light, 10);
    165.                 if (light>50) on=0;
    166.                 if (light<=50)on=1;
    167.                
    168.                
    169. }        // END lights on.
    170.        
    171. void main (void)
    172. {
    173.    
    174. setup();         //runs setup
    175.         __delay_ms(1000);
    176.   // TMR1ON=1;    // timer1
    177.          on=0;
    178.        GIE=0;        //interrupt off
    179.            while (1)// runs loop
    180.          
    181.        {
    182.            lights_on();
    183.            if (on==0)
    184.            {
    185.          
    186.            __delay_ms(1000);      
    187.            }
    188.            if (on==1)
    189.            {
    190.                house_on();
    191.            }
    192.          }//end while endless loop
    193. }//End main
     
  2. ErnieM

    AAC Fanatic!

    Apr 24, 2011
    7,392
    1,606
    The attached schematic does not show the LDR or resistor connected to AN1. In fact, it doesn't even show AN1.

    See if your chip has a comparator; these can sense against a voltage and kick off an interrupt from an otherwise asleep processor.

    When an AN input and a comparator input share a pin they may both be enables so the A2D and comparator read the same pin.
     
  3. JohnInTX

    Moderator

    Jun 26, 2012
    2,347
    1,029
    RA1 is AN1.
    It looks like RA1 is set to analog (but you should remove all of the commented out junk to make it easier to read)
    You don't have an interrupt routine so be sure you never set GIE. The other interrupts should not be enabled as a matter of good programming practice.

    The main problem I see is that you are never actually reading the ADC. In lights_on, 'light' is converted to a string AND compared to a threshold but 'light' is never loaded with anything. You'd have to read the ADC in the result registers and convert to an integer. I would maintain 'light' as the most current light level as measured by the ADC then do any tests, conversion to ASCII etc. in separate routines.

    The variable 'on' is 1)mis-declared as 'volatile' and 2)set as a side-effect in 'lights_on' - not a particularly good programming practice. 3)not a particularly good name - what is turned 'on'? Also, searching for 'on' to see where it occurs in the source gets lots of hits unrelated to the actual variable I'm looking for. Just one of my pet peeves - sorry.

    In general you want to
    1) Set GO/DONE to start the ADC reading
    2) wait for DONE - a good time to do some housekeeping or other tasks.
    3) read ADRES registers to form an unsigned int (or char if you take the upper 8 bits only - probably good enough) - into 'light' so that..
    4) on = ('light' < some_threshold); // TRUE or FALSE loaded into 'on' depending on comparison
    5) Take some action on 'on'.
    6) repeat

    The ADC is pretty fast - you might not need interrupt control at all. As you loop around main, if DONE is set, read the ADC result and set GO again. The conversion will probably be done by the time the program gets back to it. Post the results then hit it again. After the first conversion the result will always be valid so you don't have to wait on the ADC if you don't want to.

    ErnieM has a good point, also. The 1509 has comparators with programmable internal reference levels and hysteresis. That would be a good fit for bang-bang control.

    Have fun.
     
    Last edited: Mar 1, 2015
  4. FroceMaster

    Thread Starter Member

    Jan 28, 2012
    400
    4
    HAve altered some codes, and yes the RA1 is AN1
    The resistor and Photodiode(LDR) is placed on schematic.

    The goal in the project is.
    1. when surrounding lights gets to dark, the housenumber (RC0 to RC7) will lid up
    2. when surrounding lights gets to bright, the housenumber will not lid up.

    Reason to use PIC, : Not really anyone, ;)
    Could have used some other components, but now i choose the PIC.


    Now i can just alter the value reading analog to deside when the surroundning is to dark, and the housenumber should start to light up.
    Code (Text):
    1. #include <htc.h>
    2. #include <stdio.h>
    3. #include <stdlib.h>
    4. #include "lcd.h"
    5. #include <string.h>
    6. __CONFIG (CLKOUTEN_OFF & FCMEN_ON & IESO_OFF & BOREN_OFF & CP_OFF & MCLRE_OFF & PWRTE_ON & WDTE_OFF & FOSC_INTOSC);//XT
    7. __CONFIG (LVP_ON & LPBOR_OFF & BOREN_ON & STVREN_ON & WRT_OFF);
    8. #define _XTAL_FREQ 4000000
    9. #define FOSC 4000000L
    10. volatile signed int lightintens;
    11. volatile bit on_housenumber;
    12.  
    13.   union
    14. {
    15. unsigned int res;
    16. char bytes[2];
    17. }
    18. ADC;
    19. char ADC_num[6];
    20.  
    21.  
    22.  
    23.  
    24.    
    25. void setup(void)
    26. {    
    27. IRCF3=1;//16MHz clock speed
    28. IRCF2=1;
    29. IRCF1=1;
    30. IRCF0=1;
    31. //REGISTER 5-1: OSCCON: OSCILLATOR CONTROL REGISTER
    32. // bit 6-3 IRCF<3:0>: Internal Oscillator Frequency Select bits
    33. //1111 = 16MHz
    34. //1110 = 8MHz
    35. //1101 = 4MHz
    36. //1100 = 2MHz
    37. //1011 = 1MHz
    38. //1010 = 500 kHz(1)
    39. //1001 = 250 kHz(1)
    40. //1000 = 125 kHz(1)
    41. //0111 = 500 kHz (default upon Reset)
    42. //0110 = 250 kHz
    43. //0101 = 125 kHz
    44. //0100 = 62.5 kHz
    45. //001x = 31.25 kHz
    46. //000x = 31kHz LF
    47.  
    48. //Port analog / digital
    49. TRISA=0; //all port ud.
    50. TRISA1=1; //set a1 in
    51. TRISB=0; // out
    52. TRISC=0; //  out.
    53. GIE = 0;  // Global interrupt disable just in case
    54.  
    55. ANSELA=0; // set all digital.
    56. ANSA1=1; //analog
    57. ANSELB=0;
    58. ANSELC=0;//turn off all analog functions
    59. ADFM=1;    //right justified
    60. ADPREF0=1;
    61. ADPREF1=0;
    62.  
    63. TRIGSEL0=0;
    64. TRIGSEL1=0;
    65. TRIGSEL2=0;
    66. TRIGSEL3=0;
    67. CHS0=1;  //an1
    68. CHS1=0;
    69. CHS2=0;
    70. CHS3=0;
    71. CHS4=0; // AN1  analog kanal  intern kanal
    72.  
    73.  
    74. } //end setup
    75.  
    76.  
    77. void housenumber_on (void)
    78. {
    79. RC0=1;
    80. __delay_ms(5);
    81. RC0=0;
    82. RC1=1;
    83. __delay_ms(5);
    84. RC1=0;
    85. RC2=1;
    86. __delay_ms(5);
    87. RC2=0;
    88. RC3=1;
    89. __delay_ms(5);
    90. RC3=0;
    91. RC4=1;
    92. __delay_ms(5);
    93. RC4=0;
    94. RC5=1;
    95. __delay_ms(5);
    96. RC5=0;
    97. RC6=1;
    98. __delay_ms(5);
    99. RC6=0;
    100. RC7=1;
    101. __delay_ms(5);
    102. RC7=0;
    103.   }
    104.  
    105. void check_lightintens (void)    //to dark or to light.
    106. {
    107.          GO_nDONE=1;                // initiate conversion on the channel 1  
    108.              while(GO_nDONE) continue;
    109.                  ADC.bytes[0]=ADRESL;
    110.                  ADC.bytes[1]=ADRESH;
    111.                 utoa(ADC_num, lightintens, 10);
    112.                 if (lightintens>50) on_housenumber=0;
    113.                 if (lightintens<=50)on_housenumber=1;
    114.                
    115.                
    116. }        // END lights on.
    117.        
    118. void main (void)
    119. {
    120.    
    121. setup();         //runs setup
    122.         __delay_ms(1000);
    123.          on_housenumber=0;
    124.    
    125.            while (1)// runs loop
    126.          
    127.        {
    128.            check_lightintens();
    129.            if (on_housenumber==0)
    130.            {
    131.          
    132.            __delay_ms(1000);      
    133.            }
    134.            if (on_housenumber==1)
    135.            {
    136.                housenumber_on();
    137.            }
    138.          }//end while endless loop
    139. }//End main
     
  5. JohnInTX

    Moderator

    Jun 26, 2012
    2,347
    1,029
    Several problems here.
    You are using the union to collect two bytes (ADRESH/L) into an integer but there is no guarantee that the bytes will be in the order you want - that's up to the compiler implementation.
    Your use of utoa is suspect. 'lightintens' is never assigned anything - its not part of the union (even if the bytes happened to be in the proper order)
    You don't need to test twice for a binary result - if lightintens is not >50, it must be <=50.
    Here's how I would do it..
    Code (Text):
    1. unsigned int LightIntensity;    // this does not need to be 'volatile' -
    2. volatile means that the compiler has no control of its value, here it does.
    3. unsigned char ADCtext[6];      // space for text represention of LightIntensity
    4. bit on_housenumber;  // TRUE means its dark
    5.  
    6.     // read ADC then..
    7.     // convert result to unsigned integer
    8.     LightIntensity = (ADRESH*256) + ADRESL; // convert two bytes to int by arithmetic
    9.         // OR
    10.     LightIntensity = (ADRESH << 8) + ADRESL; // convert by logical shift
    11.  
    12.     // test value of the unsigned int (LightIntensity)
    13.     on_housenumber = (LightIntensity <= 50); // true/false assigned to bit
    14.         // OR
    15.     if(LightIntensity <= 50)       // another way to to the same thing
    16.         on_housenumber = 1;
    17.     else
    18.         on_housenumber = 0;
    19.    
    20.     // Finally, convert LightIntensity to an  ASCII string for display only
    21.     //utoa converts UNSIGNED to ASCII - LightIntensity is the input parameter
    22.     utoa(ADCtext,LightIntensity,10); // convert LightIntensity to text
    23.  
    You should use MPSIM or a PICkit debugger to step through your code - all of these problems would jump right out. For simulating the ADC you can use a stimulus file but I'd just use two char variables that I could load and pass them to the convert routine.
    Any better?
     
  6. FroceMaster

    Thread Starter Member

    Jan 28, 2012
    400
    4
    Hi
    Have done a lot of fixing,
    Have just these questions.
    1. The sub "housenumber_on", can this be made some more clever, ex a loop ?
    2. Will it be best to check ADC value , or somehow make a comparetor ?

    Code (Text):
    1. #include <htc.h>
    2. #include <stdio.h>
    3. #include <stdlib.h>
    4. #include "lcd.h"
    5. #include <string.h>
    6. __CONFIG (CLKOUTEN_OFF & FCMEN_ON & IESO_OFF & BOREN_OFF & CP_OFF & MCLRE_OFF & PWRTE_ON & WDTE_OFF & FOSC_INTOSC);//XT
    7. __CONFIG (LVP_ON & LPBOR_OFF & BOREN_ON & STVREN_ON & WRT_OFF);
    8. #define _XTAL_FREQ 4000000
    9. #define FOSC 4000000L
    10. signed int LightIntensity;
    11. bit on_housenumber;
    12.  
    13.   union
    14. {
    15. unsigned int res;
    16. char bytes[2];
    17. }
    18. ADC;
    19. unsigned char ADC_num[6];
    20.  
    21.  
    22.  
    23.  
    24.    
    25. void setup(void)
    26. {    
    27. IRCF3=1;//16MHz clock speed
    28. IRCF2=1;
    29. IRCF1=1;
    30. IRCF0=1;
    31. //REGISTER 5-1: OSCCON: OSCILLATOR CONTROL REGISTER
    32. // bit 6-3 IRCF<3:0>: Internal Oscillator Frequency Select bits
    33. //1111 = 16MHz
    34. //1110 = 8MHz
    35. //1101 = 4MHz
    36. //1100 = 2MHz
    37. //1011 = 1MHz
    38. //1010 = 500 kHz(1)
    39. //1001 = 250 kHz(1)
    40. //1000 = 125 kHz(1)
    41. //0111 = 500 kHz (default upon Reset)
    42. //0110 = 250 kHz
    43. //0101 = 125 kHz
    44. //0100 = 62.5 kHz
    45. //001x = 31.25 kHz
    46. //000x = 31kHz LF
    47.  
    48. //Port analog / digital
    49. TRISA=0; //all port ud.
    50. TRISA1=1; //set a1 in
    51. TRISB=0; // out
    52. TRISC=0; //  out.
    53. GIE = 0;  // Global interrupt disable just in case
    54.  
    55. ANSELA=0; // set all digital.
    56. ANSA1=1; //analog
    57. ANSELB=0;
    58. ANSELC=0;//turn off all analog functions
    59. ADFM=1;    //right justified
    60. ADPREF0=1;
    61. ADPREF1=0;
    62.  
    63. TRIGSEL0=0;
    64. TRIGSEL1=0;
    65. TRIGSEL2=0;
    66. TRIGSEL3=0;
    67. CHS0=1;  //an1
    68. CHS1=0;
    69. CHS2=0;
    70. CHS3=0;
    71. CHS4=0; // AN1  analog
    72.  
    73.  
    74. } //end setup
    75.  
    76.  
    77. void housenumber_on (void)
    78. {
    79. RC0=1;
    80. __delay_ms(5);
    81. RC0=0;
    82. RC1=1;
    83. __delay_ms(5);
    84. RC1=0;
    85. RC2=1;
    86. __delay_ms(5);
    87. RC2=0;
    88. RC3=1;
    89. __delay_ms(5);
    90. RC3=0;
    91. RC4=1;
    92. __delay_ms(5);
    93. RC4=0;
    94. RC5=1;
    95. __delay_ms(5);
    96. RC5=0;
    97. RC6=1;
    98. __delay_ms(5);
    99. RC6=0;
    100. RC7=1;
    101. __delay_ms(5);
    102. RC7=0;
    103.   }
    104.  
    105. void check_lightintens (void)    //to dark or to light.
    106. {
    107.          GO_nDONE=1;                // initiate conversion on the channel 1  
    108.              while(GO_nDONE) continue;
    109.                  ADC.bytes[0]=ADRESL;
    110.                  ADC.bytes[1]=ADRESH;
    111.                  LightIntensity = (ADRESH << 8) + ADRESL;
    112.                
    113.                 on_housenumber = (LightIntensity <= 50);
    114.                
    115.                              
    116.                
    117. }        // END lights on.
    118.        
    119. void main (void)
    120. {
    121.    
    122. setup();         //runs setup
    123.      
    124.          on_housenumber=0;
    125.    
    126.            while (1)// runs loop
    127.          
    128.        {
    129.            check_lightintens();
    130.            if (on_housenumber==0)
    131.            {
    132.          
    133.            __delay_ms(1000);      
    134.            }
    135.            if (on_housenumber==1)
    136.            {
    137.                housenumber_on();
    138.            }
    139.          }//end while endless loop
    140. }//End main
     
  7. paulfjujo

    New Member

    Mar 6, 2014
    20
    3
    pay attention Photodiode is not a LDR,behavior is different.
    to find the good triger level will be more difficult.
     
  8. FroceMaster

    Thread Starter Member

    Jan 28, 2012
    400
    4
    All has now been testet, but i have one small problem.
    When the MCU is reading analog, the "pause" is to long, and the LEDS will be off.
    Somehow i will need the "on_housenumber" to run even when reading analog, can this be done ?
    The "pause" is not long, just some milliseconds, but enough to see the LEDS off.
     
Loading...