tiny 6410 ds18b20 温度传感器采集数据偶尔出错误

cdaniel 2012-05-23 11:19:20

硬件 tiny 6410 ds18b20 传感器
系统:linux 2.3.68
问题:读取的数据有时候会产生错误,例如突然变成0度 或者1000度 然后在恢复。
驱动代码。

驱动代码
/*
* Temperature sensor driver for zc6410
*
register list:
* DQ:EINT8(GPN8)
* GPNCON:0x7F008830
* GPNDAT:0x7F008834
* GPNPUD:0x7F008838
*
* register contorl:
* GPN8[17:16] 00=input 01=output 10=Ext.interrupt[8] 11=reserved
*
*/

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/platform_device.h>
#include <linux/cdev.h>
#include <linux/miscdevice.h>
#include <linux/ioctl.h>
#include <linux/io.h>
#include <linux/ioport.h>

#include <asm/uaccess.h>
//#include <regs-gpio.h>
//#include <mach/hardware.h>

#define DEBUG_18B20 0
#define DEVICE_NAME "ds18b20"

#define DSDATA 0x7F008830
#define DATAOUTP 1
#define DATAINP 0

#define DS18B20_MAGIC 'k'
#define DS18B20_RESET _IO(DS18B20_MAGIC, 0)

static void *pVmem = NULL;

#define s3c6410_gpio_cfgpin(pin, state) \
(state?({unsigned int vmem; vmem = ioread32(pin); vmem &= ~(3<<16); vmem |= 1<<16; iowrite32(vmem, pin);}):({unsigned int vmem; vmem = ioread32(pin); vmem &= ~(3<<16); iowrite32(vmem, pin);}))
#define s3c6410_gpio_setpin(pin, state) \
(state?({unsigned int vmem; vmem = ioread32(pin+4); vmem |= (1<<8); iowrite32(vmem, pin+4);}):({unsigned int vmem; vmem = ioread32(pin+4); vmem &= ~(1<<8); iowrite32(vmem, pin+4);}))
#define s3c6410_gpio_getpin(pin) ((ioread32(pin+4)>>8) & 1)

static ssize_t ds18b20_read(struct file *filp, char __user *buff, size_t count, loff_t *offp)
{

volatile int i, size=count;
unsigned char ddat = 0;

if (size > 2)
size = 1;

for (i=0; i<8; i++)
{
ddat >>= 1;
s3c6410_gpio_cfgpin(pVmem, DATAOUTP);
s3c6410_gpio_setpin(pVmem, 0);
udelay(4); //4us
s3c6410_gpio_setpin(pVmem, 1);
s3c6410_gpio_cfgpin(pVmem, DATAINP);
if ( s3c6410_gpio_getpin(pVmem) )
{
ddat |= 0x80;
}
udelay(80); // >70us
s3c6410_gpio_cfgpin(pVmem, DATAOUTP);
s3c6410_gpio_setpin(pVmem, 1);
udelay(3); // >1us
}
s3c6410_gpio_cfgpin(pVmem, DATAINP);

if(copy_to_user(buff, &ddat, size))
{
return -1;
}

return size;
}

static ssize_t ds18b20_write(struct file *filp, const char __user *buff, size_t count, loff_t *offp)
{

volatile int i, size=count;
char ddat=0;

if (size > 2)
size = 1;

if (copy_from_user(&ddat, buff, size))
{
printk("write data error\n");
return -1;
}

s3c6410_gpio_cfgpin(pVmem, DATAOUTP);
for (i=0; i<8; i++)
{
s3c6410_gpio_setpin(pVmem, 0);
udelay(5); //5us
if (ddat & 0x01)
{
s3c6410_gpio_setpin(pVmem, 1);
}
udelay(80); // >70us
s3c6410_gpio_setpin(pVmem, 1);
udelay(3); // >1us
ddat >>= 1;
}
s3c6410_gpio_cfgpin(pVmem, DATAINP);

return size;
}

static int ds18b20_ioctl( struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
{
int ret = 0;

switch(cmd)
{
//case DS18B20_RESET: // reset
case 0: // reset
s3c6410_gpio_cfgpin(pVmem, DATAOUTP);
s3c6410_gpio_setpin(pVmem, 1);
udelay(27);
s3c6410_gpio_setpin(pVmem, 0);
udelay(500); // 500us
s3c6410_gpio_setpin(pVmem, 1);
udelay(27);
s3c6410_gpio_cfgpin(pVmem, DATAINP);
udelay(60);
ret = s3c6410_gpio_getpin(pVmem);
msleep(3);
default:
return -EINVAL;
}

return ret;
}

static int ds18b20_open(struct inode *inode, struct file *file)
{
/* GPN8[17:16] = 00 */
s3c6410_gpio_cfgpin(pVmem, DATAINP);

#if DEBUG_18B20
printk("context of 0x%x is 0x%x\n", DSDATA, ioread32(pVmem));
#endif

return 0;
}

static int ds18b20_release(struct inode *inode, struct file *file)
{
return 0;
}

static struct file_operations ds18b20_fops = {
.owner = THIS_MODULE,
.open = ds18b20_open,
.release = ds18b20_release,
.unlocked_ioctl = ds18b20_ioctl,
.read = ds18b20_read,
.write = ds18b20_write,
//.compat_ioctl = ds18b20_ioctl,
};

static struct miscdevice misc = {
.minor = MISC_DYNAMIC_MINOR,
.name = DEVICE_NAME,
.fops = &ds18b20_fops,
};

// register ds18b20
static int __init dev_init(void)
{
int ret;

ret = misc_register(&misc);

if(!request_mem_region(DSDATA, 0x8, DEVICE_NAME))
goto error;
pVmem = ioremap(DSDATA, 0x8);

printk(DEVICE_NAME"\tinitialized\n");

return ret;

error:
misc_deregister(&misc);
return -EFAULT; /* bad address */
}

// unregister ds18b20
static void __exit dev_exit(void)
{
iounmap(pVmem);
release_mem_region(DSDATA, 0x8);
misc_deregister(&misc);
}

module_init(dev_init);
module_exit(dev_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("modified by __eabi");


测试代码!!

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <error.h>
#include <time.h>
#include <fcntl.h>

#define DS18B20_MAGIC 'k'
#define DS18B20_RESET _IO(DS18B20_MAGIC, 0)

static int fd=0;
static unsigned char a=0;
static unsigned char b=0;


/*****读取温度*****/
static unsigned int ReadTemperature(void)
{
unsigned int t=0;

ioctl(fd, DS18B20_RESET, 0); //初始化
a = 0xcc;
write(fd, &a, 1); //跳过读序号列号的操作
a = 0x44;
write(fd, &a, 1); //启动温度转换

sleep(1);
ioctl(fd, DS18B20_RESET, 0); //初始化
a = 0xcc;
write(fd, &a, 1); //跳过读序号列号的操作
a = 0xbe;
write(fd, &a, 1); //读取温度寄存器

read(fd, &a, 1); //读低8位
read(fd, &b, 1); //读高8位

t = b;
t <<= 8;
t = t | a;


usleep(5000);

return t;
}


int main(int argc, char **argv)
{
int val;
float fval;

fd = open("/dev/ds18b20", O_RDWR);
if (fd < 0)
{
perror("open device ds18b20!");
return -1;
}

while(1)
{
val = ReadTemperature();
val <<= 16;
val >>= 16; // 扩展符号位
printf("Temperature is ");
if (val < 0)
{
printf("-");
val = -val;
}
fval = val >> 4; // 整数
fval += (val & 0x000F) * 0.0625; // 小数
printf("%f \n",fval);
sleep(1);
}

close(fd);

return 0;
}

...全文
526 3 打赏 收藏 转发到动态 举报
写回复
用AI写文章
3 条回复
切换为时间正序
请发表友善的回复…
发表回复
hannax 2012-05-26
  • 打赏
  • 举报
回复
我贴的这个代码能够得到温度,但是没做太多的测试,也就展示了一下18b20的基本工作原理,驱动中也没有考虑并发的问题,另外你的那个ioctl函数在驱动层使用的cmd等于是0的时候复位,没有使用格式化命令。
hannax 2012-05-26
  • 打赏
  • 举报
回复
#include<stdio.h>
#include<unistd.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<sys/types.h>

float change_to_temperature(char *temperature);

int main(int argc, char *argv[])
{
int fd;
int i = 10;
char temperature[2];
if((fd = open("/dev/18b20_driver", O_RDONLY)) < 0)
printf("open 18b20_driver file error!\n");


while(i--){
read(fd,temperature ,sizeof(temperature));
printf("temperature is: %f\n",change_to_temperature(temperature));
sleep(1);
}

return 0;
}

float change_to_temperature(char *temperature)
{
int tmp = 0;
tmp = (int)temperature[1] << 8;
tmp |= temperature[0];
return tmp * 0.0625;
}
hannax 2012-05-25
  • 打赏
  • 举报
回复
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/miscdevice.h>
#include <linux/delay.h>
#include <asm/irq.h>
#include <mach/hardware.h>
#include <linux/cdev.h>
#include <linux/device.h>

#include <linux/gpio.h>
#include <plat/gpio-cfg.h>

#define DEVICE_NAME "TEM"
#define tp_MAJOR 232


//static unsigned char data[2];
void tm_18b20_reset(void) //18b20初始化
{

s3c_gpio_cfgpin(S3C64XX_GPN(8), S3C_GPIO_SFN(1));//设置引脚为输出
gpio_set_value(S3C64XX_GPN(8), 1);
udelay(5);
gpio_set_value(S3C64XX_GPN(8), 0);//产生下降沿
udelay(600);//持续600us低电平
gpio_set_value(S3C64XX_GPN(8), 1);//拉回高电平
udelay(60);//持续60us
s3c_gpio_cfgpin(S3C64XX_GPN(8), S3C_GPIO_SFN(0));//设置引脚为输入
}

void tm_18b20_writeb(unsigned char dat) //写一个字节函数
{
unsigned char j;
s3c_gpio_cfgpin(S3C64XX_GPN(8), S3C_GPIO_SFN(1));//输出模式

for (j = 1; j <= 8; j++){
gpio_set_value(S3C64XX_GPN(8), 0);//产生下降延
udelay(1);
if((dat&0x01)==1)//根据dat的位值来设置数据线值
gpio_set_value(S3C64XX_GPN(8), 1);

udelay(60);
gpio_set_value(S3C64XX_GPN(8), 1);//拉回高电平
udelay(10);
dat = dat >> 1;
}

gpio_set_value(S3C64XX_GPN(8), 1);//设置完后将端口拉回高电平
}


unsigned char tm_18b20_readb(void) //读一个字节函数
{
unsigned char i,temp=0;

for (i = 1; i <= 8; i++){
s3c_gpio_cfgpin(S3C64XX_GPN(8), S3C_GPIO_SFN(1));//设置端口为输出
gpio_set_value(S3C64XX_GPN(8), 0);//产生下降延
udelay(1);
temp >>= 1;
gpio_set_value(S3C64XX_GPN(8), 1);//拉回高电平
s3c_gpio_cfgpin(S3C64XX_GPN(8), S3C_GPIO_SFN(0));//设置端口为输入
udelay(10);
if( gpio_get_value(S3C64XX_GPN(8))) //如果为高电平
temp = temp | 0x80;
udelay(60);
}
return (temp);
}

void DS18B20PRO(void)
{
tm_18b20_reset(); //复位
udelay(420);
tm_18b20_writeb(0xcc); //跳过序列号命令
tm_18b20_writeb(0x44); //发转换命令 44H,

mdelay(750);

tm_18b20_reset (); //复位
udelay(400);
tm_18b20_writeb(0xcc); //跳过序列号命令
tm_18b20_writeb(0xbe); //发送读取命令
//data[0] = tm_18b20_readb(); //读取低位温度
//data[1] = tm_18b20_readb(); //读取高位温度
}

static ssize_t s3c6410_18b20_read(struct file *filp, char __user *buf, size_t len, loff_t *off)
{
DS18B20PRO();

buf[0] = tm_18b20_readb();
buf[1] = tm_18b20_readb();

return 0;
}

static struct file_operations s3c6410_18b20_fops = {
.owner = THIS_MODULE,
.read = s3c6410_18b20_read,
};

static struct cdev cdev_18b20;

static int __init s3c6410_18b20_init(void)
{
int result;
dev_t devno = MKDEV(tp_MAJOR,0);
struct class *tem_class;

result = register_chrdev_region(devno,1,DEVICE_NAME);

if(result){
printk(KERN_NOTICE "Error %d register 18b20",result);
return result;
}

cdev_init(&cdev_18b20,&s3c6410_18b20_fops);

result = cdev_add(&cdev_18b20,devno,1);
if(result){
printk(KERN_NOTICE "Error %d adding 18b20",result);
return result;
}

tem_class = class_create(THIS_MODULE, "tem_class");
device_create(tem_class, NULL, MKDEV(tp_MAJOR, 0), "ds18b20","TEM%d", 0);

return 0;
}

static void __exit s3c6410_18b20_exit(void)
{
cdev_del(&cdev_18b20);
unregister_chrdev_region(MKDEV(tp_MAJOR,0),1);
}


module_init(s3c6410_18b20_init);
module_exit(s3c6410_18b20_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("hannax<hannax@foxmail.com>");
你看看这个

21,619

社区成员

发帖
与我相关
我的任务
社区描述
硬件/嵌入开发 驱动开发/核心开发
社区管理员
  • 驱动开发/核心开发社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧