狂人呓语

ATmega16 模拟方式I2C实现【以PCF8563为例题】

关键问题:

因为SDA与SCL都接了上拉电阻,因此,直接操作IO口将不可靠,当IO口为高电平时,器件无法将电平拉低,因此,通过设置IO口的输入和输出模式来进行解决。当IO口为输入时,因外部上拉电阻的作用下,器件呈现高电平状态,因为当IO口为输入模式的时候,IO口为开路,当器件将总线拉低,总线将会整个拉低,当IO为输出时,默认PORTx为0,因此总线呈现为低电平。

DDRx = 0xFF时 --> 总线=L
DDRx = 0x00时 --> 总线=H 器件可拉低

具体程序如下,如果需要更改IO口,可直接修改宏定义,无需修改代码

/* PCF8563实时时钟 IIC/TWI 时序操作程序 时钟线SCL PC0 数据线SDA PC1 */ #ifndef _IIC_ #define _IIC_ #include "util/delay.h" #include "avr/io.h" //DDR为输入的时候,该线路为高电平,输出为低电平 #define SCL_L DDRC |= BIT(0) #define SCL_H DDRC &= ~BIT(0) #define SDA_L DDRC |= BIT(1) #define SDA_H DDRC &= ~BIT(1) #define SDA_PIN (PINC & 0x02) #define SDA_IN DDRC &= ~BIT(1) #define WAIT _delay_us(1) void i2c_start() //起始信号 { SDA_H; WAIT; SCL_H; WAIT; SDA_L; WAIT; SCL_L; WAIT; } void i2c_stop() //停止信号 { SDA_L; WAIT; SCL_H; WAIT; SDA_H; WAIT; } uchar i2c_send(uchar sz) //I2C发送数据 sz=1应答 sz=0不应答 { uchar tmp; for(int i=0;i<8;i++) //发送数据 { if(sz & 0x80) SDA_H; else SDA_L; WAIT; SCL_H; WAIT; SCL_L; WAIT; sz<<=1; } SDA_IN; //输入模式 WAIT; SCL_H; WAIT; if(SDA_PIN) tmp=0; else tmp=1; SCL_L; WAIT; //i2c_stop(); return tmp; } uchar i2c_read(uchar ack) //I2C读1个字节 { uchar tmp; SDA_IN; //输入模式 for(int i=0;i<8;i++) { SCL_L; WAIT; SCL_H; WAIT; tmp<<=1; if(SDA_PIN) tmp++; } SCL_L; WAIT; if(ack) SDA_L; else SDA_H; WAIT; SCL_H; WAIT; SCL_L; return tmp; } /* 读1个字节 device_addr 器件地址 ram_addr 内存地址 data 数据 */ void Write_byte(uchar device_addr,uchar ram_addr,uchar data) { i2c_start(); i2c_send(device_addr); i2c_send(ram_addr); i2c_send(data); i2c_stop(); _delay_ms(10); } /* 读1个字节 device_addr 器件地址 ram_addr 内存地址 */ uchar Read_byte(uchar device_addr,uchar ram_addr) { uchar temp; i2c_start(); i2c_send(device_addr); i2c_send(ram_addr); i2c_start(); i2c_send(device_addr | 1); //读模式 temp = i2c_read(0); //不应答 i2c_stop(); _delay_ms(10); return temp; } #endif

未经允许不得转载:狂人呓语 » ATmega16 模拟方式I2C实现【以PCF8563为例题】

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址