將DHT11移植到Linux系統上(轉)
阿新 • • 發佈:2017-07-20
ati amp 裸奔 電平 repl bre details 現象 word
由於項目需要,需要將DHT11移植到Linux。驅動程序如下
[plain] view plain copy
- #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!\n",__LINE__);
- break;
- }
- }
- i=0;
- while(gpio_get_value(PIN))
- {
- udelay(5);
- i++;
- if(i>20)
- {
- printk("humidity_read_data %d err!\n",__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\n");
- printk("humidity=[%d],temp=[%d]\n",buf[0],buf[2]);
- }
- else
- {
- check_flag=0x0;
- printk("humidity check fail\n");
- }
- }
- }
- 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\n");
- return -EAGAIN;
- }
- else
- return 0;
- }
- else
- return -EAGAIN;
- }
- static int humidiy_open(struct inode *inode, struct file *file)
- {
- printk("open in kernel\n");
- return 0;
- }
- static int humidiy_release(struct inode *inode, struct file *file)
- {
- printk("humidity release\n");
- 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\n", DEVICE_NAME,PIN , ret);
- return ret;
- }
- gpio_direction_output(PIN, 1);
- ret = misc_register(&humidity_dev);
- printk("humidity_dev_init\n");
- 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")
測試程序如下
[plain] view plain copy
- #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\n");
- return 0; }
- while(1){
- ret=read(humidityfd,buf,sizeof(buf));
- if(ret<0)
- printf("read err!\n");
- else{
- humidiyz =buf[0];
- humidiyx =buf[1];
- tempz =buf[2] ;
- tempx =buf[3];
- printf("humidity = %d.%d%%\n", humidiyz, humidiyx);
- printf("temp = %d.%d\n",tempz,tempx);
- }
- sleep(2);
- }
- close(humidityfd);
- return 0;
- }
本想,這驅動調試起來應該簡單的。但在調試到過程中,發現采集到的數據有時正確,有時錯誤,成功率約為50%。於是按照手冊微調一下時序,並沒有解決問題。網上查閱相關資料,發現都是用單片機來編程的。當程序本來就是以裸奔的思想跑的,為什麽移植到Linux會出錯呢?從dht11出來的信號都正常啊。誤打誤撞,使用local_irq_disable這個函數後,讀出的數據都正常啦。local_irq_disable通過屏蔽中斷標誌位,從而禁止內核的搶占。我猜測是Linux是個多任務系統,該系統按照一定的算法(每隔一段時間就會去跑另一段程序,時間不固定),調用一次驅動去讀取數據的過程中(時間較長相對於時間片),這期間CPU去做其他事情了,等重新回來讀取數據時,有可能錯過了時序中的某個片段,從而出現有時讀取數據正常,有時錯誤這種現象。
http://blog.csdn.net/mike8825/article/details/50804978
將DHT11移植到Linux系統上(轉)