合宙air103 手搓模拟i2c

为什么手搓i2c

本来合宙官方的固件中已经包含了硬件i2c和模拟i2c两个模块,完全没必要再自己写一个。但是i2c是一个很重要的通信协议,我想通过自己手搓的方式去更加的熟悉这个协议。然后呢,百度发现网上没有关于合宙手搓模拟i2c的例子,毕竟官方都做好了,直接用就好了,很少有人再自己折腾。

i2c需要实现的功能

  • 启动
  • 停止
  • 写入数据
  • 读取数据
  • 发送ACK/NACK
  • 接受ACK

这部分希望能看得懂,不懂可以去百度i2c协议,毕竟不是面对i2c小白。

i2c示例代码

代码里边加入了一些测试用的代码,主要是查看i2c协议是否是正常工作的。因为没有逻辑分析仪,只能读取引脚状态然后打印出来。

local I2c = {}
-- 软件模型i2c
sys = require("sys")

-- 引脚变量,下面好操作一点
pin_sda = pin.PA4
pin_sck = pin.PA1

-- 定义引脚功能,这样对引脚的控制方便一点
function sck_0() gpio.set(pin_sck,0) end
function sck_1() gpio.set(pin_sck,1) end
function sda_0() gpio.set(pin_sda,0) end
function sda_1() gpio.set(pin_sda,1) end
function sda_read() return gpio.get(pin_sda) end -- 读取sda引脚

-- 延时函数
function Delay()
    sys.wait(2)
end

-- sda引脚输入或输出模式
-- 在开始,发送数据,ACK的时候,引脚需要设置为输出模式。
-- 读取的时候需要设置为输入模式
function pin_SdaMode(mode)
    if mode == 1 then
        Sda = gpio.setup(pin_sda,nil,gpio.PULLDOWN) -- 输入模式
    else
        Sda = gpio.setup(pin_sda,1,gpio.PULLUP) -- 输出模式
    end
end

-- 初始化引脚
function I2c.GPIO_init()
    Sck = gpio.setup(pin_sck,1,gpio.PULLUP)
    pin_SdaMode(0)
    -- I2c.io()	-- 查看引脚状态,测试用
end

-- i2c开始
function I2c.start()
    pin_SdaMode(0)  -- 输出模式
    sda_1()
    sck_1()
    Delay()

    sda_0() Delay()
    sck_0() Delay()
end

-- i2c结束
function I2c.stop()
    pin_SdaMode(0)
    sda_0()
    sck_1() Delay()
    sda_1() Delay()
end

-- ACK响应
function ACK()
    pin_SdaMode(0)
    sda_0() Delay()
    sck_1() Delay()
    sck_0() Delay()
    sda_1() -- 释放总线
end

-- NACK响应
function NACK()
    sda_1() Delay()
    sck_1() Delay()
    sck_0() Delay()
end

-- 读取从Ack,如果发送数据给从设备没有响应,后面的数据将没有意义
function I2c.ReadAck()
    pin_SdaMode(1)
    Ack = nil
    sck_1() Delay()
    if gpio.get(pin_sda) == 0 then
        Ack = 1
    else
        Ack = 0
    end
    sck_0() Delay()
    return Ack
end

-- 给从设备写入数据
function I2c.Write(data)
    pin_SdaMode(0)
    for i=0,7 do
        if (data & 0x80)>0 then
            sda_1()
            -- print("1")
        else
            sda_0()
            -- print("0")
        end

        Delay()
        sck_1() Delay()
        sck_0() Delay()
        data = data<<1
    end
    sda_1() -- 释放总线
    Delay()
end

-- 从 从机读取数据
function I2c.Read(ack)
    pin_SdaMode(1)

    local Data = 0
    for i=0,7 do
        Data = Data<<1

        sck_1() Delay()
        if gpio.get(pin_sda)==1 then
            Data=Data+1
        end
        sck_0() Delay()
    end

    if ack == 1 then    -- 是否发送响应
        ACK()
    else
        NACK()
    end
    return Data
end

-- 读取引脚状态,查看引脚的电平变化,没有逻辑分析仪的无奈之举
function I2c.io()
    print("sck",gpio.get(pin_sck),"sda",gpio.get(pin_sda))
end

-- 给模块发送地址,地址正确返回1
function I2c.CheckDevice(addr)
    I2c.start()
    I2c.Write(addr<<1)
    local ack = I2c.ReadAck()
    -- print("ack",ack)
    I2c.stop()
end

return I2c

使用bh1750测试i2c协议

local bh1750_soft = {}

i2c = require "I2c_soft"

-- BH1750 命令
local BH1750_POWER_DOWN   	    =   0x00	-- 断电
local BH1750_POWER_ON			=   0x01	-- 通电
local BH1750_RESET			    =   0x07	-- 重置寄存器
local BH1750_CON_H_RES_MODE	    =   0x10	-- 连续高分辨率模式
local BH1750_CON_H_RES_MODE2	=   0x11	-- 连续高分辨率模式2
local BH1750_CON_L_RES_MODE	    =   0x13	-- 连续低分辨率
local BH1750_ONE_H_RES_MODE	    =   0x20	-- 一次高分辨率 测量后断电模式
local BH1750_ONE_H_RES_MODE2	=   0x21	-- 一次高分辨率2
local BH1750_ONE_L_RES_MODE	    =   0x23	-- 一次高分辨率

-- 模块初始化
function bh1750_soft.init()
    i2c.GPIO_init()
    i2c.start()
    i2c.Write(0x23<<1)	-- 设备寻址
    i2c.ReadAck()

    i2c.Write(BH1750_POWER_ON)  -- 启动模块
    i2c.ReadAck()

    i2c.stop()
end

-- 读取亮度信息
function bh1750_soft.readData ()
    i2c.start()
    i2c.Write(0x23<<1)	
    i2c.ReadAck()

    i2c.Write(BH1750_CON_H_RES_MODE2)  -- 读取模式
    i2c.ReadAck()
    sys.wait(180)   -- 测量需要120ms

    i2c.start()
    i2c.Write((0x23<<1)+1)
    i2c.ReadAck()

    local data1 = i2c.Read(1)
    local data2 = i2c.Read(0)
    -- print("data1 data2",data1,data2)
    local data = (data1<<8) + data2
    data = data/1.2
    -- print("data",data)
    i2c.stop()
    return data
end

return bh1750_soft

实验效果

在这里插入图片描述

结语

这个程序并不完美,但我测试并没有问题,如果有很好的解决方案可以提出哈。同时,很多地方没有很好的去解释,希望能看懂。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值