[OK210開發(fā)板體驗(yàn)]功能篇(4)Linux字符驅(qū)動(dòng)之DS18B20溫度傳感器驅(qū)動(dòng)
		    [OK210開發(fā)板體驗(yàn)]入門篇(1):開箱驗(yàn)板
    [OK210開發(fā)板體驗(yàn)]入門篇(2):板載資源
    [OK210開發(fā)板體驗(yàn)]入門篇(3):開發(fā)環(huán)境(軟件安裝,開發(fā)環(huán)境,燒寫系統(tǒng))
    [OK210開發(fā)板體驗(yàn)]入門篇(4):編程入門(NFS登錄,驅(qū)動(dòng)入門) 
    [OK210開發(fā)板體驗(yàn)]功能篇(1):Linux字符驅(qū)動(dòng)之Led
    [OK210開發(fā)板體驗(yàn)]功能篇(2):Linux字符驅(qū)動(dòng)之Key按鍵
    [OK210開發(fā)板體驗(yàn)]功能篇(3):Linux Input子系統(tǒng)之Key按鍵
今天是功能篇的第四篇:Linux字符驅(qū)動(dòng)之DS18B20,本節(jié)主要分3部分:硬件分析,軟件基礎(chǔ),驅(qū)動(dòng)編程。
一、硬件分析
在 [OK210開發(fā)板體驗(yàn)]的第二篇:板載資源中,簡單分析了DS18B20傳感器的功能和作用。其實(shí)對(duì)DS18B20的操作,包含兩部分,一是對(duì)字符設(shè)備驅(qū)動(dòng)的深入理解,二是對(duì)DS18B20傳感器時(shí)序的掌握。前面3篇功能體驗(yàn),分別對(duì)GPIO的輸出(LED)和輸入(Key)進(jìn)行了驅(qū)動(dòng)的編寫,而這篇將同時(shí)涉及GPIO的輸入和輸出。
首先從OK210的底板原理圖中可知,OK210開發(fā)板上的DS18B20連接通過一個(gè)上拉電阻連接到了核心板的XM0ADDR3引腳上,如下圖所示:
 
	
 
 
		而XM0ADDR3引腳由S5PV210用戶手冊(cè),可知,該引腳位于MP0_4[3]引腳上,默認(rèn)連接到了EBI接口上,如下圖所示:
 
	
 
 
		所以,我們要對(duì)DS18B20進(jìn)行操作,就是通過對(duì)MP0_4[3]引腳的設(shè)置進(jìn)行實(shí)現(xiàn)
二、軟件基礎(chǔ)
該部分首先總結(jié)一下,字符設(shè)備驅(qū)動(dòng)的注冊(cè)過程,然后簡單介紹一下DS18B20驅(qū)動(dòng)編寫過程中,注意的事項(xiàng):
1 字符設(shè)備的注冊(cè)與注銷
以下的步驟,一般在驅(qū)動(dòng)初始化函數(shù)中和驅(qū)動(dòng)退出函數(shù)中實(shí)現(xiàn)。
第一步:注冊(cè)設(shè)備號(hào)                                    信息#tail -f /var/log/message
        注冊(cè)函數(shù):
           register_chrdev_region() 或               查看#lsmod
           alloc_chrdev_region()    或               查看#cat /proc/devices
           register_chrdev()
        注銷函數(shù):
           unregist_chrdev_region() 或
           unregister_chrdev() 
	
初始化cdev
靜態(tài)初始化cdev_init() 或
動(dòng)態(tài)初始化cdev_alloc()
添加到系統(tǒng)函數(shù)
cdev_add()
從系統(tǒng)刪除函數(shù)
cdev_del()
創(chuàng)建類
class_create() 將放于/sysfs 查看#ls /sys/class
刪除類
class_destroy()
創(chuàng)建節(jié)點(diǎn)
device_create() 或 class_device_create() 將存放于/dev 查看#ls /dev
刪除節(jié)點(diǎn)
device_destroy() 或 class_device_destroy()
		2 DS18B20注意事項(xiàng)
 DS18B20是由DALLAS半導(dǎo)體公司推出的一種的“一線總線”接口的溫度傳感器。與傳統(tǒng)的熱敏電阻等測溫元件相比,它是一種新型的體積小、適用電壓寬、與微處理器接口簡單的數(shù)字化溫度傳感器。一線總線結(jié)構(gòu)具有簡潔且經(jīng)濟(jì)的特點(diǎn),可使用戶輕松地組建傳感器網(wǎng)絡(luò),從而為測量系統(tǒng)的構(gòu)建引入全新概念,測量溫度范圍為-55~+125℃,精度為±0.5℃。現(xiàn)場溫度直接以“一線總線”的數(shù)字方式傳輸,大大提高了系統(tǒng)的抗干擾性。它能直接讀出被測溫度,并且可根據(jù)實(shí)際要求通過簡單的編程實(shí)現(xiàn)9~l2位的數(shù)字值讀數(shù)方式。它工作在3—5.5 V的電壓范圍,采用多種封裝形式,從而使系統(tǒng)設(shè)計(jì)靈活、方便,設(shè)定分辨率及用戶設(shè)定的報(bào)警溫度存儲(chǔ)在EEPROM中,掉電后依然保存。其內(nèi)部結(jié)構(gòu)如下圖所示: 
	
 
 
		 
 
	 
 
	如上所述,驅(qū)動(dòng)的編寫,主要包括兩部分,一是根據(jù)DS18B20時(shí)序,編寫讀寫函數(shù),二是根據(jù)字符設(shè)備,編寫設(shè)備驅(qū)動(dòng)程序。具體的代碼見下,最后附上效果圖:
 
  
	- 
					#include    <linux/module.h>
 
- 
					#include    <linux/fs.h>
 
- 
					#include    <linux/kernel.h>
 
- 
					#include    <linux/init.h>
 
- 
					#include    <linux/delay.h>
 
- 
					#include    <linux/cdev.h>
 
- 
					#include    <linux/device.h>
 
- 
					#include    <linux/gpio.h>
 
- 
					#include    <plat/gpio-cfg.h>
 
- 
					
 
- 
					#define    DEVICE_NAME "DS18B20"
 
- 
					
 
- 
					static struct cdev cdev;
 
- 
					struct class *tem_class;
 
- 
					static dev_t devno;
 
- 
					static int major = 100;
 
- 
					
 
- 
					unsigned int gpio=S5PV210_MP04(3);
 
- 
					
 
- 
					void tem_reset(void)
 
- 
					{
 
- 
					    s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(1));
 
- 
					    gpio_set_value(gpio, 1);
 
- 
					    //gpio_direction_output(gpio,1);
 
- 
					    udelay(100);
 
- 
					    gpio_set_value(gpio, 0);
 
- 
					    udelay(600);
 
- 
					    gpio_set_value(gpio, 1);
 
- 
					    udelay(100);
 
- 
					    s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(0));
 
- 
					//    gpio_direction_input(gpio);
 
- 
					}
 
- 
					
 
- 
					void tem_wbyte(unsigned char data)
 
- 
					{
 
- 
					    int i;
 
- 
					
 
- 
					    s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(1));
 
- 
					    for (i = 0; i < 8; ++i)
 
- 
					    {
 
- 
					        gpio_set_value(gpio, 0);
 
- 
					        udelay(1);
 
- 
					
 
- 
					        if (data & 0x01)
 
- 
					        {
 
- 
					            gpio_set_value(gpio, 1);
 
- 
					        }
 
- 
					        udelay(60);
 
- 
					        gpio_set_value(gpio, 1);
 
- 
					        udelay(15);
 
- 
					        data >>= 1;
 
- 
					    }
 
- 
					    gpio_set_value(gpio, 1);
 
- 
					}
 
- 
					
 
- 
					unsigned char tem_rbyte(void)
 
- 
					{
 
- 
					    int i;
 
- 
					    unsigned char ret = 0;
 
- 
					
 
- 
					    for (i = 0; i < 8; ++i)
 
- 
					    {
 
- 
					        s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(1));
 
- 
					        gpio_set_value(gpio, 0);
 
- 
					//        gpio_direction_output(gpio,0);
 
- 
					        udelay(1);
 
- 
					        gpio_set_value(gpio, 1);
 
- 
					
 
- 
					        s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(0));
 
- 
					//        gpio_direction_input(gpio);
 
- 
					        ret >>= 1;
 
- 
					        if (gpio_get_value(gpio))
 
- 
					        {
 
- 
					            ret |= 0x80;
 
- 
					        }
 
- 
					        udelay(60);
 
- 
					    }
 
- 
					    s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(1));
 
- 
					
 
- 
					
 
- 
					    return ret;
 
- 
					}
 
- 
					
 
- 
					static ssize_t tem_read(struct file *filp, char *buf, size_t len, loff_t *offset)
 
- 
					{
 
- 
					    unsigned char low, high;
 
- 
					
 
- 
					    tem_reset();
 
- 
					    udelay(420);
 
- 
					    tem_wbyte(0xcc);
 
- 
					    tem_wbyte(0x44);
 
- 
					
 
- 
					    mdelay(750);
 
- 
					    tem_reset();
 
- 
					    udelay(400);
 
- 
					    tem_wbyte(0xcc);
 
- 
					    tem_wbyte(0xbe);
 
- 
					
 
- 
					    low = tem_rbyte();
 
- 
					    high = tem_rbyte();
 
- 
					
 
- 
					    *buf = low / 16 + high * 16;
 
- 
					
 
- 
					    *(buf + 1) = (low & 0x0f) * 10 / 16 + (high & 0x0f) * 100 / 16 % 10;
 
- 
					    return 0;
 
- 
					}
 
- 
					
 
- 
					static struct file_operations tem_fops =
 
- 
					{
 
- 
					    .owner    = THIS_MODULE,
 
- 
					    .read    = tem_read,
 
- 
					};
 
- 
					
 
- 
					static int __init tem_init(void)
 
- 
					{
 
- 
					    int result;
 
- 
					    devno = MKDEV(major, 0);
 
- 
					
 
- 
					    result = register_chrdev_region(devno, 1, DEVICE_NAME);
 
- 
					    if (result)
 
- 
					    {
 
- 
					        printk("register failed\n");
 
- 
					        return result;
 
- 
					    }
 
- 
					    cdev_init(&cdev, &tem_fops);
 
- 
					    cdev.owner = THIS_MODULE;
 
- 
					    cdev.ops = &tem_fops;
 
- 
					    result = cdev_add(&cdev, devno, 1);
 
- 
					    if (result)
 
- 
					    {
 
- 
					        printk("cdev add failed\n");
 
- 
					        goto fail1;
 
- 
					    }
 
- 
					
 
- 
					    tem_class = class_create(THIS_MODULE, "tmp_class");
 
- 
					    if (IS_ERR(tem_class))
 
- 
					    {
 
- 
					        printk("class create failed\n");
 
- 
					        goto fail2;
 
- 
					    }
 
- 
					
 
- 
					    device_create(tem_class, NULL, devno, DEVICE_NAME, DEVICE_NAME);
 
- 
					    return 0;
 
- 
					fail2:
 
- 
					    cdev_del(&cdev);
 
- 
					fail1:
 
- 
					    unregister_chrdev_region(devno, 1);
 
- 
					    return result;
 
- 
					}
 
- 
					
 
- 
					static void __exit tem_exit(void)
 
- 
					{
 
- 
					    device_destroy(tem_class, devno);
 
- 
					    class_destroy(tem_class);
 
- 
					    cdev_del(&cdev);
 
- 
					    unregister_chrdev_region(devno, 1);
 
- 
					}
 
- 
					
 
- 
					module_init(tem_init);
 
- 
					module_exit(tem_exit);
 
- 
					
 
- 
					MODULE_LICENSE("GPL");
 
- 
					MODULE_AUTHOR("gjianw217@163.com");
 
- MODULE_DESCRIPTION("DS18B20 driver");
		2 測試程序
 
	
- 
					#include "stdio.h"
 
- 
					#include "sys/types.h"
 
- 
					#include "sys/ioctl.h"
 
- 
					#include "stdlib.h"
 
- 
					#include "termios.h"
 
- 
					#include "sys/stat.h"
 
- 
					#include "fcntl.h"
 
- 
					#include "sys/time.h"
 
- 
					
 
- 
					main()
 
- 
					{
 
- 
					    int fd;
 
- 
					    unsigned char buf[2]={0};
 
- 
					    float result;
 
- 
					
 
- 
					    if ((fd=open("/dev/DS18B20",O_RDWR | O_NDELAY | O_NOCTTY)) < 0)
 
- 
					    {
 
- 
					        printf("Open Device DS18B20 failed.\r\n");
 
- 
					        exit(1);
 
- 
					    }
 
- 
					    else
 
- 
					    {
 
- 
					        printf("Open Device DS18B20 successed.\r\n");
 
- 
					        while(1)
 
- 
					        {
 
- 
					            read(fd, buf, sizeof(buf));
 
- 
					            printf("%d.%d C\r\n", buf[0], buf[1]);
 
- 
					            sleep(1);
 
- 
					        }
 
- 
					        close(fd);
 
- 
					    }
 
- }
3 Makefile
		
	
- 
				#DS18B20 Makefile
 
- 
				ARCH=arm
 
- 
				CROSS_COMPILE=/home/ok210/arm-2009q3/bin/arm-none-linux-gnueabi-
 
- 
				APP_COMPILE=/home/ok210/arm-2009q3/bin/arm-none-linux-gnueabi-
 
- 
				#obj-m := app-drv.o
 
- 
				obj-m := ds18b20-drv.o
 
- 
				#KDIR := /path/to/kernel/linux/
 
- 
				KDIR := /home/ok210/android-kernel-samsung-dev/
 
- 
				PWD := $(shell pwd)
 
- 
				default:
 
- 
				        make -C $(KDIR) M=$(PWD) ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE) modules
 
- 
				app:ds18b20-app.c
 
- 
				        $(APP_COMPILE)gcc -o app ds18b20-app.c
 
- 
				clean:
 
- $(MAKE) -C $(KDIR) M=$(PWD) clea
復(fù)制代碼
		
 
	
		
	
相關(guān)產(chǎn)品 >
- 
                OKMX6UL-C開發(fā)板 飛凌嵌入式專注imx6系列imx6ul開發(fā)板、飛思卡爾imx6ul核心板等ARM嵌入式核心控制系統(tǒng)研發(fā)、設(shè)計(jì)和生產(chǎn),i.mx6UL系列產(chǎn)品現(xiàn)已暢銷全國,作為恩智浦imx6ul,imx6ul開發(fā)板,i.mx6提供者,飛凌嵌入式提供基于iMX6 iMX6UL解決方案定制。 了解詳情 
- 
                OKMX6ULL-C開發(fā)板 40*29mm,雙網(wǎng)雙CAN,8路串口| i.MX6ULL開發(fā)板是基于NXP i.MX6ULL設(shè)計(jì)開發(fā)的的一款Linux開發(fā)板 ,主頻800MHz,體積小,其核心板僅40*29mm,采用板對(duì)板連接器,適應(yīng)場景豐富。 了解詳情 

 
                                             換一批
換一批


