Jump to content
ra68gi

"pic Micro Programming In Boostc For Beginners"

Recommended Posts

ra68gi    0

" Please don't reply to this thread"

 

Hello friends,

 

This thread is started with the intension of providing quick start to beginners in programming PIC microcontrollers using BoostC compiler.

 

All code examples have been tested by me either using the simulator or by hard wiring the device.

 

Who will benefit from this thread?

 

1. Absolute beginners.

2. Those wanting to migrate from other compilers/languages like PicBasic,PicPascal, etc.

 

If you have suggestions or questions please post it on a new thread.

 

Raghunathan

Edited by ra68gi

Share this post


Link to post
Share on other sites
ra68gi    0

 

/*

WINK LED

 

Our first c program.Blinking two LEDs on portb pin0 & pin1.

Chip-16F84,8 i/o pins on portb & 5 i/o pins on porta.

 

TO DO THIS PROJECT YOU REQUIRE..

 

1. Source Boost(SB)IDE - FREE Down load is available from

www.sourceboost.com

2. BoostC compiler - Comes along with the SB IDE

3. Take a print of the IDE user's manual and follow instructions.

4. Take a print of BoostC compiler reference manual.

5. PIC16F84 microcontroller & components listed below.

6. PIC16F84 data sheet available from microchip website.

7. Any PIC programmer.

 

How to Build/compile your C Program?

 

1. Select tool suit, target chip and clock rate from settings in the toolbar

& view the same on the source boost IDE status bar at the bottom of the

screen.

At this point your screen is blank.

2. First click the New button on the tool bar.

3. You can Copy & paste this code from this thread or type in the code as

written below.

4. Now choose, save as & save your file.

5. Go to the project button on the toolbar.

6. Select the project you want to build by clicking on the appropriate file.

In our case it is WINK LED. The sreen will go blank at this point.

7. Now your poject is selected and ready to build.

8. Now open the file again by clicking the file button or open button from

the tool bar.

9. To cross check again if its the program you are going to compile, press

the project button & see if the name of your file is right at the top of

list of projects.

10.Now press Build button.

 

If every thing works out well you can see success on your build/output window

at the bottom of the IDE.

 

How to check if your code is working?

 

Before you load the hex file onto your chip, you can use the built in simulator

on the SourceBoost IDE to check if your code is working just as intended.Read

the IDE user's manual to get help to configure your plugins.

 

 

Connections:

pin4- MCLR pin to +5v via 4.7K resistor

pin15-16 4mhz crystal(across pin 15 & 16)

connect 22pf capacitors( between pin15 & gnd, pin16 & gnd)

pin6-RB0-connect LED to pin6 via 470 ohms. Cathode of LED to gnd.

pin7-RB1-connect LED to pin7 via 470 ohms. Cathode of LED to gnd.

*/

#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
void main()
{
   trisb = 0;        //configure port B pins as output
   while( 1 )      //endless loop
   {
     portb.0=1;        // set portb pin0 to high.
     portb.1=0;        // set portb pin1 to low.
     delay_ms( 250 );  // pause 0.5 seconds
     delay_ms( 250 );  // (note we have to call delay_ms twice because it's 
                       //  argument has unsigned char type)
     portb=0x02;       // shows hex notation for entering data.
     delay_ms( 250 );  // you can also write portb=2 in decimal
     delay)ms( 250 );
   }
}

/* The PIC 16F84 contains two I/O ports, portA & PortB. Each port

has two registers associated with it, TRIS (Tri state) register and

port register itself. The tris register controls whether a particular

pin on a port is configured as input pin or output pin.Once the pins

have been configured using tris register you may read or write data

to the port using the port register.

 

Writing a zero to a bit in tris register will make the corresponding

bit or pin in port as output, capable of sourcing and sinking current.

writing a one to a bit in tris register will make the corresponding

pin in port as input. The microcontroller is capable of reading data

placed on this pin. The same pin can be changed from input to output

within a program by setting the tris register bit associated with it.

 

In the above example we have entered zero into the trisb register

there by making all the eight pins in portb as output.

portb=255; will make all pins as input. You can also use binary

notation to select individual bits for input or output.

example: trisb = 0B10101011; .

 

BoostC also allows us to choose individual bits in a register.

example: trisb.0=0; makes portb pin0 as output.

 

Once the pins have been configured as output, placing a one

in the port register will make it high(+5v) & placing a zero

in the port register will make it low(0v, capable of sinking

25ma current).

 

I am really amazed by the compact code size generated by this

compiler. It takes just 34 words of program memory space comp-

ared to 54 words by PicBasicPro and 70 words by mikroC.

 

*/

pic_project.bmp

Edited by Pavel

Share this post


Link to post
Share on other sites
ra68gi    0

/* BINARY COUNT
This is a simple binary counting program that will light eight
LEDs connected to portb pins of PIC16f84. The binary count program
will light the LEDs in sequence from "0" to"255" incrementing by
one. Each binary 1 in a number will be represented with a lit LED.
Every 0.5 seconds the count is incremented. After reaching the
binary number 255 ( the maximum byte value ), the sequence repeats,
from zero.

Before you load the hex file onto your chip, you can use the built
in simulator on the SourceBoost IDE to check if your code is working
just as intended.Read the IDE user's manual to get help to configure
your plugins.

Connections:
pin4- MCLR pin to +5v via 4.7K resistor
pin15-16 4mhz crystal(across pin 15 & 16)
connect 22pf capacitors( between pin15 & gnd, pin16 & gnd)
pin6-RB0-connect LED to pin6 via 470 ohms. Cathode of LED to gnd.
pin7-RB1-connect LED to pin7 via 470 ohms. Cathode of LED to gnd.
pin8-RB2-connect LED to pin8 via 470 ohms. Cathode of LED to gnd.
pin9-RB3-connect LED to pin9 via 470 ohms. Cathode of LED to gnd.
pin10-RB4-connect LED to pin10 via 470 ohms. Cathode of LED to gnd.
pin11-RB5-connect LED to pin11 via 470 ohms. Cathode of LED to gnd.
pin12-RB6-connect LED to pin12 via 470 ohms. Cathode of LED to gnd.
pin13-RB7-connect LED to pin13 via 470 ohms. Cathode of LED to gnd.
*/

#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
void main()   // Program entry point,mandatory for every C program.
{
 trisb=0;      // configure port B pins as output
 char b0;      // Define b0 as character
 while(1)      // Infinite loop
 {
  for(b0=0;b0<256;b0++)   // For loop in C. See description below.
  {
   portb=b0;              // Place b0 value at Portb to light LEDs.
   delay_ms(250);         // Pause for 0.5 seconds & then go to display
   delay_ms(250);          
  }                       // the next incremented b0 value.
 }                        // Because b0 has char data type it never reaches 256 
                          // so this loop never exits.
}                         
  

/* In our second program BINARY COUNT, we see two new statements.
The first is char b0;. b0 is a variable declared by us as character.
In BoostC variables or data can be declared as bit, char, unsigned char,
signed char, short, unsigned short, signed short, int ( integer ),
unsigned int, signed int, long ( 32 bit data ), unsigned long, signed long.
Please see BoostC user's manual for more info.
The second statement is for(b0=0;b0<256;b0++). for is a loop control
construct. It controls the number of times a block of statements is
executed. The construct has an initial value, and a loop-count value that
is incremented each time after the block is executed.
This is similar to the Basic command "for x = 0 to 255".
Program memory space used in this program is 31 words.
*/

PIC4.bmp

Edited by Pavel

Share this post


Link to post
Share on other sites
ra68gi    0

/* BINARY PROGRESSION
The binary progression program lights each LED in sequence,
starting from the first LED connected to RB0, then the second
led(RB1) while the first is switched off and then the third led
connected to RB2 is switched on while the second led is switched
off and so on. So the LEDs will scroll from left to right.

Before you load the hex file onto your chip, you can use the built
in simulator on the SourceBoost IDE to check if your code is working
just as intended. Read the IDE user's manual to get help to configure
your plugins.

Connections:
pin4- MCLR pin to +5v via 4.7K resistor
pin15-16 4mhz crystal(across pin 15 & 16)
connect 22pf capacitors( between pin15 & gnd, pin16 & gnd)
pin6-RB0-connect LED to pin6 via 470 ohms. Cathode of LED to gnd.
pin7-RB1-connect LED to pin7 via 470 ohms. Cathode of LED to gnd.
pin8-RB2-connect LED to pin8 via 470 ohms. Cathode of LED to gnd.
pin9-RB3-connect LED to pin9 via 470 ohms. Cathode of LED to gnd.
pin10-RB4-connect LED to pin10 via 470 ohms. Cathode of LED to gnd.
pin11-RB5-connect LED to pin11 via 470 ohms. Cathode of LED to gnd.
pin12-RB6-connect LED to pin12 via 470 ohms. Cathode of LED to gnd.
pin13-RB7-connect LED to pin13 via 470 ohms. Cathode of LED to gnd.
*/

#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
void main() 
{
 trisb=0;                      // make portb pins as output
 char b0;                      // declare b0 as character
 char b1;                      // declare b1 as character
 while(1)                      // endless loop
 {
  b0=1;                        // initialize b0 variable to 1.
  portb=b0;                    // display b0 value on portb
  delay_ms(250);               // pause 0.5s for us to see the lit LED
  delay_ms(250);
  for(b1=0;b1<7;b1++)          // for loop for seven times
  {
    b0*=2;                     // C syntax for multiply and assign.
    portb=b0;                  // similar to basic syntax of b0=b0*2
    delay_ms(250);             // pause 0.5 sec to see the LED on.
    delay_ms(250);
   } 
 }   
}

/* The only statement new in this C program is " b0*=2;". Here the
C compiler multiplies b0 value with 2 and assigns this new value
to b0. It is similar to b0=b0*2. Multiplying b0 with 2, causes
the bits in b0 to shift left by one place.
Take a print of BoostC compiler reference manual and you will
find the list of arithmatic operators, assignment operator,
comparison operator, logical operators.
This program compiles to 43 words.

In the above code change b0=1; as b0=128; in the while loop
and also change b0 *= 2; as b0 /= 2; in the for loop. Build the
code and check it on the simulator. What do you see?
You can see the LED patern has reversed, ie. the LEDs would
scroll from left to right. You could call it regression. If you wish
to store it, use the save as option first and then build it using the
quick buid option in the project menu of the tool bar.
*/

Edited by Pavel

Share this post


Link to post
Share on other sites
ra68gi    0

 

 

/* BUTTON TEST

In this program we make our microcontroller(PIC16F84) to read

switches connected to porta which will dynamically modify the

program as it runs. We have connected three switches to the porta.

We have named them button1, button2, button3. The main program

is the scrolling LED program we had seen earlier. Pressing button1

will change the direction in which the LEDs scroll. Pressing butt-

on2 will increment the delay time for which the LEDs are lit. pres-

sing button3 will reduce the delay time for which the LEDs are lit.

 

Before you load the hex file onto your chip, you can use the built

in simulator on the SourceBoost IDE to check if your code is working

just as intended.Read the IDE user's manual to get help to configure

your plugins.

 

Connections:

pin4- MCLR pin to +5v via 4.7K resistor

pin15-16 4mhz crystal(across pin 15 & 16)

connect 22pf capacitors( between pin15 & gnd, pin16 & gnd)

pin6-RB0-connect LED to pin6 via 470 ohms. Cathode of LED to gnd.

pin7-RB1-connect LED to pin7 via 470 ohms. Cathode of LED to gnd.

pin8-RB2-connect LED to pin8 via 470 ohms. Cathode of LED to gnd.

pin9-RB3-connect LED to pin9 via 470 ohms. Cathode of LED to gnd.

pin10-RB4-connect LED to pin10 via 470 ohms. Cathode of LED to gnd.

pin11-RB5-connect LED to pin11 via 470 ohms. Cathode of LED to gnd.

pin12-RB6-connect LED to pin12 via 470 ohms. Cathode of LED to gnd.

pin13-RB7-connect LED to pin13 via 470 ohms. Cathode of LED to gnd.

pin17-RA0-connect switch, button1.

pin18-RA1-connect switch, button2.

pin1-RA2-connect switch, button3.

 

There are two different ways in which you can configure your switch.

.ie. the switch can output a high when pressed or a low when pressed.

Based on this information you need to modify the code in your

if statement.But this code works as it is on the simulator. In the

future i will provide the schematic for all the projects done here.

If you hard wire this project, make sure your micro sees the right

switch state.

*/

 

#include <system.h>
#pragma CLOCK_FREQ 4000000
// Set configuration fuse
#pragma DATA _CONFIG, _XT_OSC & _WDT_OFF & _CP_OFF & _PWRTE_OFF
void check1(void);    // declare that you are using a routine
                     // called check1.
void check2(void);    // declare that you are using a routine
                     // called check2.
int duration;         // duration is declared as global variable.

#define button1 porta.0         // button1 is alais for porta.0
#define button2 porta.1         // button2 is alais for porta.1
#define button3 porta.2         // button3 is alais for porta.2
 
void main(void)
{                            // Program entry point.
 trisa=7;                   // set porta pin0-pin2 as inputs.
 trisb=0;                   // set portb pins as output.
 portb=0;                   // set portb pins to low.
 duration=250;              // set initial value of delay at 250ms
 while(1)                   // infinite loop.
{
 if(button2)                // if button2 is pressed, execute
 {                          // the following statements.
   duration+=10;            // increment duration by 10ms.
   if(duration==1000)       // if duration equals 1000ms,
   {
   duration=990;            // make it 990ms.
   }                        // this will limit the max delay.
     }
 if(button3)                // if button3 is pressed, execute
 {                          // the following statements.
   duration-=10;            // reduce delay by 10ms.
   if(duration==10)         // if delay equals 10ms,
   {
   duration=20;             // make it 20ms.
   }                        // this will limit the min delay.
     }
 if(button1==0)             // if button1 pin is not pressed,
 {                          // execute the statements below 
 check1();                  // call routine check1.
 portb <<= 1;          // shift bits in portb to its left, ones.
 delay_ms(duration);        // pause for the value of duration.
 }
 else                         // else if porta.0 pin is high
 {                            // execute the statements below.
 check2();                    // call routine check2.
 portb>>=1;     // shift bits in portb to its right by one place.
 delay_ms(duration);          // pause for the value of duration.
 }
 }
   }
  
void check1(void)              // check1 routine.
{
 if(portb==0)                 // if portb equals zero,
{                             // then execute the statements below.
   portb=1;                   // make portb to display 1.
   delay_ms(duration);        // pause for the value of duration.
   } 
  
} 
void check2(void)              // check2 routine.
{
 if(portb==0)                 // if portb equals zero,
{                        // then execute the following statements.
   portb=128;                 // make portb to display 128.
   delay_ms(duration);        // pause for the value of duration.
   }
  
}

 

 

/* Lets try to understand the C program line by line. In the beginning

of the program you can see two routines check1 & check2. These routines

get called from the main routine void main(void). In Basic programming

we call it sub-routines. Unlike the Basic sub-routine it does not have

a return statement.It is important that you declare all the routines

used at the beginning of the code for the compiler to recognize it latter

in the program.

 

The routine check1 checks if portb value is zero and if found true makes

it equal to one, so that the binay progression can repeatedly continue.

Similarly check2 checks if portb valve is zero and if true makes it equal

to 128, so that the binary regression can continue. See that check2 rou-

tine is called only if button1 is pressed or true.

 

Next in line is int duration; statement. See that duration is declared

as an integer because we require more than one byte to store a duration

of 1000. Also you can see that it is declared outside the all the

routines, meaning that all routines can access the variable and modify

it. Thats why we call it global variable.

 

The next statement is #define button1 porta.0. What the compiler does is,

it simply replaces button1 with porta.0 while compiling. For us its more

convenient and easy to understand the code.So the name button1 is an alais

for porta.0.

 

The rest of the program is self explanatory.In the main routine trisa=7;

sets porta pins 0-2 as input. trisb=0 makes all pins in portb as output.

The delay variable is given an initial value of 250ms. Then the program

enters the endless loop, while(1);. In this loop we check if the buttons

are pressed. The if statement if(button2) is same as if(button2==1). It

means if button2 is true or 1 execute the statements that follows.

One other new operator we have used is portb>>=0; and portb<<=0;.

They are shift right & assign and shift left and assign operators. They create

the same effect as b0*=2; and b0/=2; used in our earlier program.

This program compiles to 98 words.

*/

PIC8modified.bmp

Edited by Pavel

Share this post


Link to post
Share on other sites
ra68gi    0

 

 

/* BINARY CODED DECIMAL DISPLAY

In this project we will display the binary data outputted by the port

on two seven segment LED modules. We will make the seven segment display

decimal 0 to 99. We can use the 4511 BCD to 7-segment converter IC for

our purpose. The lower nibble of portb is connected to one of the 7-seg-

ment via 4511 to display the units value & the higher nibble of portb is

connected to the second 7-segment via another 4511 to display the tens

value.

Source Boost IDE has got this plugin on its simulator. So its very easy

to verify your code.

 

Connections:

pin4- MCLR pin to +5v via 4.7K resistor.

pin15-16 4mhz crystal(across pin 15 & 16).

connect 22pf capacitors( between pin15 & gnd, pin16 & gnd).

lower nibble or units display.

pin6-RB0-connect to pin7 of 4511(1).

pin7-RB1-connect to pin1 of 4511(2).

pin8-RB2-connect to pin2 of 4511(4).

pin9-RB3-connect to pin6 of 4511(8).

upper nibble or tens display.

pin10-RB4-connect to pin7 of 4511.

pin11-RB5-connect to pin1 of 4511.

pin12-RB6-connect to pin2 of 4511.

pin13-RB7-connect to pin6 of 4511.

 

Remaining pin connections of 4511.

pin13-to "A" segment of 7-segment via 470 ohms.

pin12-to "B" segment of 7-segment via 470 ohms.

pin11-to "C" segment of 7-segment via 470 ohms.

pin10-to "D" segment of 7-segment via 470 ohms.

pin9- to "E" segment of 7-segment via 470 ohms.

pin15-to "F" segment of 7-segment via 470 ohms.

pin14-to "G" segment of 7-segment via 470 ohms.

pin16-to +5v.

pin3-to +5v.

pin4-to +5v.

pin5-to ground.

pin8-to ground.

 

7-segment display-common cathode-to ground.

 

*/

#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
void main()
{
trisb=0;                   //make portb as output.
portb=0;                   //set portb pins to low.
char b0;                   //declare b0 as character type variable.
char units;                //declare units as character type variable.
char tens;                 //declare tens as character type variable.
char bcd;                  //declare bcd as character type variable.
while(1)                   //endless loop
{
for(b0=0;b0<100;b0++)      //for loop, which outputs 0-99 as BCD.
{
tens=b0/10;              //tens value is first calculated.
units=b0%10;             //next units value is derived.
tens *= 16;           //we shift the tens value to the upper nibble.
bcd=units+tens;  //we add the upper & lower nibble to get BCD value.
portb=bcd;             //out the BCD value on portb.
delay_ms(250);           //wait half a second for us to see display.
delay_ms(250);
}
}
 }

/* This program compiles to 91 words. In the above program change all

char variables to unsigned char variables and see the program words saved.

*/

Edited by Pavel

Share this post


Link to post
Share on other sites
ra68gi    0


/* 3-digit-7-segment_display
(Using PIC16F84)
In this project we will connect three common cathode 7-segment modules
in parallel & then connect them to the 7 pins of portb(RB1thro'RB7) via
470 ohms resistors. In all our future projects we will use RB1 TO RB7
pins for our 7 LEDs of the segment module. We will demultiplex the data
to the 7-segment modules by using three transistors connected to the
common cathode pin of each of the module. The base of the transistors are
driven from porta pins. This project will form the base for our future
projects like A/D converter or a digital thermometer, digital clock etc.
The C program will display decimal 0 to 999 on the three segments. The
program is in a loop and so will continue to display from 0 once again
after it reaches the value off 999.

We can't use the simulator for this project. So we have to hard wire to see
our code work. I have checked it on my board. You can probably use a bread
board to test it.

Connections:
PIC16F84
pin4- MCLR pin to +5v via 4.7K resistor.
pin15-16 4mhz crystal(across pin 15 & 16).
connect 22pf capacitors( between pin15 & gnd, pin16 & gnd).
pin6-RB0-no connection.
pin7-RB1-connect to segment "e" of the 7-segment display via 470 ohms.
pin8-RB2-connect to segment "a" of the 7-segment display via 470 ohms.
pin9-RB3-connect to segment "f" of the 7-segment display via 470 ohms.
pin10-RB4-connect to segment "c" of the 7-segment display via 470 ohms.
pin11-RB5-connect to segment "g" of the 7-segment display via 470 ohms.
pin12-RB6-connect to segment "b" of the 7-segment display via 470 ohms.
pin13-RB7-connect to segment "d" of the 7-segment display via 470 ohms.
pin14-connect to +5v supply.
pin5- connect to ground.
Base of transistor(U) is connected to RA2(pin1 of micro) via 2.2k resistor.
Base of transistor(T) is connected to RA1(pin18 of micro) via 2.2k resistor.
Base of transistor(H) is connected to RA0(pin17 of micro) via 2.2k resistor.

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 RA2(pin1 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 RA1(pin18 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 RA0(pin17 of micro) via 2.2k resistor.

Transistor type-BC 547 NPN.
*/

 

#include <system.h>
#pragma CLOCK_FREQ 4000000
// Set configuration word
#pragma DATA _CONFIG, _XT_OSC & _WDT_OFF & _CP_OFF & _PWRTE_OFF
//declare function get_value.
unsigned char get_value(unsigned char y); 
unsigned char y;
unsigned char units;       //declare units as unsigned char variable.
unsigned char tens;        //declare tens as unsigned char variable.
unsigned char hundreds;    //hundreds as unsigned char variable.
 
void main(void)
{
trisa=0;        //make porta as output.
porta=0;        //make porta pins low.
trisb=0;        //make portb as output.
portb=0;        //make portb pins low.

while(1)        //endless loop.
{
unsigned int b0;   //declare b0 as unsigned integer variable.
unsigned char b1;  //declare b1 as unsigned character.
for (b0=0;b0<1000;b0++)   //for loop to display 0-999.
{
hundreds=b0/100;    //get the hundred's value.
tens=(b0%100)/10;   //get the ten's value.
units=b0%10;        //get the unit's value.
for (b1=0;b1<100;b1++)  //display data hundred times.
{
portb = get_value(hundreds);  //get segment value.
porta.0=1;           //switch on tranisistor(H).
delay_ms(1);         //pause 1ms to see data.
porta.0=0;           //switch off transistor(H).
portb=get_value(tens);       //get segment value.
porta.1=1;           //switch on tranisistor(T).
delay_ms(1);         //pause 1ms to see data.
porta.1=0;           //switch off transistor(T).
portb=get_value(units);      //get segment value.
porta.2=1;           //switch on tranisistor(U).
delay_ms(1);         //pause 1ms to see.
porta.2=0;           //switch off transistor(U).
}
}
}
}
//lookup table for the segment values.
unsigned char get_value(unsigned char y)
{
unsigned char segments[10]={0xDE,0x50,0xE6,0xF4,0x78,0xBC,0xBE,0x54,0xFE,0xFC};
return segments[y];
}

 

/* The C program first intializes the ports as output. Next we
enter the while loop where we have created a for loop which will
make b0 to take values from 0-999. Next we proceed to determine
the hundred's, ten's and unit's value of b0. These values are then
passed on to the lookup table which is an array of values. The array
contains the segment value that has to be outputted on portb. The
values are for "0" to "9" decimal.When this value is outputted on
portb, the appropriate leds light up to from the digits. First we
output the hundred's value on portb & switch on the transistor(H)
connected to the hundreds digit for a brief period of 1ms and then
switch it off. Next we place the ten's value on portb and switch
on & off the transistor(T) & then we do the same thing for the units
value. This is repeated for 100 times so that we can see all the three
digits on all the time. Changing the loop value b1 will change the rate
at which numbers will appear on the display. You can vary the delay
time as well as the loop value b1 to see the effect.See how an array
is declare in the function get_value & how the return statement returns
the appropriate segment value.All variables are declared as unsigned
character in order to save program words.This program compiles to
208 words.
*/

pic13.bmp

pic11modified.bmp

Edited by Pavel

Share this post


Link to post
Share on other sites
ra68gi    0

/* Thermometer1.c
In our previous program we learnt how to display values on 7-segment display.
In this program we make PIC16F84A display temperature read from LM35 tempera-
ture sensor.PIC16F84A doesn't have built in analog to digital converter.So we
shall use an external analog to digital converter(adc) TLC549.This adc is an
serial adc & outputs the adc value serially on its (SDA OUT) pin6.

A little information about analog and digital signals.

An analog signal is infinitely variable between any two of its measuring
points, no matter how close the two measuring points may be.For example,
the number of possible readings between 1volt and 2 volts are infinite.
similarly between 1volt and 1.0001volt we can have infinite values of vol-
tages like 1.000001 or 1.000000001volts & so on.So we can have infinitesi-
mally varying values of voltages.

A digital signal equivalent of an analog signal is not infinitely variable.
The digital equivalent of an analog signal varies in step proportion deter-
mined by the resolution of the a/d converter.

Lets take a typical example.
suppose we have an anolog signal which varies from 0 to 5volts. and suppose
we use an 8 bit adc, then the resolution of our converter is 256(8 bit values)
or the adc will typically return values from 0 to 255.The adc will return 0
if it finds a analog voltage value of 0 and return 255 if it finds an analog
voltage of 5volts (provided the reference to the adc is +5volts).
step resolution of the converter is the step increment in the analog value
for a step change in digital signal.In our above case its 5volts divided by
255(not 256) which is 0.0196volts.Which means that when ever the analog vol-
tage changes by 0.0196volts the adc will increment its digital output value
by 1.

some adc values for the analog inputs for the above example are
analog value--------------adc value
0volts-------------------------0
0.0196v-----------------------1
0.0392v-----------------------2
0.0588v-----------------------3
.........................................
.........................................
5.0v---------------------------255

Some information about LM35 temperature sensor.

NATIONAL SEMICONDUCTORS LM35 DATA SHEET
LM35
Precision Centigrade Temperature Sensors
General Description
The LM35 series are precision integrated-circuit temperature
sensors, whose output voltage is linearly proportional to the
Celsius (Centigrade) temperature. The LM35 thus has an
advantage over linear temperature sensors calibrated in
° Kelvin, as the user is not required to subtract a large
constant voltage from its output to obtain convenient Centigrade
scaling. The LM35 does not require any external
calibration or trimming to provide typical accuracies of ±1/4°C
at room temperature and ±3/4°C over a full -55 to +150°C
temperature range. Low cost is assured by trimming and
calibration at the wafer level. The LM35’s low output impedance,
linear output, and precise inherent calibration make
interfacing to readout or control circuitry especially easy. It
can be used with single power supplies, or with plus and
minus supplies. As it draws only 60 µA from its supply, it has
very low self-heating, less than 0.1°C in still air. The LM35 is
rated to operate over a -55° to +150°C temperature range,
while the LM35C is rated for a -40° to +110°C range (-10°
with improved accuracy). The LM35 series is available packaged
in hermetic TO-46 transistor packages, while the
LM35C, LM35CA, and LM35D are also available in the
plastic TO-92 transistor package. The LM35D is also available
in an 8-lead surface mount small outline package and a
plastic TO-220 package.
Features
1 Calibrated directly in ° Celsius (Centigrade)
2 Linear + 10.0 mV/°C scale factor
3 0.5°C accuracy guaranteeable (at +25°C)
4 Rated for full -55° to +150°C range
5 Suitable for remote applications
6 Low cost due to wafer-level trimming
7 Operates from 4 to 30 volts
8 Less than 60 µA current drain
9 Low self-heating, 0.08°C in still air
10 Nonlinearity only ±1/4°C typical
11 Low impedance output, 0.1 W for 1 mA load

In our project we will use the sensor in the range of0°C-150°C.

Some information about Texas Instruments TLC549 serial adc .

TLC549 data sheet.

Microprocessor Peripheral or Standalone Operation
8-Bit Resolution A/D Converter
Differential Reference Input Voltages
Conversion Time . . . 17 ms Max
Total Access and Conversion Cycles Per Second
TLC548 . . . up to 45 500
TLC549 . . . up to 40 000
On-Chip Software-Controllable
Sample-and-Hold Function
Total Unadjusted Error . . . ±0.5 LSB Max
4-MHz Typical Internal System Clock
Wide Supply Range . . . 3 V to 6 V
Low Power Consumption . . . 15 mW Max
Ideal for Cost-Effective, High-Performance
Applications including Battery-Operated
Portable Instrumentation
Pinout and Control Signals Compatible
With the TLC540 and TLC545 8-Bit A/D
Converters and with the TLC1540 10-Bit
A/D Converter
CMOS Technology

description
The TLC548 and TLC549 are CMOS analog-to-digital converter (ADC) integrated
circuits built around an 8-bit switched-capacitor successive-approximation
ADC. These devices are designed for serial interface with a microprocessor
or peripheral through a 3-state data output and an analog input. The TLC548
and TLC549 use only the input/output clock (I/O CLOCK) input along with the
chip select (CS) input for data control.The maximum I/O CLOCK input frequency
of the TLC548 is 2.048 MHz, and the I/O CLOCK input frequency of the TLC549
is specified up to 1.1 MHz.
For certain applications, such as strobing applications, it is necessary to
start conversion at a specific point in time.This device accommodates these
applications. Although the on-chip sample-and-hold function begins sampling
upon the high-to-low transition of the fourth I/O CLOCK cycle, the hold fun-
ction does not begin until the high-to-low transition of the eighth I/O CLO-
CK cycle, which should occur at the moment when the analog signal must be
converted. The TLC548 and TLC549 continue sampling the analog input until
the high-to-low transition of the eighth I/O CLOCK pulse. The control circu-
itry or software then immediately lowers I/O CLOCK and starts the holding f-
unction to hold the analog signal at the desired point in time and starts
the conversion.

Circuit Connections:
PIC16F84
pin4- MCLR pin to +5v via 4.7K resistor.
pin15-16 4mhz crystal(across pin 15 & 16).
connect 22pf capacitors( between pin15 & gnd, pin16 & gnd).
pin6-RB0-no connection.
pin7-RB1-connect to segment "e" of the 7-segment display via 470 ohms.
pin8-RB2-connect to segment "a" of the 7-segment display via 470 ohms.
pin9-RB3-connect to segment "f" of the 7-segment display via 470 ohms.
pin10-RB4-connect to segment "c" of the 7-segment display via 470 ohms.
pin11-RB5-connect to segment "g" of the 7-segment display via 470 ohms.
pin12-RB6-connect to segment "b" of the 7-segment display via 470 ohms.
pin13-RB7-connect to segment "d" of the 7-segment display via 470 ohms.
pin14-connect to +5v supply.
pin5- connect to ground.
Base of transistor(U) is connected to RA2(pin1 of micro) via 2.2k resistor.
Base of transistor(T) is connected to RA1(pin18 of micro) via 2.2k resistor.
Base of transistor(H) is connected to RA0(pin17 of micro) via 2.2k resistor.

TLC549 connections:
pin1(Ref+)- connect this pin to the center or variable terminal or pin of a
5k potentiometer. Connect one end of the pot to +5v and other to the ground.

pin2(Analog input)- connect this pin to LM35 signal out pin.If LM35 is TO92
package,its the center lead.other two pins of LM35 is given to +5v and ground.
Again if LM35 is in TO92 pack then its pin1 is +5 & pin3 is ground.Please see
data sheet.

pin3(Ref-)- connect this pin to ground.
pin4(Gnd)- connect to ground.
pin5(CS)- chip select pin is active low.connect this pin to RA3(pin2 of 16f84).
pin6(Data out)- connect this pin to RB0(pin6 of 16f84).
pin7(i/o clock)- connect this pin to RA4(pin3 of 16f84).
Note- Pin RA4 is open drain & so use a 1k pullup resistor to +5v.
pin8(Vcc)- connect to +5volts.

FIXING THE REFERENCE VOLTAGE.
Using a precision multimeter,adjust the 5k pot connected to the Ref+ pin of
TLC549 to around 2.55volts.This will make calculations 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 RA2(pin1 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 RA1(pin18 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 RA0(pin17 of micro) via 2.2k resistor.

Transistor type-BC 547 NPN.

One main difference between this project's display schematic & the previous
is that in this project we invert the units display module.Please note we
only physically rotate the module through 180° but the electrical connections
remain the same. We do this so that the decimal point in the segment appears to
the top left position, so that we can create the character "°C".
Until the temperature of 99 the units digits will display "°C",beyond 99 it will
display all three decimal digits.Since the last digit is inverted i have used
a seperate set of segment values or lookup table for it.

When i finished programming i realized that i had no pin left to connect the
decimal point in the units segment.
So i decided to directly connect this pin to +5volts via 470 ohms. The only odd
thing is that it will be lit even while displaying temperatures beyond 99°C.

*/

 

#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
#include <system.h>
//A function to create clock pulse for TLC549
void clk(void);
//A function to get adc value serially from TLC549
void serial_adc(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.
//units 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 bit access in
serial_adc() function which is used in main().*/
unsigned char adc;
//Variable temperature is made global for easy access.
unsigned char temperature;
void main()
{ 
 trisa=0;        //set porta as output.
 trisb=1;        //set porb.0 as input & rest of the pins as output.
 portb=0;        //zero all portb pins.
 porta=8;        // make chip select pin of TLC549 high. 
 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++)
 {
 serial_adc();
 sample += adc;
 }
 temperature=sample/20; 
 if(temperature<99)      //call seven_segment1 if temperature is less
 seven_segment1();       //than 99 else  call seven_segment2.
 else
 seven_segment2(); 
 }
 }
 
void serial_adc(void)  //serial_adc routine.
{
 adc=0;
 porta.3=0;          // bring chip select low to start adc.
 adc.7=portb.0;      //load the most significant bit of adc.
 clk();              //send clock pulse to get the next adc bit.
 adc.6=portb.0;      //load it onto the next significant bit.
 clk();              // & so on until the last adc bit.
 adc.5=portb.0;
 clk();
 adc.4=portb.0;
 clk();
 adc.3=portb.0;
 clk();
 adc.2=portb.0;
 clk();
 adc.1=portb.0;
 clk();
 adc.0=portb.0;
 clk();
 porta.3=1;
 }
 
void clk(void)       //The clock routine.   
{
 porta.4=1;         //Make porta.4 high.
 porta.4=0;         //Make porta.4 low.
}
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
 porta.0=1;                //turn on transistor(H).
 delay_ms(1);              //keep it on for 1ms.
 porta.0=0;                //turn off transistor(H).
 portb=get_value1(units);  //place the segment value of units.
 porta.1=1;                //turn on transistor(T).
 delay_ms(1);              //keep it on for 1ms.
 porta.1=0;                //turn it off.
 portb=0xD4;        //place character "C" to represent degree celsius.
 porta.2=1;         //turn on transistor(U).
 delay_ms(1);       //keep it on for 1ms.
 porta.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);
 porta.0=1;
 delay_ms(1);
 porta.0=0;
 portb=get_value1(tens);
 porta.1=1;
 delay_ms(1);
 porta.1=0;
 portb=get_value2(units);
 porta.2=1;
 delay_ms(1);
 porta.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];
}

 


/*Whats new in this program?
See how the function serial_adc() milks out the adc value bit by bit
and stores it.
Twenty samples of adc values are taken and is averaged out to get a
more stable read out. Try for yourself with different number of samples.

You can see two different display routines. One for displaying upto 99°C
& another for beyond 99°C.Since the last segment module is inverted in-
order to display °C, i had to use a different look table (get_value2())
to put the units value of temperature readings beyond 99.

This program compiles to 338 words.

You have also got 10bit serial adc chips. Try using them in your projects.
Our next project will use the built in adc of the PIC microcontroller.
I wish to use PIC16F72. This chip is available for less than a Dollar in
my place & so i purchased them.Try downloading its data sheet and go thro-
ugh its adc specs & how to configure them.
*/

PIC33.bmp

pic13modified_tlc549_thermometer.bmp

Edited by Pavel

Share this post


Link to post
Share on other sites
ra68gi    0

/* 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.

*/

 

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

*/

Edited by Pavel

Share this post


Link to post
Share on other sites
ra68gi    0

 

 

/* timer0_interrupt.c

In this project we make the timer0 of the PIC microcontroller to measure

a time interval of 250 micro seconds.The timer0(tmr0) is made to generate

an interrupt every 250us.We then count 4000 of such interrupts to get a

precise 1 second interval. We change the state of an LED once we finish

counting 4000. So the LED will be lit for a duration of 1sec & off for the

next 1sec & it keeps switching on & off. The idea behind this project is

to help you understand as to how the tmr0 can be set to generate an accurate

1sec interval.This code will turn out to be the building block of our next

project a digital clock, which will display hours,minutes & seconds.

 

What's an interrupt?

Anything that interrupts our normal course of activity (or program) can be

considered an interrupt.Suppose we are doing our normal house hold activity

of cleaning our house & all of a sudden we hear the calling bell ringing, you

can then consider the ringing of the bell as an interrupt. What do we do?

We immediately stop the current activity of cleaning & attend to the person

who rang the calling bell. In a similar fashion the main program in the

microcontroller gets interrupted by what we call hardware interrupts.

Note,here the word main in the main program is not suggestive of the importance

of the program. Hardware interrupts will cause the microcontroller to halt the

execution of the current code & jump to a location in the program memory where the more important task or program also called interrupt service routine (ISR) is stored.After executing the ISR it gets back to the main program from where it had abruptly left.

When an interrupt occurs the first thing the microcontroller does before it

jumps to the ISR is to save the contents of the files.ie. the status register,

w register,port setting etc so that when it returns back from the ISR it can

restore these settings & carry on with its actvity from the setting in which it

had left.

Interrupt sources on PIC16F84

1.External interrupt RB0/INT pin.

2.TMR0 overflow interrupt.

3.PORTB change interrupts(pins RB7:RB4)

4.Data EEPROM write complete interrupt

See the microcontroller data sheet for more information on interrupts.

In our project we will be using the tmr0 interrupt.

 

Now i will show you how to set the tmr0 interrupt.

 

The timer0 module.

The timer0 module timer/counter has the following fearutes:

1.8-bit timer/counter

2.Readable & writable

3.Internal or external clock select

4.Edge select for external clock

5.8-bit software programmable prescaler

6.Interrupt-on-overflow from 255 to 0

 

First we need to know the various registers associated with tmr0.

They are..

 

1.tmr0 module register

This register is a counter that can display values 0 to 255 so its a

8bit counter.If the prescaler assignment bit(in the option register)

is set to 1 & t0cs( tmr0 clock source select bit) bit in the option

register is set to 0 then tmr0 counter value increments itself every

instruction cycle.

 

2.option register(option_reg)(address 0x81)

note:In the older chips, data sheet call them option_reg, but in the new

ones they call it just option.The SB compiler recognizes only option_reg.

The names of these register can be seen from the .h files in the include

folder,which in itself are in the SB folder.

 

In this project we are only concerned with the t0cs(tmr0 clock source

select bit) & the psa(prescaler assignment bit) of the option_reg.

 

bit5....t0cs: tmr0 clock source select bit

1 = transition on RA4/TOCKI pin

0 = internal instruction cycle clock.(we will use this mode for our proj-

ect, so make option_reg.5=0)

 

bit3....psa: prescaler assignment bit

1 = prescaler assigned to WDT. ( we use this mode for our project)

0 = prescaler assigned to tmr0 module

so we make option_reg.3=1

 

bit2-0....ps2:ps0: prescaler rate select bits

I have made all three bits as 0 & have chosen 1:1 for the

WDT. This setting is not going to be important to us since we have disabled

the WDT through our pragma directive(configuration word).

To learn more about prescaler see data sheet.

 

Now our option_reg is configured to the value..

option_reg = 0b00001000; //or option_reg=8;

 

3.intcon register(interrupt controller register)(address 0x0b)(its also

mirrored onto all other banks of the chip).

Here we are only concerned with three control bits they are..

 

bit7....gie: global interrupt enable bit

1 = enable all unmasked interrupts.(we choose this bit to enable interrupt)

0 = disable all interrupts.

 

bit5....toie: tmr0 overflow interrupt enable bit.

 

bit2....t0if: tmr0 overflow interrupt flag bit.

1 = tmr0 register has overflowed.(we clear this flag in the ISR so that we

can enable the next interrupt)

0 = tmr0 has not overflowed.

 

Circuit connection: Device PIC16F84

pin4- MCLR pin to +5v via 4.7K resistor

pin15-16 4mhz crystal(across pin 15 & 16)

connect 22pf capacitors( between pin15 & gnd, pin16 & gnd)

pin6-RB0-connect LED to pin6 via 470 ohms. Cathode of LED to gnd.

 

Buid this program & step thro' the code using the source boost simulator.

See how the micro spends most of its time in while loop and jumps to the

ISR every time the tmr0 rolls over from 255 to 0.Since we have connected

a 4MHz crystal the internal clock frequency is Fosc/4 = 1MHz & so the tmr0

increments its self every instuction cycle which in our case is 1us.We have

set the tmr0 in such a way as to count 250us for an interrupt to occur.This

we do by writing tmr0+=9; in the ISR.We count 4000 of such interrupts which

will result in 4000*250us = 1000000us or 1second and we change the state of

the led to indicate this.

 

*/

 

#include <system.h>
// Set clock frequency to 4MHz.
#pragma CLOCK_FREQ 4000000
//set configuration fuse.
#pragma DATA _CONFIG, _XT_OSC & _WDT_OFF & _CP_OFF & _PWRTE_OFF
/*Interrupt service routine (ISR).On timer0 interrupt, program
 will jump to this code location.  */   
void interrupt( void )
{
unsigned char tick;
unsigned char tick1;
// writing 9 onto tmr0 will generate interrupts at 250us interval.
   tmr0 +=9;   
   tick++;       //increment variable tick.
   if(tick>19)   //if tick equals 20, increment tick1 & reset tick.
   {
   tick=0;
   tick1++;      //if tick1 equals 200,we have counted 4000 ticks
if(tick1>199)    //in total, which equals 1 second(4000*250us).
   {
   tick1=0;        //reset tick1.
portb.0=~portb.0;   //toggle the led to show that 1sec has elapsed.
    }
    }
    intcon.2=0;  //clear TMR0 overflow flag
}
// The main code configures the option & intcon registers.
void main()
{
    trisb = 0;         //configure port B
    portb = 0;         //clear port B
    option_reg = 8;     //no prescaler & start tmr0
   
// enable interrupts
    intcon.5=1;     //enable tmr0 overflow interrupt   
    intcon.7=1;     //enable global interrupt
   
/*simply write 6 to tmr0 counter value.This line will not alter
the accuracy of the clock, so it can be removed if you wish.
*/
    tmr0=6; 

    while( 1 ); //do nothing & wait for tmr0 interrupt.
}

 

/*

To check the accuracy of the timer interrupt code we have written you

can use the stop watch in the mplab simulator. For this you need to

integrate the boostC compiler with mplab ide. Look into the BoostC com-

iler reference manual for information on integrating with mplab.

*/

Edited by Pavel

Share this post


Link to post
Share on other sites
ra68gi    0


/* digital_clock.c
Now that you know how to configure the timer0 to generate accurate
time interval, let's construct a digital clock that will display
hours, minutes and seconds on six led segment display. We will use
the same common cathode segment used in our earlier projects. We will
use PIC16F72 for this project because it has 22 i/o pins. The main
features of this project at a glance.

a)Uses tmr0 for time keeping.
b)We use PIC16F72
c)4MHZ crystal frequency
d)six no. of 7-segment display, to display hours, minutes & seconds.
e)two button switch to set hours and minutes.
f)six BC547(NPN)transistors to demultiplex the data bus(portb).

In the previous project i had explained about interrupts by comparing
the similarity in real world like the example of calling bell ringing
& that of microcontrollers hardware interrupts. Let's apply the calling
bell example to our digital clock. If you look at the program below,
you will see that the microcontroller spends most of its time firing
the transistors to display the hours, minutes & seconds segments, this
is similar to us doing our household activity. But in the background
the tmr0 counter keeps ticking without any of our intervention. In fact
we are not even aware that the tmr0 is ticking until an interrupt occurs
when it rolls over from 255 to 0.And when the interrupt occurs we quickly
update the tick, tick1, seconds, minutes, hours in the ISR and then get
back to doing our usual work of lighting the segments. The interrupt
generated by tmr0 can be considered similar to the ringing of the calling
bell.

This code may initially look more convoluted with the function
sec(), min(),hrs(),but you will soon see how advantageous it would
be to call them only when the data gets updated & rest of the time
we simply display the old value of data. By doing this we get a
flicker free display.

I had made this circuit on a bread board. Since the segments are dirctly
connected to the PIC via 150 ohms without any driver and since multiplexing
six segments will reduce the mean led current, you will see that the segments
are not very bright, but i found it excellent when seen with a red filter.

Circuit connection:
pin20- VDD pin to +5v.
pin8- VSS pin to 0v.
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-no connection.

Seven segment modules.
The segment pins of the six 7-segment module must be paralled,ie. all
"a" segments are connected together & all "b" segments are connected &
so on.

pin22-RB1-connect to segment "e" of the 7-segment display via 150 ohms.
pin23-RB2-connect to segment "a" of the 7-segment display via 150 ohms.
pin24-RB3-connect to segment "f" of the 7-segment display via 150 ohms.
pin25-RB4-connect to segment "c" of the 7-segment display via 150 ohms.
pin26-RB5-connect to segment "g" of the 7-segment display via 150 ohms.
pin27-RB6-connect to segment "b" of the 7-segment display via 150 ohms.
pin28-RB7-connect to segment "d" of the 7-segment display via 150 ohms.

pin11-RC0-to base of Q1 driving the units segment of seconds via 10k.
pin12-RC1-to base of Q2 driving the tens segment of seconds via 10k.
pin13-RC2-to base of Q3 driving the units segment of minutes via 10k.
pin14-RC3-to base of Q4 driving the tens segment of seconds via 10k.
pin15-RC4-to base of Q5 driving the units segment of hours via 10k.
pin16-RC5-to base of Q6 driving the tens segment of hours via 10k.

collector of Q1 is connected to cc(common cathode)of units segment of
seconds digit & its Emitter to ground.
collector of Q2 is connected to cc of tens segment of seconds digit & its
Emitter to ground.
collector of Q3 is connected to cc of units segment of minutes digit & its
Emitter to ground.
collector of Q4 is connected to cc of tens segment of minutes digit & its
Emitter to ground.
collector of Q5 is connected to cc of units segment of hours digit & its
Emitter to ground.
collector of Q6 is connected to cc of tens segment of hours digit & its
Emitter to ground.

Q1,Q2,Q3,Q4,Q5,Q6- BC547 NPN transistors.

button switch connection:
button switches will generally have two pins which are normally open and
on pressing the button gets closed.
Connect a 10k resistor to +5v. on the other end of the resitor is conncted
both to PIC micros input pin & one of the pins of the button switch. The
other pin of the button switch is grounded.
When the button switch is NOT pressed the PIC micro will read a high & when
pressed it will read a low.

pin17-RC6 to button switch1 and a pullup resistor of 10k connected to +5v.
pin18-RC7 to button switch2 and a pullup resistor of 10k connected to +5v.

pressing button switch1 will increment minutes.
pressing button switch2 will increment hours.

How to set the clock?
You have two button switches connected to portc.6 & postc.7. As soon
as you power on the circuit you will see the hours and minutes segements
flash 00 alternately. Now pressing the hours button(portc.7)will increment
the hours. As soon as it reaches the right hours, stop pressing or release
the button. next press the minutes button(portc.6) & set it similarly. Once
both value are set press both these buttons(portc.6 & portc.7) simultaneously.
It will immediately jump to the clock routine and the clock will start to
tick( you can see the seconds segment increment).

*/

 

#include <system.h>
// Set configuration word
#pragma CLOCK_FREQ 4000000
#pragma DATA _CONFIG, _XT_OSC & _WDT_OFF & _CP_OFF & _PWRTE_OFF
/*all of the below variables are made global for easy access in
our functions.*/
bit updatesec = 0;
bit updatemin = 0;
bit updatehrs = 0;
unsigned char seconds = 0;
unsigned char minutes = 0;
unsigned char hours = 0;
unsigned char unitsec = 0;
unsigned char tensec = 0;
unsigned char unitmin = 0;
unsigned char tenmin = 0;
unsigned char unithrs = 0;
unsigned char tenhrs = 0;
//timer0 interrupt service routine.   
void interrupt( void )
{
unsigned char tick;
unsigned char tick1;
   tmr0 +=9;  // add 9 to generate interrupt every 250us.
   tick++;
   if(tick>19)
   {
   tick=0;
   tick1++;
   if(tick1>199)
   {
   tick1=0;
   seconds++;
//a flag to indicate that seconds has been updated   
   updatesec=1; 
   if(seconds>59)
   {
   seconds=0;
   minutes++;
//a flag to indicate that minutes has been updated
   updatemin=1;
   if(minutes>59)
   {
   minutes=0;
   hours++;
//a flag to indicate that hours has been updated
   updatehrs=1;
   if(hours>23)
  {
   hours=0;
     }
    }
  }
 }
}
    intcon.2=0;  //clear TMR0 overflow flag
}
//function to get segment values.
unsigned char get_value(unsigned char y)
{
unsigned char segments[10]={0xDE,0x50,0xE6,0xF4,0x78,0xBC,0xBE,0x54,0xFE,0xFC};
return segments[y];
}

//a function to get tens & units place for seconds.
void sec(void)
{
  tensec = get_value(seconds/10);
  unitsec= get_value(seconds%10);
}
//a function to get tens & units place for minutes.
void min(void)
{
  tenmin = get_value(minutes/10);
  unitmin = get_value(minutes%10);
}
//a function to get tens & units place for hours.
void hrs(void)
{
  tenhrs = get_value(hours/10);
  unithrs = get_value(hours%10);
} 
 
//main program starts here.   
void main()
{
unsigned char a;
    trisb = 0;        //configure port B
    portb = 0;        //clear port B
//portc.7 & portc.6 are made as inputs & the rest as outputs.   
   trisc = 0b11000000; 
    portc = 0;
   
   while(1)
   {
//set time by pressing the appropriate button.   
  
//if both switches are closed start clock.   
   if((portc.6 == 0) && (portc.7 == 0))
   {
    goto clock;
     }
//if switch in portc.6 is pressed increment minutes     
   if(portc.6 == 0)
   {
    minutes++;
    if(minutes>59)
    {
     minutes=0;
      }
    }
//call function min() to get units & tens value for minutes.   
   min();
   for(a=0;a<250;a++)
   {
    portb = unitmin;
    portc.2=1;
    delay_ms(2);
    portc.2=0;
    portb = tenmin;
    portc.3=1;
    delay_ms(2);
    portc.3=0;
     }
//again check for both switches to be closed.
    if((portc.6 == 0) && (portc.7 == 0))
    {
     goto clock;
      }
//if switch in portc.7 is pressed increment hours.     
    if(portc.7 == 0)
    {
     hours++;
     if(hours>23)
     {
      hours=0;
       }
     }
//call function min() to get units & tens value for hours.     
    hrs();
    for(a=0;a<250;a++)
    {
     portb = unithrs;
     portc.4=1;
     delay_ms(2);
     portc.4=0;
     portb = tenhrs;
     portc.5=1;
     delay_ms(2);
     portc.5=0;
     }
    if((portc.6 == 0) && (portc.7 == 0))
    {
     goto clock;
       }
}
//start clock
clock:
    updatesec=1;
    updatemin=1;
    updatehrs=1;
  
//assign prescaler to wdt & start tmr0.
    option_reg = 8;   
   
   // enable interrupts
    intcon.5=1; //enable tmr0 overflow interrupt   
    intcon.7=1; //enable global interrupt
//set tmr0 to genterate interrupt at every 250us.   
    tmr0=6;   

    while( 1 )   //endless loop
    {
   if(updatesec==1)  //check for update flag,if set
    {
    updatesec=0;  //clear the flag & call function sec
    sec();        // to get units & tens value
    }             //for seconds.
    for(a=0;a<60;a++)
    {
    portb = unitsec;
    portc.0=1;
    }
    portc.0=0;
    for(a=0;a<60;a++)
    {
    portb = tensec;
    portc.1=1;
    }
    portc.1=0;
    if(updatemin==1)
    {
    updatemin=0;
    min();
    }
    for(a=0;a<60;a++)
    {
    portb = unitmin;
    portc.2=1;
    }
    portc.2=0;
    for(a=0;a<60;a++)
    {
    portb = tenmin;
    portc.3=1;
    }
    portc.3=0;
    if(updatehrs==1)
    {
    updatehrs=0;
    hrs();
    }
    for(a=0;a<60;a++)
    {
    portb = unithrs;
    portc.4=1;
    }
    portc.4=0;
    for(a=0;a<60;a++)
    {
    portb = tenhrs;
    portc.5=1;
    }
    portc.5=0;
 }
}

 

/*
In the ISR see how the tick, tick1 gets incremented. Also see how
the seconds minutes and hours gets incremented. See how these update
flag bits are set and cleared.
This code compiles to 397 words
*/

Edited by Pavel

Share this post


Link to post
Share on other sites

Your content will need to be approved by a moderator

Guest
You are commenting as a guest. If you have an account, please sign in.
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoticons maximum are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...

×