一、说明
单片机IO模拟,使用E2PROM 24C02C
1. 起始信号保持时间 Thd:sta >4us
2. 起始信号的建立时间 Tsu:sta >4.7us
3. SCL低电平持续时间 Tlow >4.7us
4. SCL高电平持续时间 Thigh > 4us
5. 停止信号的建立时间 Tsu:sta > 4us
二、演示
3.代码
/**
* 8051/2 DEMO 3
* 常用的本地通讯方式
* 1. 串口UART, 波特率:9600
* 接设备的时候,一般只接GND RX TX,不会接Vcc,避免与目标设备上的供电冲突。
* 1.1 RS485标准( +2V ~ +6V:1 / -6V ~ -2V:0)
* 1.2 RS232标准( -15V ~ -3V:1 / +3V ~ +15V:0),需要MAX232进行电平反转后,才能与MCU进行通讯
* 1.3 TTL标准( 2.4V--5V:1 / 0V--0.5V:0 )
*
* 2. I2C(SCL,SDA)
* 3. SPI (SCLK,SDO,SDI) 全双工
*/
#include "REG52.H"
#include <string.h>
typedef unsigned char U8;
/**
* 2. I2C(SCL,SDA)
* P2^0 和 P2^1
*
使用E2PROM 24C02C 规定
1. 起始信号保持时间 Thd:sta >4us
2. 起始信号的建立时间 Tsu:sta >4.7us
3. SCL低电平持续时间 Tlow >4.7us
4. SCL高电平持续时间 Thigh > 4us
5. 停止信号的建立时间 Tsu:sta > 4us
**/
sbit SCL = P2^0;
sbit SDA = P2^1;
//串口初始化 - 为了打印数据用
void uart_init()
{
SCON = 0x50;
TMOD = 0x20; //选择 定时器1
//装在波特率 高8位和低8位,9600
TH1 = 0xFD;
TL1 = 0xFD;
ES = 1; //打开串口中断
TR1 = 1; //打开定时器1
EA = 1; //打开总中断
}
//发送一个字符
void uart_send_char(char str)
{
SBUF = str; //将待发送的字符串放入缓冲器
while(TI==0); //等待完发送
TI=0; // 发送中断标志 清0
}
//串口中断业务处理
void uart_handle() interrupt 4
{
}
//delay 延迟 6us , 空函数延迟为 3us 保证超过信号的所有建立时间,保证所有的信号生效
void i2c_delay(){
U8 a;
for(a=1;a>0;a--);
}
//I2C 初始化 SDA 和 SCL 高电平 ,处于空闲状态
// 说明: SCL为高电平,SDA出现从高电平 -> 低电平
void i2c_start()
{
SDA = 1;
i2c_delay();
SCL = 1;
i2c_delay();
SDA = 0;
i2c_delay();
SCL = 0;
i2c_delay();
}
//I2c 写入1字节的数据
bit i2c_write(U8 dat)
{
U8 a=0,b=0;
for(a=0;a<8;a++)//要发送8位,从最高位开始
{
SDA=dat>>7; //起始信号之后SCL=0,所以可以直接改变SDA信号
dat=dat<<1;
i2c_delay();
SCL=1;
i2c_delay();//建立时间>4.7us
SCL=0;
i2c_delay();//时间大于4us
}
//ack 应答
SDA=1;
i2c_delay();
SCL=1;
while(SDA)//等待应答
{
b++;
if(b>200) //如果超过2000us没有应答发送失败,或者为非应答,表示接收结束
{
SCL=0;
i2c_delay();
return 1;
}
}
SCL=0;
i2c_delay();
return 0;
}
//读取i2c 1个字节的数据
U8 i2c_read()
{
U8 a=0,dat=0;
SDA=1; //起始和发送一个字节之后SCL都是0
i2c_delay();
for(a=0;a<8;a++)//接收8个字节
{
SCL=1;
i2c_delay();
dat<<=1;
dat|=SDA;
i2c_delay();
SCL=0;
i2c_delay();
}
return dat;
}
// I2c 停止
// 说明: SCL为高电平,SDA出现从低电平 -> 高电平
void i2c_stop()
{
SDA = 0;
i2c_delay();
SCL = 1;
i2c_delay();
SDA = 1;
i2c_delay();
}
//写入某个从机,某个地址,的值
void i2c_device_write(U8 slave ,U8 addr ,U8 val)
{
bit ack;
i2c_start();
ack = i2c_write(slave);
if(ack==0)
{
i2c_write(addr); //选择写入的地址
i2c_write(val); //写入值
}
i2c_stop();
}
//读取某个从设备的,某个地址上的数据
U8 i2c_device_read(U8 slave, U8 addr)
{
bit ack;
U8 dota=0xFF;
i2c_start();
ack = i2c_write(slave);
if(ack==0)
{
i2c_write(addr);
i2c_start();
i2c_write(slave|1); //0xA1
dota=i2c_read(); //读取数据
}
i2c_stop();
return dota;
}
//延迟1s
void delay1s()
{
unsigned char a,b,c;
for(c=13;c>0;c--)
for(b=247;b>0;b--)
for(a=142;a>0;a--);
}
void main()
{
U8 dat1,dat2;
//串口初始化为了打印 dota
uart_init();
//向设备:1010 000 => 0x50 << 1 = 0xA0,的1地址上,写入0x04
i2c_device_write(0xA0,1,0x05);
//需要延迟一下,否则读写切换太快将无法读出数据
delay1s();
//向0xA3 , 的1地址上写入 0x02
i2c_device_write(0xA3,1,0x02);
delay1s();
//读取 1号地址的数据
dat1 = i2c_device_read(0xA0,1);
delay1s();
//读取 2号地址的数据 , 空数据为:0xFF
dat2 = i2c_device_read(0xA0,2);
//读取到的值发送到串口吧
uart_send_char(dat1);
uart_send_char(dat2);
while (1){
}
}
感谢您的支持,写的文章如对您有所帮助,开源不易,请您打赏,谢谢啦~