基于AVR单片机的Arduino提供了使用I2C总线的库,使用很方便,但是若想有个性化的功能就很难实现
本文就在AVR单片机上使用I2C作简要介绍
先简单介绍一下I2C总线
I2C有两根线,SDA,SCL,最多允许128个设备在总线上,每个设备都有唯一的地址
设备之间是有主从的关系的,主设备产生时钟信号,开始和结束数据传输
每次传输都有开始信号和结束信号,开始信号是在SCL高的时候拉低SDA,结束是在SCL高的时候拉高SDA
在数据传输过程中,但SCL高时,SDA必须保持不变
在开始信号和结束信号之间,总线忙
因为I2C又叫TWI(Two Wire Interface),所以AVR中相关寄存器都以TW开头
寄存器名都是英文的缩写,所以就不写中文名称了
TWBR:用来从CPU频率来产生SCL频率,可用如下公式,通过设置TWBR与PrescalerValue的值来确定总线频率
TWCR:control register
TWSR:status register
TWDR:data register
又比如如下几个寄存器,INT是中断的缩写,STA,STO分别是开始和结束,EN则是使能
理解了这些寄存器,便能轻松理解程序了
TWINT
TWSTATWSTO
TWEN
总线初始化函数
void i2c_init(void)
{
TWSR = 0; // 把PrescalerValue设置为1
TWBR = ((F_CPU / I2C_SPEED) - 16) / 2; // 通过实现设置的I2C_SPEED来确定TWBR
TWCR = 1<<TWEN; // 使能I2C
}
开始函数
void i2c_start(uint8_t address)
{
TWCR = (1<<TWINT) | (1<<TWSTA) | (1<<TWEN) ; // 开始
waitTransmissionI2C(); // 等待传输结束
TWDR = address; // 发送设备地址
TWCR = (1<<TWINT) | (1<<TWEN);
waitTransmissionI2C(); // 等待传输结束
}
结束函数
void i2c_stop(void)
{
TWCR = (1 << TWINT) | (1 << TWEN) | (1 << TWSTO);
}
等待传输结束函数
void waitTransmissionI2C()
{
uint16_t count = 255;
while (!(TWCR & (1<<TWINT))) //若传输出现故障,开始计数
{
count--;
if (count==0) //当计数达到255扔故障,放弃传输
{
TWCR = 0; //重置TWINT
i2c_errors_count++; //记录I2C故障
break;
}
}
}
uint8_t i2c_read(uint8_t ack)
{
TWCR = (1<<TWINT) | (1<<TWEN) | (ack? (1<<TWEA) : 0);
waitTransmissionI2C();
uint8_t r = TWDR; //返回TWDR(数据寄存器)中的值
if (!ack) i2c_stop();
return r;
}
uint8_t i2c_readAck()
{
return i2c_read(1);
}
uint8_t i2c_readNak(void)
{
return i2c_read(0);
}
写函数
void i2c_write(uint8_t data )
{
TWDR = data; // 向设备写一个字节
TWCR = (1<<TWINT) | (1<<TWEN);
waitTransmissionI2C();
}
有了这些函数,便可根据不同原件的要求,通过I2C进行读写操作了
参考资料:http://www.embedds.com/programming-avr-i2c-interface/
https://code.google.com/p/multiwii/