• 单总线通讯协议


    用软件实现1-Wire®通信

    摘要:在没有专用总线主机(如DS2480B、DS2482)的情况下,微处理器可以轻松地产生1-Wire时序信号。本应用笔记给出了一个采用‘C’语言编写、支持标准速率的1-Wire主机通信基本子程序实例。1-Wire总线的四个基本操作是:复位、写“1”、写“0”和读数据位。字节操作可以通过反复调用位操作实现,本文提供了通过各种传输线与1-Wire器件进行可靠通信的时间参数。

    引言

    在没有专用总线主机的情况下,微处理器可以轻松地产生1-Wire时序信号。本应用笔记给出了一个采用C语言编写、支持标准速率的1-Wire主机通信基本子程序实例。此外,本文也讨论了高速通信模式。要使该实例中的代码正常运行,系统必须满足以下几点要求:

    1. 微处理器的通信端口必须是双向的,其输出为漏极开路,且线上具有弱上拉。这也是所有1-Wire总线的基本要求。关于简单的1-Wire主机微处理器电路实例,请参见应用笔记4206:"为嵌入式应用选择合适的1-Wire主机"中的1类部分。
    2. 微处理器必须能产生标准速度1-Wire通信所需的精确1µs延时和高速通信所需要的0.25µs延时。
    3. 通信过程不能被中断。

    1-Wire总线有四种基本操作:复位、写1位、写0位和读位操作。在数据资料中,将完成一位传输的时间称为一个时隙。于是字节传输可以通过多次调用位操作来实现,下面的1是各个操作的简要说明以及实现这些操作所必须的步骤列表。1为其时序波形图。2给出了通常线路条件下1-Wire主机与1-Wire器件通信的推荐时间。如果与1-Wire主机相连的器件比较特殊或者线路条件比较特殊,则可以采用最值。请参考可下载的工作表中的系统和器件参数,确定最小值和最大值。
    1. 1-Wire操作

    Operation

    Description

    Implementation

    Write 1 bit

    Send a '1' bit to the 1-Wire slaves (Write 1 time slot)

    Drive bus low, delay A
    Release bus, delay B

    Write 0 bit

    send a '0' bit to the 1-Wire slaves (Write 0 time slot)

    Drive bus low, delay C
    Release bus, delay D

    Read bit

    Read a bit from the 1-Wire slaves (Read time slot)

    Drive bus low, delay A
    Release bus, delay E
    Sample bus to read bit from slave
    Delay F

    Reset

    Reset the 1-Wire bus slave devices and ready them for a command

    Delay G
    Drive bus low, delay H
    Release bus, delay I
    Sample bus, 0 = device(s) present, 1 = no device present
    Delay J

    clip_image001
    1. 1-Wire时序图
    2. 1-Wire主机时序

    image

    计算这些值的工作表可供下载。

    示例代码:

    /*
     * Copyright (c) 2015 tingpan
     * Copyright 2012-2015 Senscom.cn
     *    tingpan <smbx-ztbz@cnblog.com>
     *
     * This program is free software; you can redistribute it and/or modify
     * it under the terms of the GNU General Public License version 2 as
     * published by the Free Software Foundation.
     *
     */
    
    #include <linux/kernel.h>
    #include <linux/init.h>
    #include <linux/miscdevice.h>  //混杂设备
    #include <linux/fs.h>
    #include <linux/module.h>
    #include <linux/delay.h>  //mdelay
    #include <linux/device.h>
    #include <linux/gpio.h>
    #include <linux/spi/spi.h>
    #include <linux/spi/spi_gpio.h>
    
    #include <linux/kfifo.h>
    #include <linux/interrupt.h>
    #include <linux/irq.h>
    
    #include <linux/types.h>  //u8
    
    #include <linux/ioctl.h>
    
    
    #define SENSORID_DEBUG    1
    
    #if (SENSORID_DEBUG == 1)
    #define PRK(...) printk(__VA_ARGS__)
    #else 
    #define PRK(...) 
    #endif
    
    #define DRV_NAME    "sensorid"
    #define DRV_DESC    "1 wire sensor id" 
    #define DRV_VERSION    "0.1.0"
    
    #define SENSORID_NODE_NAME DRV_NAME
    
    #define sensorid_pin 13
    
    
    u16 A,B,C,D,E,F,G,H,I,J;
    u8 rom[8];
    
    
    static void set_speed(int standard)
    {
        if (standard) { // Adjust tick values depending on speed
            // Standard Speed
            A = 6 ;
            B = 64 ;
            C = 60 ;
            D = 10 ;
            E = 9 ;
            F = 55 ;
            G = 0;
            H = 480 ;
            I = 70 ;
            J = 410 ;
        } else {
            // Overdrive Speed
            A = 2 ;
            B = 8 ;
            C = 8 ;
            D = 3 ;
            E = 1 ;
            F = 7 ;
            G = 3 ;
            H = 70 ;
            I = 9 ;
            J = 40 ;
        }
    }
    
    
    static int init_ds2431(void) //初始化DS2431
    {   
        int presece;
        udelay(G); 
        gpio_direction_output(sensorid_pin, 0);  //将DQ信号线拉低
        udelay(H);                           //保持DQ低电平480us
        gpio_set_value(sensorid_pin,1);       //将DQ信号拉高、释放总线
        udelay(I);                            //保持DQ高电平70us
        gpio_direction_input(sensorid_pin);
        presece = gpio_get_value(sensorid_pin);
        udelay(J);
        return presece; //为1表示该总线上没有设备,为0表示有设备
    }
    
    static int read_bit(void) //从单总线上读取一个数据位
    {
        int result;
        gpio_direction_output(sensorid_pin,0);//启动读时序
        udelay(A);
        gpio_set_value(sensorid_pin,1);//释放总线,等待从机返回数据位
        udelay(E);
        gpio_direction_input(sensorid_pin);
        result = gpio_get_value(sensorid_pin);
        udelay(F);
        gpio_direction_output(sensorid_pin,1);//返回总线状态
        return result;
    }
    
    static void write_bit(u8 bit)  //向单总线设备写入一个数据位
    {
        if (bit){ //写 "1"
            gpio_direction_output(sensorid_pin,0);//启动写时序
            udelay(A);
            gpio_set_value(sensorid_pin,1);
            udelay(B);
        } else { //写 "0"
            gpio_direction_output(sensorid_pin,0);//启动写时序
            udelay(C);
            gpio_set_value(sensorid_pin,1);
            udelay(D);
        }
    }
    
    static void write_byte(u8 data)//向单总线写一个字节
    {
        u8 i;
        for (i = 0; i < 8; i++) { //先低位,后高位
            write_bit(data & 0x01);
            data >>= 1;
        }
    }
    
    static int read_byte(void)
    {
        u8 i,value=0;
        for (i = 0; i < 8; i++) {  //先读低位,再读高位
            if(read_bit()) value = value | (0x01 << i); //如果当前读取的数据位为1,将返回字节对应的位置1
        }
        return value; //返回读取的数据
    }
    
    static u8 crccheck(u8* p,u8 len) //CRC校验,返回CRC检验值
    {
        u8 bit0,cbit,i,j,byte,temp;
        temp = 0;
        for (j = 0; j < len; j++) {
            byte = p[j];
            for(i = 0; i < 8; i++) {
                cbit = temp & 0x01;
                bit0 = byte & 0x01;
                temp = temp >> 1;
                if ((cbit^bit0)) temp ^= 0x8c;
                byte >>= 1;
            }
        }
        return temp;
    }
    
    static int read_2431_serial(void) //读 2431序列号
    {
        int i;
        u8 crc;
        set_speed(1);// set the speed to 'standard'
        if (init_ds2431()) {// Reset the 1-Wire bus
            PRK(KERN_INFO "no device on the bus
    ");
            return -1; // Return if no devices found
        }
        write_byte(0x33); // Send Read ROM command to select single device
        // read the page data
        udelay(60);
        for (i = 0; i < 8; i++)
            rom[i] = read_byte();
        crc = crccheck(rom, 8);
        PRK(KERN_INFO "crc value is %x
    ",crc);
        if (!crc) {  //crc校验为0,则读取正确
            return 0;
        } else {
            return -1;
        }
        return 0;
    }
    
    static ssize_t op_sensorid_read(struct file *file, char __user * dat, 
                                        size_t len, loff_t *loff)
    {
        int err = 0;
        err = !access_ok(VERIFY_WRITE, (void __user *)dat, _IOC_SIZE(len));
        if (err) {
            PRK(KERN_INFO " access not allowed!
    ");
            return -EFAULT;
        }
        err = read_2431_serial();
        if (err) {
            PRK("[%d]read_2431_serial failed.
    ", __LINE__);
            return -1;
        }
        __copy_to_user(dat, &rom, sizeof(rom));
        return 0;
    }
    
    static ssize_t op_sensorid_write(struct file *file, char __user * dat, 
                                        size_t len, loff_t *loff)
    {
    
    }
    
    static int op_sensorid_open(struct inode *inode, struct file *file)
    {
        int err;
    
        err = gpio_request(sensorid_pin, "sensorid_pin");//管脚申请
        if (err) {
            PRK("[%d]gpio_request sensorid_pin failed.
    ", __LINE__);
            return -1;
        }
        gpio_direction_output(sensorid_pin, 1);//该管脚设为输出,且输出为高电平
    
        PRK(KERN_INFO " op_sensorid_open
    ");
        return 0;
    }
    
    static int op_sensorid_release(struct inode *inode, struct file *file)
    {
        gpio_free(sensorid_pin);//释放IO口
    
        PRK(KERN_INFO " op_sensorid_release
    ");
    
        return 0;
    }
    
    static const struct file_operations sensorid_fops =
    {
        .owner   = THIS_MODULE,
        
        .open    = op_sensorid_open,
        .read    = op_sensorid_read,
        .write    = op_sensorid_write,
        .release = op_sensorid_release,
    };
    
    static struct miscdevice sensorid_miscdev =
    {
        //次设备号,驱动注册时,如果次号指定MISC_DYNAMIC_MINOR,则进行动态分配。
        .minor = MISC_DYNAMIC_MINOR,
        .name = SENSORID_NODE_NAME,//设备名称,将在/dev文件夹下显示
        .fops = &sensorid_fops,
    };
    static int __init sensorid_init(void)//放后面,因为 misc_register 要包含前面的内容
    {
        int ret;
    
        ret = misc_register(&sensorid_miscdev);
        if (ret) {
            printk("misc_unregister error
    ");
            return ret;
        }
        
        printk(KERN_INFO DRV_NAME " ver " DRV_VERSION" init
    ");
    
        return 0;
    }
    
    module_init(sensorid_init);
    
    static void __exit sensorid_exit(void)
    {
        int ret;
    
        ret = misc_deregister(&sensorid_miscdev);//注销
        if (ret) {
            printk("misc_register error
    ");
            return ;
        }
    
        printk(KERN_INFO DRV_NAME " ver " DRV_VERSION" exit
    ");
    }
    module_exit(sensorid_exit);
    
    MODULE_DESCRIPTION(DRV_DESC);//描述
    MODULE_VERSION(DRV_VERSION);//版本
    MODULE_AUTHOR("tingpan <smbx-ztbz@cnblogs.com>");//作者
    MODULE_LICENSE("GPL v2");//协议
  • 相关阅读:
    oracle-高级查询
    java-集合框架
    java-String-StringBuffer
    ROS消息, 服务, 主题, 订阅 5
    ROS消息, 服务, 主题, 订阅 4
    ROS消息, 服务, 主题, 订阅 3
    ROS消息, 服务, 主题, 订阅 2
    ROS消息, 服务, 主题, 订阅 1
    可交互的Marker
    RVIZ建Maker
  • 原文地址:https://www.cnblogs.com/smbx-ztbz/p/4996201.html
Copyright © 2020-2023  润新知