IIC程序设计
IIC基本原理
多主机IIC总线系统结构
IIC是两线式串行总线,这两个总线分别是数据线SDA和时钟线SCL。可以发送和接收数据。在CPU与被控IC之间、IC与IC之间进行双向传输,高速的IIC总线一般可达到400Kbps以上。IIC是半双工通信,即同一时间只能接收或发送。
IIC总线结构图如下所示:
首先要对IIC进行初始化,实现代码如下所示:
void I2CInit(void)
{
GPIO_InitTypeDef GPIO_InitStructure = {0};
GPIO_InitStructure.Pin = GPIO_PIN_7 | GPIO_PIN_6;
GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStructure.Pull = GPIO_PULLUP;
GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOB, &GPIO_InitStructure);
}
开始/停止信息
当SCL保持高电平时,SDA由高电平变为低电平,此时即为开始条件。
当SCL保持高电平时,SDA由低电平变为高电平,此时即为停止条件。
两个条件如下图所示:
实现此功能的程序如下所示:
void I2CStart(void)//IIC开始信号
{
SDA_Output(1);
delay1(DELAY_TIME);
SCL_Output(1);
delay1(DELAY_TIME);
SDA_Output(0);
delay1(DELAY_TIME);
SCL_Output(0);
delay1(DELAY_TIME);
}
void I2CStop(void)//IIC结束信号
{
SCL_Output(0);
delay1(DELAY_TIME);
SDA_Output(0);
delay1(DELAY_TIME);
SCL_Output(1);
delay1(DELAY_TIME);
SDA_Output(1);
delay1(DELAY_TIME);
}
应答信号ACK
发送器每次发送一个字节,就在时钟脉冲期间释放数据线,由接收器反馈一个应答信号。如果应答信号为低电平时,规定为有效应答位(ACK),表示接收器已经成功接收了这个字节;如果应答信号为高电平,规定为非应答位(NACK),一般表示接收器没有成功接收这个字节。
应答时序图如下所示:
对应的应答信号ACK代码如下所示:
unsigned char I2CWaitAck(void)
{
unsigned short cErrTime = 5;
SDA_Input_Mode();
delay1(DELAY_TIME);
SCL_Output(1);
delay1(DELAY_TIME);
while(SDA_Input())
{
cErrTime--;
delay1(DELAY_TIME);
if (0 == cErrTime)
{
SDA_Output_Mode();
I2CStop();
return ERROR;
}
}
SCL_Output(0);
delay1(DELAY_TIME);
SDA_Output_Mode();
return SUCCESS;
}
数据信息
一个数据位在每一个时钟脉冲期间传输。SDA线上的数据必须在时钟脉冲的高电平期间保持稳定,这个期间数据线上的改变被当作控制信号。
时序图如下所示:
实现代码如下所示:
/**
* @brief I2C发送一个字节
* @param cSendByte 需要发送的字节
* @retval None
*/
void I2CSendByte(unsigned char cSendByte)
{
unsigned char i = 8;
while (i--)
{
SCL_Output(0);
delay1(DELAY_TIME);
SDA_Output(cSendByte & 0x80);
delay1(DELAY_TIME);
cSendByte += cSendByte;
delay1(DELAY_TIME);
SCL_Output(1);
delay1(DELAY_TIME);
}
SCL_Output(0);
delay1(DELAY_TIME);
}
空闲状态
IIC总线的SDA和SCL两条信号线同时处于高电平时,规定为总线的空闲状态。这两条信号线各自的上拉电阻把他们的电平拉高。
24C02存储器基本原理
概述与特点
24C02是低工作电压的2K位串行电可擦除只读存储器,内部组织为256个字节(每个字节八位)。
24C02的芯片地址为1010(A2 A1 A0)(R =1,W=0)
0xa0写
0xa1读
主要特性
原理图
结构框图
AT24C02存储器内部进行页的读写时,不可以产生跨页的现象???
写操作时序
void iic_24c02_write(unsigned char *pucBuf,unsigned char ucAddr,unsigned char ucNum)
{
I2CStart();
I2CSendByte(0xa0);
I2CWaitAck();
I2CSendByte(ucAddr);
I2CWaitAck();
while(ucNum--)
{
I2CSendByte(*pucBuf++);
I2CWaitAck();
}
I2CStop();
delay1(500);
}
读操作时序
void iic_24c02_read(unsigned char *pucBuf,unsigned char ucAddr,unsigned char ucNum)
{
I2CStart();
I2CSendByte(0xa0);
I2CWaitAck();
I2CSendByte(ucAddr);
I2CWaitAck();
I2CStart();
I2CSendByte(0xa1);
I2CWaitAck();
while(ucNum--)
{
*pucBuf++ =I2CReceiveByte();
if(ucNum)
{
I2CSendAck();
}
else
{
I2CSendNotAck();
}
}
I2CStop();
}
MCP4017可编程电阻原理
原理图
写进去的一个数字(0-127),读出来也是一个数字
转化为电阻阻值:R = 787.4 * read_resistor 欧
电压:3.3*(R/(R+10)) (假设外接的电压为3.3)
MCP4017写程序
void write_resistor(uint8_t value)
{
I2CStart();
I2CSendByte(0x5e);
I2CWaitAck();
I2CSendByte(value);
I2CWaitAck();
I2CStop();
}
MCP4017读程序
uint8_t read_resistor(void)
{
uint8_t value;
I2CStart();
I2CSendByte(0x5F);
I2CWaitAck();
value = I2CReceiveByte();
I2CSendNotAck();
I2CStop();
return value;
}