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

进阶四 带记忆功能的000-255 计数器

一、实验目的

  1. 掌握89C51单片机的基本操作和编程方法
  2. 学习I2C总线协议及其在单片机中的应用
  3. 实现基于AT24C02 EEPROM的带记忆功能的计数器
  4. 掌握LCD1602液晶显示模块的使用方法

二、实验设备

  1. 89C51单片机开发板板载
  2. AT24C02 EEPROM芯片板载
  3. LCD1602液晶显示屏板载
  4. 按键开关板载

三、实验原理

1. 系统组成

本实验系统主要由以下几部分组成:

  1. 89C51单片机:作为主控制器,负责处理按键输入、I2C通信和LCD显示
  2. AT24C02 EEPROM:用于存储计数器的当前值,实现断电记忆功能
  3. LCD1602液晶显示屏:用于显示当前计数值
  4. 按键开关:用于增加计数值

2. I2C总线协议

I2C总线是一种简单的双向二线制同步串行总线,由数据线SDA和时钟线SCL组成。本实验使用89C51的P2.0和P2.1引脚模拟I2C总线与AT24C02通信。

3. AT24C02 EEPROM

AT24C02是一种2Kbit的串行EEPROM,采用I2C接口。其设备地址为0xA0(写)和0xA1(读)。本实验使用其第一个地址(0x00)存储计数值。

4. LCD1602液晶显示

LCD1602是一种字符型液晶显示模块,可以显示两行,每行16个字符。本实验使用其第一行显示当前计数值。

四、实验电路连接

  1. LCD1602连接:
  1. RS引脚连接P3.5
  2. RW引脚连接P3.6
  3. EN引脚连接P3.4
  4. 数据线D0-D7连接P0口
  1. AT24C02连接:
  1. SDA引脚连接P2.1
  2. SCL引脚连接P2.0
  1. 按键连接:
  1. 按键一端连接P3.2,另一端接地

五、实验代码分析

  1. 头文件和宏定义

#include <reg52.h>

#include <intrins.h>

#define unchar unsigned char

#define uint unsigned int

  1. 全局变量和常量定义

unchar code dis_table[] = "0123456789";  // 数字显示表

sbit button = P3^2; // 定义按键

sbit lcden = P3^4; // 定义LCD的E端口

sbit lcdrw = P3^6; // 定义LCD的RW端口

sbit lcdrs = P3^5; // 定义LCD的RS端口

sbit SCL = P2^0; // 定义SCL时钟线端口

sbit SDA = P2^1; // 定义SDA数据线端口

  1. 延时函数

void Delay() {

    _nop_();    _nop_();    _nop_();    _nop_();    _nop_();

}

void DelayMs(uint ms) {

    uint i;

    while(ms--) {

        for(i = 110; i > 0; i--) ;

     }

}

  1. LCD1602操作函数

void Write_Com(unchar com) {

    lcdrs = 0; // 选择指令寄存器

    P0 = com;

    DelayMs(5);

    lcden = 1;

    DelayMs(5);

    lcden = 0;

}

void Write_data(unchar datas) {

    lcdrs = 1; // 选择数据寄存器

    P0 = datas;

    DelayMs(5);

    lcden = 1;

    DelayMs(5);

    lcden = 0;

}

void init() {

    lcdrw = 0; // 写操作

    lcden = 0;

    Write_Com(0x38);  // 8位数据接口,两行显示,5x7点阵

    Write_Com(0x0c);  // 显示开,光标关,闪烁关

    Write_Com(0x06);  // 写入新数据后光标右移,显示不移动

    Write_Com(0x01);  // 清屏

}

  1. I2C操作函数

void IIC_init() {

    SCL = 1;

    Delay();

    SDA = 1;

    Delay();

}

void IIC_start() {

    SDA = 1;

    Delay();

    SCL = 1;

    Delay();

    SDA = 0;

    Delay();

}

void IIC_respons() {

    unchar i = 0;

    SCL = 1;

    Delay();

    while(SDA == 1 && (i < 255)) {

        i++;

    }

    SCL = 0;

    Delay();

}

void IIC_stop() {

    SDA = 0;

    Delay();

    SCL = 1;

    Delay();

    SDA = 1;

    Delay();

}

void IIC_writebyte(unchar date) {

    unchar i, temp;

    temp = date;

    for(i = 0; i < 8; i++) {

        temp = temp << 1;

        SCL = 0;

        Delay();

        SDA = CY;

        Delay();

        SCL = 1;

        Delay();

    }

    SCL = 0;

    Delay();

    SCL = 1;

    Delay();

}

unchar IIC_readbyte() {

    unchar i, Data;

    SCL = 0;

    Delay();

    SDA = 1;

    for(i = 0; i < 8; i++) {

        SCL = 1;

        Delay();

        SDA = 1;

        Data = (Data << 1) | SDA;

        SCL = 0;

        Delay();

    }

    Delay();

    return Data;

}

  1. EEPROM读写函数

void Write_add(unchar date, unchar address) {

    IIC_start();

    IIC_writebyte(0xa0);  // 写入设备地址

    IIC_respons();

    IIC_writebyte(address);  // 写入存储地址

    IIC_respons();

    IIC_writebyte(date);  // 写入数据

    IIC_respons();

    IIC_stop();

}

unchar Read_add(unchar address) {

    unchar datas;

    IIC_start();

    IIC_writebyte(0xa0);  // 写入设备地址

    IIC_respons();

    IIC_writebyte(address);  // 写入存储地址

    IIC_respons();

    IIC_start();

    IIC_writebyte(0xa1);  // 读取设备地址

    IIC_respons();

    date = IIC_readbyte();  // 读取数据

    IIC_stop();

    return datas;

}

  1. 显示函数

void display(unchar date) {

    Write_Com(0x80);  // 设置显示位置为第一行第一个字符

    Write_data(dis_table[date/100]);  // 显示百位

    Write_data(dis_table[date%100/10]);  // 显示十位

    Write_data(dis_table[date%10]);  // 显示个位

}

  1. 主函数

void main() {

    unchar num, NUM;

    init();

    IIC_init();

    

    while(1) {

        if(button == 0) {  // 检测按键按下

            DelayMs(10);  // 消抖

            if(button == 0) {

                num = Read_add(0x00);  // 读取当前计数值

                num++;

                if(num > 255) num = 0;  // 限制计数值在0-255范围内

                Write_add(num, 0x00);  // 将新值写入EEPROM

            }

            while(button == 0);  // 等待按键释放

        }

        NUM = Read_add(0x00);  // 读取当前计数值

        display(NUM);  // 显示计数值

    }

}

六、实验步骤

  1. 按照电路连接图连接好硬件电路
  2. 将编译好的程序烧录到89C51单片机中
  3. 接通电源,观察LCD1602显示初始计数值(应为0)
  4. 按下按键,观察计数值增加
  5. 断电后重新上电,观察计数值是否保持断电前的值

七、实验结果与分析

  1. 实验结果
  1. 系统上电后,LCD1602显示初始计数值0
  2. 每次按下按键,计数值增加1
  3. 当计数值达到255后,再按一次按键,计数值变为0
  4. 断电后重新上电,计数值保持断电前的值
  1. 结果分析
  1. 系统能够正确读取和写入EEPROM中的数据,实现了断电记忆功能
  2. 按键消抖处理有效,避免了按键抖动导致的误计数
  3. LCD1602显示正常,能够实时显示当前计数值
  4. 计数值范围限制在0-255之间,符合设计要求

八、实验总结

通过本次实验,我掌握了以下知识和技能:

  1. 89C51单片机的基本编程方法
  2. I2C总线协议及其在单片机中的应用
  3. AT24C02 EEPROM的使用方法
  4. LCD1602液晶显示模块的编程和显示控制
  5. 按键消抖处理的方法

实验中遇到的问题及解决方法:

  1. 问题:初始上电时LCD显示乱码
    解决:检查发现LCD初始化时序不正确,调整延时后解决
  2. 问题:按键按下时计数值多次增加
    解决:增加按键消抖处理,并在按键按下后等待释放
  3. 问题:断电后重新上电计数值不记忆
    解决:检查EEPROM读写函数,发现I2C时序不正确,调整后解决

九、实验要求

  1. 可以增加减计数功能,通过另一个按键实现
  2. 可以增加清零功能,通过长按按键实现
  3. 可以优化I2C通信的延时函数,提高通信效率
  4. 可以增加计数值范围限制的提示信息
http://www.xdnf.cn/news/13860.html

相关文章:

  • 基于Python的热门微博数据可视化分析-Flask+Vue
  • 蚂蚁集团法人变更:韩歆毅接任,公司治理的正常安排
  • 第17篇:数据库中间件的弹性伸缩与容量规划实战
  • MySQL库操作
  • 升级openssl后无法使用cmake和curl的解决方法
  • Logic Error: 如何识别和修复逻辑错误
  • C++题解 P4933 2.间谍原题:
  • 斗式提升机的负载特性对变频驱动的要求
  • 三星MZQL2960HCJR-00BAL高性能固态硬盘控制器SSD云计算和高端存储专用 电子元器件解析
  • 深刻理解深度学习的注意力机制Attention
  • Python 轻量化环境管理利器 UV 入门与 Windows 下安装实战
  • liquibase 集成 pt-online-schema-change
  • 穿越时空的刀剑之旅:走进VR刀剑博物馆​
  • python打卡day53
  • java中LinkedList和ArrayList的区别和联系?
  • python第51天
  • React Native【实战范例】网格导航 FlatList
  • oceanbase导出导入数据csv
  • 【Python教程】CentOS系统下Miniconda3安装与Python项目后台运行全攻略
  • visual studio2019+vcpkg管理第三方库
  • Vastbase的常用操作
  • 表格对比工具推荐,快速比对Excel文件
  • 用AI思维重塑人生:像训练神经网络一样优化自己
  • 图数据库如何构筑 Web3 风控防线 | 聚焦批量注册与链上盗转
  • Node.js 检测视频链接是否可以播放(批量检测)
  • C++题解 P1525 Cantor表
  • (十四)自然语言处理中的深度学习:语言表征、模型架构与计算语言学基础
  • vue3 双容器自动扩展布局 根据 内容的多少 动态定义宽度
  • 【Pytorch】(1)Pytorch环境安装-②安装Pytorch
  • 激光雷达 + 视觉相机:高精度位姿测量方案详解