gpio模拟单总线驱动DS18B20读取温度
#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/slab.h>
#include <linux/device.h>
#include <linux/io.h>
#include <linux/delay.h>
#include <linux/of_gpio.h>
#include <linux/gpio.h>
#include <linux/uaccess.h>
#include <asm/uaccess.h>
#define gpionum 30
#define HIGH 1
#define LOW 0
#define DS18B20_ReadROM 0x33
#define DS18B20_MatchROM 0x55
#define DS18B20_SkipROM 0xCC
#define DS18B20_SearchROM 0xF0
#define DS18B20_AlarmROM 0xEC
#define DS18B20_WriteSCR 0x4E
#define DS18B20_ReadSCR 0xBE
#define DS18B20_CopySCR 0x48
#define DS18B20_ConvertTemp 0x44
#define DS18B20_RecallEP 0xB8
#define DS18B20_ReadPower 0xB4
#define DEVICE_NAME "DS18B20"
typedef unsigned char U8;
typedef unsigned short U16;
static int DS18B20_Major = 0;
U16 temp;
U8 DS18B20_ID[8] = {0};
U8 DS18B20_Init(void)
{
gpio_direction_output(gpionum,HIGH);
gpio_set_value(gpionum, LOW);
udelay(700);
gpio_set_value(gpionum, HIGH);
udelay(4);
gpio_direction_input(gpionum);
udelay(100);
return 0;
}
u8 DS18B20_ReadBit(void)
{
U8 dat;
gpio_direction_output(gpionum,HIGH);
gpio_set_value(gpionum, LOW);
udelay(2);
gpio_set_value(gpionum, HIGH);
gpio_direction_input(gpionum);
udelay(10);
if(gpio_get_value(gpionum)!=0)
dat=1;
else
dat=0;
gpio_direction_output(gpionum,HIGH);
gpio_set_value(gpionum, HIGH);
udelay(50);
return (dat);
}
U8 DS18B20_ReadByte(void)
{
U8 i,j,dat;
dat=0;
for(i=1;i<=8;i++)
{
j=DS18B20_ReadBit();
dat=(j<<7)|(dat>>1);
}
return(dat);
}
void DS18B20_WriteByte(U8 dat)
{
U8 j;
U8 testb;
gpio_direction_output(gpionum,HIGH);
for(j=1;j<=8;j++){
testb=dat&0x01;
dat=dat>>1;
if(testb) {
gpio_set_value(gpionum, LOW);
udelay(8);
gpio_set_value(gpionum, HIGH);
udelay(50);
}
else{
gpio_set_value(gpionum, LOW);
udelay(90);
gpio_set_value(gpionum, HIGH);
udelay(8);
}
}
}
void DS18B20_ReadID(void)
{
udelay(1);
DS18B20_Init();
DS18B20_WriteByte(DS18B20_ReadROM);
DS18B20_ID[0] = DS18B20_ReadByte();
DS18B20_ID[1] = DS18B20_ReadByte();
DS18B20_ID[2] = DS18B20_ReadByte();
DS18B20_ID[3] = DS18B20_ReadByte();
DS18B20_ID[4] = DS18B20_ReadByte();
DS18B20_ID[5] = DS18B20_ReadByte();
DS18B20_ID[6] = DS18B20_ReadByte();
DS18B20_ID[7] = DS18B20_ReadByte();
}
void DS18B20_Match(void)
{
DS18B20_WriteByte(DS18B20_MatchROM);
DS18B20_WriteByte(DS18B20_ID[0]);
DS18B20_WriteByte(DS18B20_ID[1]);
DS18B20_WriteByte(DS18B20_ID[2]);
DS18B20_WriteByte(DS18B20_ID[3]);
DS18B20_WriteByte(DS18B20_ID[4]);
DS18B20_WriteByte(DS18B20_ID[5]);
DS18B20_WriteByte(DS18B20_ID[6]);
DS18B20_WriteByte(DS18B20_ID[7]);
}
void DS18B20_TmpChange(void)
{
while(DS18B20_Init());
udelay(100);
DS18B20_WriteByte(DS18B20_SkipROM);
DS18B20_WriteByte(DS18B20_ConvertTemp);
}
u16 DS18B20_Temperature(void)
{
U8 a,b;
while(DS18B20_Init());
udelay(100);
DS18B20_WriteByte(DS18B20_SkipROM);
DS18B20_WriteByte(DS18B20_ReadSCR);
udelay(4);
a=DS18B20_ReadByte();
b=DS18B20_ReadByte();
temp=b;
temp<<=8;
temp=temp|a;
return temp;
}
static int RK3568_ds18b20_open(struct inode *inode, struct file *file)
{
DS18B20_TmpChange();
mdelay(1000);
DS18B20_Temperature();
DS18B20_TmpChange();
mdelay(1000);
DS18B20_Temperature();
return 0;
}
static int RK3568_ds18b20_release(struct inode *inode, struct file *file)
{
printk("RK3568-DS18B20 Driver Release Called!\n");
return 0;
}
ssize_t RK3568_ds18b20_read(struct file *filp, char *buf, size_t count, loff_t *f_pos)
{
unsigned int ret;
u16 ds18b20_val;
DS18B20_TmpChange();
mdelay(500);
ds18b20_val =DS18B20_Temperature();
printk("DS18B20 Temperature=%u\r\n",ds18b20_val);
ret=copy_to_user(buf, &ds18b20_val, sizeof(ds18b20_val));
if(!ret) return ret;
return 0;
}
static struct file_operations RK3568_ds18b20_fops =
{
.owner = THIS_MODULE,
.open = RK3568_ds18b20_open,
.release = RK3568_ds18b20_release,
.read = RK3568_ds18b20_read,
};
static struct class *ds18b20_class;
static int __init RK3568_ds18b20_init(void)
{
printk("RK3568 DS18B20 DRIVER MODULE INIT\n");
DS18B20_Init();
DS18B20_Major = register_chrdev(0, DEVICE_NAME, &RK3568_ds18b20_fops);
if (DS18B20_Major < 0)
{
printk(DEVICE_NAME " can't register major number\n");
return DS18B20_Major;
}
printk("register RK3568-DS18B20 Driver OK! Major = %d\n", DS18B20_Major);
ds18b20_class = class_create(THIS_MODULE, DEVICE_NAME);
if(IS_ERR(ds18b20_class))
{
printk("Err: failed in RK3568-DS18B20 class. \n");
return -1;
}
device_create(ds18b20_class, NULL, MKDEV(DS18B20_Major, 0), NULL, DEVICE_NAME);
printk(DEVICE_NAME " initialized\n");
return 0;
}
static void __exit RK3568_ds18b20_exit(void)
{
printk("RK3568 DS18B20 DRIVER MODULE EXIT\n");
unregister_chrdev(DS18B20_Major, DEVICE_NAME);
device_destroy(ds18b20_class, MKDEV(DS18B20_Major, 0));
class_destroy(ds18b20_class);
}
module_init(RK3568_ds18b20_init);
module_exit(RK3568_ds18b20_exit);
MODULE_AUTHOR("pang");
MODULE_DESCRIPTION("RK3568 DS18B20 Driver");
MODULE_LICENSE("GPL");
|