一个arduino解析I2C协议的例子,自己备忘
arduino的库只能使用bOOt-L0ader中编号的IO,使用了非编号IO,库就不能用了,分享个解决模拟I2C主机协议的示例,
就是一个头文件sim_iic.h, 内容如下:
#ifndef __SIM_IIC_H__
#define __SIM_IIC_H__
#include <avr/io.h>
//Please include this file into your project. e.g. #include "sim_iic.h"
//Do not modify the following values,
//This address corresponds to the chip end.
#define SLAW0x5A
#define SLAR0x5B
typedef enum { I2C1=1, I2C2, I2C3 }DEV;
//Defined IO number of Simulated IIC
#define Pin_SDA1 7 //F7
#define Pin_SDA2 6 //F6
#define Pin_SDA3 5 //F5
#define Pin_SCL 2 //E2
//Defined Port of Simulated IIC
#define PORT_SDAPORTF
#define PIN_SDA PINF
#define DDR_SDA DDRF
#define PORT_SCLPORTE
#define DDR_SCL DDRE
#define PIN_SCL PINE
#define SDA1_L do {bitClear(PORT_SDA, Pin_SDA1); bitSet(DDR_SDA,Pin_SDA1); nops();} while(0)
#define SDA1_H do {bitClear(DDR_SDA,Pin_SDA1); bitSet(PORT_SDA, Pin_SDA1); nops();} while(0)
#define SDA1_GET ((uint8_t)(PIN_SDA & bit(Pin_SDA1)) ? 1 : 0)
#define SDA2_L do {bitClear(PORT_SDA, Pin_SDA2); bitSet(DDR_SDA,Pin_SDA2); nops();} while(0)
#define SDA2_H do {bitClear(DDR_SDA,Pin_SDA2); bitSet(PORT_SDA, Pin_SDA2); nops();} while(0)
#define SDA2_GET ((uint8_t)(PIN_SDA & bit(Pin_SDA2)) ? 1 : 0)
#define SDA3_L do {bitClear(PORT_SDA, Pin_SDA3); bitSet(DDR_SDA,Pin_SDA3); nops();} while(0)
#define SDA3_H do {bitClear(DDR_SDA,Pin_SDA3); bitSet(PORT_SDA, Pin_SDA3); nops();} while(0)
#define SDA3_GET ((uint8_t)(PIN_SDA & bit(Pin_SDA3)) ? 1 : 0)
#define SDA_L(dev)\
do { \
switch(dev) { \
case I2C1: SDA1_L; break; \
case I2C2: SDA2_L; break; \
case I2C3: SDA3_L; break; \
} \
} while(0)
#define SDA_H(dev)\
do { \
switch(dev) { \
case I2C1: SDA1_H; break; \
case I2C2: SDA2_H; break; \
case I2C3: SDA3_H; break; \
} \
} while(0)
inline uint8_t SDA_GET(DEV dev)
{
switch(dev)
{
case I2C1: return SDA1_GET;
case I2C2: return SDA2_GET;
case I2C3: return SDA3_GET;
}
}
#define SCL_L do { bitClear(PORT_SCL, Pin_SCL); bitSet(DDR_SCL,Pin_SCL); nops();} while(0)
#define SCL_H do { bitClear(DDR_SCL,Pin_SCL); bitSet(PORT_SCL, Pin_SCL); nops();} while(0)
#define SCL_PIN ((uint8_t)(PIN_SCL & bit(Pin_SCL)) ? 1 : 0) //unused
#define ACK 1
#define NOACK 0
inline void nops(void)
{
uint8_t dly = 10;
while (--dly){ _NOP();}
}
inline void delayus(uint8_t n)
{
while (--n) { nops(); }
}
inline void i2c_start(DEV dev)
{
SDA_H(dev);
SCL_H;
delayus(10);
SDA_L(dev);
SCL_L;
}
inline void i2c_stop(DEV dev)
{
SCL_L;
SDA_L(dev);
SCL_H;
SDA_H(dev);
delayus(10);
}
//Send ACK (LOW)
inline void i2c_ack(DEV dev, uint8_t ack)
{
if (ack) {
SDA_H(dev);
} else {
SDA_L(dev);
}
SCL_H;
SCL_L;
}
//write a byte, return ack
inline uint8_t i2c_write_byte(DEV dev, uint8_t dat)
{
uint8_t i, ack=0;
for (i=0; i<8; i++)
{
if(dat & 0x80) {
SDA_H(dev);
} else {
SDA_L(dev);
}
SCL_H;
SCL_L;
dat <<= 1;
}
SCL_H;
ack = SDA_GET(dev); //从机应答
SCL_L;
return ack;
}
//read a byte, ack=1:ack, ack=0:no ack
inline uint8_t i2c_read_byte(DEV dev)
{
uint8_t i, chr=0;
SDA_H(dev);
for (i=0; i<8; i++)
{
SCL_H;
chr <<= 1;
if (SDA_GET(dev)) chr += 1; //从机返回的数据
SCL_L;
}
return chr;
}
//call this function to write iic device. do not use it now!!
inline void i2c_write(DEV dev, uint8_t addr, uint8_t *p, uint8_t len)
{
uint8_t i;
i2c_start(dev);
i2c_write_byte(dev, SLAW);
i2c_write_byte(dev, addr);
for (i=0; i<len; i++)
{
i2c_write_byte(dev, *p);
p++;
}
i2c_stop(dev);
}
//call this function to read iic device.
inline void i2c_read(DEV dev, uint8_t addr, uint8_t *p, uint8_t len)
{
uint8_t i;
i2c_start(dev);
i2c_write_byte(dev, SLAW); //write
i2c_write_byte(dev, addr);
i2c_start(dev);
i2c_write_byte(dev, SLAR); //read
for(i=0; i<len; i++)
{
*p++ = i2c_read_byte(dev);
i2c_ack(dev, (i==(len-1)));
}
i2c_stop(dev);
}
#endif
使用也很简单,例如读取iic从设备地址0开始的4个字节:
i2c_read(dev, 0x00, recvbuf, 4); 我自己写的,没版权问题,发这里就是为了备忘,
任何代码带来的问题,我不负责的. 感谢分享! 连续读的时序有问题,很多人都忽略这个细节 iffi123 发表于 2024-3-20 15:38
连续读的时序有问题,很多人都忽略这个细节
是个行家
我知道,一般能适应,没遇到有问题的.
页:
[1]