本人比较懒,每次遇见iic的时候,都是移植别人的驱动,底层能不管就不管。这次参加电赛,调试LDC1314的时候,没有现成的驱动可移植,没有办法,只有从iic看起走了,而且LDC1314的板子是我们在实验室做的,不清楚能否使用,必须自己保证程序运行没有问题,因此照着时序写了一份iic程序,历经千辛万苦终于能够使用,在这里分享出来,也防止以后忘记再到处找资料。
一、iic协议时序图
写时序:
1、起始信号:SCL高电平时,SDA下降沿,进入数据传输状态。
2、数据传输:不论是写还是读,iic规定在SCL被拉高之前,数据必须放在SDA上待读取,SCL一旦处于高电平,SDA上的数据必须稳定,如果有跳变就会成为起始信号和停止信号发生错误,这点在写程序时一定要注意。
3、读写位:高电平-读 低电平-写。
4、应答信号:总线上每传送完一个字节,被传送方都会在第9个时钟吧总线拉低,以示回应。
5、停止信号:SCL高电平时,SDA上升沿,结束此次传输。
整个传输过程就是:
主机发出起始信号->高7位写设备地址,低0位写0->等待回应->写设备内部寄存器地址->等待回应->写n个字节,并等待回应(n>=1)->主机发出停止信号
读时序:
1:读信号。
2:应答信号:和写入不同,应该由主机发出,读取一个字节发出一个应答信号。
3:无应答信号:第9个时钟不拉低SDA。注意,在一次读取多个字节的时候,最后一个字节应该不应答,直接stop,否则会出错,实测。
整个流程如下:
主机发出起始信号->写7位从机地址+1位写信号->等从机应答->写寄存器地址->等从机应答->主机发出起始信号->写7位从机地址+1位读信号->等从机应答->读字节->发出应答信号->...->读字节->无应答->主机发出停止信号
注意几点:
1、iic总线在硬件上,应该保证线与,即一条线上有一个为低,那么整条线就为低。解决办法就是挂载在总线上的设备io口设置为开漏模式,并挂一个上拉电阻。
2、在不需要使用SDA的时候,主机应该释放,保证从机能够传输电平信号,比如上图的ack by slave,如果主机不释放SDA,始终为低电平,根本无法判断是主机拉低的还是从机拉低的。
3、在进入传输状态的时候,如果没有传输数据,SCL应该为低电平,因为SCL如果为高电平,SDA有任何的电平抖动都会被识别为起始或是停止信号,导致此次传输失败。
二、c代码
OIIC.h
-
/***************************************************************
-
portable iic driver
-
author:logic
-
date:2016-7-23
-
***************************************************************/
-
-
#ifndef _OIIC_H
-
#define _OIIC_H
-
#include "MK60_port.h"
-
#include "MK60_gpio.h"
-
-
-
/*
-
*public:
-
*/
-
void OIIC_init();
-
void OIIC_writeByte(unsigned char devAddr,unsigned char regAddr,unsigned char byte);
-
void OIIC_writeWord(unsigned char devAddr,unsigned char regAddr,unsigned int word);
-
void OIIC_writeBytes(unsigned char devAddr,unsigned char regAddr,unsigned char *bytes,int length);
-
unsigned char OIIC_readByte(unsigned char devAddr,unsigned char regAddr);
-
unsigned int OIIC_readWord(unsigned char devAddr,unsigned char regAddr);
-
void OIIC_readBytes(unsigned char devAddr,unsigned char regAddr,unsigned char *bytes,int length);
-
-
/*
-
*private:
-
*/
-
void OIIC_delay(int t);
-
void OIIC_start();
-
void OIIC_stop();
-
void OIIC_waitForResponse();
-
void OIIC_response();
-
void OIIC_noResponse();
-
void OIIC_putByteOnBus(unsigned char byte);
-
unsigned char getByteOnBus();
-
-
#define OSCL_H() (PTXn_T(PTE25,OUT)=1)
-
#define OSCL_L() (PTXn_T(PTE25,OUT)=0)
-
#define OSCL_V() PTXn_T(PTE25,IN)
-
#define OSDA_H() (PTXn_T(PTE24,OUT)=1)
-
#define OSDA_L() (PTXn_T(PTE24,OUT)=0)
-
#define OSDA_V() PTXn_T(PTE24,IN)
-
#define OSDA_OUT() (1==1)//ignore it when GPIO is openDrain and pullUp mode
-
#define OSDA_IN() (1==1)
-
-
-
-
-
#endif
OIIC.c
-
#include "OIIC.h"
-
-
-
void OIIC_delay(int t)
-
{
-
while(t>0)
-
{
-
t-=2;//adjustable
-
}
-
}
-
-
void OIIC_init()
-
{
-
/*
-
initialize handware
-
*/
-
gpio_init(PTE24,GPO,1);
-
gpio_init(PTE25,GPO,1);
-
port_init_NoALT(PTE24,ODO|PULLUP);//openDrain and pullUp
-
port_init_NoALT(PTE25,ODO|PULLUP);
-
-
-
OSCL_H();
-
OSDA_H();
-
}
-
-
void OIIC_start()
-
{
-
OSCL_H();
-
OIIC_delay(1000);
-
OSDA_L();
-
OIIC_delay(1000);
-
OSCL_L();//wait for data
-
OIIC_delay(1000);
-
//OSDA_H();
-
//OIIC_delay(1000);
-
}
-
-
void OIIC_stop()
-
{
-
OSDA_L();
-
OIIC_delay(1000);
-
OSCL_H();
-
OIIC_delay(1000);
-
OSDA_H();
-
OIIC_delay(1000);
-
}
-
void OIIC_waitForResponse()
-
{
-
int i=0;
-
OSDA_H();
-
OIIC_delay(1000);
-
OSCL_H();
-
OSDA_IN();
-
while(OSDA_V()&&i<255){i+=1;}
-
OIIC_delay(1000);//can be removed
-
OSDA_OUT();
-
OSCL_L();
-
OIIC_delay(1000);
-
-
}
-
void OIIC_response()
-
{
-
OSDA_L();
-
OIIC_delay(1000);
-
OSCL_H();
-
OIIC_delay(1000);
-
OSCL_L();
-
OIIC_delay(1000);
-
OSDA_H();
-
OIIC_delay(100);
-
}
-
void OIIC_noResponse()
-
{
-
OSDA_H();//NACK
-
OIIC_delay(1000);
-
OSCL_H();
-
OIIC_delay(1000);
-
OSCL_L();
-
OIIC_delay(1000);
-
}
-
-
void OIIC_putByteOnBus(unsigned char byte)
-
{
-
int i;
-
for(i=0;i<8;i+=1)
-
{
-
if(byte&(0x80>>i))
-
OSDA_H();
-
else
-
OSDA_L();
-
OIIC_delay(1000);
-
OSCL_H();//send data
-
OIIC_delay(1000);
-
OSCL_L();
-
OIIC_delay(1000);
-
}
-
OSDA_H();//release
-
OIIC_delay(1000);
-
}
-
unsigned char OIIC_getByteOnBus()
-
{
-
unsigned char data=0;
-
int i;
-
OSDA_H();//release SDA to get data
-
OSDA_IN();
-
OIIC_delay(1000);
-
for(i=0;i<8;i+=1)
-
{
-
OSCL_H();//to get data
-
OIIC_delay(1000);
-
if(OSDA_V())
-
data=data|(0x80>>i);
-
OSCL_L();//to refresh data
-
OIIC_delay(1000);
-
}
-
OSDA_OUT();
-
return data;
-
}
-
void OIIC_writeByte(unsigned char devAddr,unsigned char regAddr,unsigned char byte)
-
{
-
OIIC_start();
-
OIIC_putByteOnBus((devAddr<<1)|0x00);
-
OIIC_waitForResponse();
-
OIIC_putByteOnBus(regAddr);
-
OIIC_waitForResponse();
-
OIIC_putByteOnBus(byte);
-
OIIC_waitForResponse();
-
OIIC_stop();
-
}
-
void OIIC_writeWord(unsigned char devAddr,unsigned char regAddr,unsigned int word)
-
{
-
OIIC_start();
-
OIIC_putByteOnBus((devAddr<<1)|0x00);
-
OIIC_waitForResponse();
-
OIIC_putByteOnBus(regAddr);
-
OIIC_waitForResponse();
-
OIIC_putByteOnBus((word>>8)&0xff);
-
OIIC_waitForResponse();
-
OIIC_putByteOnBus(word&0xff);
-
OIIC_waitForResponse();
-
OIIC_stop();
-
}
-
void OIIC_writeBytes(unsigned char devAddr,unsigned char regAddr,unsigned char *bytes,int length)
-
{
-
int i;
-
OIIC_start();
-
OIIC_putByteOnBus((devAddr<<1)|0x00);
-
OIIC_waitForResponse();
-
OIIC_putByteOnBus(regAddr);
-
OIIC_waitForResponse();
-
for(i=0;i<length;i+=1)
-
{
-
OIIC_putByteOnBus(bytes[i]);
-
OIIC_waitForResponse();
-
}
-
OIIC_stop();
-
}
-
unsigned char OIIC_readByte(unsigned char devAddr,unsigned char regAddr)
-
{
-
unsigned char byte;
-
OIIC_start();
-
OIIC_putByteOnBus((devAddr<<1)|0x00);
-
OIIC_waitForResponse();
-
OIIC_putByteOnBus(regAddr);
-
OIIC_waitForResponse();
-
OIIC_start();
-
OIIC_putByteOnBus((devAddr<<1)|0x01);
-
OIIC_waitForResponse();
-
byte=OIIC_getByteOnBus();
-
OIIC_noResponse();
-
OIIC_stop();
-
return byte;
-
}
-
unsigned int OIIC_readWord(unsigned char devAddr,unsigned char regAddr)
-
{
-
unsigned int word=0;
-
OIIC_start();
-
OIIC_putByteOnBus((devAddr<<1)|0x00);
-
OIIC_waitForResponse();
-
OIIC_putByteOnBus(regAddr);
-
OIIC_waitForResponse();
-
OIIC_start();
-
OIIC_putByteOnBus((devAddr<<1)|0x01);
-
OIIC_waitForResponse();
-
word=OIIC_getByteOnBus()<<8;
-
OIIC_response();
-
word|=OIIC_getByteOnBus();
-
OIIC_noResponse();
-
OIIC_stop();
-
return word;
-
}
-
void OIIC_readBytes(unsigned char devAddr,unsigned char regAddr,unsigned char *bytes,int length)
-
{
-
int i;
-
OIIC_start();
-
OIIC_putByteOnBus((devAddr<<1)|0x00);
-
OIIC_waitForResponse();
-
OIIC_putByteOnBus(regAddr);
-
OIIC_waitForResponse();
-
OIIC_start();
-
OIIC_putByteOnBus((devAddr<<1)|0x01);
-
OIIC_waitForResponse();
-
for(i=0;i<length;i+=1)
-
{
-
bytes[i]=OIIC_getByteOnBus();
-
if(i==length-1)
-
OIIC_noResponse();
-
else
-
OIIC_response();
-
}
-
OIIC_stop();
-
}
---------------------------------------------------------------------------------------------
注意:
以上代码已被我无情抛弃,因为没有采用面向对象的编程方式,导致无法实例化多个i2c设备,故重新实现了一套,命名为universal_i2c,可以跑在任何单片机上,欢迎使用,多多提issue。
github传送门:
阅读(6439) | 评论(4) | 转发(0) |