总线学习2--使用GPIO模拟I2C

代码还有问题。发命令是没问题,但是发数据还有问题。。。

这篇也是2月份就TODO了,但是一直没写。没动工的原因也是一直忙,有限的时间内不知道如何下手,最后搞定了micropython之后,这些内容才算能推进。

所有的步骤还是继续上一篇:

总线①I2C-CSDN博客

只是把实现I2C改成直接操作GPIO。其实核心功能就是那么几个,start,stop,write,read。

START

先看第一个吧。(所有的图都是上面是SDA,下面是SCL)

SDA拉低,SCL维持高位。

    def start(self):
        self.sda.value(0)
        time.sleep_us(5)
        self.scl.value(0)
        time.sleep_us(5)

STOP

主设备在 SCL 保持高电平的情况下,将 SDA 线从低电平拉高。

    def stop(self):
        self.scl.value(0)
        self.sda.value(0)
        time.sleep_us(WAITTIME)
        self.scl.value(1)
        time.sleep_us(WAITTIME)
        self.sda.value(1)
        time.sleep_us(WAITTIME)

DATA

这个最麻烦

    def write_byte(self, byte):
        for i in range(8):
            self.sda.value((byte >> (7 - i)) & 1)
            time.sleep_us(WAITTIME)
            self.scl.value(1)
            time.sleep_us(WAITTIME)
            self.scl.value(0)
            time.sleep_us(WAITTIME)
        self.sda.init(Pin.IN, Pin.PULL_UP)
        time.sleep_us(WAITTIME)
        self.scl.value(1)
        ack = self.sda.value()
        time.sleep_us(WAITTIME)
        self.scl.value(0)
        self.sda.init(Pin.OUT, Pin.PULL_UP)
        return ack

READ

这个暂时没有图

    def read_byte(self, ack):
        byte = 0
        self.sda.init(Pin.IN, Pin.PULL_UP)
        for i in range(8):
            self.scl.value(1)
            time.sleep_us(WAITTIME)
            byte = (byte << 1) | self.sda.value()
            self.scl.value(0)
            time.sleep_us(WAITTIME)
        self.sda.init(Pin.OUT, Pin.PULL_UP)
        self.sda.value(ack)
        time.sleep_us(WAITTIME)
        self.scl.value(1)
        time.sleep_us(WAITTIME)
        self.scl.value(0)
        time.sleep_us(WAITTIME)
        return byte

最后是仿照I2C的接口,还有两个封装。

    def writeto(self, addr, write_list):
        self.start()
        ack = self.write_byte(addr << 1)
        if ack != 0:
            print("NACK received")
            self.stop()
            return
        for data in write_list:
            ack = self.write_byte(data << 1)
            if ack != 0:
                print("NACK received")
                self.stop()
                return
        self.stop()
    
    def writevto(self, addr, vectors):
        self.start()
        ack = self.write_byte(addr << 1)
        if ack:
            print("writevto NACK received")
            self.stop()
            return False
        for vector in vectors:
            for byte in vector:
                ack = self.write_byte(byte)
                if ack:
                    print("writevto NACK received")
                    self.stop()
                    return False
        self.stop()
        return True

最后是完整代码:

import time
from machine import Pin

WAITTIME = 2

class SoftI2C:
    
    def __init__(self, scl_pin, sda_pin):
        self.scl = Pin(scl_pin, Pin.OUT, Pin.PULL_UP)
        self.sda = Pin(sda_pin, Pin.OUT, Pin.PULL_UP)
        self.scl.value(1)
        self.sda.value(1)
        
    def start(self):
        self.sda.value(0)
        #time.sleep_us(5)
        time.sleep_us(WAITTIME)
        self.scl.value(0)
        time.sleep_us(WAITTIME)
        
    def stop(self):
        self.scl.value(0)
        self.sda.value(0)
        time.sleep_us(WAITTIME)
        self.scl.value(1)
        time.sleep_us(WAITTIME)
        self.sda.value(1)
        time.sleep_us(WAITTIME)
        
    def write_byte(self, byte):
        for i in range(8):
            self.sda.value((byte >> (7 - i)) & 1)
            time.sleep_us(WAITTIME)
            self.scl.value(1)
            time.sleep_us(WAITTIME)
            self.scl.value(0)
            time.sleep_us(WAITTIME)
        self.sda.init(Pin.IN, Pin.PULL_UP)
        time.sleep_us(WAITTIME)
        self.scl.value(1)
        ack = self.sda.value()
        time.sleep_us(WAITTIME)
        self.scl.value(0)
        self.sda.init(Pin.OUT, Pin.PULL_UP)
        return ack
    
    def read_byte(self, ack):
        byte = 0
        self.sda.init(Pin.IN, Pin.PULL_UP)
        for i in range(8):
            self.scl.value(1)
            time.sleep_us(WAITTIME)
            byte = (byte << 1) | self.sda.value()
            self.scl.value(0)
            time.sleep_us(WAITTIME)
        self.sda.init(Pin.OUT, Pin.PULL_UP)
        self.sda.value(ack)
        time.sleep_us(WAITTIME)
        self.scl.value(1)
        time.sleep_us(WAITTIME)
        self.scl.value(0)
        time.sleep_us(WAITTIME)
        return byte
    
    def writeto(self, addr, write_list):
        self.start()
        ack = self.write_byte(addr << 1)
        if ack != 0:
            print("NACK received")
            self.stop()
            return
        for data in write_list:
            ack = self.write_byte(data << 1)
            if ack != 0:
                print("NACK received")
                self.stop()
                return
        self.stop()
    
    def writevto(self, addr, vectors):
        self.start()
        ack = self.write_byte(addr << 1)
        if ack:
            print("writevto NACK received")
            self.stop()
            return False
        for vector in vectors:
            for byte in vector:
                ack = self.write_byte(byte)
                if ack:
                    print("writevto NACK received")
                    self.stop()
                    return False
        self.stop()
        return True
'''
# 示例使用
scl_pin = 17  # SCL引脚编号
sda_pin = 16  # SDA引脚编号
i2c = SoftI2C(scl_pin, sda_pin)
# 向从设备地址0x3C写入一个字节0x01
i2c.start()
ack = i2c.write_byte(0x3C << 1)  # 写操作
if ack == 0:
    print("ACK received")
else:
    print("NACK received")
i2c.write_byte(0x01)
i2c.stop()
# 从从设备地址0x3C读取一个字节
i2c.start()
i2c.write_byte((0x3C << 1) | 1)  # 读操作
data = i2c.read_byte(1)  # 发送ACK
i2c.stop()
print(f"Read data: {data}")'''

  • 4
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值