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] How to achieve 2ms sampling rate by using PIC16F877a

Status
Not open for further replies.

Luckky26

Newbie level 4
Joined
Nov 17, 2016
Messages
5
Helped
0
Reputation
0
Reaction score
0
Trophy points
1
Activity points
81
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.
 

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
 
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
 

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
 
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 ).
 
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.
 

Status
Not open for further replies.

Similar threads

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top