最后,歡迎大家交流學習,給我批評指正!
[code="CSHARP"]
/**
* ;功能說明:DHT90與LCD1602的溫濕度顯示
* ;文件名稱:DHT90.c
*
* ;微處理器:AT89S52
* ;編譯環(huán)境:Keil uVision V2.38a
*
* ;作 者:
* ;版 權:(c)
* ;創(chuàng)建日期:2008.08.15
* ;版 本:V1.2
* ;修改日期:2008.08.16
* ;修改說明:添加了一個LCD_disp_str()函數
* ;**********************************************************************************
*/
/**
* ************定義接口********************
* P0------DB0~DB7 (LCD1602)
* P2.0------RS (LCD1602)
* P2.1------RW (LCD1602)
* P2.2------E (LCD1602)
* P2.6------SCK (DHT90)
* P2.7------DATA (DHT90)
*/
#include <AT89x51.h>
#include <intrins.h>
#include <math.h> //Keil library
#include <stdio.h> //Keil library
// *********************第一部分LCD1602設置 START****************************************
#define LCD_DB P0
sbit LCD_RS = P2 ^ 0; //P2^0是p2.0的意思;LCD_RS與P2.0等效起來,對LCD_RS 讀寫,就是對P2.0讀寫 好處在于LCD_RS含義直接明了,寫程序多了就會知道有必要de
sbit LCD_RW = P2 ^ 1; //P2^1是p2.1的意思
sbit LCD_E = P2 ^ 2; //P2^2是p2.2的意思
/**
* *****定義函數***************
*/
// define uchar unsigned char
// define uint unsigned int
void LCD_init(void); //初始化函數
void LCD_write_command(uchar command); //寫指令函數
void LCD_write_data(uchar dat); //寫數據函數
void LCD_disp_char(uchar x, uchar y, uchar dat); //在某個屏幕位置上顯示一個字符,X(0-15),y(1-2)
void LCD_disp_str(uchar x, uchar y, uchar * str); //LCD1602顯示字符串函數
void delay_n10us(uint n); //延時函數
/**
* --------------------------------------
* ;模塊名稱:LCD_init();
* ;功 能:初始化LCD1602
* ;占用資源:--
* ;參數說明:--
* ;創(chuàng)建日期:2008.08.15
* ;版 本:FV1.0(函數版本Function Version)
* ;修改日期:--
* ;修改說明:--
* ;-------------------------------------
*/
void LCD_init(void) {
delay_n10us(10);
LCD_write_command(0x38); //設置8位格式,2行,5x7
delay_n10us(10);
LCD_write_command(0x0c); //整體顯示,關光標,不閃爍
delay_n10us(10);
LCD_write_command(0x06); //設定輸入方式,增量不移位
delay_n10us(10);
LCD_write_command(0x01); //清除屏幕顯示
delay_n10us(100); //延時清屏,延時函數,延時約n個10us
}
/**
* --------------------------------------
* ;模塊名稱:LCD_write_command();
* ;功 能:LCD1602寫指令函數
* ;占用資源: P2.0--RS(LCD_RS),P2.1--RW(LCD_RW),P2.2--E(LCD_E).
* ;參數說明:dat為寫命令參數
* ;創(chuàng)建日期:2008.08.15
* ;版 本:FV1.0(函數版本Function Version)
* ;修改日期:--
* ;修改說明:--
* ;-------------------------------------
*/
void LCD_write_command(uchar dat) {
delay_n10us(10);
LCD_RS = 0; //指令
LCD_RW = 0; //寫入
LCD_E = 1; //允許
LCD_DB = dat;
delay_n10us(10); //實踐證明,我的LCD1602上,用for循環(huán)1次就能完成普通寫指令。
LCD_E = 0;
delay_n10us(10); //實踐證明,我的LCD1602上,用for循環(huán)1次就能完成普通寫指令。
}
/**
* --------------------------------------
* ;模塊名稱:LCD_write_data();
* ;功 能:LCD1602寫數據函數
* ;占用資源: P2.0--RS(LCD_RS),P2.1--RW(LCD_RW),P2.2--E(LCD_E).
* ;參數說明:dat為寫數據參數
* ;創(chuàng)建日期:2008.08.15
* ;版 本:FV1.0(函數版本Function Version)
* ;修改日期:--
* ;修改說明:--
* ;-------------------------------------
*/
void LCD_write_data(uchar dat) {
delay_n10us(10);
LCD_RS = 1; //數據
LCD_RW = 0; //寫入
LCD_E = 1; //允許
LCD_DB = dat;
delay_n10us(10);
LCD_E = 0;
delay_n10us(10);
}
/**
* --------------------------------------
* ;模塊名稱:LCD_disp_char();
* ;功 能:LCD1602顯示一個字符函數,在某個屏幕位置上顯示一個字符,X(0-15),y(1-2)。
;占用資源:--
* ;參數說明:X為1602的列值(取值范圍是0-15),y為1602的行值(取值范圍是1-2),dat為所要顯示字符對應的地址參數。
;創(chuàng)建日期:2008.08.15
* ;版 本:FV1.0(函數版本Function Version)
* ;修改日期:--
* ;修改說明:--
* ;-------------------------------------
*/
void LCD_disp_char(uchar x, uchar y, uchar dat) {
uchar address;
if (y == 1)
address = 0x80 + x;
else
address = 0xc0 + x;
LCD_write_command(address);
LCD_write_data(dat);
}
/**
* --------------------------------------
* ;模塊名稱:LCD_disp_str();
* ;功 能:LCD1602顯示字符串函數,在某個屏幕起始位置{X(0-15),y(1-2)}上顯示一個字符串。
;占用資源:--
* ;參數說明:X為1602的列值(取值范圍是0-15),y為1602的行值(取值范圍是1-2),str為所要顯示字符串對應的指針參數。
;創(chuàng)建日期:2008.08.16
* ;版 本:FV1.0(函數版本Function Version)
* ;修改日期:--
* ;修改說明:--
* ;-------------------------------------
*/
void LCD_disp_str(uchar x, uchar y, uchar * str) {
uchar address;
if (y == 1)
address = 0x80 + x;
else
address = 0xc0 + x;
LCD_write_command(address);
while (* str != '\0') {
LCD_write_data(* str);
str++;
}
}
/**
* --------------------------------------
* ;模塊名稱:delay_n10us();
* ;功 能:延時函數,延時約n個10us
* ;占用資源:--
* ;參數說明:--
* ;創(chuàng)建日期:2008.08.15
* ;版 本:FV1.1(函數版本Function Version)
* ;修改日期:2008.08.16
* ;修改說明:修改為較精確的延時函數
;-------------------------------------
*/
void delay_n10us(uint n) {
uint i;
for(i = n;i > 0;i--) {
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_(); //延時10us@12M晶振
}
}
// *********************第一部分LCD1602設置 END****************************************
// *********************第二部分DHT90設置 START****************************************
sbit SCK = P2 ^ 6; //定義通訊時鐘端口
sbit DATA = P2 ^ 7; //定義通訊數據端口
typedef union {
unsigned int i; //定義了兩個共用體
float f;
}
value;
enum {
TEMP, HUMI}; //TEMP=0,HUMI=1
// define noACK 0 //用于判斷是否結束通訊
// define ACK 1 //結束數據傳輸
// adr command r/w
// define STATUS_REG_W 0x06 //000 0011 0
// define STATUS_REG_R 0x07 //000 0011 1
// define MEASURE_TEMP 0x03 //000 0001 1
// define MEASURE_HUMI 0x05 //000 0010 1
// define RESET 0x1e //000 1111 0
/**
* ***************定義函數***************
*/
void s_transstart(void); //啟動傳輸函數
void s_connectionreset(void); //連接復位函數
char s_write_byte(unsigned char value); //DHT90寫函數
char s_read_byte(unsigned char ack); //DHT90讀函數
char s_measure(unsigned char * p_value, unsigned char * p_checksum, unsigned char mode); //測量溫濕度函數
void calc_dht90(float * p_humidity , float * p_temperature); //溫濕度補償
/**
* --------------------------------------
* ;模塊名稱:s_transstart();
* ;功 能:啟動傳輸函數
* ;占用資源:--
* ;參數說明:--
* ;創(chuàng)建日期:2008.08.15
* ;版 本:FV1.0(函數版本Function Version)
* ;修改日期:--
* ;修改說明:--
* ;-------------------------------------
*/
void s_transstart(void)
// generates a transmission start
// _____ ________
// DATA: |_______|
// ___ ___
{ // SCK : ___| |___| |______
DATA = 1;
SCK = 0; //Initial state
_nop_();
SCK = 1;
_nop_();
DATA = 0;
_nop_();
SCK = 0;
_nop_();
_nop_();
_nop_();
SCK = 1;
_nop_();
DATA = 1;
_nop_();
SCK = 0;
}
/**
* --------------------------------------
* ;模塊名稱:s_connectionreset();
* ;功 能:連接復位函數
* ;占用資源:--
* ;參數說明:--
* ;創(chuàng)建日期:2008.08.15
* ;版 本:FV1.0(函數版本Function Version)
* ;修改日期:--
* ;修改說明:--
* ;-------------------------------------
*/
void s_connectionreset(void)
// communication reset: DATA-line=1 and at least 9 SCK cycles followed by transstart
// _____________________________________________________ ________
// DATA: |_______|
// _ _ _ _ _ _ _ _ _ ___ ___
{ // SCK : __| |__| |__| |__| |__| |__| |__| |__| |__| |______| |___| |______
unsigned char i;
DATA = 1;
SCK = 0; //Initial state
for(i = 0;i < 9;i++) { // 9 SCK cycles
SCK = 1;
SCK = 0;
}
s_transstart(); //transmission start
}
/**
* --------------------------------------
* ;模塊名稱:s_write_byte();
* ;功 能:DHT90寫函數
;占用資源:--
* ;參數說明:--
* ;創(chuàng)建日期:2008.08.15
* ;版 本:FV1.0(函數版本Function Version)
* ;修改日期:--
* ;修改說明:--
* ;-------------------------------------
*/
char s_write_byte(unsigned char value)
// ----------------------------------------------------------------------------------
{ // writes a byte on the Sensibus and checks the acknowledge
unsigned char i, error = 0;
for (i = 0x80;i > 0;i /= 2) { // shift bit for masking
if (i &value) DATA = 1; //masking value with i , write to SENSI-BUS
else DATA = 0;
SCK = 1; //clk for SENSI-BUS
_nop_();
_nop_();
_nop_(); //pulswith approx. 5 us
SCK = 0;
}
DATA = 1; //release DATA-line
SCK = 1; //clk #9 for ack
error = DATA; //check ack (DATA will be pulled down by DHT90),DATA在第9個上升沿將被DHT90自動下拉為低電平。
_nop_();
_nop_();
_nop_();
SCK = 0;
DATA = 1; //release DATA-line
return error; //error=1 in case of no acknowledge //返回:0成功,1失敗
}
/**
* --------------------------------------
* ;模塊名稱:s_read_byte();
* ;功 能:DHT90讀函數
;占用資源:--
* ;參數說明:--
* ;創(chuàng)建日期:2008.08.15
* ;版 本:FV1.0(函數版本Function Version)
* ;修改日期:--
* ;修改說明:--
* ;-------------------------------------
*/
char s_read_byte(unsigned char ack)
{ // reads a byte form the Sensibus and gives an acknowledge in case of "ack=1"
unsigned char i, val = 0;
DATA = 1; //release DATA-line
for (i = 0x80;i > 0;i /= 2) { // shift bit for masking
SCK = 1; //clk for SENSI-BUS
if (DATA) val = (val | i); //read bit
_nop_();
_nop_();
_nop_(); //pulswith approx. 5 us
SCK = 0;
}
if (ack == 1)DATA = 0; //in case of "ack==1" pull down DATA-Line
else DATA = 1; //如果是校驗(ack==0),讀取完后結束通訊
_nop_();
_nop_();
_nop_(); //pulswith approx. 5 us
SCK = 1; //clk #9 for ack
_nop_();
_nop_();
_nop_(); //pulswith approx. 5 us
SCK = 0;
_nop_();
_nop_();
_nop_(); //pulswith approx. 5 us
DATA = 1; //release DATA-line
return val;
}
/**
* --------------------------------------
* ;模塊名稱:s_measure();
* ;功 能:測量溫濕度函數
;占用資源:--
* ;參數說明:--
* ;創(chuàng)建日期:2008.08.15
* ;版 本:FV1.0(函數版本Function Version)
* ;修改日期:--
* ;修改說明:--
* ;-------------------------------------
*/
char s_measure(unsigned char * p_value, unsigned char * p_checksum, unsigned char mode)
{ // makes a measurement (humidity/temperature) with checksum
unsigned error = 0;
unsigned int i;
s_transstart(); //transmission start
switch (mode) { // send command to sensor
case TEMP : error += s_write_byte(MEASURE_TEMP);
break;
case HUMI : error += s_write_byte(MEASURE_HUMI);
break;
default : break;
}
for (i = 0;i < 65535;i++) if (DATA == 0) break; //wait until sensor has finished the measurement
if (DATA) error += 1; // or timeout (~2 sec.) is reached * (p_value) = s_read_byte(ACK); //read the first byte (MSB) * (p_value + 1) = s_read_byte(ACK); //read the second byte (LSB) * p_checksum = s_read_byte(noACK); //read checksum
return error;
}
/**
* --------------------------------------
* ;模塊名稱:calc_dht90();
* ;功 能:溫濕度補償函數
;占用資源:--
* ;參數說明:--
* ;創(chuàng)建日期:2008.08.15
* ;版 本:FV1.0(函數版本Function Version)
* ;修改日期:--
* ;修改說明:--
* ;-------------------------------------
*/
void calc_dht90(float * p_humidity , float * p_temperature)
// calculates temperature [C] and humidity [%RH]
// input : humi [Ticks] (12 bit)
// temp [Ticks] (14 bit)
// output: humi [%RH]
{ // temp [C]
const float C1 = -4.0; // for 12 Bit
const float C2 = + 0.0405; // for 12 Bit
const float C3 = -0.0000028; // for 12 Bit
const float T1 = + 0.01; // for 14 Bit @ 5V
const float T2 = + 0.00008; // for 14 Bit @ 5V
float rh = * p_humidity; // rh: Humidity [Ticks] 12 Bit
float t = * p_temperature; // t: Temperature [Ticks] 14 Bit
float rh_lin; // rh_lin: Humidity linear
float rh_true; // rh_true: Temperature compensated humidity
float t_C; // t_C : Temperature [C]
t_C = t * 0.01 - 40; //calc. temperature from ticks to [C]
rh_lin = C3 * rh * rh + C2 * rh + C1; //calc. humidity from ticks to [%RH]
rh_true = (t_C-25) * (T1 + T2 * rh) + rh_lin; //calc. temperature compensated humidity [%RH]
if (rh_true > 100)rh_true = 100; //cut if the value is outside of
if (rh_true < 0.1)rh_true = 0.1; //the physical possible range
* p_temperature = t_C; //return temperature [C] * p_humidity = rh_true; //return humidity[%RH]
}
// *********************第二部分DHT90設置 END****************************************
// *********主函數*****************
void main(void) {
value humi_val, temp_val;
unsigned char error, checksum;
unsigned int wendu, shidu;
LCD_init();
s_connectionreset();
LCD_disp_str(0, 1, "TE");
LCD_disp_str(0, 2, "RH");
// *********初始化溫度顯示區(qū)*********
LCD_disp_str(2, 1, "TTT.TC");
// *********初始化濕度顯示區(qū)*********
LCD_disp_str(2, 2, "RRR.R%");
delay_n10us(20000); //延時0.2s
while (1) {
error = 0;
error += s_measure((unsigned char *) &humi_val . i, &checksum, HUMI); //measure humidity
error += s_measure((unsigned char *) &temp_val . i, &checksum, TEMP); //measure temperature
if (error != 0) s_connectionreset(); //in case of an error: connection reset
else {
humi_val . f = (float)humi_val . i; //converts integer to float
temp_val . f = (float)temp_val . i; //converts integer to float
calc_dht90(&humi_val . f, &temp_val . f); //calculate humidity, temperature
wendu = 10 * temp_val . f;
LCD_disp_char(2, 1, wendu / 1000 + '0'); //顯示溫度百位
LCD_disp_char(3, 1, (wendu % 1000) / 100 + '0'); //顯示溫度十位
LCD_disp_char(4, 1, (wendu % 100) / 10 + '0'); //顯示溫度個位
LCD_disp_char(6, 1, (wendu % 10) + '0'); //顯示溫度小數點后第一位
shidu = 10 * humi_val . f;
LCD_disp_char(2, 2, shidu / 1000 + '0'); //顯示濕度百位
LCD_disp_char(3, 2, (shidu % 1000) / 100 + '0'); //顯示濕度十位
LCD_disp_char(4, 2, (shidu % 100) / 10 + '0'); //顯示濕度個位
LCD_disp_char(6, 2, (shidu % 10) + '0'); //顯示濕度小數點后第一位
}
// ----------wait approx. 0.8s to avoid heating up SHTxx------------------------------
delay_n10us(80000); //延時約0.8s
}
}
[/code]