新聞中心

        EEPW首頁 > 嵌入式系統 > 設計應用 > 基于S3C2440嵌入式Linux系統下的一個DS18B20驅動

        基于S3C2440嵌入式Linux系統下的一個DS18B20驅動

        作者: 時間:2016-11-20 來源:網絡 收藏
        用Linux驅動編程的方法寫一個DS18B20的溫度傳感器驅動,從底層采集溫度信息。以下乃本人所寫的驅動和測試的源碼,嵌入式Linux內核版本為2.6.29,硬件平臺是友善之臂的QQ2440,DS18B20引腳連接S3C2440的GPIOB1,程序難免存在一定的漏洞,希望大家指出。


        #include
        #include
        #include
        #include
        #include
        #include
        #include
        #include
        #include
        #include
        #include

        本文引用地址:http://www.104case.com/article/201611/318872.htm

        typedef unsigned char BYTE;

        #define DS18B20_PIN S3C2410_GPB1
        #define DS18B20_PIN_OUTP S3C2410_GPB1_OUTP
        #define DS18B20_PIN_INP S3C2410_GPB1_INP
        #define HIGH 1
        #define LOW 0
        #define DEV_NAME "DS18B20"
        #define DEV_MAJOR 232
        static BYTE data[2];

        // DS18B20復位函數
        BYTE DS18b20_reset (void)
        {
        // 配置GPIOB0輸出模式
        s3c2410_gpio_cfgpin(DS18B20_PIN, DS18B20_PIN_OUTP);

        // 向18B20發送一個上升沿,并保持高電平狀態約100微秒
        s3c2410_gpio_setpin(DS18B20_PIN, HIGH);
        udelay(100);

        // 向18B20發送一個下降沿,并保持低電平狀態約600微秒
        s3c2410_gpio_setpin(DS18B20_PIN, LOW);
        udelay(600);

        // 向18B20發送一個上升沿,此時可釋放DS18B20總線
        s3c2410_gpio_setpin(DS18B20_PIN, HIGH);
        udelay(100);

        // 以上動作是給DS18B20一個復位脈沖
        // 通過再次配置GPIOB1引腳成輸入狀態,可以檢測到DS18B20是否復位成功
        s3c2410_gpio_cfgpin(DS18B20_PIN, DS18B20_PIN_INP);

        // 若總線在釋放后總線狀態為高電平,則復位失敗
        if(s3c2410_gpio_getpin(DS18B20_PIN)){ printk("DS18b20 reset failed.rn"); return 1;}

        return 0;
        }

        void DS18b20_write_byte (BYTE byte)
        {
        BYTE i;
        // 配置GPIOB1為輸出模式
        s3c2410_gpio_cfgpin(DS18B20_PIN, DS18B20_PIN_OUTP);

        // 寫“1”時隙:
        // 保持總線在低電平1微秒到15微秒之間
        // 然后再保持總線在高電平15微秒到60微秒之間
        // 理想狀態: 1微秒的低電平然后跳變再保持60微秒的高電平
        //
        // 寫“0”時隙:
        // 保持總線在低電平15微秒到60微秒之間
        // 然后再保持總線在高電平1微秒到15微秒之間
        // 理想狀態: 60微秒的低電平然后跳變再保持1微秒的高電平
        for (i = 0; i < 8; i++)
        {
        s3c2410_gpio_setpin(DS18B20_PIN, LOW); udelay(1);
        if(byte & HIGH)
        {
        // 若byte變量的D0位是1,則需向總線上寫“1”
        // 根據寫“1”時隙規則,電平在此處翻轉為高
        s3c2410_gpio_setpin(DS18B20_PIN, HIGH);
        }
        else
        {
        // 若byte變量的D0位是0,則需向總線上寫“0”
        // 根據寫“0”時隙規則,電平在保持為低
        // s3c2410_gpio_setpin(DS18B20_PIN, LOW);
        }
        // 電平狀態保持60微秒
        udelay(60);

        s3c2410_gpio_setpin(DS18B20_PIN, HIGH);
        udelay(15);

        byte >>= 1;
        }
        s3c2410_gpio_setpin(DS18B20_PIN, HIGH);
        }

        BYTE DS18b20_read_byte (void)
        {
        BYTE i = 0;
        BYTE byte = 0;
        // 讀“1”時隙:
        // 若總線狀態保持在低電平狀態1微秒到15微秒之間
        // 然后跳變到高電平狀態且保持在15微秒到60微秒之間
        // 就認為從DS18B20讀到一個“1”信號
        // 理想情況: 1微秒的低電平然后跳變再保持60微秒的高電平
        //
        // 讀“0”時隙:
        // 若總線狀態保持在低電平狀態15微秒到30微秒之間
        // 然后跳變到高電平狀態且保持在15微秒到60微秒之間
        // 就認為從DS18B20讀到一個“0”信號
        // 理想情況: 15微秒的低電平然后跳變再保持46微秒的高電平
        for (i = 0; i < 8; i++)
        {
        s3c2410_gpio_cfgpin(DS18B20_PIN, DS18B20_PIN_OUTP);
        s3c2410_gpio_setpin(DS18B20_PIN, LOW);

        udelay(1);
        byte >>= 1;

        s3c2410_gpio_setpin(DS18B20_PIN, HIGH);
        s3c2410_gpio_cfgpin(DS18B20_PIN, DS18B20_PIN_INP);

        // 若總線在我們設它為低電平之后若1微秒之內變為高
        // 則認為從DS18B20處收到一個“1”信號
        // 因此把byte的D7為置“1”
        if (s3c2410_gpio_getpin(DS18B20_PIN)) byte |= 0x80;
        udelay(60);
        }
        return byte;
        }

        void DS18b20_proc(void)
        {
        while(DS18b20_reset());

        udelay(120);

        DS18b20_write_byte(0xcc);
        DS18b20_write_byte(0x44);

        udelay(5);

        while(DS18b20_reset());
        udelay(200);

        DS18b20_write_byte(0xcc);
        DS18b20_write_byte(0xbe);

        data[0] = DS18b20_read_byte();
        data[1] = DS18b20_read_byte();
        }

        static ssize_t s3c2440_18b20_read(struct file *filp, char *buf, size_t len, loff_t *off)
        {
        DS18b20_proc();

        buf[0] = data[0];
        buf[1] = data[1];

        return 1;
        }

        static struct file_operations s3c2440_18b20_fops =
        {
        .owner = THIS_MODULE,
        .read = s3c2440_18b20_read,
        };

        static int __init s3c2440_18b20_init(void)
        {
        if (register_chrdev(DEV_MAJOR, DEV_NAME, &s3c2440_18b20_fops) < 0)
        {
        printk(DEV_NAME ": Register major failed.rn");
        return -1;
        }

        devfs_mk_cdev(MKDEV(DEV_MAJOR, 0),S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP, DEV_NAME);

        while(DS18b20_reset());
        }

        static void __exit s3c2440_18b20_exit(void)
        {
        devfs_remove(DEV_NAME);
        unregister_chrdev(DEV_MAJOR, DEV_NAME);
        }
        module_init(s3c2440_18b20_init);
        module_exit(s3c2440_18b20_exit);

        #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];
        float result;

        if ((fd=open("/dev/DS18B20",O_RDWR | O_NDELAY | O_NOCTTY)) < 0)
        {
        printf("Open Device DS18B20 failed.rn");
        exit(1);
        }
        else
        {
        printf("Open Device DS18B20 successed.rn");
        while(1)
        {
        read(fd, buf, 1);
        result = (float)buf[0];
        result /= 16;
        result += ((float)buf[1] * 16);

        printf("%.1f `Crn", result);
        sleep(1);
        }
        close(fd);
        }
        }

        obj-m := s3c2440_ds18b20.o

        KERNELDIR ?= ../../kernel/linux-2.6.29
        PWD := $(shell pwd)
        CC := arm-linux-gcc
        CLEAN := rm -rf


        all : s3c2440_ds18b20.c test_ds18b20
        $(MAKE) -C $(KERNELDIR) M=$(PWD) modules

        test_ds18b20 : test_ds18b20.c
        $(CC) test_ds18b20.c -o test_ds18b20

        clobber :
        $(CLEAN) test_ds18b20 s3c2440_ds18b20.ko
        clean :
        $(CLEAN) *.mod.* *.o *~ modules.order Module.symvers

        這個驅動是基于Linux的2.6.29內核樹編譯的,內核樹的路徑是當前目錄的../../kernel/linux-2.6.29,若以來其他的Linux的內核樹,編譯時可能會出現找不到某些文件的情況,如hardware.h等,只需要在內核樹中作一些軟鏈接就可以解決,還有聲明一點的就是:Makefile中的命令操作前的并非空格,而是TAB跳格。

        make編譯,編譯完畢后產生許多文件,我們只關心test_ds18b20和s3c2440_ds18b20.ko這兩個。

        把以上兩個文件下載到開發板中,創建一個設備節點:

        mknod /dev/DS18B20 c 232 0

        把s3c2440_ds18b20這個模塊加載到內核:

        insmod s3c2440_ds18b20.ko

        加載成功后我們可以通過模塊列表查看:

        之后把test_ds18b20測試文件改為可執行狀態:

        chmod 0111 test_ds18b20

        執行后可以觀察到以下的結果:



        評論


        技術專區

        關閉
        主站蜘蛛池模板: 太康县| 湾仔区| 东光县| 海晏县| 札达县| 南华县| 东至县| 巴南区| 垫江县| 文安县| 安图县| 潜山县| 江安县| 新田县| 蓬安县| 高州市| 玉溪市| 比如县| 金阳县| 琼海市| 抚州市| 台州市| 承德市| 墨脱县| 五莲县| 红桥区| 武隆县| 德化县| 白朗县| 寿宁县| 互助| 林州市| 景宁| 襄城县| 宁南县| 刚察县| 台南市| 云林县| 忻州市| 庄河市| 鄂伦春自治旗|