目录
I2C时序结构
I2C代码
AT24C02代码(继承I2C底层代码)
PCF8591
PCB上线的长短可能影响数据传输的时间,写I2C时序可能就要加一点延时
I2C时序结构
- 起始条件:SCL高电平期间,SDA从高电平切换到低电平
- 终止条件:SCL高电平期间,SDA从低电平切换到高电平
发送一个字节:SCL低电平期间,主机将数据位依次放到SDA线上(高位在前),然后拉高SCL,从机将在SCL高电平期间读取数据位,素有SCL高电平期间SDA不允许有数据变化,依次循环上述过程8次,即可发送一个字节
接收一个字节:SCL低电平期间,从机将数据位依次放到SDA线上(高位在前),然后拉高SCL,主机将在SCL高电平期间读取数据位,所以SCL高电平期间SDA不允许有数据变化,依次循环上述过程8次,即可接收一个字节(主机在接收之前,需要释放SDA)
- 发送应答:在接收完一个字节之后,主机在下一个时钟发送一位数据,数据0表示应答,数据1表示非应答
- 接收应答:在发送完一个字节之后,主机在下一个时钟接收一位数据,判断从机是否应答,数据0表示应答,数据1表示非应答(主机在接收前,需要释放SDA)
I2C代码
#include "I2C.h"
//15开发板中AT24C02的IIC通信引脚
sbit I2C_SDA = P2^1;
sbit I2C_SCL = P2^0;
/**
* @brief I2C起始信号
* @param 无
* @retval 无
*/
void I2C_Start(void)
{
I2C_SDA = 1; //拼接其他块,确保默认是1
I2C_SCL = 1;
I2C_SDA = 0; //时序上先拉低
I2C_SCL = 0;
}
/**
* @brief I2C停止信号
* @param 无
* @retval 无
*/
void I2C_Stop(void)
{
I2C_SDA = 0; //确保默认0,保证由低电平拉高至高电平
I2C_SCL = 1;
I2C_SDA = 1;
}
/**
* @brief I2C发送一个字节数据
* @param Byte 要发送的字节
* @retval 无
*/
void I2C_SendByte(unsigned char Byte)
{
unsigned char i;
// I2C_SCL = 0; //起始信号已经拉低了,无需重复
for (i = 0; i < 8; i ++)
{
I2C_SDA = Byte & (0x80>>i); //把Byte最高位取出,赋值给I2C_SDA,依次从高到底
I2C_SCL = 1;
// _nop_();_nop_();_nop_();_nop_();_nop_();//需要0.4us
I2C_SCL = 0;
}
}
/**
* @brief I2C接收一个字节数据
* @param 无
* @retval 接受到的一个字节数据
*/
unsigned char I2C_ReceiveByte(void)
{
unsigned char i,Byte=0x00;
I2C_SDA = 1; //接收之前,先把I2C_SDA置1,释放总线
for(i=0;i<8;i++)
{
I2C_SCL = 1; //拉高SCL,SCL读取SDA
if(I2C_SDA == 1){Byte |= (0x80>>i);}
/*如果读取到的SDA为1,把Byte最高位置1,如果读取到的SDA为0,不处理,默认最高位为0,放在循环里从高位到低位依次读取*/
I2C_SCL = 0; //拉低SCL,结束当前循环
}
return Byte;
}
/**
* @brief I2C发送应答
* @param AckBit 应答位,0为应答,1为非应答
* @retval 无
*/
void I2C_SendAck(unsigned char AckBit)
{
I2C_SDA = AckBit;//给应答就是0,不给应答就是1
I2C_SCL = 1;
I2C_SCL = 0;
}
/**
* @brief I2C接收应答
* @param 无
* @retval 接收到的应答位,0为应答,1为非应答
*/
unsigned char I2C_ReceiveAck(void)
{
unsigned char AckBit;
I2C_SDA = 1; //先释放SDA
I2C_SCL = 1; //高电平期间读取SDA
AckBit=I2C_SDA; //读取到什么,就返回什么
I2C_SCL = 0;
return AckBit; //返回0,代表有应答,返回1,代表无应答
}
#ifndef __I2C_H__
#define __I2C_H__
#include <STC15F2K60S2.H>
#include "intrins.h"
void I2C_Start(void);
void I2C_Stop(void);
void I2C_SendByte(unsigned char Byte);
unsigned char I2C_ReceiveByte(void);
void I2C_SendAck(unsigned char AckBit);
unsigned char I2C_ReceiveAck(void);
#endif
AT24C02设备地址:
A2A1A0这三个引脚是用来扩展的,如果不用就默认是000
所以默认设备地址是10100000(0xA0 写数据),10100001(0xA1 读数据)
AT24C02代码(继承I2C底层代码)
#include "AT24C02.h"
#define AT24C02_ADDRESS 0xA0 //从机地址+写 1010 0000
/**
*@brief 名称:AT24C02写入一个字节
*@param 参数:WordAddess 要写入字节的地址(0~255)
*@param 参数: Data 要写入的数据
*@retval返回值:无
*/
void AT24C02_WriteByte(unsigned char WordAddress, unsigned char Data)
{
// unsigned char Ack;
I2C_Start();
I2C_SendByte(AT24C02_ADDRESS);//从机地址+写
// Ack = I2C_ReceiveAck();
// if(Ack == 0)
// {
// P2 = 0x80; // 1000 0000
// P0 = 0x00;
// } //先测试是否有应答,定义的Ack被I2C_ReceiveAck();赋值,然后就可以测试了
I2C_ReceiveAck();
I2C_SendByte(WordAddress); //要写入数据的地址
I2C_ReceiveAck();
I2C_SendByte(Data); //写入数据
I2C_ReceiveAck();
I2C_Stop();
}
/**
*@brief 名称:AT24C02读取一个字节
*@param 参数:WordAddess 要读出字节的地址
*@retval返回值:读出的数据
*/
unsigned char AT24C02_ReadByte(unsigned char WordAddess)
{
unsigned char Data;
I2C_Start();
I2C_SendByte(AT24C02_ADDRESS); //从机地址+写
I2C_ReceiveAck(); //接受应答
I2C_SendByte(WordAddess); //数据的地址
I2C_ReceiveAck();
I2C_Start();
I2C_SendByte(AT24C02_ADDRESS | 0x01);//发送从机地址+读本函数第二个函数,或上0x01变成读地址(0xA1)
I2C_ReceiveAck();
Data = I2C_ReceiveByte();
I2C_SendAck(1); //不发送应答
I2C_Stop();
return Data;
}
#ifndef __AT24C02_H__
#define __AT24C02_H__
#include <STC15F2K60S2.H>
#include "I2C.h"
void AT24C02_WriteByte(unsigned char WordAddress, unsigned char Data);
unsigned char AT24C02_ReadByte(unsigned char WordAddress);
#endif
测试:先写入,不读取,然后下载只读取的函数,如果读出数值没有问题,那就正确了
#include <STC15F2K60S2.H>
#include "smg.h"
#include "I2C.h"
#include "AT24C02.h"
unsigned char Data;
void main()
{
All_Init();
AT24C02_WriteByte(0,88);
Delay_ms(5); //写数据的周期 5ms
Data = AT24C02_ReadByte(0);
while(1)
{
Nixie(1,Data/10);
Nixie(2,Data%10);
}
}
PCF8591
PCF8591地址:1001 0000(0x90 写),1001 0001(0x91 读)
支持四路AD转换(模拟信号转数字信号),支持一路DA转换(数字信号转模拟信号)
程序有问题,不粘贴了,调成功了在粘贴过来
学习资料:
江科大自化协---51单片机入门教程-2020版 程序全程纯手打 从零开始入门【12-2】