这篇总结下IIC协议
简介
- IIC,Inter-Integrated Circuit,集成电路总线,需要2根线连接拓扑,是半双工,适用于"字节型"设备。
特点
- 拓扑如下:
SDA — 串行数据线
SCL — 串行时钟线 - 通讯速率标准模式下100kb/s,快速模式下400kb/s
- 连接到总线的IC最大负载电容400pf
- 需要上拉电阻
原因:
- 总线空闲时要求是高电平
- IIC的数据线SDA是开漏的,无法输出高电平,只能输出低电平
- 起到保护作用,如果某个器件拉低,并且不接上拉电阻就电源-地短路了
- 对于不明确负载,IC不能很大的保证输出功率,接上拉电阻则负载所需功率由电源提供,保护IC
- 上拉电阻选取见下面这篇文章关于IIC的上拉电阻
时序
- 开始信号、结束信号
在SCL为高电平时,SDA由高跳变到低时开始信号
在SCL为高电平时,SDA由低跳变到高时开始信号 - 有效数据
传输有效数据时SDA只能在SCL为低时发生变化,SCL为高时要保持不变,否则就成的开始结束信号 - 应答、非应答
主机每发生一个字节数据,主机总是需要等待从机给主机反馈一个应答或者非应答信号,确保数据是否接收。在SCL第9个脉冲时之前把SDA设置为输入,检测SDA,为低是应答信号,为高则是非应答信号。
下面是用IO模拟的iic
#include "myiic.h"
uint16_t SlaveAddr;
uint8_t SlaveAddrLen=1;
uint16_t SubAddr;
uint8_t SubAddrLen=2;
uint8_t IICReadBuf[IIC_SIZE]={0};
uint8_t IICWriteBuf[IIC_SIZE]={0};
uint16_t IICLen;
void SDA_IN(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = IIC_SDA_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;
GPIO_InitStructure.GPIO_OType = GPIO_OType_OD;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(IIC_GPIO, &GPIO_InitStructure);
}
void SDA_OUT(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = IIC_SDA_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitStructure.GPIO_OType = GPIO_OType_OD;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(IIC_GPIO, &GPIO_InitStructure);
}
void IIC_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9 | GPIO_Pin_10;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitStructure.GPIO_OType = GPIO_OType_OD;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(IIC_GPIO, &GPIO_InitStructure);
IIC_SCL_H;
IIC_SDA_H;
}
void IIC_close(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9 | GPIO_Pin_10;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_Init(IIC_GPIO, &GPIO_InitStructure);
IIC_SCL_H;
IIC_SDA_H;
}
uint8_t IIC_Start(void)
{
SDA_OUT();
IIC_SDA_H;
IIC_SCL_H;
delay_us(5);
if(!READ_SDA) return 1;
IIC_SDA_L;
delay_us(5);
if(READ_SDA) return 1;
IIC_SCL_L;
return 0;
}
void IIC_Stop(void)
{
SDA_OUT();
IIC_SCL_L;
IIC_SDA_L;
delay_us(5);
IIC_SCL_H;
delay_us(5);
IIC_SDA_H;
delay_us(5);
}
uint8_t IIC_Wait_Ack(void)
{
uint8_t ucErrTime=0;
SDA_IN();
IIC_SDA_H;delay_us(1);
IIC_SCL_H;delay_us(1);
while(READ_SDA)
{
ucErrTime++;
delay_us(1);
if(ucErrTime>250)
{
IIC_Stop();
return 1;
}
}
IIC_SCL_L;
return 0;
}
void IIC_Ack(void)
{
IIC_SCL_L;
SDA_OUT();
delay_us(3);
IIC_SDA_L;
delay_us(3);
IIC_SCL_H;
delay_us(3);
IIC_SCL_L;
delay_us(3);
}
void IIC_NAck(void)
{
IIC_SCL_L;
SDA_OUT();
delay_us(3);
IIC_SDA_H;
delay_us(3);
IIC_SCL_H;
delay_us(3);
IIC_SCL_L;
delay_us(3);
}
void IIC_Send_Byte(uint8_t txd)
{
uint8_t t;
SDA_OUT();
IIC_SCL_L;
for(t=0;t<8;t++)
{
if(((txd&0x80)>>7)){IIC_SDA_H;}
else {IIC_SDA_L;}
txd<<=1;
delay_us(2);
IIC_SCL_H;
delay_us(4);
IIC_SCL_L;
delay_us(2);
}
}
uint8_t IIC_Read_Byte(unsigned char ack)
{
unsigned char i,receive=0;
SDA_IN();
IIC_SCL_L;
for(i=0;i<8;i++ )
{
IIC_SCL_L;
delay_us(4);
IIC_SCL_H;
receive<<=1;
if(READ_SDA)receive++;
delay_us(4);
}
if (!ack)
IIC_Ack();
else
IIC_NAck();
return receive;
}
uint8_t IIC_WriteDate(uint8_t SlaveAddr,uint16_t SubAddr,uint8_t *pWriteData,uint16_t Len)
{
uint16_t i=0;
IIC_Start();
if(SlaveAddrLen==2)
{
IIC_Send_Byte(((SlaveAddr&0xFF00)>>8));
if(IIC_Wait_Ack()==1) return 1;
delay_us(30);
}
IIC_Send_Byte(SlaveAddr&0x00FE);
if(IIC_Wait_Ack()==1) return 1;
delay_us(30);
if(SubAddrLen==2)
{
IIC_Send_Byte(((SubAddr&0xFF00)>>8));
if(IIC_Wait_Ack()==1) return 1;
delay_us(30);
}
IIC_Send_Byte((SubAddr&0x00FF));
if(IIC_Wait_Ack()==1) return 1;
delay_us(30);
for(i=0;i<Len;i++)
{
IIC_Send_Byte((pWriteData[i]));
if(IIC_Wait_Ack()==1) return 1;
delay_us(30);
}
IIC_Stop();
return 0;
}
uint8_t IIC_ReadDate(uint8_t SlaveAddr,uint16_t SubAddr,uint8_t *pReadData,uint16_t Len)
{
uint8_t i=0;
if(IIC_Start()==1) return 1;
if(SlaveAddrLen==2)
{
IIC_Send_Byte(((SlaveAddr&0xFF00)>>8));
if(IIC_Wait_Ack()==1) return 1;
delay_us(30);
}
IIC_Send_Byte(SlaveAddr&0x00FE);
if(IIC_Wait_Ack()==1) return 1;
delay_us(30);
if(SubAddrLen==2)
{
IIC_Send_Byte(((SubAddr&0xFF00)>>8));
if(IIC_Wait_Ack()==1) return 1;
delay_us(30);
}
IIC_Send_Byte((SubAddr&0x00FF));
if(IIC_Wait_Ack()==1) return 1;
delay_us(30);
IIC_Start();
if(SlaveAddrLen==2)
{
IIC_Send_Byte(((SlaveAddr&0xFF00)>>8));
if(IIC_Wait_Ack()==1) return 1;
delay_us(30);
}
IIC_Send_Byte(((SlaveAddr&0x00FE)|0x01));
if(IIC_Wait_Ack()==1) return 1;
delay_us(30);
for(i=0;i<(Len-1);i++)
{
pReadData[i]=IIC_Read_Byte(0);
delay_us(30);
}
pReadData[Len-1]=IIC_Read_Byte(1);
delay_us(30);
IIC_Stop();
return 0;
}
uint8_t IIC_StateCheck(uint8_t SlaveAddr)
{
if(IIC_Start()==1){IIC_Stop();return 1;}
if(SlaveAddrLen==2)
{
IIC_Send_Byte(((SlaveAddr&0xFF00)>>8));
if(IIC_Wait_Ack()==1) {IIC_Stop(); return 1;}
delay_us(30);
}
IIC_Send_Byte(SlaveAddr&0x00FE);
if(IIC_Wait_Ack()==1) {IIC_Stop(); return 1;}
delay_us(30);
IIC_Stop();
return 0;
}
#ifndef __MYIIC_H
#define __MYIIC_H
#include "stm32f0xx.h"
#include "delay.h"
#define IIC_GPIO GPIOA
#define IIC_SCL_PIN GPIO_Pin_9
#define IIC_SDA_PIN GPIO_Pin_10
#define IIC_SIZE 128
extern uint16_t SlaveAddr;
extern uint8_t SlaveAddrLen;
extern uint16_t SubAddr;
extern uint8_t SubAddrLen;
extern uint8_t IICReadBuf[IIC_SIZE];
extern uint8_t IICWriteBuf[IIC_SIZE];
extern uint16_t IICLen;
#define IIC_SCL_L GPIO_WriteBit(IIC_GPIO,IIC_SCL_PIN,(BitAction)0)
#define IIC_SCL_H GPIO_WriteBit(IIC_GPIO,IIC_SCL_PIN,(BitAction)1)
#define IIC_SDA_L GPIO_WriteBit(IIC_GPIO,IIC_SDA_PIN,(BitAction)0)
#define IIC_SDA_H GPIO_WriteBit(IIC_GPIO,IIC_SDA_PIN,(BitAction)1)
#define READ_SDA GPIO_ReadInputDataBit(IIC_GPIO, IIC_SDA_PIN)
#define READ_SCL GPIO_ReadInputDataBit(IIC_GPIO, IIC_SCL_PIN))
void IIC_Init(void);
uint8_t IIC_Start(void);
void IIC_Stop(void);
void IIC_Send_Byte(uint8_t txd);
uint8_t IIC_Read_Byte(unsigned char ack);
uint8_t IIC_Wait_Ack(void);
void IIC_Ack(void);
void IIC_NAck(void);
uint8_t IIC_StateCheck(uint8_t SlaveAddr);
uint8_t IIC_WriteDate(uint8_t SlaveAddr,uint16_t SubAddr,uint8_t *pWriteData,uint16_t Len);
uint8_t IIC_ReadDate(uint8_t SlaveAddr,uint16_t SubAddr,uint8_t *pReadData,uint16_t Len);
#endif
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)