#include<reg52.h>
#include <intrins.h>
typedef unsigned char uint8;
#define uint unsigned int
#define uchar unsigned char
sbit DQ = P3^3; // 定義DQ引腳為P3.3
uchar code Bw[10]= {0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39};//百位編碼
ucharcodeXsw[16]={0x30,0x31,0x31,0x32,0x33,0x33,0x34,0x34,0x35,0x36,0x36,0x37,0x38,0x38,0x39,0x39};//小數位編碼
sbit RS = P2^0 ;
sbit RW = P2^1 ;
sbit EN = P2^2 ;
sbit BUSY = P0^7;
uchar wendu;
uchar temp_g,temp_d;
unsigned char code word1[]={"Temperature:"};
void delay(uint xms)
{
uint i,j;
for(i=xms;i>0;--i)
for(j=110;j>0;--j);
}
void Delayus(int t) //在11.059MHz的晶振條件下調用本函數需要24μs ,然后每次計數需16μs
{
int s;
for (s=0; s<t;s++);
}
void wait(void)// 等待繁忙標志
{
P0 = 0xFF;
do
{
RS = 0;
RW = 1;
EN = 0;
EN = 1;
}while (BUSY == 1);
EN = 0;
}
void w_dat(uint8 dat)// 寫數據
{
wait();
EN = 0;
P0 = dat;
RS = 1;
RW = 0;
EN = 1;
EN = 0;
}
void w_cmd(uint8 cmd)// 寫命令
{
wait();
EN = 0;
P0 = cmd;
RS = 0;
RW = 0;
EN = 1;
EN = 0;
}
void w_string(uint8 addr_start, uint8 *p)// 發送字符串到LCD
{
w_cmd(addr_start);
while (*p != '\0')
{
w_dat(*p++);
}
}
void Init_LCD1602(void)// 初始化1602
{
w_cmd(0x38); // 16*2顯示,5*7點陣,8位數據接口
w_cmd(0x0c); // 顯示器開、光標開、光標允許閃爍
w_cmd(0x06); // 文字不動,光標自動右移
w_cmd(0x01); // 清屏
}
uchar Reset()//完成單總線的復位操作。
{
uchar d;
DQ = 0; // 將 DQ 線拉低
Delayus(29); // 保持 480μs .復位時間為480μs,因此延時時間為(480-24)/16 = 28.5,取29μs。
DQ = 1; // DQ返回高電平
Delayus(3); // 等待存在脈沖.經過70μs之后檢測存在脈沖,因此延時時間為(70-24)/16 = 2.875,取3μs。
d = DQ; // 獲得存在信號
Delayus(25); // 等待時間隙結束
return(d); // 返回存在信號,0 = 器件存在, 1 = 無器件
}
void write_bit(uchar bitval)//向單總線寫入1位值:bitval
{
DQ = 0; // 將DQ 拉低開始寫時間隙
if(bitval==1)
DQ =1; // 如果寫1,DQ 返回高電平
Delayus(5);// 在時間隙內保持電平值,
DQ = 1; // Delayus函數每次循環延時16μs,因此Delayus(5)=5*16+24=104μs
}
void ds18write_byte(char val)//向單總線寫入一個字節值:val
{
uchar i;
uchar temp;
for (i=0; i<8; i++)// 寫入字節, 每次寫入一位
{
temp = val>>i;
temp &= 0x01;
write_bit(temp);
}
Delayus(5);
}
uchar read_bit()//從單總線上讀取一位信號,所需延時時間為15μs,因此無法調用前面定義
{ //的Delayus()函數,而采用一個for()循環來實現延時。
uchar i;
DQ = 0; //將DQ 拉低開始讀時間隙
DQ = 1; // 然后返回高電平
for (i=0; i<3; i++); // 延時15μs
return(DQ); // 返回 DQ 線上的電平值
}
uchar ds18read_byte()//從單總線讀取一個字節的值
{
uchar i;
uchar value = 0;
for (i=0;i<8;i++)
{ // 讀取字節,每次讀取一個字節
if(read_bit())
value|=0x01<<i; // 然后將其左移
Delayus(6);
}
return(value);
}
int Readtemperature()//如果單總線節點上只有一個器件則可以直接掉用本函數。如果節點上有多個器
{ //件,為了避免數據沖突,應使用Match ROM函數來選中特定器件。
uchar temp_d,temp_g,k,get[2],temp;
Reset();
ds18write_byte(0xcc); // 跳過 ROM
ds18write_byte(0x44); // 啟動溫度轉換
Delayus(5);
Reset();
ds18write_byte(0xcc); // 跳過 ROM
ds18write_byte(0xbe); // 讀暫存器
for (k=0;k<2;k++)
{
get[k]=ds18read_byte();
}
temp_d = get[0];//低位
temp_g = get[1];//高位
if((temp_g&0xf0)==0xf0) //正負號判斷
{
temp_d=~temp_d;
if(temp_d==0xff) //保證-48(1111110100000000)、-32和-16顯示正常
{
temp_d=temp_d+0x01;//00000000
temp_g=~temp_g;//00000010
temp_g=temp_g+0x01;//00000011
}
else
{
temp_d=temp_d+0x01;
temp_g=~temp_g;
}
w_cmd(0xc5);
w_dat(Xsw[temp_d&0x0f]); //查表得小數位的值
temp=((temp_d&0xf0)>>4)|((temp_g&0x0f)<<4);
w_cmd(0xc1);
w_dat(0x2d);//負號
}
else //正數
{
w_cmd(0xc5);
w_dat(Xsw[temp_d&0x0f]); //查表得小數位的值
temp=((temp_d&0xf0)>>4)|((temp_g&0x0f)<<4);
w_cmd(0xc1);
w_dat(Bw[temp/100]);
}
return temp;
}
main()
{
Init_LCD1602();
w_string(0x80,word1);
while (1)
{
wendu=Readtemperature();
temp_g=wendu%100/10+'0';
temp_d=wendu%10+'0';
w_cmd(0xc2);
delay(2);
w_dat(temp_g);
delay(2);
w_dat(temp_d);
delay(2);
w_cmd(0xc4);
delay(2);
w_dat(0x2e);//小數點
delay(2);
w_cmd(0xc6);
delay(2);
w_dat(0xdf);//溫度符號
delay(2);
w_dat(0x43);
}
}
卡爾曼濾波部分代碼
#include "KalmanFilter.h"
float R=0.999f;
float Q=0.001f;
float x0=0.0f;
float p0=1555.0f;
float k,x,p;
float KalmanFilter(float Measure)
{
x=x0;
p=p0+Q;
k=p/(p+R);
x=x+k*(Measure-x);
p=(1-k)*p;
p0=p;
x0=x;
return x;
}
#include "KalmanFilter.h"
float R=0.999f;
float Q=0.001f;
float x0=0.0f;
float p0=1555.0f;
float k,x,p;
float KalmanFilter(float Measure)
{
x=x0;
p=p0+Q;
k=p/(p+R);
x=x+k*(Measure-x);
p=(1-k)*p;
p0=p;
x0=x;
return x;
}
|