wordpress 做wiki手機優(yōu)化軟件排行
????????DHT11的通信協(xié)議是單總線協(xié)議,可以用之前學習的pinctl和gpio子系統(tǒng)完成某IO引腳上數(shù)據(jù)的讀與寫。
一.在設備樹下添加dht11的設備結點
1.流程圖
2.設備樹代碼
(1).在設備樹的 iomuxc結點下添加 pinctl_dht11
(2).在根節(jié)點下添加 dht11 結點
(3).在內核源碼根目錄下重新編譯設備樹文件
linux@ubuntu:~/IMX6ULL/my_linux_kernel$ make dtbs
(4).將新的 dtb 文件更新到開發(fā)板上,檢查是否有 dht11 這個結點
????????啟動后在/proc/device-tree/目錄中查看是否有 dht11 這個節(jié)點。
????????????
二.編寫 dht11 時序代碼
#define DHT11_DelayMs(t) mdelay(t)
#define DHT11_DelayUs(t) udelay(t) #define DHT11_PIN_HIGH 1
#define DHT11_PIN_LOW 0 #define DHT11_IO_OUT() gpio_direction_output(dht11.dht11_gpio, 1);
#define DHT11_IO_IN() gpio_direction_input(dht11.dht11_gpio)
#define DHT11_WRITE(bit) gpio_set_value(dht11.dht11_gpio, bit)
#define DHT11_READ() gpio_get_value(dht11.dht11_gpio)/*** @description: 等待響應
*/
//等待響應
static int dht11_wait_for_ready(void)
{ int timeout;timeout = 400;while (DHT11_READ() && timeout) // 等待低電平到來 {udelay(1);--timeout;}if (!timeout) {printk("dht11_wait_for_ready timeout1 %d\n", __LINE__);return -1; // 超時 }timeout = 1000; //1000while (!DHT11_READ() && timeout) // 等待高電平到來 {udelay(1);--timeout;}if (!timeout) {printk("dht11_wait_for_ready timeout2 %d\n", __LINE__);return -1; // 超時 }timeout = 1000;while (DHT11_READ() && timeout) // 等待高電平結束{udelay(1);--timeout;}if (!timeout) {printk("dht11_wait_for_ready timeout3 %d\n", __LINE__);return -1; // 超時 }return 0;
}/*** @description: 起始信號
*/
static int dht11_start(void)
{DHT11_IO_OUT();DHT11_WRITE(0);mdelay(25);DHT11_WRITE(1);udelay(35);DHT11_IO_IN(); // 設置為輸入 udelay(2);if (dht11_wait_for_ready()) return -1;return 0;
}/*** @description: 讀取一個字節(jié)
*///讀取數(shù)據(jù)
static int dht11_read_byte(unsigned char *byte)
{unsigned char i;unsigned char bit = 0;unsigned char data = 0;int timeout = 0; for (i = 0; i < 8; i++){timeout = 1000; while (DHT11_READ() && timeout) // 等待變?yōu)榈碗娖?{udelay(1);--timeout;}if (!timeout) {printk("dht11_read_byte timeout1 %d\n", __LINE__); return -1; // 超時 }timeout = 1000;while (!DHT11_READ() && timeout) // 等待變?yōu)楦唠娖?{udelay(1);--timeout;}if (!timeout) {printk("dht11_read_byte timeout2 %d\n", __LINE__);return -1; // 超時 }udelay(40);bit = DHT11_READ();data <<= 1; if (bit) {data |= 0x01;}}*byte = data;return 0;
}//從DHT11讀取一次數(shù)據(jù)
//temp:溫度值(范圍:0~50°)
//humi:濕度值(范圍:20%~90%)
//返回值:0,正常;1,讀取失敗
static int dht11_read_data(void)
{ unsigned char data[5] = {0};int i = 0,ret = 0;// 啟動信號 if (dht11_start() != 0){printk("dht11 start failed\n");ret = -EFAULT;}// 讀出5字節(jié)數(shù)據(jù)for (i = 0; i < 5; i++) {if (dht11_read_byte(&data[i])){printk("read data err\n");ret = -EAGAIN;}}if (data[4] != (data[0]+data[1]+data[2]+data[3])){printk("check data failed\n");ret = -EAGAIN;}dht11.humidity = data[0];dht11.temperature = data[2];return 0;
}
三.總的驅動代碼
1.流程圖
2.代碼
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/ide.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/gpio.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_gpio.h>
#include <linux/semaphore.h>
#include <asm/mach/map.h>
#include <linux/timer.h>
#include <asm/uaccess.h>
#include <asm/io.h>#define DHT11_CNT 1
#define DHT11_NAME "dht11"#define DHT11_DelayMs(t) mdelay(t)
#define DHT11_DelayUs(t) udelay(t) #define DHT11_PIN_HIGH 1
#define DHT11_PIN_LOW 0 #define DHT11_IO_OUT() gpio_direction_output(dht11.dht11_gpio, 1);
#define DHT11_IO_IN() gpio_direction_input(dht11.dht11_gpio)
#define DHT11_WRITE(bit) gpio_set_value(dht11.dht11_gpio, bit)
#define DHT11_READ() gpio_get_value(dht11.dht11_gpio)/* dht11設備結構體 */
struct dht11_dev
{dev_t devid;struct cdev cdev;struct class *class;struct device *device;int major;int minor;struct device_node *nd;int dht11_gpio;uint16_t humidity, temperature; //檢測到的溫濕度數(shù)據(jù)
};struct dht11_dev dht11;/*** @description: 等待響應
*/
//等待響應
static int dht11_wait_for_ready(void)
{ int timeout;timeout = 400;while (DHT11_READ() && timeout) // 等待低電平到來 {udelay(1);--timeout;}if (!timeout) {printk("dht11_wait_for_ready timeout1 %d\n", __LINE__);return -1; // 超時 }timeout = 1000; //1000while (!DHT11_READ() && timeout) // 等待高電平到來 {udelay(1);--timeout;}if (!timeout) {printk("dht11_wait_for_ready timeout2 %d\n", __LINE__);return -1; // 超時 }timeout = 1000;while (DHT11_READ() && timeout) // 等待高電平結束{udelay(1);--timeout;}if (!timeout) {printk("dht11_wait_for_ready timeout3 %d\n", __LINE__);return -1; // 超時 }return 0;
}/*** @description: 起始信號
*/
static int dht11_start(void)
{DHT11_IO_OUT();DHT11_WRITE(0);mdelay(25);DHT11_WRITE(1);udelay(35);DHT11_IO_IN(); // 設置為輸入 udelay(2);if (dht11_wait_for_ready()) return -1;return 0;
}/*** @description: 讀取一個字節(jié)
*///讀取數(shù)據(jù)
static int dht11_read_byte(unsigned char *byte)
{unsigned char i;unsigned char bit = 0;unsigned char data = 0;int timeout = 0; for (i = 0; i < 8; i++){timeout = 1000; while (DHT11_READ() && timeout) // 等待變?yōu)榈碗娖?{udelay(1);--timeout;}if (!timeout) {printk("dht11_read_byte timeout1 %d\n", __LINE__); return -1; // 超時 }timeout = 1000;while (!DHT11_READ() && timeout) // 等待變?yōu)楦唠娖?{udelay(1);--timeout;}if (!timeout) {printk("dht11_read_byte timeout2 %d\n", __LINE__);return -1; // 超時 }udelay(40);bit = DHT11_READ();data <<= 1; if (bit) {data |= 0x01;}}*byte = data;return 0;
}//從DHT11讀取一次數(shù)據(jù)
//temp:溫度值(范圍:0~50°)
//humi:濕度值(范圍:20%~90%)
//返回值:0,正常;1,讀取失敗
static int dht11_read_data(void)
{ unsigned char data[5] = {0};int i = 0,ret = 0;// 啟動信號 if (dht11_start() != 0){printk("dht11 start failed\n");ret = -EFAULT;}// 讀出5字節(jié)數(shù)據(jù)for (i = 0; i < 5; i++) {if (dht11_read_byte(&data[i])){printk("read data err\n");ret = -EAGAIN;}}if (data[4] != (data[0]+data[1]+data[2]+data[3])){printk("check data failed\n");ret = -EAGAIN;}dht11.humidity = data[0];dht11.temperature = data[2];return 0;
}/*** @description: DHT11初始化函數(shù)
*/
static int dht11io_init(void)
{/* 找到設備樹中的結點 */dht11.nd = of_find_node_by_path("/dht11");if(NULL == dht11.nd){return -EINVAL;}/* 獲取io編號 */dht11.dht11_gpio = of_get_named_gpio(dht11.nd,"dht11-gpio",0);if(0 > dht11.dht11_gpio){printk("can not get dht11 io\r\n");return -EINVAL;}printk("dht11 gpio num = %d \r\n",dht11.dht11_gpio);/* 初始化io */gpio_request(dht11.dht11_gpio,"dht11a");gpio_direction_output(dht11.dht11_gpio,1); //初始化為輸出高電平return 0;
}/*** @description: 打開DHT11設備* @param - inode : 傳遞給驅動的inode* @param - filp : 設備文件* @return : 0 成功,其他 失敗
*/
static int dht11_open(struct inode *inode,struct file *filp)
{int ret = 0;filp->private_data = &dht11;ret = dht11io_init();if(0 > ret){return ret;}return 0;
}/*** @description: 讀取dht11的數(shù)據(jù)* @param - filp : 文件描述符* @param - buf : 傳遞給用戶空間的緩沖區(qū)* @param - cnt : 要讀取的字節(jié)數(shù)* @param - offt : 相對于文件首地址的偏移量* @return : 讀取到的字節(jié)數(shù)
*/
static ssize_t dht11_read(struct file *filp,char __user *buf,size_t cnt,loff_t *offt)
{int ret = 0;uint16_t databuf[2] = {0,0};dht11_read_data();databuf[0] = dht11.humidity;databuf[1] = dht11.temperature;ret = copy_to_user(buf,databuf,sizeof(databuf));return ret;
}/*** @description: 釋放設備* @param - filp : 設備文件* @return : 0 成功,其他 失敗
*/
static int dht11_release(struct inode *inode,struct file *filp)
{return 0;
}/* 綁定操作函數(shù) */
struct file_operations dht11_fops =
{.owner = THIS_MODULE,.open = dht11_open,.read = dht11_read,.release = dht11_release,
};/*** @description: 驅動入口函數(shù)* @param - : 無* @return : 無
*/
static int __init dht11_init(void)
{/* 注冊字符設備驅動 *//* 1.創(chuàng)建設備號 */if(dht11.major){dht11.devid = MKDEV(dht11.major,0);register_chrdev_region(dht11.devid,DHT11_CNT,DHT11_NAME);}else{alloc_chrdev_region(&dht11.devid,0,DHT11_CNT,DHT11_NAME);dht11.major = MAJOR(dht11.devid);dht11.minor = MINOR(dht11.devid);}printk("dht11 major = %d,minor = %d\r\n",dht11.major,dht11.minor);/* 2.初始化cdev */dht11.cdev.owner = THIS_MODULE;cdev_init(&dht11.cdev,&dht11_fops);/* 3.添加一個cdev */cdev_add(&dht11.cdev,dht11.devid,DHT11_CNT);/* 4.創(chuàng)建類 */dht11.class = class_create(THIS_MODULE,DHT11_NAME);if(IS_ERR(dht11.class)){return PTR_ERR(dht11.class);}/* 5.創(chuàng)建設備 */dht11.device = device_create(dht11.class,NULL,dht11.devid,NULL,DHT11_NAME);if(IS_ERR(dht11.device)){return PTR_ERR(dht11.device);}return 0;
}/*** @description: 驅動出口函數(shù)
*/
static void __exit dht11_exit(void)
{/* 注銷字符設備驅動 */gpio_free(dht11.dht11_gpio);cdev_del(&dht11.cdev);unregister_chrdev_region(dht11.devid,DHT11_CNT);device_destroy(dht11.class,dht11.devid);class_destroy(dht11.class);
}module_init(dht11_init);
module_exit(dht11_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("kaneki");
Makefile:
KERNELDIR := /home/linux/IMX6ULL/my_linux_kernel
CURRENT_PATH :=$(shell pwd)
obj-m := dht11.o
build: kernel_modules
kernel_modules:$(MAKE) -C $(KERNELDIR) M=$(CURRENT_PATH) modules
clean:$(MAKE) -C $(KERNELDIR) M=$(CURRENT_PATH) clean