当前位置: 首页 > article >正文

51单片机快速入门之 IIC I2C通信

51单片机快速入门之 IIC 总线通信

协议:

  1. 空闲时 SCL/SDA 为高电平
  2. SCL高时   SDA下降沿 为开始信号
  3. 开始信号之后:

                                SCL高电平时 SDA不能变化  ,

                                SCL低电平时 SDA才可变  

                                SDA 传数据时 从高到低按位传输  SCL一个脉冲高电平对应一位数据

      4.SCL高电平时 SDA上升沿 为停止信号

数据格式:

1.单字节格式:

                        开始信号>数据(高到低)>应答(ACK)信号接收方SDA低电平>停止信号

2.多字节格式:

       开始信号>发送设备地址和读写方向>应答(ACK)信号>数据传输>应答(ACK)信号接收方SDA低电平>停止信号

I2C 元器件  24c02(E^2PROM)

读/写操作: 

1.单字节写流程:

开始信号>7位地址(1010固 0A 0B 0C)+读1/写0>24C02回复ACK信号>发送一个字节>ACK信号>停止信号

2.页写流程(多字节):

开始信号>7位地址(1010固 0A 0B 0C)+读1/写0>24C02回复ACK信号>发第一个字节数据地址>ACK>第一个字节数据>ACK>第二个字节数据...>一直到停止信号 或者16字节

最多可一次写入2-16字节!

超出会自动从初始位置覆盖数据 17时覆盖第一个字节数据,之后还有数据往后递增覆盖


3.立即地址读操作:

N范围(0~255)00H~FFH

开始信号>7位地址(1010固 0A 0B 0C)+读1/写0>ack回复>读取一个字节数据(上次操作地址N+1的数据)>停止信号

N=255时 下一个跳转读取 0 

4.选择读操作:

任选地址读

开始信号>7位地址(1010固 0A 0B 0C)+读1/写0>低0伪写操作>ack>N字节地址>从ack>开始信号>7位地址(1010固 0A 0B 0C)+读1/写0>读信号 1>从ack>获取N地址下的数据>停止信号

5.连续读操作:

立即地址读操作 连续

开始信号>7位地址+读1>读取FFH(255)为第一个数据,>主ACK>00H>主ack...直到出现主ack不回复 停下来>停止信号才结束本次读取

选择读操作 连续

开始信号>7位地址(1010固 0A 0B 0C)+读1/写0>低0伪写操作>ack>N字节地址>从ack>开始信号>7位地址(1010固 0A 0B 0C)+读1/写0>读信号 1>从ack>获取N地址下的数据>ack>N+1数据>ack .....直到停止信号

电路图:

捣鼓了好几天,终于调试通了原来这元器件和书上的不同 所以说还是要多看看元器件数据手册才好,不然出了问题都找不到在哪!  就是这里 地址位我弄错了,书上很模糊所以我理解为

A0 A1 A2  顺序错了 实际上是A2 A1 A0 

代码(简单发送):

#include <STC89C5xRC.H>//加载头文件,晶振12MHz

sbit SCL=P2^0;  //时钟线
sbit SDA=P2^1;  //数据线

void delay(unsigned int t); // 延时函数声明
void startI2C();//开始信号
void stopI2C();//停止信号




void SendByte(unsigned char dat);//发送字节数据


void main()
{
    SendByte(0xA2);//发送从机地址
   SendByte(0x00);//发送需要存入那个字节的地址 00H~FFH
   SendByte(0x44);    //发送需要存储的数据      

    P17=0;模拟环境提示操作成功用 ,实际使用可删除
    while(1); // 防止程序重复运行
}


void startI2C() //开始信号
{

      SDA=1;  //首先拉高SDA
	  delay(10);//给他点时间
    SCL=1; //拉高SCL
    delay(10);    //1us
    SDA=0; //拉低SDA 触发开始信号
		delay(10);    //1us
	  SCL=0; //手动拉低确保时序准确 初始化以接受数据
    delay(10);    //1us
}

void stopI2C() //停止信号
{
    if(SCL==1&&SDA==0) //只有当SCL=1 而且SDA=0时才触发 SDA=0保证已经接受到ACK回复信号
 {
        delay(10); //等一会
        SDA=1; //拉高SDA ,上升沿触发停止信号
    } else if(SCL==0)  //当SCL=0时,这句没啥用其实 ,防止   SCL=0 触发不了停止信号 
{
        delay(10);
        SCL=1; //把scl 拉高
        if(SDA==0)  //判断是否接收到ACK回复
{
            delay(10);
            SDA=1;
        }
    }

}


void SendByte(unsigned char dat)//发送字节数据
{
    unsigned char bita;
    startI2C();//发送开始信号
    for(bita=0; bita<8; bita++) {

        if((dat<<bita)&0x80) //每次根据bita 的值左移 bita位 再和 0x80(1000 0000) 与操作(只保最高位)
{
            SDA=1; //如果是1,拉高sda传送一个1 过去

        } else {
            SDA=0;// 反之给0

        }
        delay(10); //让它们稳定一下


        SCL=1;//上升读取  因开始信号已经拉低SCL
        delay(10);  //稳定时间       
				
				SCL=0;   //下降写入数据  也可以说这是复位
        delay(10);  //稳定时间
    }  
		 SDA=1;  //8位传完就拉高等待ACK触发
		 SCL=0;   //下降写入数据 保证循环正确输出8位
		 SCL=1;   //拉高以配合ACK 
     delay(10);//等待
    if(SDA!=1)  //sda=0 证明 ack已回复 触发停止信号
{stopI2C();
        P30=0;  //模拟环境提示操作成功用 ,实际使用可删除
    } else {
        
        P10=0;//模拟环境提示操作成功用 ,实际使用可删除
    }
    


}



void delay(unsigned int t) // 简单延迟函数
{
    while(t--);
}

运行效果:

程序设置了一个监视,操作成功会拉低P30

 代码(简单读取):

#include <STC89C5xRC.H>

sbit SCL=P2^0;  //时钟线
sbit SDA=P2^1;  //数据线
sbit DQ=P2^4;//读取按键
void delay(unsigned int t); // 延时函数声明
void startI2C();//开始信号
void stopI2C();//停止信号
bit x; //用于存储ACK信息
unsigned char u;


void SendByte(unsigned char dat);//发送字节数据

void main()
{
    SendByte(0xA2);//发送从机地址  最后一位置0 写入
    x=0;
    SendByte(0x01);//发送字节地址
    x=0;
    SendByte(0x66);    //发送需要存储的数据

    if(x==1) {
        stopI2C();   //停止信号
    }

    P1=0;
    x=0;
    while(DQ==1);//阻断程序运行,当按钮按下往下执行
    //按键判断读取并赋值给P1寄存器
    if(DQ==0) {

        SendByte(0xA3);//发送从机地址  最后一位置1 实际读取


        if(x==1) { //表示读取请求被响应

            unsigned char red,bint;

            P33=0;
            red=0;
            // 在读取数据的循环之前添加SDA释放
            if(SDA!=1&&SCL!=1) {
                SDA = 1; // 释放SDA线
                delay(0);
            }
            // 读取数据的循环
            for(bint=0; bint<8; bint++) {
                delay(20);//延时等待
                SCL=0;//读取数据
                delay(20);//延时等待
                SCL=1;//
                delay(20);

                // 检查SDA状态,并更新red的值
                if(SDA==1) { //如果读取到高电平
                    red |=1<<(7 - bint); // 设置对应位为1

                } else {
                    red |=0<<(7-bint);
                }
                delay(10);//延时等待

            }
            SCL=0;//读取数据
            delay(10);//延时等待
            SDA = 1; // nack
            delay(10);
            P1=red;//把获取到的值直接用到P1中
            stopI2C(); //停止信号
        }

    }





    while(1); // 防止程序重复运行
}


void startI2C()
{

    SDA=1;
    delay(10);
    SCL=1;
    delay(10);    //1us
    SDA=0;
    delay(10);    //1us
    SCL=0; //手动拉低确保时序准确
    delay(10);    //1us
}

void stopI2C()
{
    if(SCL==1&&SDA==0) {
        delay(10);
        SDA=1;
    } else if(SCL==0) {
        delay(10);
        SCL=1;
        if(SDA==0) {
            delay(10);
            SDA=1;
        }
    }

}


void SendByte(unsigned char dat)//发送字节数据
{
    unsigned char bita;
    startI2C();//发送开始信号
    for(bita=0; bita<8; bita++) {

        if((dat<<bita)&0x80) {
            SDA=1;

        } else {
            SDA=0;

        }
        delay(10);


        SCL=1;//上升读取  因开始信号已经拉低SCL
        delay(10);

        SCL=0;   //下降写入数据
        delay(10);
    }
    SDA=1;
    SCL=0;   //下降写入数据 保证循环正确输出8位
    SCL=1;
    delay(10);
    if(SDA==0) {
        x=1; //有回复为1
        P30=0;
    } else {
        x=0; //无回复为0
        // P10=0;
    }



}



void delay(unsigned int t) // 简单延迟函数
{
    while(t--);
}
读取运行效果 :

由图可以看出,元器件根本没有回复数据(试过选择地址读取,也没效果) 所以就这样吧!


最后更新于2024/10/24 0:01


http://www.kler.cn/news/364389.html

相关文章:

  • Pytorch学习--如何下载及使用Pytorch中自带数据集,如何把数据集和transforms联合在一起使用
  • 程序员的最终出路在哪
  • vue3+ts实时播放视频,视频分屏
  • 学习的内核,如何更好的学习呢?
  • 使用Vue.js构建响应式Web应用
  • Android组件化开发
  • 昇思MindSpore进阶教程--安装常见问题(中)
  • Modbus转IEC61850网关iGate-850实现电力系统采集电力仪表
  • Facebook区块链生态系统:去中心化社交平台的未来
  • docker XML详解
  • 深度学习 简易环境安装(不含Anaconda)
  • Zypher Network Layer3 主网上线,“宝藏方舟”活动是亮点
  • React综合指南(一)
  • 微服务的一些基本概念
  • 【Java】ArrayList相关操作及其案例
  • 安全见闻(4)
  • 什么是恶意爬虫,有什么应对措施
  • iOS 18.2开发者预览版 Beta 1版本发布,欧盟允许卸载应用商店
  • 字符串使用方法:
  • AI模型架构如(CNN)、(RNN)(LSTM、GRU)、(如BERT、GPT等)在不同领域中的具体应用
  • 分布式---raft算法
  • 民峰金融智能交易模型的应用与未来趋势
  • 【操作系统】Linux之进程管理一
  • 51单片机快速入门之 步进电机的使用与 ULN2003 2024/10/21
  • 没有AWS账号能不能在手机上使用AWS服务吗?
  • 【MAC OS】rocketmq搭建可视化工具rocketmq-dashboard