Linux内核:Linux3.0.8
硬件:友善之臂smart210开发板,A8内核
编译器:arm-linux-gcc 4.5.1
DS18B20是常用的温度传感器,具有体积小,硬件开销低,抗干扰能力强,精度高的特点。工作电压 3.0~5.5V/DC
超低功耗静态功耗<3uA,测温范围 -55℃~+125℃,
测量结果以9~12位数字量方式串行传送。
面对着扁平的那一面,左负右正,一旦接反就会立刻发热,有可能烧毁!同时,接反也是导致该传感器总是显示85℃的原因。
DS18B20实物图
驱动代码如下
DS18B20_driver.c
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include //其中copy_to*在其中
#include
#include
#include
/*基于友善之臂smart210开发板,DS18B20数据引脚GPH2(0),位于开发板左上角GPIO,第二排排针倒数第五引脚*/
spinlock_t lock; //不用也行
unsigned int tmp_wendu ;
#define DEVICE_NAME "DS18B20"
#define NODE_NAME "DS18B20"
//********************************
//功能:设置引脚为输入功能
//********************************
void set_con_in(void)
{
s3c_gpio_cfgpin(S5PV210_GPH2(0), S3C_GPIO_INPUT);
//gpio_set_value(S5PV210_GPH2(0), 1);
}
//********************************
//功能:设置引脚为输出功能
//********************************
void set_con_out(void)
{
s3c_gpio_cfgpin(S5PV210_GPH2(0), S3C_GPIO_OUTPUT);
}
//********************************
//功能:引脚输出高或低电平功能,i=1(高)
//********************************
void set_output_data(int i)
{
if (i == 0) {
gpio_set_value(S5PV210_GPH2(0), 0);
} else if(i == 1) {
gpio_set_value(S5PV210_GPH2(0), 1);
}
}
//********************************
//功能:ds18b20复位
//********************************
int init_DS18B20(void)
{
int result = 10;
set_con_out();
__udelay(3); //短时间延迟
set_output_data(1);
__udelay(3); //短时间延迟
set_output_data(0);
__udelay(550); //480-960us
set_output_data(1);
__udelay(20); //15-60us,最好大于15us
set_con_in();
__udelay(100); //60-240us, ds18b20回应值保持时间
result = gpio_get_value(S5PV210_GPH2(0));
printk("init_DS18B20--result:%d\n", result);
set_con_out();
__udelay(3);
set_output_data(1);
//__udelay(300);
return result;
}
//*************************************
//功能:从ds18b20读一个字节的数据
//*************************************
unsigned char read_one_char(void)
{
unsigned char i = 0;
unsigned char dat = 0;
unsigned char temp = 0;
spin_lock(&lock);
for(i=0; i<8; i++) {
set_con_out();
__udelay(3);
set_output_data(1);
dat >>= 1;
set_output_data(0); //该行与下行等效该行上面的4行
__udelay(18); //按时序来延时,不能太小或太大
set_con_in();
__udelay(1);
temp = gpio_get_value(S5PV210_GPH2(0)) & 0x01;
if (temp)
dat |= 0x80;
else
dat |= 0x00;
printk("read_one_char--temp: %d\n", temp);
__udelay(65);
}
spin_unlock(&lock);
printk("read_one_char--dat: %d\n", dat);
return dat;
}
//*************************************
//功能:向ds18b20写一个字节的数据
//*************************************
void write_one_char(unsigned char dat)
{
//printk("write_one_char--dat: %d\n", dat);
unsigned char i = 0;
spin_lock(&lock);
set_con_out();
for(i=0; i<8; i++) {
set_output_data(1);
__udelay(1);
set_output_data(0);
__udelay(5);
set_output_data(dat & 0x01);
__udelay(55);
set_output_data(1);
__udelay(2);
dat >>= 1;
}
spin_unlock(&lock);
__udelay(30);
}
//********************************
//功能:读取ds18b20的温度
//********************************
unsigned int read_wendu(void)
{
unsigned char dat_L = 0, dat_H = 0;
unsigned int wendu_value;
int ds18b20_back_value;
ds18b20_back_value = init_DS18B20();
if (ds18b20_back_value)
printk("ds18b20 init error!!!\n");
else
printk("ds18b20_back_value %d\n", ds18b20_back_value);
write_one_char(0xCC);
write_one_char(0x44);
if (init_DS18B20())
printk("ds18b20 init error!!!\n");
else
printk("ds18b20 init ok \n");
write_one_char(0xcc);
write_one_char(0xBE);
dat_L = read_one_char();
dat_H = read_one_char();
if((dat_H & 0xf8) != 0x00) {
dat_L = (~dat_L) + 1;
if (dat_L > 255)
dat_H = (~dat_H) + 1;
}
wendu_value = (dat_H * 16 + dat_L/16) * 10 +((dat_L%16)*10/16);
printk("read_wendu--dat_L: %d dat_H: %d wendu: %d.%d\n",dat_L, dat_H, \
wendu_value/10, wendu_value%10);
return(wendu_value);
}
static int ds18b20_open(struct inode *inode, struct file *filp)
{
printk (KERN_INFO "Device opened\n");
spin_lock_init(&lock);
return 0;
}
/*读取数据*/
static int ds18b20_read(struct file *filp, char __user *buffer, size_t count, loff_t *ppos)
{
unsigned int wendu_value = 0;
int res = 0;
wendu_value = read_wendu();
if (wendu_value>2000)
{
wendu_value = tmp_wendu;
}
tmp_wendu = wendu_value;
printk("wendu_valu is %d\n", wendu_value);
res=copy_to_user(buffer, &wendu_value, sizeof(wendu_value));
if (res < 0)
{
printk("copy_to_user error! ");
}
printk("copy_to_user len! %d\n ", res);
return 0;
}
/*写命令,在此置空*/
static int ds18b20_write(struct file *file, const char *buffer, size_t count, loff_t * ppos)
{
return 0;
}
static int ds18b20_release(struct inode *inode,struct file *filp)
{
printk (KERN_INFO "device closed\n");
return 0;
}
static long ds18b20_ioctl(struct file *filp, unsigned int cmd,
unsigned long arg)
{
return 0;
}
static struct file_operations ds18b20_fops = {
.owner = THIS_MODULE,
.open = ds18b20_open,
.read = ds18b20_read,
.write = ds18b20_write,
.unlocked_ioctl = ds18b20_ioctl,
.release = ds18b20_release,
};
static struct miscdevice ds18b20_dev = {
.minor = MISC_DYNAMIC_MINOR,
.name = DEVICE_NAME,
.nodename = NODE_NAME,
.fops = &ds18b20_fops,
};
static int __init ds18b20_dev_init(void) {
int ret;
ret = gpio_request(S5PV210_GPH2(0), "DS18B20");
if (ret) {
printk("%s: request GPIO %d for GPE0 failed, ret = %d\n", DEVICE_NAME,
S5PV210_GPH2(0), ret);
return ret;
s3c_gpio_cfgpin(S5PV210_GPH2(0), S3C_GPIO_OUTPUT);
gpio_set_value(S5PV210_GPH2(0), 1);
}
ret = misc_register(&ds18b20_dev);//注册杂设备驱动
printk(DEVICE_NAME"\tinitialized\n");
return ret;
}
static void __exit ds18b20_dev_exit(void) {
int i;
for (i = 0; i < 1; i++) {
gpio_free(S5PV210_GPH2(0));
}
misc_deregister(&ds18b20_dev);
}
module_init(ds18b20_dev_init);
module_exit(ds18b20_dev_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("GaoZhe.");
Makefile
ifneq ($(KERNELRELEASE),)
obj-m := DS18B20_driver.o
else
PWD := $(shell pwd)
KDIR:= /home/bishe/kernel/linux-3.0.8
all:
make -C $(KDIR) M=$(PWD)
clean:
rm -rf *.o *.order *.ko *.mod.c *.symvers *.c~ *~
endif
应用程序如下
#include
#include
#include
#include
int main(int argc, char *argv[])
{
int fd, i;
char *buf;
unsigned int a=0;
fd = open("/dev/DS18B20", O_RDWR);
if(-1 == fd)
{
perror("open file error\r\n");
exit(-1);
}
printf("open /dev/DS18B20 success!\n");
while(1)
{
int i=read(fd,&a,5);
if(i<0)
{
printf("read tempture is error!\n");
}
printf("test_temptureis:%d.%d\n",a/10,a%10);
sleep(1);
}
close(fd);
return 0;
}
在这里用的是misc杂项设备的,#make之后,会生成DS18B20_driver.ko,然后#insmod DS18B20_driver.ko加载模块,执行#cat /proc/devices 发现并没有DS18B20这个驱动模块啊,而多了一个主设备号为10的misc,同时,#ls /dev 会发现自动生成了DS18B20设备文件,为什么呢?因为misc杂项设备驱动共用一个主设备号,区分不同设备的依据是次设备号,这里共用的是主设备号是10,次设备号是系统自动分配的。当#insmod后,系统会自动在/dev目录下创建设备文件,不需要手动mknod创建。