找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 4339|回复: 2
收起左侧

51单片机IIC协议 & EEPROM读写程序

  [复制链接]
ID:825513 发表于 2021-5-8 21:07 | 显示全部楼层 |阅读模式
来到51黑电子也有一段时间了,单片机萌新一个,一直都是看别人的贴子,很感谢论坛里热心指导的大佬们,今天萌新也来贡献一下代码吧,写了一个IIC读写EEPROM的源码,经过编译和烧录,成功在开发板上实现。
一个00~99的计数器,每秒计数一次,具有断电记忆功能(开机后,从关机前的最新数值继续计数),软件模拟IIC协议。

源码以及开发板上的与本源码相关的电路部分如下(第一次发文,不懂别人帖子里的源码框怎么弄,尴尬.gif):
AT89S52
Snipaste_2021-05-08_19-47-05.png

数码管显示
Snipaste_2021-05-08_19-48-24.png

EEPROM模块以及受影响的DS1302模块
Snipaste_2021-05-08_19-50-02.png

单片机源程序如下:
#include<reg52.h>
#include<intrins.h>

bit x=0;                //将计时值写入EEPROM的标志位
sbit SCL=P2^1;
sbit SDA=P2^0;
sbit X=P2^4;                //引脚P2^4为开发板上DS1302模块的复位引脚
sbit DU=P2^6;                //数码管模块段选位
sbit WE=P2^7;                //数码管模块位选位

unsigned char num=0;
unsigned char i=0;

unsigned char LEDS[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};                //共阴数码管的段码

void LEDS_IO()                //数码管锁存
{
        WE=1;
        P0=1;
        WE=0;
        DU=1;
        P0=0;
        DU=0;
}

void Delay5ms()
{
        unsigned char i,j;
        i=9;
        j=244;
        do
        {
                while(--j);
        }
        while(--i);
}

void IIC_Delay()
{
        _nop_();
        _nop_();
}

void IIC_INIT()                //IIC初始化
{
        X=0;                //DS1302模块的复位电平为低电平,令DS1302模块一直处于复位状态,使其I/O端口(P2^0)不输出,避免干扰EEPROM模块的SDA端口(P2^0)
        SDA=1;
        IIC_Delay();
        SCL=1;
        IIC_Delay();
}

void IIC_Start()                //IIC起始信号
{
        SDA=1;
        IIC_Delay();
        SCL=1;
        IIC_Delay();
        SDA=0;
        IIC_Delay();
}

void IIC_Stop()                //IIC停止信号
{
        SDA=0;
        IIC_Delay();
        SCL=1;
        IIC_Delay();
        SDA=1;
        IIC_Delay();
}

void IIC_ACK()                //等待应答信号;“应答”信号:SDA=0;“非应答”信号:SDA=1
{
        unsigned char i;
        SCL=1;
        IIC_Delay();
        while((SDA==1)&&(i<256))                //若超时,则视为“非应答”
        {
                i++;
        }
        SCL=0;
        IIC_Delay();
}

void IIC_Write(unsigned char DATA)                //IIC发送数据
{
        unsigned char i;
        unsigned char temp;
        temp=DATA;
        for(i=0;i<8;i++)
        {
                temp=temp<<1;
                SCL=0;
                IIC_Delay();
                SDA=CY;                //IIC数据的发送从高位开始,需要使用左移指令,而C语言的左移和右移指令,CY参与其中(CY并不是只有在进位和借位中用到),左移出来的一位赋给CY
                IIC_Delay();
                SCL=1;
                IIC_Delay();
        }
        SCL=0;                //将SCL置低电平,准备接收应答信号
        IIC_Delay();
        SDA=1;                //释放SDA,准备接收从器件反馈的应答信号
        IIC_Delay();
}

unsigned char IIC_Read()                //IIC接收数据
{
        unsigned char i;
        unsigned char DATA;
        SCL=0;
        IIC_Delay();
        SDA=1;
        IIC_Delay();
        for(i=0;i<8;i++)
        {
                SCL=1;
                IIC_Delay();
                DATA=(DATA<<1)|SDA;
                SCL=0;
                IIC_Delay();
        }
        return DATA;
}

void EEPROM_Write(unsigned char ADDRESS,unsigned char DATA)                //写入EEPROM
{
        IIC_Start();
        IIC_Write(0xa0);                //发送IIC从器件(EEPROM)地址,并选择“写”操作
        IIC_ACK();
        IIC_Write(ADDRESS);                //发送将要写入的EEPROM的存储地址
        IIC_ACK();
        IIC_Write(DATA);                //发送写入EEPROM的数据
        IIC_ACK();
        IIC_Stop();
}

unsigned char EEPROM_Read(unsigned char ADDRESS)                //读取EEPROM
{
        unsigned char DATA;
        IIC_Start();
        IIC_Write(0xa0);
        IIC_ACK();
        IIC_Write(ADDRESS);
        IIC_ACK();
        IIC_Start();
        IIC_Write(0xa1);                //发送IIC从器件(EEPROM)地址,并选择“读”操作
        IIC_ACK();
        DATA=IIC_Read();
        IIC_Stop();
        return DATA;
}

void LEDS_OUTPUT(unsigned char m,unsigned char n)                //数码管显示
{
        DU=0;
        P0=LEDS[m];
        DU=1;
        DU=0;
        WE=0;
        P0=0x3e;
        WE=1;
        WE=0;
        Delay5ms();
        DU=0;
        P0=LEDS[n];
        DU=1;
        DU=0;
        WE=0;
        P0=0x3d;
        WE=1;
        WE=0;
        Delay5ms();
}

void main()
{
        IIC_INIT();
        LEDS_IO();
        num=EEPROM_Read(0x00);
        TMOD=0x01;
        TH0=0x4c00;
        TL0=0x4c00;
        TR0=1;
        ET0=1;
        EA=1;
        while(1)
        {
                LEDS_OUTPUT(num/10,num%10);
                if(x==1)
                {
                        x=0;
                        EEPROM_Write(0x00,num);
                }
        }
}

void T() interrupt 1                //每0.05秒中断一次
{
        TH0=0x4c00;
        TL0=0x4c00;
        i++;
        if(i==20)                //中断20次,即1秒
        {
                i=0;
                num++;
                x=1;
                if(num==100)
                {
                        num=0;
                }
        }
}

评分

参与人数 1黑币 +50 收起 理由
admin + 50 共享资料的黑币奖励!

查看全部评分

回复

使用道具 举报

ID:480627 发表于 2022-4-15 11:22 | 显示全部楼层
谢谢楼主了,对我很有用,比看那些好几个又是C又是H的调来调去的直观多了
回复

使用道具 举报

ID:205485 发表于 2022-4-17 09:27 | 显示全部楼层
不错,条理分明,简洁易懂。对于初学者来说,最最重要的就是代码简洁,能看懂是首要任务,其次才是效率、占用资源、优化这些东西。我看了几个老师的视频,他们的学识不可谓不渊博,但绝大多数都犯了这种错误,几课过后,就忘记了听众都是小白了。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表