|
|
View previous topic :: View next topic |
Author |
Message |
gr1ph0n
Joined: 17 Oct 2009 Posts: 6
|
pic16f84 thermometer using DS18B20 |
Posted: Sat Oct 17, 2009 4:35 am |
|
|
Hello. I've built a digital thermometer with pic16f84 and DS18B20 from this site: http://www.coolcircuit.com/project/digitemp/ and it's not working very well. The sensor is showing about 72 degrees C in a room. In the original project the sensor is DS1820 but I only have DS18B20. Could someone help me modify the source codes thus showing the right temperature? I have no programming experience, that is why I am asking for your help.
The source codes:
main.c
Code: |
#include <16F84A.h>
#use delay(clock=4000000)
#fuses NOWDT,XT, NOPUT, NOPROTECT
#include <mylcd.c>
#include <ds1820.c>
//=====================================
// main program start here
//=====================================
void main(void)
{
int buff[9], sensor, n,temp,temp_dec;
delay_ms(50);
lcd_init();
while(true)
{
sensor=0;
init_ds1820(sensor);
write_ds1820_one_byte(0xcc, sensor); // skip ROM
write_ds1820_one_byte(0x44, sensor); // perform temperature conversion
while (read_ds1820_one_byte(sensor)==0xff); // wait for conversion complete
init_ds1820(sensor);
write_ds1820_one_byte(0xcc, sensor); // skip ROM
write_ds1820_one_byte(0xbe, sensor); // read the result
for (n=0; n<9; n++) // read 9 bytes but, use only one byte
{
buff[n]=read_ds1820_one_byte(sensor); // read DS1820
}
temp=buff[0]>>1;
if ((buff[0] & 0x1)==1)
temp_dec=5;
else
temp_dec=0;
lcd_putc("\f");
printf(lcd_putc,"Temp :");
printf(lcd_putc," %u.%u'C",temp,temp_dec);
delay_ms(1000);
}
} //enf of main program
|
ds1820:
Code: |
#BYTE TRISA=0x85
#BYTE PORTA=0x5
#BYTE STATUS=0x3
#define RP0 5
#define C 0
// The following are standard 1-Wire routines.
void make_ds1820_high_pin(int sensor)
{
TRISA = 0xff;
}
void make_ds1820_low_pin(int sensor)
{
PORTA = 0x00;
TRISA = 0xff & (~(0x01 << sensor));
}
// delay routines
void delay_10us(int t)
{
#asm
BCF STATUS, RP0
DELAY_10US_X:
CLRWDT
NOP
NOP
NOP
NOP
NOP
NOP
DECFSZ t, F
GOTO DELAY_10US_X
#endasm
}
void delay_ms(long t) // delays t millisecs
{
do
{
delay_10us(100);
} while(--t);
}
void init_ds1820(int sensor)
{
make_ds1820_high_pin(sensor);
make_ds1820_low_pin(sensor);
delay_10us(50);
make_ds1820_high_pin(sensor);
delay_10us(50);
}
int read_ds1820_one_byte(int sensor)
{
int n, i_byte, temp, mask;
mask = 0xff & (~(0x01<<sensor));
for (n=0; n<8; n++)
{
PORTA=0x00;
TRISA=mask;
TRISA=0xff;
#asm
CLRWDT
NOP
NOP
#endasm
temp=PORTA;
if (temp & ~mask)
{
i_byte=(i_byte>>1) | 0x80; // least sig bit first
}
else
{
i_byte=i_byte >> 1;
}
delay_10us(6);
}
return(i_byte);
}
void write_ds1820_one_byte(int d, int sensor)
{
int n, mask;
mask = 0xff & (~(0x01<<sensor));
for(n=0; n<8; n++)
{
if (d&0x01)
{
PORTA=0;
TRISA=mask; // momentary low
TRISA=0xff;
delay_10us(6);
}
else
{
PORTA=0;
TRISA=mask;
delay_10us(6);
TRISA=0xff;
}
d=d>>1;
}
}
|
I don't know if this is necessary but I'll post it anyway.
lcd.c
Code: |
struct lcd_pin_map { // This structure is overlayed
BOOLEAN enable; // on to an I/O port to gain
BOOLEAN rs; // access to the LCD pins.
BOOLEAN rw; // The bits are allocated from
BOOLEAN unused; // low order up. ENABLE will
int data : 4; // be pin B0.
}
lcd;
#byte lcd = 6 // on to port B (at address 6)
#define set_tris_lcd(x) set_tris_b(x)
#define lcd_type 1 // 1 lines
#define lcd_line_two 0x40 // LCD RAM address for the second line
BYTE const LCD_INIT_STRING[4] = {0x20 | (lcd_type << 3),0xC,1,6};
// These bytes need to be sent to the LCD
// to start it up.
// The following are used for setting
// the I/O port direction register.
struct lcd_pin_map const LCD_WRITE = {0,0,0,0,0}; // For write mode all pins are out
struct lcd_pin_map const LCD_READ = {0,0,0,0,15}; // For read mode data pins are in
BYTE lcd_read_byte()
{
BYTE low,high;
set_tris_lcd(LCD_READ);
lcd.rw = 1;
delay_cycles(1);
lcd.enable = 1;
delay_cycles(1);
high = lcd.data;
lcd.enable = 0;
delay_cycles(1);
lcd.enable = 1;
delay_us(1);
low = lcd.data;
lcd.enable = 0;
set_tris_lcd(LCD_WRITE);
return( (high<<4) | low);
}
void lcd_send_nibble( BYTE n )
{
lcd.data = n;
delay_cycles(1);
lcd.enable = 1;
delay_us(2);
lcd.enable = 0;
}
void lcd_send_byte( BYTE address, BYTE n )
{
lcd.rs = 0;
while ( bit_test(lcd_read_byte(),7) ) ;
lcd.rs = address;
delay_cycles(1);
lcd.rw = 0;
delay_cycles(1);
lcd.enable = 0;
lcd_send_nibble(n >> 4);
lcd_send_nibble(n & 0xf);
}
void lcd_init()
{
BYTE i;
set_tris_lcd(LCD_WRITE);
lcd.rs = 0;
lcd.rw = 0;
lcd.enable = 0;
delay_ms(15);
for(i=1;i<=3;++i) {
lcd_send_nibble(3);
delay_ms(5);
}
lcd_send_nibble(2);
for(i=0;i<=3;++i)
lcd_send_byte(0,LCD_INIT_STRING[i]);
}
void lcd_gotoxy( BYTE x, BYTE y)
{
BYTE address;
if(y!=1)
address=lcd_line_two;
else
address=0;
address+=x-1;
lcd_send_byte(0,0x80|address);
}
void lcd_putc( char c)
{
switch (c) {
case '\f' : lcd_send_byte(0,1);
delay_ms(2);
break;
case '\n' : lcd_gotoxy(1,2); break;
case '\b' : lcd_send_byte(0,0x10); break;
default : lcd_send_byte(1,c); break;
}
}
char lcd_getc( BYTE x, BYTE y)
{
char value;
lcd_gotoxy(x,y);
while ( bit_test(lcd_read_byte(),7) ); // wait until busy flag is low
lcd.rs=1;
value = lcd_read_byte();
lcd.rs=0;
return(value);
}
|
|
|
|
gr1ph0n
Joined: 17 Oct 2009 Posts: 6
|
|
Posted: Sun Oct 18, 2009 4:37 am |
|
|
Nobody can help me? |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Sun Oct 18, 2009 3:05 pm |
|
|
Quote: | The sensor is showing about 72 degrees C in a room. |
What was the real temperature in your room during this test ?
(Measured by a thermometer, or by your estimate). |
|
|
gr1ph0n
Joined: 17 Oct 2009 Posts: 6
|
|
Posted: Tue Oct 20, 2009 10:09 am |
|
|
Sorry for not responding, for 2 days i had trouble with my internet connection. The real temperature was 24 degrees C. The sensor is responding, when I put it near a heat source the temperature start to grow.
Although I have no programming experience, by logic (I guess) and with examples from this site, I made a program, please don't laugh because I was desperate to made my thermometer work for my baby.
When I compile it I receive this error: "Out of ROM, A segment or the program is too large @PRINTF_L32D_74FPFPF.
And this is the program:
Code: |
#include <16f84.h>
#use delay(clock=4000000)
#fuses NOWDT,XT, NOPUT, NOPROTECT
#include "1wire.c"
#include "mylcd.c"
float ds1820_read()
{
int8 busy=0, temp1, temp2;
signed int16 temp3;
float result;
onewire_reset();
onewire_write(0xCC);
onewire_write(0x44);
delay_ms(200);
while (busy == 0)
busy = onewire_read();
onewire_reset();
onewire_write(0xCC);
onewire_write(0xBE);
temp1 = onewire_read();
temp2 = onewire_read();
temp3 = make16(temp2, temp1);
result = (float) temp3 / 16.0; //0.1 deg C resolution
delay_ms(200);
return(result);
}
void main()
{
float temperature;
delay_ms(50);
lcd_init();
//for 10 bit resolution mod
onewire_write(0xCC);
onewire_write(0x4E);
onewire_write(125);
onewire_write(-55); //this should be done for proper working of DS18B20
onewire_write(127);
onewire_reset();
onewire_write(0xCC);
onewire_write(0x48);
delay_ms(15);
while (1)
{
temperature = ds1820_read();
lcd_putc("\f");
printf(lcd_putc,"Temp:");
printf (lcd_putc," %3.1f\n\r",temperature);
|
Help me if you can, please! |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
|
gr1ph0n
Joined: 17 Oct 2009 Posts: 6
|
|
Posted: Tue Oct 20, 2009 10:51 am |
|
|
That is what I have used. One question. I saw that, when I used "%3.1f" the error apears, can you tell me why %3.1f was put there, please. Thank you. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Tue Oct 20, 2009 10:59 am |
|
|
The 16F84A only has 1K rom. Floating point code uses a large amount
of ROM space. There isn't enough ROM space to do your floating point
printf statement. |
|
|
gr1ph0n
Joined: 17 Oct 2009 Posts: 6
|
|
Posted: Tue Oct 20, 2009 11:02 am |
|
|
PCM programmer wrote: | The 16F84A only has 1K rom. Floating point code uses a large amount
of ROM space. There isn't enough ROM space to do your floating point
printf statement. |
Can I do something? I don't want something fancy, just to show the temperature.
Sorry for my noob questions and for my ignorance. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Tue Oct 20, 2009 11:14 am |
|
|
Try displaying the result as a signed integer instead of a float.
Make the changes shown in bold below:
Quote: | printf (lcd_putc," %d\n\r", (signed int)temperature); |
|
|
|
gr1ph0n
Joined: 17 Oct 2009 Posts: 6
|
|
Posted: Wed Oct 21, 2009 3:48 am |
|
|
It worked. Thank you very much!
This is the code that worked for me with PIC16F84:
Code: |
#include <16f84.h>
#use delay(clock=4000000)
#fuses NOWDT,XT, NOPUT, NOPROTECT
#include "1wire.c"
#include "mylcd.c"
float ds1820_read()
{
int8 busy=0, temp1, temp2;
signed int16 temp3;
float result;
onewire_reset();
onewire_write(0xCC);
onewire_write(0x44);
delay_ms(200);
while (busy == 0)
busy = onewire_read();
onewire_reset();
onewire_write(0xCC);
onewire_write(0xBE);
temp1 = onewire_read();
temp2 = onewire_read();
temp3 = make16(temp2, temp1);
result = (float) temp3 / 16.0; //0.1 deg C resolution
delay_ms(200);
return(result);
}
void main()
{
float temperature;
delay_ms(50);
lcd_init();
//for 10 bit resolution mod
onewire_write(0xCC);
onewire_write(0x4E);
onewire_write(125);
onewire_write(-55); //this should be done for proper working of DS18B20
onewire_write(127);
onewire_reset();
onewire_write(0xCC);
onewire_write(0x48);
delay_ms(15);
while (1)
{
temperature = ds1820_read();
lcd_putc("\f");
printf(lcd_putc,"Temp:");
printf (lcd_putc," %d", (signed int) temperature);
delay_ms(100);
}
}
|
I want to make a statement: This is not my code! |
|
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|