PIC16F877A ADC and seven segment multiplexing

Status
Not open for further replies.

john120

Banned
Joined
Aug 13, 2011
Messages
257
Helped
11
Reputation
22
Reaction score
10
Trophy points
1,298
Visit site
Activity points
0
Hey,who could help me for reading temperature with LM35DZ and display it on 2 seven segment display.
I read on many links but the code did not help me.
I am using CCS C and common anode seven segment display driven by 2 NPN transistors BC337.
See the code here below:

#include<16f877a.h>
#fuses HS,NOWDT
#use delay(clock=20000000)
#include<stdio.h>
#include<STDLIB.H>
#use standard_io(A)
#use standard_io(B)
#use standard_io(D)
#define PORTB
#DEFINE PORTC
#define PORTA

byte const digit[]={0b1111001,0b0100100,0b0110000,0b0011001,0b001001 0,0b0000010,0b1111000,0b0000000,0b0010000};

char display[2];
int value;
int volt;
int value2;
void main()
{
set_tris_A(0xFF);
set_tris_B(0X00);
set_tris_D(0x00);

while(TRUE)
{
setup_comparator(NC_NC_NC_NC);
setup_adc(ADC_CLOCK_INTERNAL);
setup_adc_ports(AN0);
set_adc_channel(0);
setup_vref(FALSE);

{
delay_us(100);
value=read_adc();
read_adc(ADC_START_ONLY);
value=read_adc(ADC_READ_ONLY);

volt=(value/1023)*10;
value2=volt*100;

display[0]=value2%10;
output_high(PIN_D0);

output_B(digit[display[0]]);
delay_ms(10);
display[1]=(value2/10)%10;
output_high(PIN_D1);

output_B(digit[display[1]]);
delay_ms(10);

}
}
}

The seven segment are showing me 77 .when I measure the output of the LM35DZ I find 0.215Volts.

Help with code in ccs c plz!!!
 

Have you tested your 7-segment display to ensure it is functioning correctly? Had it display a sequence of numbers?

BigDog
 
Yes I test ,beacuse I try to show fixed numbers like ,25 and I display it very well!!
 

Good,

I just wanted to narrow down the possible source of the problem.

I haven't used CCS as yet. Are the ADC subroutines your code or CCS's?

BigDog
 
Do you have a schematic of your design?

I'll see if I can find the docs for the CCS library functions. Also have you tried to running the code with a debugger to see at what point the conversion process is failing?

BigDog

---------- Post added at 09:09 ---------- Previous post was at 09:01 ----------

One thing I noticed almost immediately.

Remove the following from the while loop:

Code:
setup_comparator(NC_NC_NC_NC);
setup_adc(ADC_CLOCK_INTERNAL);
setup_adc_ports(AN0);
set_adc_channel(0);
setup_vref(FALSE);

The initialization should only be ran once, so move it above the while loop.


BigDog

---------- Post added at 09:13 ---------- Previous post was at 09:09 ----------

You also have an extra code block without a loop statement:

Code:
{
delay_us(100);
value=read_adc();
read_adc(ADC_START_ONLY);
value=read_adc(ADC_READ_ONLY);

volt=(value/1023)*10;
value2=volt*100;

display[0]=value2%10;
output_high(PIN_D0);

output_B(digit[display[0]]);
delay_ms(10);
display[1]=(value2/10)%10;
output_high(PIN_D1);

output_B(digit[display[1]]);
delay_ms(10);

}

This should not effect code execution, however it is confusing and distracting so you may want to clean it up.
 
Already removed,but nothing new.I don't have my own shcematic but the one I am using is on the link below:

**broken link removed**
 

I found an example which uses a LCD display rather than a 7-segment. The ADC code section is almost identical to your configuration.

The code does have

Code:
#device adc=10

which maybe the problem. Also they use a clock divide on the ADC sampling which would make sense.

Code:
setup_adc (ADC_CLOCK_DIV_8);

I've attached the code and schematic.

Do you have a link to the CCS Library or can you upload it as a PDF?

Let me know if you have any progress.

BigDog
 

Attachments

  • LM35.zip
    58.4 KB · Views: 108
I've fixed the code. Here it is:
Code:
#include<16f877a.h>
#device ADC = 10         // Need to tell compiler ADC is configured for 10-bit reading
#fuses HS,NOWDT
#use delay(clock=20000000)
#include<stdio.h>
#include<STDLIB.H>
#use standard_io(A)
#use standard_io(B)
#use standard_io(D)
#define PORTB
#DEFINE PORTC
#define PORTA


byte const digit[]={0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90}; //Changed this as there was error in the previous one

char display[2];
int value;
unsigned long volt;
unsigned int value2;

void main(){
   set_tris_A(0xFF);
   set_tris_B(0X00);
   set_tris_D(0x00);
   output_b(0);
   output_d(0);

   setup_comparator(NC_NC_NC_NC);
   setup_adc(ADC_CLOCK_INTERNAL);
   setup_adc_ports(AN0);
   set_adc_channel(0);
   setup_vref(FALSE);
   
   while(TRUE){
      delay_us(100);
      //value=read_adc(); //Not required
      read_adc(ADC_START_ONLY);
      delay_us(100);
      value=read_adc(ADC_READ_ONLY);

      volt=(value*500)/1023; //I changed this part of the code
      value2=volt;

      output_low(PIN_D1);
      display[0]=value2/10;
      output_high(PIN_D0);

      output_B(digit[display[0]]);
      delay_ms(10);
      output_low(PIN_D0);
      display[1]=value2%10;
      output_high(PIN_D1);

      output_B(digit[display[1]]);
      delay_ms(10);

   }
}

Hope this helps.
Tahmid.

---------- Post added at 14:57 ---------- Previous post was at 14:56 ----------

I've simulated the above code and it runs fine.
 
The problem is not those statements ,I inserted them but nothing new!!

---------- Post added at 12:09 ---------- Previous post was at 12:03 ----------

I find the code are running very well,now i want to add the third seven segment for display the value which comes after comma ,how to add its statements??

Thanks you very much!!For the reply
 

Is this the situation: you want to show temperature from 0 to 150 'C, so you need the 3rd digit? I'm editing the code for that. But it should be quite straightforward. If you can interface 2 seven segments, the 3rd is done the same way.
 
I tried and it is running now,I want to display three digits with a value which comes after comma.How can I preceed??

---------- Post added at 12:19 ---------- Previous post was at 12:17 ----------

Not up to 150 but for example 23.5 or 25.8 and so on

Thanks
 

I don't think you'll get such accuracy with LM35

---------- Post added at 15:33 ---------- Previous post was at 15:29 ----------

In the datasheet, it's mentioned that the guaranteed accuracy is to 0.5'C. So, you get 23.5'C but you can't reliably get 25.8'C, that is, if you get it at all.
 
Dear Tahimid what if I want to use Common cathode seven segment the digit[] will it change?
I fyes what will it be?
 

You can keep it same and use an inverter at the output. Or you can change it to: {0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x07, 0x7F, 0x6F}

---------- Post added at 15:49 ---------- Previous post was at 15:41 ----------

Let me explain the changes I made to this part of the code:
Code:
      volt=(value*500)/1023; //I changed this part of the code
      value2=volt;

      output_low(PIN_D1);
      display[0]=value2/10;
      output_high(PIN_D0);

      output_B(digit[display[0]]);
      delay_ms(10);
      output_low(PIN_D0);
      display[1]=value2%10;
      output_high(PIN_D1);

      output_B(digit[display[1]]);
      delay_ms(10);

Firstly, I declared the variable volt as long type. The problem with your code is, first you divide by 1023. So, this means that the ADC reading is divided by 1023. So, since volt is an integer (meaning whole number, not int) data type, for any ADC reading between 0 to 1022, the result is 0, and for 1023, the result is 1. So, in that particular line of yours, you always either get 0 or 10.

Then, the "scaling/processing" of the input variable. Let's say that the temperature is 80'C. So, LM35 produces output of 80*10 = 800mV = 0.8V
This corresponds to an ADC reading of (0.8/5)* 1023 = 163.68 (stored as 164)

Let's say I want it such that the ADC reading is converted to the temperature and stored in the register "volt".
So, 163.68 corresponds to 80'C. 1023 corresponds to 500. This is what we multiplied by.

Code:
display[0]=value2/10;
Let's say value2 now holds 82. So, 82/10 is returned as 8 - the value to be displayed.
Code:
display[1]=value2%10;
Again, if value2 holds 82, 82%10 is returned as 2 - the value to be displayed.

Hope this helps.
Tahmid.
 
Dear Tahimid,I changed the array for driving now common cathode because are the one I have in enough quantity,now I drive them with BC327 (NPN Transistor) and change PIC16F877A to PIC16F876A but the pin corresponding to A of my seven segment is not working .
for example two(2) is displayed incomplete what is the problem.

Thank you for your explainations!!
 

Yes the circuits is the same except
the common anode I changed to Common Cathode
BC337 changed to BC327
The array of the code for seven segment which has been modified to the one of common cathode

Thx!!

---------- Post added at 13:07 ---------- Previous post was at 13:03 ----------

Dear Tahimid I want also to use a switch which can switch the circuit on and off
what is the loop can I use
I used
while(input(PIN_A1)==0)
because I connected it to the ground but I switch on only but off is not going.
Help me also on that!!
 

Just to clarify, this should be the circuit:


and the code:
Code:
#include<16f877a.h>
#device ADC = 10         // Need to tell compiler ADC is configured for 10-bit reading
#fuses HS,NOWDT
#use delay(clock=20000000)
#include<stdio.h>
#include<STDLIB.H>
#use standard_io(A)
#use standard_io(B)
#use standard_io(D)
#define PORTB
#DEFINE PORTC
#define PORTA


byte const digit[]={0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x07, 0x7F, 0x6F}; //Changed this as there was error in the previous one

char display[2];
int value;
unsigned long volt;
unsigned int value2;

void main(){
   set_tris_A(0xFF);
   set_tris_B(0X00);
   set_tris_D(0x00);
   output_b(0);
   output_d(0);

   setup_comparator(NC_NC_NC_NC);
   setup_adc(ADC_CLOCK_INTERNAL);
   setup_adc_ports(AN0);
   set_adc_channel(0);
   setup_vref(FALSE);
   
   while(TRUE){
      delay_us(100);
      //value=read_adc(); //Not required
      read_adc(ADC_START_ONLY);
      delay_us(100);
      value=read_adc(ADC_READ_ONLY);

      volt=(value*500)/1023; //I changed this part of the code
      value2=volt;

      output_low(PIN_D1);
      display[0]=value2/10;
      output_high(PIN_D0);

      output_B(digit[display[0]]);
      delay_ms(10);
      output_low(PIN_D0);
      display[1]=value2%10;
      output_high(PIN_D1);

      output_B(digit[display[1]]);
      delay_ms(10);

   }
}

The above circuit and code simulates properly.

Hope this helps.
Tahmid.

---------- Post added at 16:08 ---------- Previous post was at 16:08 ----------

Wait, working on the switch.

---------- Post added at 16:18 ---------- Previous post was at 16:08 ----------

Here's the code:
Code:
#include<16f877a.h>
#device ADC = 10         // Need to tell compiler ADC is configured for 10-bit reading
#fuses HS,NOWDT
#use delay(clock=20000000)
#include<stdio.h>
#include<STDLIB.H>
#use standard_io(A)
#use standard_io(B)
#use standard_io(D)
#define PORTB
#DEFINE PORTC
#define PORTA


byte const digit[]={0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x07, 0x7F, 0x6F}; //Changed this as there was error in the previous one

char display[2];
int value;
unsigned long volt;
unsigned int value2;

void main(){
   set_tris_A(0xFF);
   set_tris_B(0X00);
   set_tris_D(0x00);
   output_b(0);
   output_d(0);

   setup_comparator(NC_NC_NC_NC);
   setup_adc(ADC_CLOCK_INTERNAL);
   setup_adc_ports(AN0);
   set_adc_channel(0);
   setup_vref(FALSE);
   
   while(TRUE){
      if (input(PIN_A1) == 0){
         delay_us(100);
         //value=read_adc(); //Not required
         read_adc(ADC_START_ONLY);
         delay_us(100);
         value=read_adc(ADC_READ_ONLY);
   
         volt=(value*500)/1023; //I changed this part of the code
         value2=volt;
   
         output_low(PIN_D1);
         display[0]=value2/10;
         output_high(PIN_D0);
   
         output_B(digit[display[0]]);
         delay_ms(10);
         output_low(PIN_D0);
         display[1]=value2%10;
         output_high(PIN_D1);
   
         output_B(digit[display[1]]);
         delay_ms(10);
      }
      else{
         output_low(PIN_D0);
         output_low(PIN_D1);
         output_B(0);
      }

   }
}

The change to the circuit will be:
A pull-up resistor will be connected to RA1 (10k resistor between RA1 and +5v). Switch is connected between RA1 and ground.

Hope this helps.
Tahmid.
 
Status
Not open for further replies.

Similar threads

Cookies are required to use this site. You must accept them to continue using the site. Learn more…