本博客大部分参考了其它人的文章,仅用来学习存储,知识积累
第一次写博客,主要是将自己自学的一点东西记下来,与其做笔记,不如写博客。这几天看了I2C协议,这是大部分芯片必用的协议,花了几天时间,找了很多资料,终于有所悟,我来分享给大家。
读时序:
无应答信号:第9个时钟不拉低SDA。注意,在一次读取多个字节的时候,最后一个字节应该不应答,直接stop,否则出错,实测。
整个流程如下:
主机发出起始信号->写7位从机地址+1位写信号->等从机应答->写寄存器地址->等从机应答->主机发出起始信号->写7位从机地址+1位读信号->等从机应答->读字节->发出应答信号->…->读字节->无应答->主机发出停止信号
注意几点:
1、 i2c总线在硬件上,应该保证线与,即一条线上有一个位低,那么整条线就为低。解决办法就是挂载在总线上的设备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;i1)
{
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;i1)
{
bytes[i]=OIIC_getByteOnBus();
if(i==length-1)
OIIC_noResponse();
else
OIIC_response();
}
OIIC_stop();
}
备注:本博主致力于嵌入式开发,I2C协议,欢迎大神纠错!