1. 程式人生 > >PIC微控制器(PIC16F877A)DS18B20溫度感測器驅動程式

PIC微控制器(PIC16F877A)DS18B20溫度感測器驅動程式

#include<pic.h>
#define uchar unsigned char
#define uint unsigned int
#define rs_h (PORTC|=0x01)
#define rs_l (PORTC&=0xfe)
#define rs_o (TRISC&=0xfe)
#define rw_h (PORTC|=0x02)
#define rw_l (PORTC&=0xfd)
#define rw_o (TRISC&=0xfd)
#define en_h (PORTC|=0x04) 
#define en_l (PORTC&=0xfb)
#define en_o (TRISC&=0xfb)
#define temp_h (PORTC|=0x08) 
#define temp_l (PORTC&=0xf7) 
#define temp_o (TRISC&=0xf7)
#define temp_i (TRISC|=0x08)
#define led_o (TRISC&=0xef)
#define led_l (PORTC&=0xef)
#define led_h (PORTC|=0x10)
#define LCD PORTB
uchar dat1,dat2;//儲存讀出的溫度z
unsigned long int dat;
void delayms(uint x) //4M晶振下,延時1ms
{
	uint y,z;
	for(y=x;y>0;y--)
		for(z=110;z>0;z--);
}
void Ds18b20_reset(void)//DS18B20初始化
{
	uint count;
	uchar i,flag=1;
	temp_o;
	temp_l;
	for(count=60;count>0;count--);//延時480us
	temp_i;
	while(flag)
	{
		if(RC3)
			flag=1;
		else
			flag=0;	
	}
	led_o;
	led_l;//開指示燈
	for(count=60;count>0;count--);//延時480us
}
void Ds18b20_write(uchar datt)//向DS18B20寫一個位元組
{
	uchar count;
	uchar i;
	temp_o;
	for(i=8;i>0;i--)
	{
		temp_o;
		temp_l;
		for(count=1;count>0;count--);
		if(datt&0x01==0x01)
			temp_i;
		else
		{	
			temp_o;
			temp_l;
		}
		for(count=23;count>0;count--);//延時60us
		temp_i;
		for(count=1;count>0;count--);
		datt>>=1;	
	}	
}
uchar Ds18b20_read(void) //從DS18B20讀一個位元組
{
	uchar i,datt;
	uchar count;
	for(i=8;i>0;i--)
	{
		datt>>=1;
		temp_o;
		temp_l;
		for(count=1;count>0;count--);
		temp_i;//改為輸入方向時,上拉電阻把資料線拉高,釋放匯流排,此語句必須有,參考datasheet的P15
		for(count=1;count>0;count--);
		if(RC3)
			datt|=0x80;
		for(count=23;count>0;count--);//延時60us	
	}
	return datt;
}
void lcd_com(uchar com)//向LCD1602寫命令
{
 	rs_o;
	rw_o;
	en_o;
	TRISB=0x00;//配置RB為輸出方向
	rs_l;	
	rw_l;
	LCD=com;
	delayms(1);
	en_h;
	delayms(1);	
	en_l;
	delayms(1);		
}
void lcd_dat(uchar dat)//向LCD1602寫資料
{
 	rs_o;
	rw_o;
	TRISB=0x00;//配置RB為輸出方向
	en_o;
	rs_h;	
	rw_l;
	LCD=dat;
	delayms(1);
	en_h;
	delayms(1);
	en_l;
	delayms(1);	
}
void lcd_write(uchar c,uchar r,uchar dat)//向LCD1602指定行、指定列、寫資料
{
	lcd_com(0x80+0x40*c+r);
	lcd_dat(dat);
	delayms(1);
}
void lcd_init(void)//LCD1602初始化,初始化後第一行顯示temperature:,第二行顯示.C
{
	lcd_com(0x38);
	lcd_com(0x0c);
	lcd_com(0x06);
	lcd_write(0,2,0x54);
	lcd_write(0,3,0x65);
	lcd_write(0,4,0x6d);
	lcd_write(0,5,0x70);
	lcd_write(0,6,0x65);
	lcd_write(0,7,0x72);
	lcd_write(0,8,0x61);
	lcd_write(0,9,0x74);
	lcd_write(0,10,0x75);
	lcd_write(0,11,0x72);
	lcd_write(0,12,0x65);
	lcd_write(0,13,0x3a);
	lcd_write(1,11,0xdf);
	lcd_write(1,12,0x43);
}
void show(void)//把溫度值送LCD1602顯示
{
	uchar flag;
	uchar t[4];
	uint temp;
	if(dat2>=240)
	{
		dat= (~(dat2*256+dat1)+1)*(0.0625*10);//取反加一,保留一位小數
		flag=1;
	}
	else
	{
		dat=(dat2*256+dat1)*(0.0625*10);
		flag=0;
	};
	temp=dat%10;
	t[0]=(0x30+temp);
	temp=dat%100;
	temp=temp/10;
	t[1]=(0x30+temp);
	temp=dat%1000;
	temp=temp/100;
	t[2]=(0x30+temp);
	temp=dat/1000;
	t[3]=(0x30+temp);
	if(flag==1)//負溫度顯示
	{
		lcd_write(1,10,t[0]);
		lcd_write(1,9,0xa5);
		lcd_write(1,8,t[1]);
		lcd_write(1,7,t[2]);
		lcd_write(1,6,t[3]);
		lcd_write(1,5,0x2d);
	}
	if(flag==0)//正溫度顯示
	{
		lcd_write(1,10,t[0]);
		lcd_write(1,9,0xa5);
		lcd_write(1,8,t[1]);
		lcd_write(1,7,t[2]);
		lcd_write(1,6,t[3]);
		lcd_write(1,5,0x20);//顯示空格,刷掉負號
	}
}
void main(void)
{
	lcd_init();
	while(1)
	{
		Ds18b20_reset();
		Ds18b20_write(0xcc);
		Ds18b20_write(0x44);//傳送溫度轉換命令
		delayms(1000);//延時1s,等待溫度轉換完成
		Ds18b20_reset();
		Ds18b20_write(0xcc);
		Ds18b20_write(0xbe);//傳送讀溫度暫存器命令
		dat1=Ds18b20_read();
		dat2=Ds18b20_read();
		show();
		led_h;//關指示燈
		delayms(2000);
	}
}
//除錯總結:
//某IO口8位未全使用時,對整個IO口讀取進行位運算無效