评论

收藏

[Oracle] 《OpenWrt开发笔记》第28章 DHT11 温湿度传感器

数据库 数据库 发布于:2021-12-29 11:58 | 阅读数:467 | 评论:0

28.1硬件原理
下图是我们温度传感器的接入引脚,3.3V 供电,io 口接 P13 的 GP0( GPIO0 的简称 )。
DHT11数字温湿度传感器 是一款含有已校准数字信号输出的温湿度复合传感器,它应用专用的数字模块采集技术和温湿度传感技术,确保产品具有极高的可靠性和卓越的长期稳定性。传感器包括一个电阻式感湿元件和一个NTC测温元件,并与一个高性能 8 位单片机相连接。因此该产品具有品质卓越、超快响应、抗干扰能力强、性价比极高等优点。每个DHT11 传感器都在极为精确的湿度校验室中进行校准。校准系数以程序的形式存在OTP内存中,传感器内部在检测型号的处理过程中要调用这些校准系数。单线制串行接口,使系统集成变得简易快捷。超小的体积、极低的功耗,使其成为该类应用中,在苛刻应用场合的最佳选择。

28.2 DHT11 相关时序
 初始化(复位)时序图
DSC0000.png

图1




  • 控制器首先至少拉低 18ms,然后拉高 20-40us 后等待 DHT11 的应答
  • 当 DHT11 检测到信号后,首先将总线拉低约 80us 然后在拉高 80us 作为应答信号。



 读取数据时序图
DSC0001.png

图2
 表示 0 的时序如下
DSC0002.png

图3
 表示 1 的时序如下
DSC0003.png

图4




  • DHT11 以低电平应答主机,然后拉高总线准备输出。输出 0 信号和 1 信号都是以低电平开始高电平结束。
  • DHT11 输出 0、 1 信号的低电平时间相同,而高电平的时间不同,输出 0 信号时高电平约 26-28us,而当输出 1 信号时高电平约为 70us。




28.2驱动程序
关于字符设备驱动程序的使用,我们可以参照点亮 led 灯的那个实验,这里只给出跟DHT11 密切相关的驱动程序,详细的程序请查看我们的驱动文件!
//配置连接温度传感器的引脚
#define DHT11_L       *GPIO21_0_DATA &= ~(1<<0)  //低电平  
#define DHT11_H       *GPIO21_0_DATA |=  (1<<0)  //高电平
#define DHT11_OUT     *GPIO21_0_DIR  |=  (1<<0)  //输出 
#define DHT11_IN  *GPIO21_0_DIR  &= ~(1<<0)  //输入 
#define DHT11_STA   *GPIO21_0_DATA & 0x01 
//寄存器定义
volatile unsigned long *GPIO21_0_DIR;
volatile unsigned long *GPIO21_0_DATA;  

/****************  基本定义 **********************/
//初始化函数必要资源定义
//用于初始化函数当中
//device number;
  dev_t dev_num;
//struct dev
  struct cdev dht11_cdev;
//auto "mknode /dev/dht11 c dev_num minor_num"
struct class *dht11_class = NULL;
struct device *dht11_device = NULL;
/********************  dht11有关的函数   ****************************/
//从dht11中读取一个字节
static unsigned char read_byte(void)
{
  unsigned char r_val = 0; 
  unsigned char t_count = 0; //计时器,防止超时;
    unsigned char i;
  for(i = 0 ; i < 8 ; i++)
  {
  t_count = 0;
  while(!DHT11_STA)
  {
    udelay(1);
    t_count++;
    if(t_count>250)
    {
    printk("read_byte error1\n");
    return 100;
    }
  }
  t_count = 0;
  udelay(32);
  if(DHT11_STA == 1)
  {
    r_val <<= 1;
    r_val |= 1;
  }
  else
  {
    r_val <<= 1;
    continue;
  }
  while( DHT11_STA == 1 )
  {
    udelay(2);
    t_count++;
    if(t_count>250)
    {
    printk("read_byte error2\n");
    return 100;
    }
   }
  }
  return r_val;
}
//从dht11中读出数据
static unsigned int read_dht11(void)
{
   unsigned char t_count = 0; //计时器;
   unsigned int  dht11 = 0;
   unsigned char h_i = 0 , h_f = 0;
   unsigned char t_i = 0 , t_f = 0;
   unsigned char check_sum = 0;
   DHT11_OUT;
   DHT11_L;
   mdelay(30); //>18ms;
   DHT11_H;
   udelay(30);
   DHT11_IN;
   while(DHT11_STA == 1)
   {
  udelay(1);
  t_count++;
  if(t_count > 50)
  {
    printk("device error: dht11!\n");
    return 0;
  }
   }
   t_count = 0;
   while(!DHT11_STA)
   {
  udelay(1);
  t_count++;
  if(t_count > 250)
  {
    printk("read_dht11 error1\n");
    return 0;
  }
   }
   t_count = 0;
   udelay(50);
   while(DHT11_STA)
   {
  udelay(1);
  t_count++;
  if(t_count > 250)
  {
    printk("read_dht11 error2\n");
    return 0;
  }
   }
   h_i = read_byte();
   h_f = read_byte();
   t_i = read_byte();
   t_f = read_byte();
   check_sum = read_byte();
   if(check_sum == (h_i+h_f+t_i+t_f) || (h_i!=100 && t_i != 100))
   {
  dht11 = t_i;
  dht11 <<= 8;
  dht11 += h_i;
   }
   else
   {
  dht11 = 0;
  printk("read_dht11 error3\n");
   }
   return dht11;
}

/**********************************************************************/
/**************** 结构体 file_operations 成员函数 *****************/
//open
static int dht11_open(struct inode *inode, struct file *file)
{
  printk("dht11 drive open...\n");
  DHT11_OUT;
  DHT11_H;
  return 0;
}
//close
static int dht11_close(struct inode *inode , struct file *file)
{
  return 0;
}
//read
static ssize_t dht11_read(struct file *file, char __user *buffer,
    size_t len, loff_t *pos)
{
  unsigned int dht11; 
  printk("dht11 drive read...\n");
  dht11 = read_dht11();
  copy_to_user(buffer, &dht11, 4);
  return 4;
}

/***************** 结构体: file_operations ************************/
//struct
static const struct file_operations dht11_fops = {
  .owner   = THIS_MODULE,
  .open  = dht11_open,
  .release = dht11_close, 
  .read  = dht11_read,
};

/*************  functions: init , exit*******************/
//条件值变量,用于指示资源是否正常使用
unsigned char init_flag = 0;
unsigned char add_code_flag = 0;
//init
static __init int dht11_init(void)
{
  int ret_v = 0;
  printk("dht11 drive init...\n");
  //函数alloc_chrdev_region主要参数说明:
  //参数2: 次设备号
  //参数3: 创建多少个设备
  if( ( ret_v = alloc_chrdev_region(&dev_num,0,1,"dht11") ) < 0 )
  {
  goto dev_reg_error;
  }
  init_flag = 1; //标示设备创建成功;
  printk("The drive info of dht11:\nmajor: %d\nminor: %d\n",
  MAJOR(dev_num),MINOR(dev_num));
  cdev_init(&dht11_cdev,&dht11_fops);
  if( (ret_v = cdev_add(&dht11_cdev,dev_num,1)) != 0 )
  {
  goto cdev_add_error;
  }
  dht11_class = class_create(THIS_MODULE,"dht11");
  if( IS_ERR(dht11_class) )
  {
  goto class_c_error;
  }
  dht11_device = device_create(dht11_class,NULL,dev_num,NULL,"dht11");
  if( IS_ERR(dht11_device) )
  {
  goto device_c_error;
  }
  printk("auto mknod success!\n");
  //------------   请在此添加您的初始化程序  --------------//

  GPIO21_0_DATA = (volatile unsigned long *)ioremap(0x10000620, 4);
  GPIO21_0_DIR =  (volatile unsigned long *)ioremap(0x10000624, 4);
    //如果需要做错误处理,请:goto dht11_error; 
   add_code_flag = 1;
  //----------------------  END  ---------------------------// 
  goto init_success;
dev_reg_error:
  printk("alloc_chrdev_region failed\n"); 
  return ret_v;
cdev_add_error:
  printk("cdev_add failed\n");
  unregister_chrdev_region(dev_num, 1);
  init_flag = 0;
  return ret_v;
class_c_error:
  printk("class_create failed\n");
  cdev_del(&dht11_cdev);
  unregister_chrdev_region(dev_num, 1);
  init_flag = 0;
  return PTR_ERR(dht11_class);
device_c_error:
  printk("device_create failed\n");
  cdev_del(&dht11_cdev);
  unregister_chrdev_region(dev_num, 1);
  class_destroy(dht11_class);
  init_flag = 0;
  return PTR_ERR(dht11_device);
//------------------ 请在此添加您的错误处理内容 ----------------//
dht11_error:
  add_code_flag = 0;
  return -1;
//--------------------      END     -------------------//
init_success:
  printk("dht11 init success!\n");
  return 0;
}
//exit
static __exit void dht11_exit(void)
{
  printk("dht11 drive exit...\n");  
  if(add_code_flag == 1)
  {   
       //----------   请在这里释放您的程序占有的资源   ---------//
    printk("free your resources...\n");        
  iounmap(GPIO21_0_DATA);
  iounmap(GPIO21_0_DIR);
    printk("free finish\n");           
    //----------------------   END    -------------------//
  }           
  if(init_flag == 1)
  {
  //释放初始化使用到的资源;
  cdev_del(&dht11_cdev);
  unregister_chrdev_region(dev_num, 1);
  device_unregister(dht11_device);
  class_destroy(dht11_class);
  }
}
/**************** module operations**********************/
//module loading
module_init(dht11_init);
module_exit(dht11_exit);
//some infomation
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("from Jafy");
MODULE_DESCRIPTION("dht11 drive");
/*********************  The End ***************************/
28.3应用程序
int main(int argc, char **argv)
{
  int fd;
  unsigned int dht11 = 0;
  unsigned int humi,temp;
  //打开温度传感器驱动模块
  fd = open("/dev/dht11", O_RDWR | O_NONBLOCK);
  if (fd < 0)
  {
  printf("can't open /dev/dht11\n");
  return -1;
  }
  read(fd, &dht11, sizeof(dht11));
  temp = dht11>>8;
  humi = dht11 &0x000000ff;
  printf("the current temperature is: %d\n",temp);
  printf("the current humidity is:  %d\n",humi);
  close(fd);
  return 0;
}

28.4实验结果
DSC0004.png



关注下面的标签,发现更多相似文章