怎么从I2C总线读数据

Python020

怎么从I2C总线读数据,第1张

i2c有其协议的,我当时从不会到掌握其协议用了一阵子,就是狂读协议和例程

我把当时用非斯卡尔单片机读i2c mems传感器的历程写在下面

#include <hidef.h>

#include "derivative.h"

#define IIC_SDA_CTL PTCDD_PTCDD1

#define IIC_SDA_DAT PTCD_PTCD1

#define IIC_SCL_CTL PTCDD_PTCDD0

#define IIC_SCL_DAT PTCD_PTCD0

#define IIC_MST_HI 0

#define IIC_MST_LO 1

void IIC_Start(void)

void IIC_Restart(void)

void IIC_Stop(void)

byte IIC_SendByte(byte)

byte IIC_Read(byte *, byte)

byte IIC_Write(byte *, byte)

void IIC_Delay(void)

void IIC_Delay(void)

{

byte i

for (i=0i<8i++) {}

}

//==============================================================

// Master generates a START condition on IIC bus

//==============================================================

void IIC_Start(void)

{

IIC_SDA_CTL = IIC_MST_HI

IIC_SCL_CTL = IIC_MST_HI

IIC_Delay()

IIC_SDA_CTL = IIC_MST_LO

IIC_SDA_DAT = 0

IIC_Delay()

IIC_SCL_CTL = IIC_MST_LO

IIC_SCL_DAT = 0

IIC_Delay()

}

//==============================================================

// Master generates a RESTART condition on IIC bus

//==============================================================

void IIC_Restart(void)

{

IIC_SDA_CTL = IIC_MST_HI//SDA back to high while SCL remain in low

IIC_Delay()

IIC_SCL_CTL = IIC_MST_HI//SCL back to high, bus idle now

IIC_Delay()

IIC_SDA_CTL = IIC_MST_LO//RESTART condition occur

IIC_Delay()

IIC_SCL_CTL = IIC_MST_LO//SCL to low for standby

IIC_Delay()

}

//==============================================================

// Master generates a STOP condition on IIC bus

//==============================================================

void IIC_Stop(void)

{

IIC_SDA_CTL = IIC_MST_LO//make sure SDA is low

IIC_Delay()

IIC_SCL_CTL = IIC_MST_HI//I2C_SCL_CTL go to high first

IIC_Delay()

IIC_SDA_CTL = IIC_MST_HI//I2C_SDA_CTL have low-high transition while SCL is high

IIC_Delay()

}

//==============================================================

// Master send out a byte of data and return with ACK/NACK

// return with 0x00 if ACK received

// return with 0xff if NACK received

//==============================================================

byte IIC_SendByte(byte outDat)

{

byte bit

//send out 8-bit data

for (bit=0bit<8bit++) {

if (outDat&0x80)

IIC_SDA_CTL = IIC_MST_HI

else

IIC_SDA_CTL = IIC_MST_LO

IIC_Delay()

IIC_SCL_CTL = IIC_MST_HI

IIC_Delay()

IIC_SCL_CTL = IIC_MST_LO

outDat <<= 1

}

//check for the ACK/NACK

IIC_SDA_CTL = IIC_MST_HI//master release SDA

IIC_Delay()

IIC_SCL_CTL = IIC_MST_HI//master send a clock

IIC_Delay()

if (IIC_SDA_DAT) bit = 0xff//NACK

else bit = 0//ACK

IIC_SCL_CTL = IIC_MST_LO

IIC_Delay()

return(bit)

}

//==============================================================

// Master write a string of bytes through IIC us

// Return with 0x00 if successful

// Return with 0xff if failed

//==============================================================

byte IIC_Write(byte *buff, byte total)

{

while (total) {

if (IIC_SendByte(*buff++)) //get NACK after data byte out

return(0xff)//abort

total--

//__RESET_WATCHDOG()//needed only for EEPROM byte-program

}

return(0)

}

//==============================================================

// Master read a byte of data and set ACK/NACK

// return with data read

//==============================================================

byte IIC_ReadByte(byte ackFlag)

{

byte bit, dat

IIC_SDA_CTL = IIC_MST_HI//make sure master release SDA

//read 8 bits sof data

for (bit=0bit<8bit++) {

dat <<= 1

IIC_SCL_CTL = IIC_MST_HI

IIC_Delay()

if (IIC_SDA_DAT) //read back data

dat |= 0x01

IIC_SCL_CTL = IIC_MST_LO

IIC_Delay()

}

//echo with ACK/NACK

if (ackFlag==0)

IIC_SDA_CTL = IIC_MST_LO//echo back ACK

else

IIC_SDA_CTL = IIC_MST_HI//echo back NACK

IIC_Delay()

IIC_SCL_CTL = IIC_MST_HI

IIC_Delay()

IIC_SCL_CTL = IIC_MST_LO

IIC_Delay()

return(dat)

}

//==============================================================

// Master read a string of data bytes through IIC us

//==============================================================

byte IIC_Read(byte *buff, byte total)

{

byte count

if (total==0) return(0)

if (total==1) { //read one byte only

buff[0] = IIC_ReadByte(1)//NACK after read

return(1)

}

else { //read more than one bytes

count = 0

while(total>1) {

IIC_Delay()

buff[count++] = IIC_ReadByte(0)//ACK after read

total--

__RESET_WATCHDOG()

}

IIC_Delay()

buff[count++] = IIC_ReadByte(1)

return(count)

}

}

然后你去网上搜索iic总线协议,把协议多读几遍慢慢就会了~~要不你把邮箱给我我发给你.总之很简单的 不用害怕,学学就会了

在前一小节中介绍了点亮第一个LED灯,这里我们准备进阶尝试下,输出第一段PWM波形。(PWM也就是脉宽调制,一种可调占空比的技术,得到的效果就是:如果用示波器测量引脚会发现有方波输出,而且高电平、低电平的时间是可调的。)

这里爪爪熊准备写成一个golang的库,并开源到github上,后续更新将直接更新到github中,如果你有兴趣可以和我联系。 github.com/dpawsbear/bear_rpi_go

我在很多的教程中都看到说树莓派的PWM(硬件)只有一个GPIO能够输出,就是 GPIO1 。这可是不小的打击,因为我想使用至少四个 PWM ,还是不死心,想通过硬件手册上找寻蛛丝马迹,看看究竟怎么回事。

手册上找寻东西稍等下讲述,这里先提供一种方法测试 树莓派3B PWM 方法:用指令控制硬件PWM。

这里通过指令的方式掌握了基本的pwm设置技巧,决定去翻一下手册看看到底PWM怎么回事,这里因为没有 BCM2837 的手册,根据之前文章引用官网所说, BCM2835 BCM2837 应该是一样的。这里我们直接翻阅 BCM2835 的手册,直接找到 PWM 章节。找到了如下图:

图中可以看到在博通的命名规则中 GPIO 12、13、18、19、40、41、45、52、53 均可以作为PWM输出。但是只有两路PWM0 PWM1。根据我之前所学知识,不出意外应该是PWM0 和 PWM1可以输出不一样的占空比,但是频率应该是一样的。因为没有示波器,暂时不好测试。先找到下面对应图:

根据以上两个图对比可以发现如下规律:

对照上面的表可以看出从 BCM2837 中印出来的能够使用在PWM上的就这几个了。

为了验证个人猜想是否正确,这里先直接使用指令的模式,模拟配置下是否能够正常输出。

通过上面一系列指令模拟发现,(GPIO1、GPIO26)、(GPIO23、GPIO24)是绑定在一起的,调节任意一个,另外一个也会发生变化。也即是PWM0、PWM1虽然输出了两路,可以理解成两路其实都是连在一个输出口上。这里由于没有示波器或者逻辑分析仪这类设备(仅有一个LED灯),所以测试很简陋,下一步是使用示波器这类东西对频率以及信号稳定性进行下测试。

小节:树莓派具有四路硬件输出PWM能力,但是四路中只能输出两个独立(占空比独立)的PWM,同时四路输出的频率均是恒定的。

上面大概了解清楚了树莓派3B的PWM结构,接下来就是探究如何使用Go语言进行设置。

因为拿到了手册,这里我想直接操作寄存器的方式进行设置,也是顺便学习下Go语言处理寄存器的过程。首先需要拿到pwm 系列寄存器的基地址,但是翻了一圈手册,发现只有偏移,没有找到基地址。

经过了一段时间的努力后,决定写一个 树莓派3B golang包开源放在github上,只需要写相关程序进行调用就可以了,以下是相关demo(pwm)(在GPIO.12 上输出PWM波,放上LED灯会有呼吸灯的效果,具体多少频率还没有进行测试)

以下是demo(pwm) 源码