The LM335 temperature sensor is an analog device which requires an ADC module to convert
the analog data which is the voltage output from the LM335 into digital
data. The LM335 has the following features:
Directly Calibrated to the Kelvin Temperature Scale
1°C Initial Accuracy Available
Operates from 400 μA to 5 mA
Less than 1-Ω Dynamic Impedance
Easily Calibrated
Wide Operating Temperature Range
200°C Overrange
Low Cost
The LM135 has a breakdown voltage directly proportional to
absolute temperature at 10 mV/°K. If the LM335 output voltage is for
example is 3.03 (3030 mV) that means the temperature is: 303 °Kelvin =
30 °Celsius.
This topic shows how to interface the LM335 temperature sensor with PIC16F877A microcontroller. Hardware Required:
Interfacing PIC16F877A with LM335 temperature sensor circuit:
The LM335 sensor has 3 pins (from left to right):
Pin 1 for calibration, not used in this example
Pin 2: output
Pin 3: GND (ground).
The output pin of the LM335 sensor is connected to analog channel 0 (AN0). I chose the 2.2K ohm because as written in the datasheet for optimum accuracy the current flows through the LM335 should be 1mA. For example if the temperature = 27°C, the output will be 3.00V and assume the supply voltage is exactly 5.00V that means the current flows through the sensor is ( 5 - 3)/2.2 = 0.90mA which is good enough. Also the value 2.2K is a standard value and well used.
The 1602 (16x2) LCD screen is connected to pins RD0~6. The 10K variable resistor is used to adjust the brightness of the screen.
In this example the PIC16F877A runs with 8MHz crystal oscillator. Interfacing PIC16F877A with LM335 sensor CCS C Code:
The following C code was tested with CCS PIC C compiler version 5.051.
/* Interfacing PIC16F877A with LM335 analog temperature sensor CCS C code. Read LM335 datasheet to understand the code! http://ccspicc.blogspot.com/ electronnote@gmail.com*///LCD module connections#define LCD_RS_PIN PIN_D0
#define LCD_RW_PIN PIN_D1
#define LCD_ENABLE_PIN PIN_D2
#define LCD_DATA4 PIN_D3
#define LCD_DATA5 PIN_D4
#define LCD_DATA6 PIN_D5
#define LCD_DATA7 PIN_D6
//End LCD module connections#include <16F877A.h>
#fuses HS,NOWDT,NOPROTECT,NOLVP
#device ADC=10
#usedelay(clock = 8MHz)
#include <lcd.c>
char message1[] = "Temp = 00.0 C";
char message2[] = "= 00.0 K";
signedint16 Kelvin, Celsius;
void main(){
setup_adc(ADC_CLOCK_INTERNAL); // ADC Module uses its internal oscillator
setup_adc_ports(AN0); // Configure AN0 pin as analog
set_adc_channel(0); // Select channel 0 (AN0)
lcd_init(); // Initialize LCD module
lcd_putc('\f'); // Clear LCDwhile(TRUE){
delay_ms(1000);
Kelvin = read_adc() * 0.489; // Read analog voltage and convert it to Kelvin (0.489 = 500/1023)
Celsius = Kelvin - 273; // Convert Kelvin to degree Celsiusif(Celsius < 0){
Celsius = abs(Celsius); // Absolute value
message1[7] = '-'; // Put minus '-' sign
}
else
message1[7] = ' '; // Put space ' 'if (Celsius > 99)
message1[7] = 1 + 48; // Put 1 (of hundred)
message1[8] = (Celsius / 10) % 10 + 48;
message1[9] = Celsius % 10 + 48;
message1[12] = 223; // Degree symbol
message2[2] = (Kelvin / 100) % 10 + 48;
message2[3] = (Kelvin / 10) % 10 + 48;
message2[4] = Kelvin % 10 + 48;
lcd_gotoxy(1, 1); // Go to column 1 row 1
printf(lcd_putc, message1); // Display message1
lcd_gotoxy(6, 2); // Go to column 6 row 2
printf(lcd_putc, message2); // Display message2
}
}
Interfacing PIC16F877A with LM335 sensor videos:
The following video shows a breadboard hardware circuit of the example.
and the second video shows simulation using Proteus software.
The DS3231 is a low cost , extremely accurate real time clock with a built-in crystal oscillator. The characteristics of the DS3231 make it one of the best choices for real time clock chips.
This project shows how to build is simple real time clock and calendar (RTCC) using PIC16F877A microcontroller and DS3231.
The DS3231 uses I2C protocol to interface with the master device which is in our example the PIC16F877A which has one I2C module.
The I2C protocol uses only two lines: SCL (Serial Clock) and SDA (Serial Data) which are in the PIC16F877A RC3 and RC4 respectively.
Simple real time clock and calendar using DS3231 and PIC16F877A circuit:
The 16x2 LCD has 7 data lines which are connected to pins RD0~6, the DS3231 SCL pin is connected to pin RC3 (#18) and SDA is connected to pin RC4 (#23) of the PIC16F877A.
In the circuit there are 2 push buttons (B1 & B2) connected to pin RB0 and pin RB1, the two push buttons are used to set the time as well as the calendar parameters. The button B1 selects the parameter and B1 increments the selected parameter as shown in the videos below.
The 3V cell battery is used as a backup to keep time and date running in
case of main power failure. The circuit can work without this battery
but its pin (#14) has to be grounded.
In this example the PIC16F877A runs with 8MHz crystal oscillator. Simple real time clock and calendar using DS3231 and PIC16F877A CCS C code:
The following C code was tested with CCS PIC C compiler version 5.051.
The hardware I2C module of the PIC16F877A is initialized and configured using the function below with a speed of 100KHz: #use I2C(master, I2C1, FAST = 100000)
master: set the microcontroller to the master mode
I2C1: use first I2C module.
The DS3231 works with BCD format only and to convert the BCD to
decimal and vise versa I used the following functions (example for minute
variable): minute = (minute >> 4) * 10 + (minute & 0x0F); // Convert BCD to decimal minute = ((minute / 10) << 4) + (minute % 10); // Convert decimal to BCD
The complete C code is the one below.
/* Simple real time clock/calendar (RTCC) using PIC16F877A & DS3231 (DS3232) CCS C code. Read DS3231 RTC datasheet to understand the code! Time & date parameters can be set using two push buttons connected to RB0 & RB1. http://ccspicc.blogspot.com/ electronnote@gmail.com*///LCD module connections#define LCD_RS_PIN PIN_D0
#define LCD_RW_PIN PIN_D1
#define LCD_ENABLE_PIN PIN_D2
#define LCD_DATA4 PIN_D3
#define LCD_DATA5 PIN_D4
#define LCD_DATA6 PIN_D5
#define LCD_DATA7 PIN_D6
//End LCD module connections#include <16F877A.h>
#fuses HS,NOWDT,NOPROTECT,NOLVP
#usedelay(clock = 8MHz)
#use fast_io(D)
#include <lcd.c>
#use I2C(master, I2C1, FAST = 100000)
char time[] = "TIME: : : ";
char calendar[] = "DATE: / /20 ";
int8 i, second, minute, hour, date, month, year;
void DS3231_display(){
// Convert BCD to decimal
second = (second >> 4) * 10 + (second & 0x0F);
minute = (minute >> 4) * 10 + (minute & 0x0F);
hour = (hour >> 4) * 10 + (hour & 0x0F);
date = (date >> 4) * 10 + (date & 0x0F);
month = (month >> 4) * 10 + (month & 0x0F);
year = (year >> 4) * 10 + (year & 0x0F);
// End conversion
time[12] = second % 10 + 48;
time[11] = second / 10 + 48;
time[9] = minute % 10 + 48;
time[8] = minute / 10 + 48;
time[6] = hour % 10 + 48;
time[5] = hour / 10 + 48;
calendar[14] = year % 10 + 48;
calendar[13] = year / 10 + 48;
calendar[9] = month % 10 + 48;
calendar[8] = month / 10 + 48;
calendar[6] = date % 10 + 48;
calendar[5] = date / 10 + 48;
lcd_gotoxy(1, 1); // Go to column 1 row 1
printf(lcd_putc, time); // Display time
lcd_gotoxy(1, 2); // Go to column 1 row 2
printf(lcd_putc, calendar); // Display calendar
}
voidblink(){
int8 j = 0;
while(j < 10 && input(PIN_B0) && input(PIN_B1)){
j++;
delay_ms(25);
}
}
unsignedint8 edit(parameter, xx, yy){
while(!input(PIN_B0)); // Wait until button RB0 is releasedwhile(TRUE){
while(!input(PIN_B1)){ // If button RB1 is pressed
parameter++;
if(i == 0 && parameter > 23) // If hours > 23 ==> hours = 0
parameter = 0;
if(i == 1 && parameter > 59) // If minutes > 59 ==> minutes = 0
parameter = 0;
if(i == 2 && parameter > 31) // If date > 31 ==> date = 1
parameter = 1;
if(i == 3 && parameter > 12) // If month > 12 ==> month = 1
parameter = 1;
if(i == 4 && parameter > 99) // If year > 99 ==> year = 0
parameter = 0;
lcd_gotoxy(xx, yy);
printf(lcd_putc,"%02u", parameter); // Display parameter
delay_ms(200); // Wait 200ms
}
lcd_gotoxy(xx, yy);
lcd_putc(" ");
blink();
lcd_gotoxy(xx, yy); // Display two spaces
printf(lcd_putc,"%02u", parameter); // Display parameterblink();
if(!input(PIN_B0)){ // If button RB0 is pressed
i++; // Increament 'i' for the next parameterreturn parameter; // Return parameter value and exit
}
}
}
void main(){
set_tris_d(0);
port_b_pullups(TRUE); // Enable PORTB internal pull-ups
lcd_init(); // Initialize LCD module
lcd_putc('\f'); // LCD clearwhile(TRUE){
if(!input(PIN_B0)){ // If RB0 button is pressed
i = 0;
hour = edit(hour, 6, 1);
minute = edit(minute, 9, 1);
date = edit(date, 6, 2);
month = edit(month, 9, 2);
year = edit(year, 14, 2);
// Convert decimal to BCD
minute = ((minute / 10) << 4) + (minute % 10);
hour = ((hour / 10) << 4) + (hour % 10);
date = ((date / 10) << 4) + (date % 10);
month = ((month / 10) << 4) + (month % 10);
year = ((year / 10) << 4) + (year % 10);
// End conversion// Write data to DS3231 RTC
i2c_start(); // Start I2C protocol
i2c_write(0xD0); // DS3231 address
i2c_write(0);
i2c_write(0); // Reset sesonds and start oscillator
i2c_write(minute); // Write minute value to DS3231
i2c_write(hour); // Write hour value to DS3231
i2c_write(1); // Write day value (not used)
i2c_write(date); // Write date value to DS3231
i2c_write(month); // Write month value to DS3231
i2c_write(year); // Write year value to DS3231
delay_ms(200); // Wait 200ms
}
i2c_start(); // Start I2C protocol
i2c_write(0xD0); // DS3231 address
i2c_write(0); // Send register address
i2c_start(); // Restart I2C
i2c_write(0xD1); // Initialize data read
second = i2c_read(1); // Read seconds from register 0
minute = i2c_read(1); // Read minuts from register 1
hour = i2c_read(1); // Read hour from register 2
i2c_read(1); // Read day from register 3 (not used)
date = i2c_read(1); // Read date from register 4
month = i2c_read(1); // Read month from register 5
year = i2c_read(0); // Read year from register 6
i2c_stop(); // Stop I2C protocol
DS3231_display(); // Diaplay time & calendar
delay_ms(50);
}
}
Simple real time clock and calendar using DS3231 and PIC16F877A video:
The following video shows a hardware circuit of the example.
and the second video shows the simulation of the example using Proteus.
The RTOS (Real Time operating System) allows more than one task to run simultaneously (in parallel), for example reading from an analog channel, blinking an LED, setting the duty cycle of a PWM signal.....
This small article shows an RTOS example using PIC16F887 microcontroller and CCS PIC C compiler.
In this example we've 5 LEDs connected to the PIC16F887 microcontroller as shown in the circuit below. It is designed that the 5 LEDs are blinking but each one has its blinking frequency.
In this example the PIC16F887 MCU uses its internal oscillator which is configured in the software @ 4MHz and MCLR pin function is disabled. RTOS Example with PIC16F887 microcontroller CCS C code:
As mentioned above our RTOS has 5 LEDs with different frequencies (periods = 1/frequency).
The first LED which is connected to RB0 pin has the following task with a period of 500ms (250ms x 2): #task(rate = 250ms, max = 50ms) void led1(){ output_toggle(PIN_B0); }
The same thing for the other LEDs.
In CCS C compiler the RTOS is configured using the following line: #use rtos(timer = 0, minor_cycle = 50ms)
Here Timer0 is selected for the RTOS but other timers (Timer1 or Timer2) can also be used.
The complete C code is the one below.
// RTOS example for PIC16F887 with CCS PIC C compiler// PIC16F887 internal oscillator used @ 4MHz// Timer0 is used for the RTOS// http://ccspicc.blogspot.com/// electronnote@gmail.com#include <16F887.h>
#fuses NOMCLR, NOBROWNOUT, NOLVP, INTRC_IO
#usedelay(clock = 4MHz)
#use fast_io(B)
#use rtos(timer = 0, minor_cycle = 50ms)
#task(rate = 250ms, max = 50ms) // 1st RTOS task (executed every 250ms)void led1(){
output_toggle(PIN_B0);
}
#task(rate = 500ms, max = 50ms) // 2nd RTOS task (executed every 500ms)void led2(){
output_toggle(PIN_B1);
}
#task(rate = 750ms, max = 50ms) // 3rd RTOS task (executed every 750ms)void led3(){
output_toggle(PIN_B2);
}
#task(rate = 1000ms, max = 50ms) // 4th RTOS task (executed every 1000ms)void led4(){
output_toggle(PIN_B3);
}
#task(rate = 1250ms, max = 50ms) // 5th RTOS task (executed every 1250ms)void led5(){
output_toggle(PIN_B4);
}
void main(){
setup_oscillator(OSC_4MHZ); // Set the internal oscillator to 8MHz
output_b(0); // All PORTB register pins are zeros
set_tris_b(0); // Configure PORTB pins as outputs
rtos_run(); // Start all the RTOS tasks
}
The following video shows Proteus simulation of the RTOS example:
Proteus simulation file can be downloaded from the following link: Download
The datasheet of DS3231 RTC (real time clock) says that it is a low-cost, extremely accurate I2C real-time clock (RTC) with an integrated temperature compensated crystal oscillator (TCXO) and crystal. The DS3231 is much better than the DS1307 which means that it is a very good choice for persons who sell real time clock products.
The DS3231 RTC comes with an internal oscillator which means there is no need for a 32.768KHz crystal oscillator.
This topic shows the interfacing of the DS3231 RTC with PIC16F887 microcontroller with full adjustment of time and date parameters.
Like the DS1307, the DS3231 uses I2C protocol which uses two lines SCL and SDA. The PIC16F887 has a hardware I2C module where the SCL and SDA pins are mapped to RC3 and RC4 respectively. Hardware Required:
0.1µF capacitor (decoupling capacitor needed for the DS3231)
3V coin cell battery
5V voltage source
Protoboard
Jumper wires
Interfacing DS3231 with PIC16F887 microcontroller circuit:
As we can see in the circuit there is a 16x2 LCD to display time and date, this LCD is connected to PORTD. The SCL and SDA pins of the DS3231 are connected to SCL (RC3) and SDA (RC4) pins of the PIC16F887 microcontroller. Two pull-up resistors of 10K are needed for the SCL and SDA lines, if these two resistors are not connected to whole circuit will not work at all and the LCD may not display any thing.
The two buttons which are connected to pins RB0 and RB1, these buttons are used to set the time as well as the date as shown in the videos below.
The 3V cell battery is used as a backup to keep time and date running in case of main power failure. The circuit can work without this battery but its pin (#14) has to be grounded.
The internal oscillator of the PIC16F887 is used and MCLR pin function is disabled.
Interfacing DS3231 with PIC16F887 microcontroller CCS C code:
The C code below is for CCS PIC C compiler (tested with version 5.051).
Please read the DS3231 datasheet to understand the code.
In CCS C it is easy to initialize the I2C module of the PIC microcontroller using the following line: #use I2C(master, I2C1, FAST = 100000)
Where:
master: set the microcontroller to the master mode
I2C1: use first I2C module (PIC16F887 has only one module)
FAST = 100000 : set the speed to100KHz
he DS3231 works with BCD format only and to convert the BCD to decimal and vise versa I used the following lines (example for minute variable): minute = (minute >> 4) * 10 + (minute & 0x0F); // Convert BCD to decimal minute = ((minute / 10) << 4) + (minute % 10); // Convert decimal to BCD
The full code is as the one below.
/* Real time clock using PIC16F887 & DS3231 (DS3232) CCS C code Read DS3231 RTC datasheet to understand the code! Internal oscillator used @ 8MHz http://ccspicc.blogspot.com/ electronnote@gmail.com*///LCD module connections#define LCD_RS_PIN PIN_D0
#define LCD_RW_PIN PIN_D1
#define LCD_ENABLE_PIN PIN_D2
#define LCD_DATA4 PIN_D3
#define LCD_DATA5 PIN_D4
#define LCD_DATA6 PIN_D5
#define LCD_DATA7 PIN_D6
//End LCD module connections#include <16F887.h>
#fuses NOMCLR NOBROWNOUT NOLVP INTRC_IO
#usedelay(clock = 8MHz)
#include <lcd.c>
#use fast_io(B)
#use I2C(master, I2C1, FAST = 100000)
char time[] = "TIME: : : ";
char calendar[] = "DATE: / /20 ";
unsignedint8 i, second, minute, hour, date, month, year;
void DS3231_display(){
// Convert BCD to decimal
second = (second >> 4) * 10 + (second & 0x0F);
minute = (minute >> 4) * 10 + (minute & 0x0F);
hour = (hour >> 4) * 10 + (hour & 0x0F);
date = (date >> 4) * 10 + (date & 0x0F);
month = (month >> 4) * 10 + (month & 0x0F);
year = (year >> 4) * 10 + (year & 0x0F);
// End conversion
time[12] = second % 10 + 48;
time[11] = second / 10 + 48;
time[9] = minute % 10 + 48;
time[8] = minute / 10 + 48;
time[6] = hour % 10 + 48;
time[5] = hour / 10 + 48;
calendar[14] = year % 10 + 48;
calendar[13] = year / 10 + 48;
calendar[9] = month % 10 + 48;
calendar[8] = month / 10 + 48;
calendar[6] = date % 10 + 48;
calendar[5] = date / 10 + 48;
lcd_gotoxy(1, 1); // Go to column 1 row 1
printf(lcd_putc, time); // Display time
lcd_gotoxy(1, 2); // Go to column 1 row 2
printf(lcd_putc, calendar); // Display calendar
}
voidblink(){
int8 j = 0;
while(j < 10 && input(PIN_B0) && input(PIN_B1)){
j++;
delay_ms(25);
}
}
unsignedint8 edit(parameter, xx, yy){
while(!input(PIN_B0)); // Wait until button RB0 is releasedwhile(TRUE){
while(!input(PIN_B1)){ // If button RB1 is pressed
parameter++;
if(i == 0 && parameter > 23) // If hours > 23 ==> hours = 0
parameter = 0;
if(i == 1 && parameter > 59) // If minutes > 59 ==> minutes = 0
parameter = 0;
if(i == 2 && parameter > 31) // If date > 31 ==> date = 1
parameter = 1;
if(i == 3 && parameter > 12) // If month > 12 ==> month = 1
parameter = 1;
if(i == 4 && parameter > 99) // If year > 99 ==> year = 0
parameter = 0;
lcd_gotoxy(xx, yy);
printf(lcd_putc,"%02u", parameter); // Display parameter
delay_ms(200); // Wait 200ms
}
lcd_gotoxy(xx, yy);
lcd_putc(" ");
blink();
lcd_gotoxy(xx, yy); // Display two spaces
printf(lcd_putc,"%02u", parameter); // Display parameterblink();
if(!input(PIN_B0)){ // If button RB0 is pressed
i++; // Increament 'i' for the next parameterreturn parameter; // Return parameter value and exit
}
}
}
void main(){
setup_oscillator(OSC_8MHZ); // Set internal oscillator to 8MHz
port_b_pullups(3); // Enable internal pull-ups for RB0 & RB1
lcd_init(); // Initialize LCD module
lcd_putc('\f'); // LCD clearwhile(TRUE){
if(!input(PIN_B0)){ // If RB0 button is pressed
i = 0;
hour = edit(hour, 6, 1);
minute = edit(minute, 9, 1);
date = edit(date, 6, 2);
month = edit(month, 9, 2);
year = edit(year, 14, 2);
// Convert decimal to BCD
minute = ((minute / 10) << 4) + (minute % 10);
hour = ((hour / 10) << 4) + (hour % 10);
date = ((date / 10) << 4) + (date % 10);
month = ((month / 10) << 4) + (month % 10);
year = ((year / 10) << 4) + (year % 10);
// End conversion// Write data to DS3231 RTC
i2c_start(); // Start I2C protocol
i2c_write(0xD0); // DS3231 address
i2c_write(0);
i2c_write(0); // Reset sesonds and start oscillator
i2c_write(minute); // Write minute value to DS3231
i2c_write(hour); // Write hour value to DS3231
i2c_write(1); // Write day value (not used)
i2c_write(date); // Write date value to DS3231
i2c_write(month); // Write month value to DS3231
i2c_write(year); // Write year value to DS3231
delay_ms(200); // Wait 200ms
}
i2c_start(); // Start I2C protocol
i2c_write(0xD0); // DS3231 address
i2c_write(0); // Send register address
i2c_start(); // Restart I2C
i2c_write(0xD1); // Initialize data read
second = i2c_read(1); // Read seconds from register 0
minute = i2c_read(1); // Read minuts from register 1
hour = i2c_read(1); // Read hour from register 2
i2c_read(1); // Read day from register 3 (not used)
date = i2c_read(1); // Read date from register 4
month = i2c_read(1); // Read month from register 5
year = i2c_read(0); // Read year from register 6
i2c_stop(); // Stop I2C protocol
DS3231_display(); // Diaplay time & calendar
delay_ms(50);
}
}
The following video shows the interfacing of PIC16F887 with the DS3231 in real hardware circuit:
And the following video shows Proteus simulation:
PIC16F887 and DS3231 RTC Proteus simulation file download: Download
This article shows how to build a simple real time clock/calendar using PIC16F887 and DS1307 RTC chip.
The DS1307 is an 8-pin integrated circuit uses I2C communication protocol to communicate with master device which is in our case the PIC16F887 microcontroller.
The PIC16F887 microcontroller has an I2C (IIC) module with two pins are used for data transfer. These are the RC3/SCK/SCL pin, which is the clock (SCL), and the RC4/SDI/SDA pin, which is the data (SDA).
The DS1307 can count seconds, minutes, hours, day, date, month and year with leap-year up to year 2100.
The DS1307 receives and transfers data (clock data and calendar data) as BCD format, so after receiving data we have to convert these data into decimal data, and before writing data to the DS1307 we have to convert this data from decimal to BCD format. For example we have the BCD number 33, converting this number into decimal gives 21.
In the CCS C code I used the following line to covert a number 'x' from BCD to decimal: x = (x >> 4) * 10 + (x & 0x0F);
And to go from decimal to BCD I used this line: x = ((x / 10) << 4) + (x % 10); Hardware Required:
DS1307 Interfacing with PIC16F887 circuit:
The circuit diagram of the example is given below.
In this example the PIC16F887 MCU uses its internal oscillator and MCLR pin function is disabled.
SCL pin of PIC16F887 (pin number 18) is connected to the SCL pin of the DS1307 (pin number 6) and SDA pin of PIC16F887 (pin number 23) is connected to the SDA pin of the DS1307 (pin number 5).
The 3V cell battery is used to keep the time running if the main power is off.
The two resistors R1 & R2 are pull-up resistors, they are necessary for the I2C protocol.
In the circuit there are two buttons to set time and calendar. The button B1 selects time or calendar parameter (minutes, hours, date, month and year) and B2 increments the selected parameter. DS1307 Interfacing with PIC16F887 CCS PIC C compiler code:
The code below can display time and calendar where their parameters such as minutes using two push buttons.
This code is tested with version 5.051.
/* Real time clock using PIC16F887 & DS1307 CCS C code Read DS1307 RTC datasheet to understand the code! Internal oscillator used @ 8MHz http://ccspicc.blogspot.com/ electronnote@gmail.com*///LCD module connections#define LCD_RS_PIN PIN_D0
#define LCD_RW_PIN PIN_D1
#define LCD_ENABLE_PIN PIN_D2
#define LCD_DATA4 PIN_D3
#define LCD_DATA5 PIN_D4
#define LCD_DATA6 PIN_D5
#define LCD_DATA7 PIN_D6
//End LCD module connections#include <16F887.h>
#fuses NOMCLR NOBROWNOUT NOLVP INTRC_IO
#usedelay(clock = 8MHz)
#include <lcd.c>
#use fast_io(B)
#use I2C(master, I2C1, FAST = 100000)
char time[] = "TIME: : : ";
char calendar[] = "DATE: / /20 ";
unsignedint8 second, minute, hour, date, month, year, day;
void ds1307_display(){
// Convert BCD to decimal
second = (second >> 4) * 10 + (second & 0x0F);
minute = (minute >> 4) * 10 + (minute & 0x0F);
hour = (hour >> 4) * 10 + (hour & 0x0F);
date = (date >> 4) * 10 + (date & 0x0F);
month = (month >> 4) * 10 + (month & 0x0F);
year = (year >> 4) * 10 + (year & 0x0F);
// End conversion
time[12] = second % 10 + 48;
time[11] = second / 10 + 48;
time[9] = minute % 10 + 48;
time[8] = minute / 10 + 48;
time[6] = hour % 10 + 48;
time[5] = hour / 10 + 48;
calendar[14] = year % 10 + 48;
calendar[13] = year / 10 + 48;
calendar[9] = month % 10 + 48;
calendar[8] = month / 10 + 48;
calendar[6] = date % 10 + 48;
calendar[5] = date / 10 + 48;
lcd_gotoxy(1, 1); // Go to column 1 row 1
printf(lcd_putc, time); // Display time
lcd_gotoxy(1, 2); // Go to column 1 row 2
printf(lcd_putc, calendar); // Display calendar
}
void ds1307_write(unsignedint8 address, data_){
i2c_start(); // Start I2C protocol
i2c_write(0xD0); // DS1307 address
i2c_write(address); // Send register address
i2c_write(data_); // Write data to the selected register
i2c_stop(); // Stop I2C protocol
}
void main(){
setup_oscillator(OSC_8MHZ); // Set internal oscillator to 8MHz
port_b_pullups(3); // Enable internal pull-ups for RB0 & RB1
lcd_init(); // Initialize LCD module
lcd_putc('\f'); // LCD clearwhile(TRUE){
if(!input(PIN_B0)){ // If RB0 button is pressed
lcd_putc('\f'); // LCD clear
lcd_gotoxy(5, 1); // Go to column 5 row 1
lcd_putc("Minute:");
delay_ms(200);
while(TRUE){
if(!input(PIN_B1)) // If RB1 button is pressed
minute++; // Increment minutesif(minute > 59)
minute = 0;
lcd_gotoxy(8, 2); // Go to column 8 row 2
printf(lcd_putc,"%02u", minute);
if(!input(PIN_B0))
break;
delay_ms(200);
}
lcd_putc('\f'); // LCD clear
lcd_gotoxy(6, 1); // Go to column 6 row 1
lcd_putc("Hour:");
delay_ms(200);
while(TRUE){
if(!input(PIN_B1))
hour++;
if(hour > 23)
hour = 0;
lcd_gotoxy(8, 2); // Go to column 8 row 2
printf(lcd_putc,"%02u", hour);
if(!input(PIN_B0))
break;
delay_ms(200);
}
lcd_putc('\f'); // LCD clear
lcd_gotoxy(6, 1); // Go to column 6 row 1
lcd_putc("Date:");
delay_ms(200);
while(TRUE){
if(!input(PIN_B1))
date++;
if(date > 31)
date = 1;
lcd_gotoxy(8, 2); // Go to column 8 row 2
printf(lcd_putc,"%02u", date);
if(!input(PIN_B0))
break;
delay_ms(200);
}
lcd_putc('\f'); // LCD clear
lcd_gotoxy(6, 1); // Go to column 6 row 1
lcd_putc("Month:");
delay_ms(200);
while(TRUE){
if(!input(PIN_B1))
month++;
if(month > 12)
month = 1;
lcd_gotoxy(8, 2); // Go to column 8 row 2
printf(lcd_putc,"%02u", month);
if(!input(PIN_B0))
break;
delay_ms(200);
}
lcd_putc('\f'); // LCD clear
lcd_gotoxy(6, 1); // Go to column 6 row 1
lcd_putc("Year:");
lcd_gotoxy(7, 2); // Go to column 7 row 1
lcd_putc("20");
delay_ms(200);
while(TRUE){
if(!input(PIN_B1))
year++;
if(year > 99)
year = 0;
lcd_gotoxy(9, 2); // Go to column 9 row 2
printf(lcd_putc,"%02u", year);
if(!input(PIN_B0)){
// Convert decimal to BCD
minute = ((minute / 10) << 4) + (minute % 10);
hour = ((hour / 10) << 4) + (hour % 10);
date = ((date / 10) << 4) + (date % 10);
month = ((month / 10) << 4) + (month % 10);
year = ((year / 10) << 4) + (year % 10);
// End conversion
ds1307_write(1, minute); // Write minute value to DS1307
ds1307_write(2, hour);
ds1307_write(4, date);
ds1307_write(5, month);
ds1307_write(6, year);
ds1307_write(0, 0); //Reset seconds and start oscillator
delay_ms(200);
break;
}
delay_ms(200);
}
}
i2c_start(); // Start I2C protocol
i2c_write(0xD0); // DS1307 address
i2c_write(0); // Send register address
i2c_start(); // Restart I2C
i2c_write(0xD1); // Initialize data read
second = i2c_read(1); // Read seconds from register 0
minute = i2c_read(1); // Read minuts from register 1
hour = i2c_read(1); // Read hour from register 2
day = i2c_read(1); // Read day from register 3
date = i2c_read(1); // Read date from register 4
month = i2c_read(1); // Read month from register 5
year = i2c_read(0); // Read year from register 6
i2c_stop(); // Stop I2C protocol
ds1307_display(); // Diaplay time & calendar
delay_ms(50);
}
}
The following video shows project simulation with Proteus:
This is an example showing how to connect LM335 temperature sensing device with PIC16F887 microcontroller.
The LM335 is an analog device which requires an ADC module to convert the analog data which is the voltage output from the LM335 into digital data. The LM335 has the following features:
Directly Calibrated to the Kelvin Temperature Scale
1°C Initial Accuracy Available
Operates from 400 μA to 5 mA
Less than 1-Ω Dynamic Impedance
Easily Calibrated
Wide Operating Temperature Range
200°C Overrange
Low Cost
The LM135 has a breakdown voltage directly proportional to absolute temperature at 10 mV/°K. If the LM335 output voltage is for example is 3.03 (3030 mV) that means the temperature is: 303 °Kelvin = 30 °Celsius. Hardware Required:
PIC16F887 Microcontroller
LM335 Temperature sensor
16x2 LCD Screen
10K ohm potentiometer or variable resistor
2.2K ohm resistor
0.1µF Ceramic capacitor (optional)
+5V Power supply source
Breadboard
Jumper wires
Interfacing PIC16F887 with LM335 sensor circuit:
This is our example circuit where the microcontroller uses its internal oscillator.
The LM335 has 3 pins:
Pin 1 for calibration, not used in this example
Pin 2: output
Pin 3: GND (ground)
Interfacing PIC16F887 with LM335 C code:
The C code used in this example is as the one below where it has been compiled with CCS PIC C compiler version 5.051.
/* Interfacing PIC16F887 with LM335 analog temperature sensor CCS C code Read LM335 datasheet to understand the code! Internal oscillator used @ 8MHz http://ccspicc.blogspot.com/ electronnote@gmail.com*///LCD module connections#define LCD_RS_PIN PIN_D0
#define LCD_RW_PIN PIN_D1
#define LCD_ENABLE_PIN PIN_D2
#define LCD_DATA4 PIN_D3
#define LCD_DATA5 PIN_D4
#define LCD_DATA6 PIN_D5
#define LCD_DATA7 PIN_D6
//End LCD module connections#include <16F887.h>
#fuses NOMCLR NOBROWNOUT NOLVP INTRC_IO
#device ADC = 10
#usedelay(clock = 8MHz)
#include <lcd.c>
char message1[] = "Temp = 00.0 C";
char message2[] = "= 00.0 K";
signedint16 Kelvin, Celsius;
void main(){
setup_oscillator(OSC_8MHZ); // Set the internal oscillator to 8MHz
setup_adc(ADC_CLOCK_INTERNAL); // ADC Module uses its internal oscillator
setup_adc_ports(sAN0); // Configure AN0 pin as analog
set_adc_channel(0); // Select channel 0 (AN0)
lcd_init(); // Initialize LCD module
lcd_putc('\f'); // Clear LCDwhile(TRUE){
delay_ms(1000);
Kelvin = read_adc() * 0.489; // Rea analog voltage and convert it to Kelvin (0.489 = 500/1023)
Celsius = Kelvin - 273; // Convert Kelvin to degree Celsiusif(Celsius < 0){
Celsius = abs(Celsius); // Absolute value
message1[7] = '-'; // Put minus '-' sign
}
else
message1[7] = ' '; // Put space ' 'if (Celsius > 99)
message1[7] = 1 + 48; // Put 1 (of hundred)
message1[8] = (Celsius / 10) % 10 + 48;
message1[9] = Celsius % 10 + 48;
message1[12] = 223; // Degree symbol
message2[2] = (Kelvin / 100) % 10 + 48;
message2[3] = (Kelvin / 10) % 10 + 48;
message2[4] = Kelvin % 10 + 48;
lcd_gotoxy(1, 1); // Go to column 1 row 1
printf(lcd_putc, message1); // Display message1
lcd_gotoxy(6, 2); // Go to column 6 row 2
printf(lcd_putc, message2); // Display message2
}
}
The following video shows Proteus simulation of LM335 and PIC16F887: