DHT 11をLinuxシステムに移植する

5986 ワード

プロジェクトの必要性のため、DHT 11をLinuxに移植する必要があります.ドライバは次のとおりです.
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/input.h>
#include <linux/init.h>
#include <linux/errno.h>
#include <linux/serio.h>
#include <linux/delay.h>
#include <linux/clk.h>
#include <linux/wait.h>
#include <linux/sched.h>
#include <linux/cdev.h>
#include <linux/miscdevice.h>
#include <linux/gpio.h>
#include <mach/gpio.h>
#include <asm-generic/uaccess.h>
#include <linux/spinlock.h>
#include <linux/mutex.h>


#define DEVICE_NAME "dht11"
#define PIN S5PV210_GPH0(0)

typedef unsigned char  U8; 
unsigned char buf[6];
unsigned char check_flag;
//spinlock_t lock=SPIN_LOCK_UNLOCKED;

//spinlock_t lock=SPIN_LOCK_UNLOCKED;

//DEFINE_SPINLOCK(lock);
static  DEFINE_MUTEX(mutex);
int read_one_bit(void)          // io       
{
    gpio_direction_input(PIN);
    return gpio_get_value(PIN);
}


void gpio_out(int value)   // io      ,     
{
    gpio_direction_output(PIN,value);
}

unsigned char  humidity_read_byte(void)
{    
    int i=0;
    int num; 
    unsigned char flag=0;
	unsigned char data=0;
	

    for(num=0;num<8;num++)
	{              
          i=0;
          while(!gpio_get_value(PIN))
		  {
            udelay(10);
            i++;
            if(i>10)
            break;
    	   }
    	    flag=0x0;
    		udelay(28);            
    	   if(gpio_get_value(PIN))
		   {
    		flag=0x01;			
    	   }
    		i=0;
    	   while(gpio_get_value(PIN))
		   {
    		udelay(10);
    		i++;
    		if(i>12)
    		break;
    	   }
    	   data<<=1;
    	   data|=flag;
    }  
	return data;
}


void humidity_read_data(void)
{
	int i=0;
	gpio_out(0);
	mdelay(30);
	gpio_out(1);
	udelay(20);    
	if(read_one_bit()== 0)
	{ 
		while(!gpio_get_value(PIN))
		{
           udelay(5);
           i++;
         	if(i>20)
         	{
				printk("humidity_read_data %d err!
",__LINE__); break; } } i=0; while(gpio_get_value(PIN)) { udelay(5); i++; if(i>20) { printk("humidity_read_data %d err!
",__LINE__); break; } } for(i=0;i<5;i++) buf[i]=humidity_read_byte(); buf[5]=buf[0]+buf[1]+buf[2]+buf[3]; if(buf[4]==buf[5]) { check_flag=0xff; printk("humidity check pass
"); printk("humidity=[%d],temp=[%d]
",buf[0],buf[2]); } else { check_flag=0x0; printk("humidity check fail
"); } } } static ssize_t humidiy_read(struct file *file, char __user *buffer, size_t size, loff_t *off) { int ret; local_irq_disable(); humidity_read_data(); local_irq_enable(); if(check_flag==0xff) { ret=copy_to_user(buffer,buf,sizeof(buf)); if(ret<0){ printk("copy to user err
"); return -EAGAIN; } else return 0; } else return -EAGAIN; } static int humidiy_open(struct inode *inode, struct file *file) { printk("open in kernel
"); return 0; } static int humidiy_release(struct inode *inode, struct file *file) { printk("humidity release
"); return 0; } static struct file_operations humidity_dev_fops={ .owner = THIS_MODULE, .open = humidiy_open, .read = humidiy_read, .release = humidiy_release, }; static struct miscdevice humidity_dev = { .minor = MISC_DYNAMIC_MINOR, .name = DEVICE_NAME, .fops = &humidity_dev_fops, }; static int __init humidity_dev_init(void) { int ret; ret = gpio_request(PIN , "humidity"); if (ret){ printk("%s: request GPIO %d for humidity failed, ret = %d
", DEVICE_NAME,PIN , ret); return ret; } gpio_direction_output(PIN, 1); ret = misc_register(&humidity_dev); printk("humidity_dev_init
"); return ret; } static void __exit humidity_dev_exit(void) { gpio_free(PIN); misc_deregister(&humidity_dev); } module_init(humidity_dev_init); module_exit(humidity_dev_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("WWW")

テスト手順は以下の通りです.
#include<stdio.h>
#include<sys/types.h>
int main()
{
	int humidityfd;
	int ret;
	char buf[5];
	unsigned char  tempz = 0;
	unsigned char  tempx = 0;     
	unsigned char  humidiyz = 0;
	unsigned char  humidiyx = 0;	
	humidityfd = open("/dev/humidity",0);
	if(humidityfd<0){
		printf("/dev/humidiy open fail
"); return 0; } while(1){ ret=read(humidityfd,buf,sizeof(buf)); if(ret<0) printf("read err!
"); else{ humidiyz =buf[0]; humidiyx =buf[1]; tempz =buf[2] ; tempx =buf[3]; printf("humidity = %d.%d%%
", humidiyz, humidiyx); printf("temp = %d.%d
",tempz,tempx); } sleep(2); } close(humidityfd); return 0; }
このドライバは簡単にデバッグできると思います.しかし、デバッグの過程で、収集したデータが正しい場合もあれば、間違っている場合もあり、成功率は約50%であることが分かった.そこでマニュアルに従ってタイミングを微調整したが,問題は解決しなかった.ネット上で関連資料を調べてみると、すべて単片機でプログラミングされていることが分かった.プログラムはもともと裸で走る思想で走っていたのに、どうしてLinuxに移植したら間違いがあったのだろうか.dht 11から出る信号はすべて正常ですね.誤打誤撞、local_を使用irq_disableという関数の後、読み出したデータは正常になりました.local_irq_disableは、割り込みフラグビットを遮断することによって、カーネルのプリエンプトを禁止する.Linuxはマルチタスクシステムだと思います.このシステムは一定のアルゴリズム(一定の時間ごとに別のプログラムを走ります.時間が固定されていません)に従って、1回の駆動を呼び出してデータを読み取る過程(時間が長いのはタイムスライスに対して)で、この間CPUは他のことをして、再び戻ってデータを読み取る時、タイミングのあるセグメントを逃した可能性があります.これにより、読み出しデータが正常であったり、エラーであったりする現象が発生します.