IIC简介
IIC总线系统架构
IIC是(串行、半双工(一条数据线)、同步)的通信。
引脚配置
因为是一条数据线,又需要输入和输出数据
SCL,SDA可以配置成推挽输出、开漏输出(上拉电阻输出1)(GPIO_Init)
当配置为开漏输出时需要线上有上拉电阻,才可以输出高电平。
然后再配置IO口的输入与输出。
//PB0设置为输入或输出
#define SDA_IN() {GPIOB->CRL&=0XFFFFFFF0,GPIOB->CRL|=8<<0;} // io设置为输入模式
#define SDA_OUT() {GPIOB->CRL&=0XFFFFFFF0,GPIOB->CRL|=3<<0;} //输出模式
通信协议
空闲位
SDA和SCL两条信号线同时处于高电平。
起始位与停止位
数据有效性 // (应答、数据传输)
SDA低电平:应答
SDA高电平:非应答
应答信号
代码示例
i2c.h 文件
#ifndef I2C_H
#define I2C_H
#include "stm32f10x.h"
#include "sys.h"
//PB9 SDA
//PB8 SCL
//SDA设置为输入、输出
#define SDA_IN() {GPIOB->CRH &=~0XF0;GPIOB->CRH|=0X80;}
#define SDA_OUT() {GPIOB->CRH &=~0XF0;GPIOB->CRH|=0X30;}
//IO操作函数
#define IIC_SCL PBout(8) //SCL
#define IIC_SDA PBout(9) //SDA
#define READ_SDA PBin(9) //输入SDA
//IIC所有操作函数
void IIC_Init(void); //初始化IIC的IO口
void IIC_Start(void); //发送IIC开始信号
void IIC_Stop(void); //发送IIC停止信号
void IIC_Send_Byte(u8 txd); //IIC发送一个字节
u8 IIC_Read_Byte(unsigned char ack);//IIC读取一个字节
u8 IIC_Wait_Ack(void); //IIC等待ACK信号
void IIC_Ack(void); //IIC发送ACK信号
void IIC_NAck(void); //IIC不发送ACK信号
void IIC_Write_One_Byte(u8 daddr,u8 addr,u8 data);
void IIC_Read_One_Byte(u8 daddr,u8 addr,u8* data);
void IIC_WriteBytes(u8 WriteAddr,u8* data,u8 dataLength);
void IIC_ReadBytes(u8 deviceAddr, u8 writeAddr,u8* data,u8 dataLength);
#endif
以下为 i2c.c 文件
//初始化IIC
void IIC_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOB, ENABLE );
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9|GPIO_Pin_8;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP ; //推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
IIC_SCL=1;
IIC_SDA=1;
}
/*
起始信号
在SCL和SDA都是高电平时,SDA由高变低
*/
void IIC_Start(void)
{
SDA_OUT(); //sda线输出
IIC_SDA=1;
IIC_SCL=1;
delay_us(4);
IIC_SDA=0;//START:when CLK is high,DATA change form high to low
delay_us(4);
IIC_SCL=0;//钳住I2C总线,准备发送或接收数据
}
/*
停止信号
在SCL是高电平时,SDA由低变高
*/
void IIC_Stop(void)
{
SDA_OUT();//sda线输出
IIC_SCL=0;
IIC_SDA=0;//STOP:when CLK is high DATA change form low to high
delay_us(4);
IIC_SCL=1;
IIC_SDA=1;//发送I2C总线结束信号
delay_us(4);
}
/*
应答信号
在SCL由低到高在到低,这个周期期间,当SDA为低电平时,表示应答
*/
void IIC_Ack(void)
{
IIC_SCL=0;
SDA_OUT();
IIC_SDA=0;
delay_us(2);
IIC_SCL=1;
delay_us(2);
IIC_SCL=0;
}
/*
非应答信号
在SCL由低到高在到低,这个周期期间,当SDA为高电平时,表示非应答
*/
void IIC_NAck(void)
{
IIC_SCL=0;
SDA_OUT();
IIC_SDA=1;
delay_us(2);
IIC_SCL=1;
delay_us(2);
IIC_SCL=0;
}
/*
等待应答信号
主机在SCLL高电平期间,判断SDA状态
从机反馈应答信号到数据线,单片机与从机之间是一条数据线,半双工,即判断SDA引脚状态即可
返回值:1:接收应答成功
0:接收应答失败
*/
u8 IIC_Wait_Ack(void)
{
u8 ucErrTime=0;
SDA_IN(); //SDA设置为输入
IIC_SDA=1;delay_us(1);
IIC_SCL=1;delay_us(1);
while(READ_SDA)
{
ucErrTime++;
if(ucErrTime>250)
{
IIC_Stop();
return 1;
}
}
IIC_SCL=0;//时钟输出0
return 0;
}
/*
发送一个字节(8位),(发送一位数据,是0或1)
*/
void IIC_Send_Byte(u8 txd)
{
u8 t;
SDA_OUT();
IIC_SCL=0;//拉低时钟开始数据传输
for(t=0;t<8;t++)
{
IIC_SDA=(txd&0x80)>>7;
txd<<=1;
delay_us(2); //对TEA5767这三个延时都是必须的
IIC_SCL=1;
delay_us(2);
IIC_SCL=0;
delay_us(2);
}
}
/*
读一个字节(8位),按位读取
*/
u8 IIC_Read_Byte(unsigned char ack)
{
unsigned char i,receive=0;
SDA_IN();//SDA设置为输入
for(i=0;i<8;i++ )
{
IIC_SCL=0;
delay_us(2);
IIC_SCL=1;
receive<<=1;
if(READ_SDA)receive++;
delay_us(1);
}
if (!ack)
IIC_NAck();//发送nACK
else
IIC_Ack(); //发送ACK
return receive;
}