您的位置 首页 开关

根据S3C2440嵌入式Linux体系下的一个DS18B20驱动

用Linux驱动编程的方法写一个DS18B20的温度传感器驱动,从底层采集温度信息。以下乃本人所写的驱动和测试的源码,嵌入式Linux内核版本为2.6…

用Linux驱动编程的办法写一个DS18B20的温度传感器驱动,从底层并重温度信息。以下乃自己所写的驱动和测验的源码,嵌入式Linux内核版别为2.6.29,硬件渠道是友善之臂的QQ2440,DS18B20引脚衔接S3C2440的GPIOB1,程序不免存在必定的缝隙,期望咱们指出。

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

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.\r\n”); 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.\r\n”);
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.\r\n”);
exit(1);
}
else
{
printf(“Open Device DS18B20 successed.\r\n”);
while(1)
{
read(fd, buf, 1);
result = (float)buf[0];
result /= 16;
result += ((float)buf[1] * 16);

printf(“%.1f `C\r\n”, 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

碑文后能够观察到以下的成果:

声明:本文内容来自网络转载或用户投稿,文章版权归原作者和原出处所有。文中观点,不代表本站立场。若有侵权请联系本站删除(kf@86ic.com)https://www.86ic.net/dianyuan/kaiguan/264266.html

为您推荐

联系我们

联系我们

在线咨询: QQ交谈

邮箱: kf@86ic.com

关注微信
微信扫一扫关注我们

微信扫一扫关注我们

返回顶部