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電路如圖如下
驅動代碼如下
DS18B20_driver.c
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/miscdevice.h>
#include <linux/fs.h>
#include <linux/types.h>
#include <linux/moduleparam.h>
#include <linux/slab.h>
#include <linux/ioctl.h>
#include <linux/cdev.h>
#include <linux/delay.h>
#include <asm/uaccess.h> //其中copy_to*在其中
#include <mach/gpio.h>
#include <mach/regs-gpio.h>
#include <plat/gpio-cfg.h>
/*基於友善之臂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 <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <sys/select.h>
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創建。