下面的代碼已詳細注釋DHT11的通信程序,想了解更多可看其資料手冊
#include <iocc2530.h>
#include <stdio.h>
#include <string.h>
#define DATA_PIN P0_0 // DHT11 的資料引腳
typedef unsigned char uchar;
/* 定義一個結構體,用來存盤DHT11傳出來的40位資料 */
typedef struct{
uchar temp_H;
uchar temp_L;
uchar humi_H;
uchar humi_L;
uchar crc;
}DHT;
/* 微秒延時 */
void Delay_us(int time)
{
while(time--){
asm("NOP");
}
}
/* 毫秒延時 */
void Delay_ms(int Time)
{
while(Time--){
Delay_us(1000);
}
}
/* 定義DHT11的資料引腳為 輸出 狀態 */
void DHT_OUT(void){
P0SEL &= ~0x01;
P0DIR |= 0x01;
}
/* 定義DHT11的資料引腳為 輸入 狀態 */
void DHT_IN(void){
P0SEL &= ~0x01;
P0DIR &= ~0x01;
P0INP &= ~0x01;
P2INP &= ~0x20;
}
/* 讀取一個位元組的資料(在DHT11回應主機之后呼叫該函式) */
uchar Read_Byte(void){
uchar temp, i;
/* 一位一位的讀取 */
for(i=0;i<8;i++){
/*每bit以50us低電平標置開始,輪詢直到從機發出 的50us 低電平 結束*/
while(DATA_PIN==0);
/*DHT11 以26~28us的高電平表示“0”,以70us高電平表示“1”,
*通過檢測 30 us后的電平即可區別這兩個狀
*/
Delay_us(30); //延時30us 這個延時需要大于資料0持續的時間即可
/* 30 us后仍為高電平表示資料“1” */
if(DATA_PIN==1){
while(DATA_PIN==1); //等待資料1的高電平結束
temp |= (uchar)(0x01<<7-i); //把第7-i位置1,MSB先行
}
else{ // 30 us后為低電平表示資料“0”
temp &= (uchar)~(0x01<<7-i); //把第7-i位置0,MSB先行
}
}
return temp;
}
DHT dh; // 用來接收DHT11發過來的40位資料
/*
*主機與DHT11通信
* 一次完整的資料傳輸為40bit,高位先出
* 8bit 濕度整數 + 8bit 濕度小數 + 8bit 溫度整數 + 8bit 溫度小數 + 8bit 校驗和
*/
uchar Read_DHT(void){
Delay_ms(1200);//等待DHT11穩定,延時大于1秒
DHT_OUT(); //輸出模式
DATA_PIN=0; //主機拉低
Delay_ms(18); //延時18ms
DATA_PIN=1; //總線拉高
Delay_us(40); //主機延時40us
DHT_IN(); //主機設為輸入 判斷從機回應信號
/*判斷從機是否有低電平回應信號 如不回應則跳出,回應則向下運行*/
if(DATA_PIN==0){
while(DATA_PIN==0); //輪詢直到從機發出 的80us 低電平 回應信號結束
while(DATA_PIN==1); //輪詢直到從機發出的 80us 高電平 標置信號結束
/*開始接收資料*/
dh.humi_H=(uchar)Read_Byte();
dh.humi_L=(uchar)Read_Byte();
dh.temp_H=(uchar)Read_Byte();
dh.temp_L=(uchar)Read_Byte();
dh.crc=(uchar)Read_Byte();
/*讀取結束,引腳改為輸出模式*/
DHT_OUT();
DATA_PIN=1; //主機拉高
/*檢查讀取的資料是否正確*/
if(dh.humi_H+dh.humi_L+dh.temp_H+dh.temp_L==dh.crc)
return 1;
else
return 0;
}
else
return 0;
}
void Init_32M(){
SLEEPCMD &=0xFB;//1111 1011 開啟2個高頻時鐘源
while(0==(SLEEPSTA & 0x40));// 0100 0000 等待32M穩定
Delay_us(63);
CLKCONCMD &=0xF8;//1111 1000 不分頻輸出
CLKCONCMD &=0XBF;//1011 1111 設定32M作為系統主時鐘
while(CLKCONSTA & 0x40); //0100 0000 等待32M成功成為當前系統主時鐘
SLEEPCMD |=0x04;
}
void Init_Uart()
{
Init_32M(); //使用32MHz的外部晶振
PERCFG&=~0x01; //有2個備用位置,0使用備用位置1;1使用備用位置2
P0SEL |= 0x0C; //P0_2 RXD P0_3 TXD 外設功能 0000 1100
U0CSR |= 0xC0; //串口接收使能 1100 0000 作業UART模式+允許接受
U0UCR |= 0x00; //無奇偶校驗,1位停止位
U0GCR |= 11; //U0GCR與U0BAUD配合
U0BAUD |= 216; // 波特率設為115200
IEN0 |= 0X04; //開串口接收中斷 'URX0IE = 1',也可以寫成 URX0IE=1;
EA=1;
}
/* 串口發送一個字符 */
void Uart0_SendCh(char ch)
{
U0DBUF = ch; //將該字符寫入串口資料發送暫存器
while(UTX0IF == 0); //檢查標志位
UTX0IF = 0; //將標志位清零
}
/* 串口發送一個字串 */
void Uart_Send_String(char *Data,int len)
{
{
int j;
for(j=0;j<len;j++) //一個字符一個字符的發送
{
Uart0_SendCh(*Data++);
}
}
}
void main(void){
char *dht11; // 將 從DHT11接收到的資料 轉換成一個字串
Init_Uart();
Uart_Send_String("Welcome DHT11 Test!\n",20);//歡迎陳述句
Delay_ms(1000);
while(1){
if(Read_DHT()){
/* 將 從DHT11接收到的資料 轉換成一個字串 */
sprintf(dht11,"濕度:%2d.%d 溫度:%2d.%d\n",dh.humi_H,dh.humi_L,dh.temp_H,dh.temp_L);
Uart_Send_String(dht11,20);// 發送給串口
}
else{
Uart_Send_String("Read DHT11 ERROR!\n",18); //讀取失敗的話,發送“Read DHT11 ERROR!”
}
}
}

轉載請註明出處,本文鏈接:https://www.uj5u.com/qianduan/187527.html
標籤:其他
