3C科技 娛樂遊戲 美食旅遊 時尚美妝 親子育兒 生活休閒 金融理財 健康運動 寰宇綜合

Zi 字媒體

2017-07-25T20:27:27+00:00
加入好友
用Raspberry Pi 學 Linux 驅動程式 [Raspberry Pi Create Driver] 資料來源: https://www.raspberrypi.com.tw/1362/dht22-device-driver-starter-kit/ GIYHUB: https://github.com/jash-git/Raspberry-Pi-Create-Driver /* dht11km.c * * dht11km - Device driver for reading values from DHT11 temperature and humidity sensor. * * By default the DHT11 is connected to GPIO pin 0 (pin 3 on the GPIO connector) * The Major version default is 80 but can be set via the command line. * Command line parameters: gpio_pin=X - a valid GPIO pin value * driverno=X - value for Major driver number * format=X - format of the output from the sensor * * Usage: * Load driver: insmod ./dht11km.ko * i.e. insmod ./dht11km.ko gpio_pin=2 format=3 * * Set up device file to read from (i.e.): * mknod /dev/dht11 c 80 0 * mknod /dev/myfile c 0 - to set the output to your own file and driver number * * To read the values from the sensor: cat /dev/dht11 * * Copyright (C) 2012 Nigel Morton * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // for put_user // include RPi harware specific constants #include #define DHT11_DRIVER_NAME "dht11" #define RBUF_LEN 256 #define SUCCESS 0 #define BUF_LEN 80 // Max length of the message from the device // set GPIO pin g as input #define GPIO_DIR_INPUT(g) *(gpio+((g)/10)) &= ~(7< 40)) { started = 1; return IRQ_HANDLED; } if((signal == 0)&(started==1)) { if(data > 80) return IRQ_HANDLED; //Start/spurious? signal if(data < 15) return IRQ_HANDLED; //Spurious signal? if (data > 60)//55 dht[bytecount] = dht[bytecount] | (0x80 >> bitcount); //Add a 1 to the data byte //Uncomment to log bits and durations - may affect performance and not be accurate! //printk("B:%d, d:%d, dt:%d\n", bytecount, bitcount, data); bitcount++; if(bitcount == 8) { bitcount = 0; bytecount++; } //if(bytecount == 5) // printk(KERN_INFO DHT11_DRIVER_NAME "Result: %d, %d, %d, %d, %d\n", dht[0], dht[1], dht[2], dht[3], dht[4]); } } return IRQ_HANDLED; } static int setup_interrupts(void) { int result; unsigned long flags; result = request_irq(INTERRUPT_GPIO0, (irq_handler_t) irq_handler, 0, DHT11_DRIVER_NAME, (void*) gpio); switch (result) { case -EBUSY: printk(KERN_ERR DHT11_DRIVER_NAME ": IRQ %d is busy\n", INTERRUPT_GPIO0); return -EBUSY; case -EINVAL: printk(KERN_ERR DHT11_DRIVER_NAME ": Bad irq number or handler\n"); return -EINVAL; default: printk(KERN_INFO DHT11_DRIVER_NAME ": Interrupt x obtained\n", INTERRUPT_GPIO0); break; }; spin_lock_irqsave(&lock, flags); // GPREN0 GPIO Pin Rising Edge Detect Enable GPIO_INT_RISING(gpio_pin, 1); // GPFEN0 GPIO Pin Falling Edge Detect Enable GPIO_INT_FALLING(gpio_pin, 1); // clear interrupt flag GPIO_INT_CLEAR(gpio_pin); spin_unlock_irqrestore(&lock, flags); return 0; } // Initialise GPIO memory static int init_port(void) { // reserve GPIO memory region. if (request_mem_region(GPIO_BASE, SZ_4K, DHT11_DRIVER_NAME) == NULL) { printk(KERN_ERR DHT11_DRIVER_NAME ": unable to obtain GPIO I/O memory address\n"); return -EBUSY; } // remap the GPIO memory if ((gpio = ioremap_nocache(GPIO_BASE, SZ_4K)) == NULL) { printk(KERN_ERR DHT11_DRIVER_NAME ": failed to map GPIO I/O memory\n"); return -EBUSY; } return 0; } static int __init dht11_init_module(void) { int result; int i; // check for valid gpio pin number result = 0; for(i = 0; (i < ARRAY_SIZE(valid_gpio_pins)) && (result != 1); i++) { if(gpio_pin == valid_gpio_pins[i]) result++; } if (result != 1) { result = -EINVAL; printk(KERN_ERR DHT11_DRIVER_NAME ": invalid GPIO pin specified!\n"); goto exit_rpi; } result = register_chrdev(driverno, DHT11_DRIVER_NAME, &fops); if (result < 0) { printk(KERN_ALERT DHT11_DRIVER_NAME "Registering dht11 driver failed with %d\n", result); return result; } printk(KERN_INFO DHT11_DRIVER_NAME ": driver registered!\n"); result = init_port(); if (result < 0) goto exit_rpi; return 0; exit_rpi: return result; } static void __exit dht11_exit_module(void) { // release mapped memory and allocated region if(gpio != NULL) { iounmap(gpio); release_mem_region(GPIO_BASE, SZ_4K); printk(DHT11_DRIVER_NAME ": cleaned up resources\n"); } // Unregister the driver unregister_chrdev(driverno, DHT11_DRIVER_NAME); printk(DHT11_DRIVER_NAME ": cleaned up module\n"); } // Called when a process wants to read the dht11 "cat /dev/dht11" static int read_dht11(struct inode *inode, struct file *file) { char result[3]; //To say if the result is trustworthy or not int retry = 0; if (Device_Open) return -EBUSY; try_module_get(THIS_MODULE); //Increase use count Device_Open++; // Take data low for min 18mS to start up DHT11 //printk(KERN_INFO DHT11_DRIVER_NAME " Start setup (read_dht11)\n"); start_read: started = 0; bitcount = 0; bytecount = 0; dht[0] = 0; dht[1] = 0; dht[2] = 0; dht[3] = 0; dht[4] = 0; GPIO_DIR_OUTPUT(gpio_pin); // Set pin to output GPIO_CLEAR_PIN(gpio_pin); // Set low mdelay(20); // DHT11 needs min 18mS to signal a startup GPIO_SET_PIN(gpio_pin); // Take pin high udelay(40); // Stay high for a bit before swapping to read mode GPIO_DIR_INPUT(gpio_pin); // Change to read //Start timer to time pulse length do_gettimeofday(&lasttv); // Set up interrupts setup_interrupts(); //Give the dht11 time to reply mdelay(10); //Check if the read results are valid. If not then try again! if((dht[0] + dht[1] + dht[2] + dht[3] == dht[4]) & (dht[4] > 0)) sprintf(result, "OK"); else { retry++; sprintf(result, "BAD"); if(retry == 5) goto return_result; //We tried 5 times so bail out clear_interrupts(); mdelay(1100); //Can only read from sensor every 1 second so give it time to recover goto start_read; } //Return the result in various different formats return_result: switch(format){ case 0: sprintf(msg, "Values: %d, %d, %d, %d, %d, %s\n", dht[0], dht[1], dht[2], dht[3], dht[4], result); break; case 1: sprintf(msg, "%0X,%0X,%0X,%0X,%0X,%s\n", dht[0], dht[1], dht[2], dht[3], dht[4], result); break; case 2: sprintf(msg, "XXXXX%s\n", dht[0], dht[1], dht[2], dht[3], dht[4], result); break; case 3: sprintf(msg, "Temperature: �\nHumidity: %d%%\nResult:%s\n", dht[0], dht[2], result); break; } msg_Ptr = msg; return SUCCESS; } // Called when a process closes the device file. static int close_dht11(struct inode *inode, struct file *file) { // Decrement the usage count, or else once you opened the file, you'll never get get rid of the module. module_put(THIS_MODULE); Device_Open--; clear_interrupts(); //printk(KERN_INFO DHT11_DRIVER_NAME ": Device release (close_dht11)\n"); return 0; } // Clear the GPIO edge detect interrupts static void clear_interrupts(void) { unsigned long flags; spin_lock_irqsave(&lock, flags); // GPREN0 GPIO Pin Rising Edge Detect Disable GPIO_INT_RISING(gpio_pin, 0); // GPFEN0 GPIO Pin Falling Edge Detect Disable GPIO_INT_FALLING(gpio_pin, 0); spin_unlock_irqrestore(&lock, flags); free_irq(INTERRUPT_GPIO0, (void *) gpio); } // Called when a process, which already opened the dev file, attempts to read from it. static ssize_t device_read(struct file *filp, // see include/linux/fs.h char *buffer, // buffer to fill with data size_t length, // length of the buffer loff_t * offset) { // Number of bytes actually written to the buffer int bytes_read = 0; // If we're at the end of the message, return 0 signifying end of file if (*msg_Ptr == 0) return 0; // Actually put the data into the buffer while (length && *msg_Ptr) { // The buffer is in the user data segment, not the kernel segment so "*" assignment won't work. We have to use // put_user which copies data from the kernel data segment to the user data segment. put_user(*(msg_Ptr++), buffer++); length--; bytes_read++; } // Return the number of bytes put into the buffer return bytes_read; } module_init(dht11_init_module); module_exit(dht11_exit_module); MODULE_DESCRIPTION("DHT11 temperature/humidity sendor driver for Raspberry Pi GPIO."); MODULE_AUTHOR("Nigel Morton"); MODULE_LICENSE("GPL"); // Command line paramaters for gpio pin and driver major number module_param(format, int, S_IRUGO); MODULE_PARM_DESC(gpio_pin, "Format of output"); module_param(gpio_pin, int, S_IRUGO); MODULE_PARM_DESC(gpio_pin, "GPIO pin to use"); module_param(driverno, int, S_IRUGO); MODULE_PARM_DESC(driverno, "Driver handler major value");

本文由jashliaoeuwordpress提供 原文連結

寫了 5860316篇文章,獲得 23313次喜歡
精彩推薦