一.IIC简介
两根通信线:SCL(Serial Clock)串行时钟线、SDA(Serial Data)串行数据线
同步,半双工
带数据应答
支持总线挂载多设备(一主多从、多主多从)
相同芯片挂载在同一个总线,需要用到器件地址的可变部分,一般器件的最后几位是在电路中可变的,一般由器件引脚确定
二.硬件电路
主机有对SCL的绝对控制权,所以SCL端口配置成推挽输出,从机的SCL就是接收引脚配置成浮空或者上拉输入。
因为是半双工的,SDA在发送的时候是输出,在接收的时候是输入,从机也是如此。为了避免总线没有协调好导致两边都输入高电平,所以IIC禁止所有的设备输出强上拉的,而是采用外置弱上拉电阻,设置成开漏输出。
三.I2C时序基本单元
发送数据
低电平主机放数据,高电平从机读数据
接收数据
主机要先释放SDA,切换成从机发送,
低电平从机放数据,高电平主机读数据
应答机制
四.IIC时序
主机是发送应答,从机是接收应答
指定地址写
当前地址读 指定地址读
sr相当于另外取一个时序,从头开始,等于是两条时序拼接成一条。
多个数据的指定地址写
指定地址写是写入了一个字节
指定位置开始读多个数据
皇帝点妃模式:皇帝想接着,就会给应答,不想继续就不给应答,控制权返还给皇帝。
五.模拟实现IIC时序
#include "stm32f10x.h" // Device header
#include "Delay.h"
void MyIIC_W_SCL(uint8_t BitValue)
{
GPIO_WriteBit(GPIOB,GPIO_Pin_10,(BitAction)BitValue);
Delay_ms(10);
}
void MyIIC_W_SDA(uint8_t BitValue)
{
GPIO_WriteBit(GPIOB,GPIO_Pin_11,(BitAction)BitValue);
Delay_ms(10);
}
uint8_t MyIIC_R_SDA()
{
uint8_t BitValue;
BitValue=GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_11);
Delay_ms(10);
return BitValue;
}
void MyIIC_Init()
{
//把SCL SDA初始化成开漏输出
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_OD;
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_10|GPIO_Pin_11;
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOB,&GPIO_InitStructure);
GPIO_SetBits(GPIOB,GPIO_Pin_10|GPIO_Pin_11);//SCL SDA为高电平,此时IIC处于空闲
}
void MyIIC_Start()
{
//先将SCL和SDA都释放,就是同时置高电平
MyIIC_W_SDA(1);//SDA置高电平(为了跟后面的重复条件做区分)
MyIIC_W_SCL(1);//SCL置高电平
MyIIC_W_SDA(0);//先拉低SDA
MyIIC_W_SCL(0);//再拉低SCL
}
void MyIIC_Stop()
{
//如果SCL和SDA都是低电平,那就先释放SCL,再释放SDA
//但是SDA不一定是低电平,所以要先拉低SDA,再释放SCL,SDA
//终止条件后SCL和SDA都回归高电平,除了终止条件SCL以高电平接收,其他都是低电平
MyIIC_W_SDA(0);//先拉低SDA
MyIIC_W_SCL(1);//SCL置高电平
MyIIC_W_SDA(1);//先拉低SDA
}
void MyIIC_SendByte(uint8_t Byte)
{
MyIIC_W_SDA(Byte&0x80);//取出数据的1000 0000位
MyIIC_W_SCL(1);//SCL拉高
MyIIC_W_SCL(0);//SCL拉低
MyIIC_W_SDA(Byte&0x40);//取出数据的0100 0000位
MyIIC_W_SCL(1);//SCL拉高
MyIIC_W_SCL(0);//SCL拉低
MyIIC_W_SDA(Byte&0x20);//取出数据的0010 0000位
MyIIC_W_SCL(1);//SCL拉高
MyIIC_W_SCL(0);//SCL拉低
MyIIC_W_SDA(Byte&0x10);//取出数据的0001 0000位
MyIIC_W_SCL(1);//SCL拉高
MyIIC_W_SCL(0);//SCL拉低
MyIIC_W_SDA(Byte&0x08);//取出数据的0000 1000位
MyIIC_W_SCL(1);//SCL拉高
MyIIC_W_SCL(0);//SCL拉低
MyIIC_W_SDA(Byte&0x04);//取出数据的0000 0100位
MyIIC_W_SCL(1);//SCL拉高
MyIIC_W_SCL(0);//SCL拉低
MyIIC_W_SDA(Byte&0x02);//取出数据的0000 0010位
MyIIC_W_SCL(1);//SCL拉高
MyIIC_W_SCL(0);//SCL拉低
MyIIC_W_SDA(Byte&0x01);//取出数据的0000 0001位
MyIIC_W_SCL(1);//SCL拉高
MyIIC_W_SCL(0);//SCL拉低
//for(uint8_t i=0;i<8;i++)
//{
// MyIIC_W_SDA(Byte&(0x80>>i));//取出数据的0000 1000位
// MyIIC_W_SCL(1);//SCL拉高
// MyIIC_W_SCL(0);//SCL拉低
//}
}
uint8_t MyIIC_ReceiveByte()
{
uint8_t Byte=0x00;
MyIIC_W_SDA(1);//从机接收之前要先置高
for(uint8_t i=0;i<8;i++)
{
MyIIC_W_SCL(1);//SCL拉高接收从机数据
if(MyIIC_R_SDA()==1)//如果读取到是高电平
{
Byte|=(0x80>>i);//把Byte最高位置1
}
MyIIC_W_SCL(0);
}
return Byte;
}
//发送应答是发送的简化版,只用发移位就可以了
void MyIIC_SendAck(uint8_t AckBit)
{
MyIIC_W_SDA(AckBit);
MyIIC_W_SCL(1);//SCL拉高
MyIIC_W_SCL(0);//SCL拉低
}
uint8_t MyIIC_ReceiveAck()
{
uint8_t AckBit;
MyIIC_W_SDA(1);//从机接收之前要先置高
MyIIC_W_SCL(1);//SCL拉高接收从机数据
AckBit=MyIIC_R_SDA();//读取到应答信号
MyIIC_W_SCL(0);//SCL拉高接收从机数据
return AckBit;
}
六.硬件实现IIC
STM32内部集成了硬件I2C收发电路,可以由硬件自动执行时钟生成、起始终止条件生成、应答位收发、数据收发等功能,减轻CPU的负担
支持多主机模型
支持7位/10位地址模式
支持不同的通讯速度,标准速度(高达100 kHz),快速(高达400 kHz)
支持DMA
兼容SMBus协议
STM32F103C8T6 硬件I2C资源:I2C1、I2C2