AM335X——1-Wire和IrDA驱动

优快云仅用于增加百度收录权重,排版未优化,日常不维护。请访问:www.hceng.cn 查看、评论。
本博文对应地址: https://hceng.cn/2019/02/15/AM335X——1-Wire和IrDA驱动/#more

记录DS18B20温度传感器、DH11温湿度传感器、红外遥控驱动。

1-wire(单总线协议)就是只使用一条线(GPIO)实现时钟/数据的双向传输。
DS18B20是比较标准的1-wire协议,可以通过逻辑分析仪显示出含义,DH11不是很标准(专利原因?),需要自己参考芯片手册理解含义。
但它们原理都差不多,且都对时序要求比较高(us级的延时)。

IrDA也是一根线,原理也差不多,因此也把它放在一起记录。
AM335X没有1-wire的控制器,因此使用GPIO模拟。

1. DS18B20

1.1 基础知识

1.1.1 性能参数

分辨率:9~12位可编程(上电默认12位)
精度:±0.5℃(在-10~+85℃)
量程:-55°C ~ 125°C
转换时间:750ms(12位分辨率)

1.1.2 温度数据格式

一次返回的温度数据为16位,前五位表示正负,中间七位表示整数部分,最低四位为小数部分;
温度传感器的分辨率为用户可编程的9、10、11或12位, 分别对应0.5℃、0.25℃、0.125℃和 0.0625℃。
因此温度计算结果为:(正负)整数部分+小数部分*分辨率

0000 0000 1010 0010为例,前五位为0,即温度为零上;中间七位0001010,即温度整数部分为10;最后四位0010,即温度小数部分为2*0.625=0.125,因此温度为+10.125

1.1.3 64Bits只读数据

低八位用于CRC校验,中间48位是DS18B20唯一序列号,高八位是产品系列号(为28h)

1.1.4 操作步骤

每次对DS18B20操作,都必须严格按照以下步骤:
1、初始化;
2、ROM指令;
3、功能指令;

1.1.5 ROM指令和功能指令

ROM指令
指令名称 指令代码 指令功能
读ROM 33H 读ROM中64Bits的只读数据
ROM匹配 55H 发出此命令后接着发64Bits的ROM编码,使单总线上与编码匹配的DS18B3做出响应
搜索ROM F0H 用于确定挂在总线上的DS18B20的个数和识别64Bits的ROM地址
跳过ROM CCH 忽略64BitsROM只读数据,接着发出功能指令,进行温度转换或读取温度
警报搜索 ECH 只有温度超过设定上限或下限的DS18B20才做出响应
功能指令
指令名称 指令代码 指令功能
温度转换 44H 启动温度转换,结果将保存在内部RAM中
读取温度 BEH 读取内部RAM中的温度数据
设置报警温度 4EH 设置上或下限报警温度指令,接着应发送两字节数据
保存报警温度 48H 将RAM中的报警温度数据,复制到EEPROM中保存
恢复RAM B8H 将EEPROM中的报警温度数据恢复到RAM
读供电方式 B4H 寄生供电返回0,外界电源供电返回1

1.1.5 初始化时序

初始化DS18B20的时序如上,先拉低480us,然后拉高释放总线,随后在60-240us内,DS18B20将会拉低总线进行响应。
此时检测总线释放被拉低既可判断出DS18B20是否初始化成功。

1.1.6 读写时序

上面的图是写0或1的时序:
如果写0,拉低至少60us(写周期为60-120us)即可;如果写1,先拉低至少1us,然后拉高,整个写周期至少为60us即可。

下面的图是读0或1的时序:
先拉低至少1us,随后读取电平,如果为0,即读到的数据是0,如果为1,即可读到的数据是1。
整个过程必须在15us内完成,15us后引脚都会被拉高。

1.2 内核驱动

内核中自带1-Wire和DS18B20的驱动。
drivers/w1/masters/w1-gpio.c是单总线的IO操作方法,用于模拟单总线时序;
drivers/w1/slaves/w1_therm.c是DS18B20的寄存器操作方法,和IO时序无关;

1.2.1 加入内核

{% codeblock lang:Makefile %}
Device Drivers —>
<> Dallas’s 1-wire support —>
[
] Userspace communication over connector
1-wire Bus Masters —>
<> GPIO 1-wire busmaster
1-wire Slaves —>
<
> Thermal family implementation
{% endcodeblock %}

1.2.2 修改设备树

{% codeblock lang:dts %}
onewire@0 {
compatible = “w1-gpio”;
gpios = <&gpio0 13 0>;
//pinctrl-0 = <&ds18b20_dq_pin>;
};
{% endcodeblock %}

1.2.3 应用测试

cat /sys/bus/w1/drivers/w1_slave_driver/28-01d58c07010c/w1_slave

1.3 自己驱动

这次驱动,吸取了前面AM335X——hwmon和input子系统的经验。

1.3.1 完整代码

{% codeblock lang:c %}
//cat /sys/class/hwmon/hwmon0/device/temperature

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/gpio.h>
#include <linux/of_gpio.h>
#include <linux/platform_device.h>
#include <linux/hwmon.h>
#include <linux/hwmon-sysfs.h>
#include <linux/irqflags.h>

struct ds18b20 {
struct device *hwmon_dev;
struct mutex lock;
int dq_pin;
u8 value[2];
u8 family_code;
u8 serial_num[6];
u8 crc;
};
static struct ds18b20 ds;

static int ds18b20_init(void)
{
int ret = 1;

mutex_lock(&ds.lock);

gpio_direction_output(ds.dq_pin, 1);
udelay(2);
gpio_direction_output(ds.dq_pin, 0); //Low level 480us for reset
udelay(480);                      
gpio_direction_output(ds.dq_pin, 1); //Pull high release bus
udelay(60);

gpio_direction_input(ds.dq_pin); //Read response pulse
ret = gpio_get_value(ds.dq_pin);
udelay(240);  //Waiting for the corresponding end

mutex_unlock(&ds.lock);

return ret;

}

static void write_byte(unsigned char data)
{
int i = 0;
unsigned long flags;

mutex_lock(&ds.lock);

local_irq_save(flags); //Save interrupt
//local_irq_disable(); //Close all interrupts

gpio_direction_output(ds.dq_pin, 1); 

for (i = 0; i < 8; i ++)
{
    gpio_direction_output(ds.dq_pin, 1); 
    udelay(2);    
    gpio_direction_output(ds.dq_pin, 0); //Start at a low level greater than 1us
    udelay(5);
    
    gpio_direction_output(ds.dq_pin, data & 0x01);  
    udelay(60); //Write cycle is greater than 60us
    
    data >>= 1;   
}
local_irq_restore(flags); //Recovery interrupt
//local_irq_enable(); //Open all interrupts

mutex_unlock(&ds.lock); 

}

static unsigned char read_byte(void)
{
int i;
unsigned long flags;
unsigned char data = 0;

mutex_lock(&ds.lock);

local_irq_save(flags);
//local_irq_disable();

for (i = 0; i < 8; i++)    
{    
    gpio_direction_output(ds.dq_pin, 1);    
    udelay(2);    
    gpio_direction_output(ds.dq_pin, 0); //Start at a low level greater than 1us
    udelay(5);    
    
    gpio_direction_output(ds.dq_pin, 1); //Pull high release bus 
    udelay(1); 
  
    data >>= 1;   
    gpio_direction_input(ds.dq_pin);
    if (gpio_get_value(ds.dq_pin)) //Must be read within 15us after being pulled low
        data |= 0x80;  
  
    udelay(60); //Read cycle is greater than 60us;   
}    

local_irq_restore(flags); 
//local_irq_enable();

mutex_unlock(&ds.lock);

return data;    

}

static ssize_t ds18b20_get_sensor_value(struct device *dev, struct device_attribute *devattr, char *buf)
{
int ret = -1;
unsigned int m, n;

ret =
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值