下面的代码已详细注释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!” } } }