/* thermometer2.c
This project is similar to the previous thermometer project, the only
difference is that we will be using the internal analog to digital
converter of the PIC16F72 microcontroller.The PIC16F72 has 5 channel
8 bit adc and 2k program memory.We will learn how to set the various
registers that controls the analog to digital conversion.
ANALOG-TO DIGITAL CONVERTER(A/D) MODULE OF PIC16F72.
The a/d converter module has five inputs for PIC16F72. The adc allows
conversion of an analog input signal to a corresponding 8-bit digital
number ie. it outputs values 0-255.The analog reference voltage is soft-
ware selectable to either the device's positive supply voltage(vdd)or
the voltage on the RA3/vref pin.
The adc module has three registers associated with it. They are,
1) a/d result register------------adres
2) a/d control register0----------adcon0
3) a/d control register1----------adcon1
Now let's see the individual registers and how to configure them.
adcon0(address 0x1F)-----This information is built into your compiler
and gets selected as soon as you slect the chip in the tool bar of your
IDE.
adcon0 is an 8-bit control register as you all know.Let's see the function
of each of its bits & how we should set them.
bit7-6........ADCS<1:0>:a/d conversion clock select bits.
00=Fosc/2
01=Fosc/8
10=Fosc/32
11=Frc(clock derived from the internal a/d module RC oscillator)
*IN THIS PROJECT WE USE 4MHZ CRYSTAL SO WE CHOOSE Fosc/8*
bit5-3........CHS<2:0>:analog channel select bits.
000=channel 0,(RA0/AN0)
001=channel 1,(RA1/AN1)
010=channel 2,(RA2/AN2)
011=channel 3,(RA3/AN3)
100=Channel 4,(RA4/AN4)
*IN THIS PROJECT WE CHOOSE ONLY CHANNEL 0(RA0)*
bit2..........GO/DONE:a/d conversion status.
First to check the status of this bit,you must set ADON bit(coming next)
to 1.
If ADON=1:
1=a/d conversion in progress(setting this bit starts a/d conversion).
0=a/d conversion completed or conversion not in progress.(this bit
is automatically cleared by the hardware when the a/d conversion is
complete).
bit1...........unimplemented,read as 0.
bit0...........ADON:a/d on bit.
1=a/d converter is working.
0=a/d converter is shut off.
So in our c program we configure adcon0 as
adcon0=0b01000001;
adcon1:a/d control register1(address 0x9F)-----This information is built
into your compiler and gets selected as soon as you slect the chip in the
tool bar of your IDE.
bits7-3........unimplented,read as 0.
bits2-0........PCFG<2:0>:a/d port configuration control bits.
PCFG2:PCFG0.....RA0....RA1....RA2....RA5....RA3....VREF
.........000.............A........A.......A........A........A........VDD
.........001.............A........A.......A........A........VREF...RA3
.........010.............A........A.......A........A........A........VDD
.........011.............A........A.......A........A........VREF...RA3
.........100.............A........A.......D........D........A........VDD
.........101.............A........A.......D........D........VREF...RA3
.........11x.............D........D......D........D........D........VDD
A=Analog input
D=Digital i/o.
*IN THIS PROJECT WE CHOOSE RA0,RA1,RA2 PINS AS ANALOG INPUTS
& RA3 AS +VREF.*
So in our c program we write
adcon1=1;
The adres register contains the result of the a/d conversion.When a/d
conversion is complete,the result is loaded into the adres register,
and the GO/DONE bit(adcon0.2)is cleared.
PIC16F72 is a 28 pin chip with porta,portb,portc.In this project i
have used portc pins to drive the transistor(base) connected
to each of the units,tens & hundreds segment ie. to demultiplex data.
The segments are connected to portb, similar to our previous project.
The units segment like in the previous project is inverted to display
"°C".
Porta is set for analog mode.The LM35's signal out pin is connected to
pin RA0.Pin RA3 is connected to the center arm of a 5k pot. The other
two ends of the pot are connected to vdd and ground respectively.
Circuit Connections:
PIC16F72
pin1- MCLR pin to +5v via 4.7K resistor.
pin9-10 4mhz crystal(across pin 9 & 10).
connect 22pf capacitors( between pin9 & gnd, pin10 & gnd).
pin21-RB0-connect to segment decimal point via 470 ohms.
pin22-RB1-connect to segment "e" of the 7-segment display via 470 ohms.
pin23-RB2-connect to segment "a" of the 7-segment display via 470 ohms.
pin24-RB3-connect to segment "f" of the 7-segment display via 470 ohms.
pin25-RB4-connect to segment "c" of the 7-segment display via 470 ohms.
pin26-RB5-connect to segment "g" of the 7-segment display via 470 ohms.
pin27-RB6-connect to segment "b" of the 7-segment display via 470 ohms.
pin28-RB7-connect to segment "d" of the 7-segment display via 470 ohms.
pin20-connect to +5v supply.
pin8- connect to ground.
Base of transistor(U) is connected to RC2(pin13 of micro) via 2.2k resistor.
Base of transistor(T) is connected to RC1(pin12 of micro) via 2.2k resistor.
Base of transistor(H) is connected to RC0(pin11 of micro) via 2.2k resistor.
CONNECTING TEMPERATURE SENSOR LM35 TO PIC16F72.
If LM35 is in TO92 pack,then its pin1 is +5 & pin3 is ground.Please see
data sheet.Pin 2 of LM35 is connected to RA0(pin2)of 16F72.
FIXING THE REFERENCE VOLTAGE.
We have programmed RA3 to be the +vref pin.
So connect the centre arm of a 5k pot to the RA3 pin(pin5). The other
two ends of the pot are connected to vdd and ground respectively.
Using a precision multimeter,adjust the 5k pot connected to the +vref pin
so that the voltage between RA3 to around is 2.55volts.This will make cal-
culations much easy for us.
Now when the analog signal input is 2.55volts the adc will out decimal 255.
Our step resolution becomes 2.55 divided by 255, which is 0.01volts.ie.for
every increment of 0.01volt in the analog signal the adc value will increment
by one.
Our temperature sensor can be used in the region of 0 to 150°C. At 0°C the
analog output is roughly zero and at 150°C its 150mv.The output varies line-
arly by 10mv for an increment of 1°C.
Seven segment modules.
The segment pins of the three 7-segment module must be paralled,ie. all
"a" segments are connected together & all "b" segments are connected &
so on.
Let's call them the units digit,tens digit & hundreds digit.
Common cathode of units digit is connected to transistor(U)'s collector.
Emitter of transistor(U) is connected to ground.
Base of transistor(U) is connected to RC2(pin13 of micro) via 2.2k resistor.
Common cathode of tens digit is connected to transistor(T)'s collector.
Emitter of transistor(T) is connected to ground.
Base of transistor(T) is connected to RC1(pin12 of micro) via 2.2k resistor.
Common cathode of hundreds digit is connected to transistor(H)'s collector.
Emitter of transistor(H) is connected to ground.
Base of transistor(H) is connected to RC0(pin11 of micro) via 2.2k resistor.
Transistor type-BC 547 NPN.
*/CODE
#include <system.h>
#pragma CLOCK_FREQ 4000000 // config clock to 4mhz.
// Set configuration fuse.
#pragma DATA _CONFIG, _XT_OSC & _WDT_OFF & _CP_OFF & _PWRTE_OFF
//A function to get adc value from pic's built-in adc.
void a_d(void);
//A function for 7-segment display to display "0°C-99°C".
void seven_segment1(void);
//A function for 7-segment display to dispaly "0-150".
void seven_segment2(void);
//A function to get segment values for hundreds & tens.
unsigned char get_value1(unsigned char x);
//A function to get segments value for units.
//unit's display module is inverted so as to display degree celsius,
//with decimal point at top of the display.
unsigned char get_value2(unsigned char y);
/*Variable adc is made global for easy access,
which is used in main().*/
unsigned char adc;
//Variable temperature is made global for easy access.
unsigned char temperature;
void main()
{
trisa=255; //set porta as input.
trisb=0; //set all portb pins as output.
trisc=0; //set all portc pins as output pins.
portc=0; //make all portc pins low.
portb=0; //zero all portb pins.
/* make RA0,RA1,RA2 pins as analog inputs & RA3 as +ref.*/
adcon1=1;
/*choose Fosc/8,RA0/AN0 as channel(0),go/done=0,adon=1.*/
adcon0=0b01000001;
unsigned int sample; //sample var holds the adc sample value.
unsigned char b0; //for loop var.
while( 1 ) //Infinite loop.
{
sample=0; //initialize the sample to zero.
for(b0=0;b0<20;b0++) //take 20 adc samples.
{
a_d(); //call function a_d().
sample += adc;
}
temperature=sample/20; //take average of 20 samples.
if(temperature<99) //call seven_segment1 if temperature is less
seven_segment1(); //than 99 else call seven_segment2.
else
seven_segment2();
}
}
void a_d(void) //adc routine.
{
adc=0;
adcon0.2=1; //start ad conversion.
while(adcon0.2==1) //check if conversion is complete.
{
}
adc=adres; //if conversion is over, load adc value.
}
void seven_segment1(void) //seven_segment1 routine.
{
unsigned char b0; //b0 as for loop counter.
unsigned char tens; //holds the tens value to be displayed
unsigned char units; //holds the units value.
tens=temperature/10; //find the tens value.
units=temperature%10; //find the units value.
for(b0=0;b0<250;b0++) //loop it 250 times to see.
{
portb=get_value1(tens); //place the segment value of tens on portb
portc.0=1; //turn on transistor(H).
delay_ms(1); //keep it on for 1ms.
portc.0=0; //turn off transistor(H).
portb=get_value1(units); //place the segment value of units.
portc.1=1; //turn on transistor(T).
delay_ms(1); //keep it on for 1ms.
portc.1=0; //turn it off.
portb=0xD5; //place character "°C" to represent degree celsius.
portc.2=1; //turn on transistor(U).
delay_ms(1); //keep it on for 1ms.
portc.2=0; //turn it off.
}
}
void seven_segment2(void) //seven_segment2 routine.
{
unsigned char b0; //same as above with the only difference
unsigned char hundreds; //in the units segment which in this case
unsigned char tens; // will display the units value instead of
unsigned char units; // character "C". i wish to remind you that
hundreds=temperature/100; //the this display is inverted & so
tens=(temperature%100)/10; //requires a diffrent set of segment
units=temperature%10; //values.This we do by calling get_value2
for(b0=0;b0<250;b0++)
{
portb=get_value1(hundreds);
portc.0=1;
delay_ms(1);
portc.0=0;
portb=get_value1(tens);
portc.1=1;
delay_ms(1);
portc.1=0;
portb=get_value2(units);
portc.2=1;
delay_ms(1);
portc.2=0;
}
}
unsigned char get_value1(unsigned char x)
{
unsigned char segments[10]={0xDE,0x50,0xE6,0xF4,0x78,0xBC,0xBE,0x54,0xFE,0xFC};
return segments[x];
}
unsigned char get_value2(unsigned char y)
{
unsigned char segments[10]={0xDE,0x0A,0xE6,0xAE,0x3A,0xBC,0xFC,0x8A,0xFE,0xBE};
return segments[y];
}
/* In this project we configured the hardware registers of the A to D
converter.See how we do a software polling of pin adcon0.2 to see if
a/d conversion is complete.
If we want we can even configure the adc interrupt bits.So that
once the a/d conversion is complete an interrupt is generated.
The bits associated with this interrupt are
clear ADIF bit
set ADIE bit
set GIE bit.
Try doing this & have lots of fun.
*/
This post has been edited by ra68gi: Mar 12 2007, 02:51 PM