8051/2单片机常用的本地通讯方式 UART,RS485,I2C,SPI 之 I2C E2PROM 3

一、说明

单片机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){
   }
}

感谢您的支持,写的文章如对您有所帮助,开源不易,请您打赏,谢谢啦~

 

 

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值