+ Post New Thread
Results 1 to 7 of 7
  1. #1
    Newbie level 4
    Points: 71, Level: 1

    Join Date
    Nov 2016
    Posts
    5
    Helped
    0 / 0
    Points
    71
    Level
    1

    How to achieve 2ms sampling rate by using PIC16F877a

    Hi
    I'm new to PIC Microcontrollers.
    My program is PIC16f877a has to take analog input (ex: sine wave) and ADC should sample that analog input with a sampling rate 0.5kHz. That should be displayed on LCD.

    Below I'm attaching a file , which has code.
    But that is not working on proteus.
    I'm using MPLAB IDE and Hitech c compiler.

    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
    
    #include<htc.h>
    #include<pic16f877a.h>
     
    #define LCD_DATA  PORTB
    #define LCD_RS RB2
    #define LCD_EN RB3
     
    #define AN0  0
    #define AN1  1
    #define AN2  2
    #define AN3  3
    #define AN4  4
    #define AN5  5
    #define AN6  6
    #define AN7  7
     
     
    #define _XTAL_FREQ   20000000 
     
    void init();
    void lcddata(unsigned char);
    void lcddisp(unsigned char);
    void lcdcmd(unsigned char);
    void delay(unsigned int);
    void display(const char*);
    unsigned int msCounter = 0;
    unsigned int secCounter = 0;
    unsigned int minCounter = 0;
    unsigned int ADC_value = 0;
     
     
    void interrupt ISR();
    void InitTimer0(void);
    void Init1msecTimerInterrupt(void);
    void UpdateTimeCounters(void);
     
     
    void InitADC(void);
    unsigned int GetADCValue(unsigned char);
     
    void main(void)
    {
        unsigned int ADC_value = 0;
        unsigned int digit1, digit2, digit3, digit4;
     
        InitADC();          // Initialize ADC
        //PORTA=0xff;
        PORTB=0x00;
        TRISB=0x00;
        init();         // Initialize LCD
     
     
    Init1msecTimerInterrupt();      // Start 2 msec timer
     
        
        while(1)
    {
        if(msCounter == 0)       // msCounter becomes zero after exact 2 sec
                {
            
     
            ADC_value = GetADCValue(AN3);       // Read ADC value from RE2(AN7) pin
     
            // ADC_value can have a value from 0 (0v) to 1023(5v) only.
            // SO display 4 digits of ADC_value
            digit1 = (unsigned int)(ADC_value/1000);                                     // Calculate digit1 of ADC_value
            digit2 = (unsigned int)((ADC_value - digit1*1000)/100);                      // Calculate digit2 of ADC_value
            digit3 = (unsigned int)((ADC_value - (digit1*1000+digit2*100))/10);          // Calculate digit3 of ADC_value
            digit4 = (unsigned int)(ADC_value - (digit1*1000+digit2*100+digit3*10));     // Calculate digit4 of ADC_value
     
            lcdcmd(0xc0);lcdcmd(0x00);
            lcddisp(digit1+0x30);       // Display digit1 of ADC_value on LCD
            lcddisp(digit2+0x30);       // Display digit2 of ADC_value on LCD
            lcddisp(digit3+0x30);       // Display digit3 of ADC_value on LCD
            lcddisp(digit4+0x30);       // Display digit4 of ADC_value on LCD
     
            __delay_ms(500);                    // Half second delay before next reading
    }
            UpdateTimeCounters();       // Update sec, min, hours counters*/
        }
    }
     
    void InitADC(void)
    {
        ADCON1  = 0x80;      // Make PORTA and PORTE analog pins
                             // Also, Vref+ = 5v and Vref- = GND
        TRISA   = 0x2f;      // Make RA5, RA3, RA2, RA1, RA0 input
        TRISE   = 0x07;      // Make RE0, RE1 and RE2 input
        ADCON0  = 0x81;      // Turn on the A/D Converter
    }
     
    unsigned int GetADCValue(unsigned char Channel)
    {
        ADCON0 &= 0xc7;         // Clear Channel selection bits
        ADCON0 |= (Channel<<3); // Select channel pin as ADC input
        
        __delay_ms(10);         // Time for Acqusition capacitor 
                                // to charge up and show correct value
        GO_nDONE  = 1;          // Enable Go/Done
     
        while(GO_nDONE);        // Wait for conversion completion
     
        return ((ADRESH<<8)+ADRESL);   // Return 10 bit ADC value
    }
     
     
    void delay(unsigned int v)
      {
      unsigned int i,j;
      for(i=0;i<v;i++)
      for(j=0;j<=1275;j++);
      return;
      }
      
     void init()
        {
        lcdcmd(0x00);lcdcmd(0x20);      // return home
        delay(5);
     
        lcdcmd(0x20);lcdcmd(0x80);      // 4 bit interfacing
        delay(5);
     
        lcdcmd(0x00);lcdcmd(0xc0);      // display on cursor off
        delay(5);
     
        lcdcmd(0x00);lcdcmd(0x60);      // to increment cursor 
        delay(5);
     
        return; 
        }
     
    void lcdcmd(unsigned char v)  
        {
        LCD_DATA=v;  // send the data into the port
        LCD_RS=0;        // command register is selected 
        LCD_EN=1;        // enable the command register
        delay(5);
        LCD_EN=0;        // disable the command register 
        return; 
        }
     
    void lcddata(unsigned char v)
        {
        LCD_DATA=v;   // send the data into the port
        LCD_RS=1;         // data register is selected 
        LCD_EN=1;         // enable the command register
        LCD_EN=0;         // disable the command register 
        return;
        } 
        
     void lcddisp(unsigned char v)
        {                                                     
        unsigned int disp,msb,lsb;
        disp=v;
        msb=disp&0xf0; 
        disp=disp<<4;
        lsb=disp&0xf0;
        lcddata(msb);
        lcddata(lsb);
        return;
        }
        
    void display(const char *s)
    {
        while(*s)
        lcddisp(*s++);
    }
     
    void InitTimer0(void)
    {
        // Timer0 is 8bit timer, select T0CS and PSA to be zero
     
        OPTION_REG &= 0xC1;     // Make Prescalar 1:4
        INTE    = 1;
        GIE     = 1;        // Enable global interrupts
        T0IE = 1;               // Enable Timer0 interrupt
    }
     
    void Init1msecTimerInterrupt(void)
    {
        InitTimer0();       // Intialize timer0 to genrate 1msec interrupts
    }
     
    void UpdateTimeCounters(void)
    {
     
        if (msCounter==2000)
        {
            secCounter++;
            msCounter=0;
         }
        
        }
     
    void interrupt ISR(void)
    {
        if(T0IF)  //If Timer0 Interrupt
        {
            TMR0 = 0x08; // Timer0 should overflow after 250 instructions (250x4 = 1msec)
            T0IF = 0;    // Clear the interrupt 
            //INTF=0;
            msCounter++;
        }
     
    }

    Plaease help me !!!

    Thank you in advance.

    •   AltAdvertisment

        
       

  2. #2
    Super Moderator
    Points: 251,535, Level: 100
    Awards:
    1st Helpful Member

    Join Date
    Jan 2008
    Location
    Bochum, Germany
    Posts
    43,802
    Helped
    13318 / 13318
    Points
    251,535
    Level
    100

    Re: How to achieve 2ms sampling rate by using PIC16F877a

    But that is not working on proteus.
    Means exactly what?



  3. #3
    Advanced Member level 4
    Points: 7,187, Level: 20

    Join Date
    Jan 2015
    Posts
    1,004
    Helped
    320 / 320
    Points
    7,187
    Level
    20

    Re: How to achieve 2ms sampling rate by using PIC16F877a

    I have no idea what problems you are experiencing, but there could well be a logical error in your code.
    In the main loop you check for the 'msCounter' value to be *exactly* 0.
    msCounter is incremented in the ISR and therefore it should be marked as 'volatile' otherwise changes made in the ISR may not be detected elsewhere.
    Also the ISR supposedly updates msCounter every 1 mSec (I think!).
    However there is also a 500mSec delay at the bottom of the main loop. That means that you are not checking the msCounter value during that 500mSec period and it could well be that it is exactly 0 during this period. Therefore the exact match can easily be missed.
    The traditional way of handling this is to set a flag in the ISR when you want something to happen in the main loop and you then test for that. This stops any timing issues.
    Also, why delay after each ADC reading? You will not make another reading for 2 seconds so just let the main loop spin and also update your counter.
    Susan


    1 members found this post helpful.

    •   AltAdvertisment

        
       

  4. #4
    Newbie level 4
    Points: 71, Level: 1

    Join Date
    Nov 2016
    Posts
    5
    Helped
    0 / 0
    Points
    71
    Level
    1

    Re: How to achieve 2ms sampling rate by using PIC16F877a

    First of all thank you for replying!

    My problem is , when I'm running this code in Proteus it is not showing anything on LCD.

    Another thing is,sampling rate (i.e. 0.5 kHz) should be done for every 2ms. ( I thought , for every 2ms if ADC stops,then I will get my required sampling rate. That's why I used timer.)
    I guess I'm wrong.

    And I have one more doubt, in any case if I want particular sampling rate (for ex: 5kHz or more) for an analog input, do we need to use timers.

    I'll once again check my code as per your suggestions.

    Thank you once again for your reply



  5. #5
    Super Moderator
    Points: 69,564, Level: 64
    Achievements:
    7 years registered
    Awards:
    Most Frequent Poster 3rd Helpful Member

    Join Date
    Apr 2014
    Posts
    14,205
    Helped
    3246 / 3246
    Points
    69,564
    Level
    64

    Re: How to achieve 2ms sampling rate by using PIC16F877a

    Hi,

    In my eyes a fixed and known sample rate is the first and very important step for reliable and calculable measurement results.
    Especially wheny you want to do:
    * averaging over a specifed time
    * running average
    * RMS
    * filtering
    * regulation loops.
    *...

    Therefore I recommend to use a microcontroller with a timer periferal that restarts itself...best if the timer can trigger the ADConversion by hardware. Then you have low jitter and it needs low processing power.

    Klaus


    1 members found this post helpful.

  6. #6
    Super Moderator
    Points: 28,508, Level: 41
    andre_teprom's Avatar
    Join Date
    Nov 2006
    Location
    Brazil
    Posts
    8,474
    Helped
    1078 / 1078
    Points
    28,508
    Level
    41
    Blog Entries
    6

    Re: How to achieve 2ms sampling rate by using PIC16F877a

    Quote Originally Posted by Luckky26 View Post
    My problem is , when I'm running this code in Proteus it is not showing anything on LCD.
    Apparently there is a problem with the definition of the microcontroller pinout that communicates with the display. You have defined the PORTB as the data bus; you make access of 8 bits and not 4 bits, however the control pins of the display are also shared in the PORTB ( e.g line #134 of your code : LCD_DATA=v but RS and EN signals are respectivelly on RB2 and RB3 I/O's ).
    --------------------------------------------------------------------------------------------------
    Part of the world that you live in, You are the part that you're giving ( Renaissance )


    1 members found this post helpful.

    •   AltAdvertisment

        
       

  7. #7
    Newbie level 4
    Points: 71, Level: 1

    Join Date
    Nov 2016
    Posts
    5
    Helped
    0 / 0
    Points
    71
    Level
    1

    Re: How to achieve 2ms sampling rate by using PIC16F877a

    Quote Originally Posted by andre_teprom View Post
    Apparently there is a problem with the definition of the microcontroller pinout that communicates with the display. You have defined the PORTB as the data bus; you make access of 8 bits and not 4 bits, however the control pins of the display are also shared in the PORTB ( e.g line #134 of your code : LCD_DATA=v but RS and EN signals are respectivelly on RB2 and RB3 I/O's ).
    Thank you for checking the code.
    I'll change that and try that once again.



--[[ ]]--