AT24C02数据存储+普中51单片机+江科大自化协
1 系统原理图

2 现象

当按键Key1被按下时,LCD1602显示的数值加1,每按下一次,自增1;当按键Key2被按下时,LCD1602显示的数值自减1;当按键Key3被按下时,单片机将LCD1602显示的数值保存在AT24C02中,掉电不丢失;当按键Key4被按下时,单片机从AT24C02中读取数据,并显示在LCD1602。
3 参考程序
(1)主函数
#include <REGX52.H>
#include "delayms.h"
#include "key.h"
#include "lcd1602.h"
#include "at24c02.h" unsigned char KeyNum;
unsigned int Num; void main()
{
LCD1602_Init();
LCD1602_ShowNum(1,1,Num,5);
while(1)
{
KeyNum=key();
if(KeyNum==1) //K1按键,Num自增
{
Num++;
LCD1602_ShowNum(1,1,Num,5);
}
if(KeyNum==2) //K2按键,Num自减
{
Num--;
LCD1602_ShowNum(1,1,Num,5);
}
if(KeyNum==3) //K3按键,向AT24C02写入数据
{
AT24C02_WriteByte(0,Num%256);
delayms(5);
AT24C02_WriteByte(1,Num/256);
delayms(5);
LCD1602_ShowString(2,1,"Write is OK");
delayms(1000);
LCD1602_ShowString(2,1," ");
}
if(KeyNum==4) //K4按键,从AT24C02读取数据
{
Num=AT24C02_ReadByte(0);
Num|=AT24C02_ReadByte(1)<<8;
LCD1602_ShowNum(1,1,Num,5);
LCD1602_ShowString(2,1,"Read is OK");
delayms(1000);
LCD1602_ShowString(2,1," ");
}
}
}
(2)I2C函数
#ifndef _i2c_h_
#define _i2c_h_ void I2C_Start(void);
void I2C_Stop(void);
void I2C_SendByte(unsigned char Byte);
unsigned char I2C_ReceiveByte(void);
void I2C_SendAck(unsigned char AckBit);
unsigned char I2C_ReceiveAck(void); #endif
#include <REGX52.H> sbit I2C_SCL=P2^1;
sbit I2C_SDA=P2^0; /**
* @brief I2C通信开始
* @param 无
* @retval 无
*/
void I2C_Start(void)
{
I2C_SCL=1; //空闲状态
I2C_SDA=1; //空闲状态
I2C_SDA=0;
I2C_SCL=0;
} /**
* @brief I2C通信结束
* @param 无
* @retval 无
*/
void I2C_Stop(void)
{
I2C_SDA=0;
I2C_SCL=1; //回到空闲状态
I2C_SDA=1; //回到空闲状态
} /**
* @brief I2C主机向从机发送一个字节,SCL为同步信号,低电平写数据
* @param Byte 要发送的字节
* @retval 无
*/
void I2C_SendByte(unsigned char Byte)
{
unsigned char i;
for(i=0;i<8;i++) //一个字节,8bit
{
I2C_SDA=Byte&(0x80>>i); //SCL为低电平,主机为发送器,写数据
I2C_SCL=1; //SCL为高电平,从机为接收器,读数据
I2C_SCL=0; //时序要求,51单片机速度比较慢
}
} /**
* @brief I2C主机接收从机一个字节,SCL为同步信号,高电平读数据
* @param 无
* @retval 接收到的一个字节数据
*/
unsigned char I2C_ReceiveByte(void)
{
unsigned char i,Byte=0x00;
I2C_SDA=1; //主机释放数据线SDA
for(i=0;i<8;i++)
{
I2C_SCL=1; //主机作为接收器
if(I2C_SDA) Byte|=(0x80>>i); //读数据
I2C_SCL=0; //从机作为发送器,写数据
}
return Byte;
} /**
* @brief I2C主机发送应答
* @param AckBit 应答位,0为应答,1为非应答
* @retval 无
*/
void I2C_SendAck(unsigned char AckBit)
{
I2C_SDA=AckBit;
I2C_SCL=1;
I2C_SCL=0;
} /**
* @brief I2C主机接收应答位
* @param 无
* @retval 接收到的应答位,0为应答,1为非应答
*/
unsigned char I2C_ReceiveAck(void)
{
unsigned char AckBit;
I2C_SDA=1;
I2C_SCL=1;
AckBit=I2C_SDA;
I2C_SCL=0;
return AckBit;
}
(3)AT24C02函数
#ifndef _at24c02_h_
#define _at24c02_h_ void AT24C02_WriteByte(unsigned char WordAddress,Data);
unsigned char AT24C02_ReadByte(unsigned char WordAddress); #endif
#include <REGX52.H>
#include "i2c.h" #define AT24C02_ADDRESS 0xA0 /**
* @brief AT24C02写入一个字节
* @param WordAddress 要写入字节的地址
* @param Data 要写入的数据
* @retval 无
*/
void AT24C02_WriteByte(unsigned char WordAddress,Data)
{
I2C_Start();
I2C_SendByte(AT24C02_ADDRESS);
I2C_ReceiveAck();
I2C_SendByte(WordAddress);
I2C_ReceiveAck();
I2C_SendByte(Data);
I2C_ReceiveAck();
I2C_Stop();
} /**
* @brief AT24C02读取一个字节
* @param WordAddress 要读出字节的地址
* @retval 读出的数据
*/
unsigned char AT24C02_ReadByte(unsigned char WordAddress)
{
unsigned char Data;
I2C_Start();
I2C_SendByte(AT24C02_ADDRESS);
I2C_ReceiveAck();
I2C_SendByte(WordAddress);
I2C_ReceiveAck(); I2C_Start();
I2C_SendByte(AT24C02_ADDRESS|0x01);
I2C_ReceiveAck();
Data=I2C_ReceiveByte();
I2C_SendAck(1);
I2C_Stop();
return Data;
}
(4)LCD1602函数
#ifndef __LCD1602_H__
#define __LCD1602_H__ void LCD1602_WriteCommand(unsigned char Command);
void LCD1602_WriteData(unsigned char Data); void LCD1602_Init(void);
void LCD1602_ShowChar(unsigned char Line,unsigned char Column,unsigned char Char);
void LCD1602_ShowString(unsigned char Line,unsigned char Column,unsigned char *String);
void LCD1602_ShowNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length);
void LCD1602_ShowSignedNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length);
void LCD1602_ShowHexNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length);
void LCD1602_ShowBinNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length); #endif
#include <REGX52.H>
#include "intrins.h" //引脚配置,硬件原理图,普中A2
sbit LCD1602_RS = P2^6;
sbit LCD1602_RW = P2^5;
sbit LCD1602_E = P2^7;
#define LCD1602_DATAPORT P0 /**
* @brief LCD1602延时函数
* @param xms=1, 延时1ms
* @retval 无
*/
void LCD1602_Delayms(unsigned char xms) //@11.0592MHz
{
unsigned char i, j,k; for(k=0;k<xms;k++)
{
_nop_();
i = 2;
j = 199;
do
{
while (--j);
} while (--i);
} } /**
* @brief LCD1602写命令,时序图
* @param Command 要写入的命令
* @retval 无
*/
void LCD1602_WriteCommand(unsigned char Command)
{
LCD1602_RS = 0;
LCD1602_RW = 0;
LCD1602_DATAPORT = Command;
LCD1602_E = 1;
LCD1602_Delayms(1); //延时1ms
LCD1602_E = 0;
LCD1602_Delayms(1); //延时1ms
} /**
* @brief LCD1602写数据,时序图
* @param Data 要写入的数据
* @retval 无
*/
void LCD1602_WriteData(unsigned char Data)
{
LCD1602_RS = 1;
LCD1602_RW = 0;
LCD1602_DATAPORT = Data;
LCD1602_E = 1;
LCD1602_Delayms(1); //延时1ms
LCD1602_E = 0;
LCD1602_Delayms(1); //延时1ms
} /**
* @brief LCD1602初始化函数
* @param 无
* @retval 无
*/
void LCD1602_Init(void)
{
LCD1602_WriteCommand(0x38); //0011_1000 功能设置,设置16x2显示,5x7点阵,8位数据接口
LCD1602_WriteCommand(0x0C); //0000_1100 显示开关控制,显示开,光标关,闪烁关
LCD1602_WriteCommand(0x06); //0000_0110 输入方式设置,数据写后,AC自动加一,画面不动
LCD1602_WriteCommand(0x01); //0000_0001 清屏,数据指针清零、所有显示清零
}
/**
* @brief LCD1602设置光标位置
* @param Line 行位置,范围:1~2
* @param Column 列位置,范围:1~16
* @retval 无
*/
void LCD1602_SetCursor(unsigned char Line,unsigned char Column)
{
if(Line == 1)
{
LCD1602_WriteCommand(0x80|(Column-1)); //设置要存入数据的DDROM地址,第一行地址
}
else
{
LCD1602_WriteCommand(0x80|(Column-1)+0x40); //设置要存入数据的DDROM地,第二行地址
}
} /**
* @brief 在LCD1602指定位置上显示一个字符
* @param Line 行位置,范围:1~2
* @param Column 列位置,范围:1~16
* @param Char 要显示的字符
* @retval 无
*/
void LCD1602_ShowChar(unsigned char Line,unsigned char Column,unsigned char Char)
{
LCD1602_SetCursor(Line,Column);
LCD1602_WriteData(Char);
} /**
* @brief 在LCD1602指定位置上显示所给字符串
* @param Line 行位置,范围:1~2
* @param Column 列位置,范围:1~16
* @param Char 要显示的字符串
* @retval 无
*/
void LCD1602_ShowString(unsigned char Line,unsigned char Column,unsigned char *String) //指针
{
unsigned char i;
LCD1602_SetCursor(Line,Column);
for(i=0;String[i]!='\0';i++) //字符串结束标志'\0'
{
LCD1602_WriteData(String[i]);
} } /**
* @brief 返回值=X的Y次方,指数运算
*/
int LCD_Power(int X,int Y)
{
unsigned char i;
int result = 1;
for(i=0;i<Y;i++)
{
result = result * X;
}
return result;
} /**
* @brief 在LCD1602指定位置开始显示所给数字
* @param Line 起始行位置,范围:1~2
* @param Column 起始列位置,范围:1~16
* @param Number 要显示的数字,范围:0~65535
* @param Length 要显示数字的长度,范围:1~5
* @retval 无
*/
void LCD1602_ShowNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length)
{
unsigned char i;
LCD1602_SetCursor(Line,Column);
for(i=Length;i>0;i--)
{
LCD1602_WriteData('0'+Number/LCD_Power(10,i-1)%10); // '0'=0x30,转换为字符显示; /**
* 789, 789/100%10, 取出百位
* 789, 789/10%10, 取出十位
* 789, 789/1%10, 取出个位
*/
}
} /**
* @brief 在LCD1602指定位置开始以有符号十进制显示所给数字
* @param Line 起始行位置,范围:1~2
* @param Column 起始列位置,范围:1~16
* @param Number 要显示的数字,范围:-32768~32767
* @param Length 要显示数字的长度,范围:1~5
* @retval 无
*/
void LCD1602_ShowSignedNum(unsigned char Line,unsigned char Column, int Number,unsigned char Length)
{
unsigned char i;
unsigned int Number1;
LCD1602_SetCursor(Line,Column);
if(Number >= 0)
{
LCD1602_WriteData('+');
Number1 = Number;
}
else
{
LCD1602_WriteData('-');
Number1 = -Number; //-32768
}
for(i=Length;i>0;i--)
{
LCD1602_WriteData('0'+Number1/LCD_Power(10,i-1)%10);
}
} /**
* @brief 在LCD1602指定位置开始以十六进制显示所给数字
* @param Line 起始行位置,范围:1~2
* @param Column 起始列位置,范围:1~16
* @param Number 要显示的数字,范围:0~0xffff
* @param Length 要显示数字的长度,范围:1~4
* @retval 无
*/
void LCD1602_ShowHexNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length)
{
unsigned char i;
unsigned char SingleNumber;
LCD1602_SetCursor(Line,Column);
for(i=Length;i>0;i--)
{
SingleNumber = Number/LCD_Power(16,i-1)%16; //从高位到低位,取出每一个十六进制数字
if(SingleNumber < 10)
LCD1602_WriteData('0'+SingleNumber);
else
LCD1602_WriteData('A'+SingleNumber-10); //SingleNumber已含有10+x
}
} /**
* @brief 在LCD1602指定位置开始以二进制显示所给数字
* @param Line 起始行位置,范围:1~2
* @param Column 起始列位置,范围:1~16
* @param Number 要显示的数字,范围:0~1111_1111_1111_1111
* @param Length 要显示数字的长度,范围:1~16
* @retval 无
*/
void LCD1602_ShowBinNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length)
{
unsigned char i;
LCD1602_SetCursor(Line,Column);
for(i=Length;i>0;i--)
{
LCD1602_WriteData('0'+Number/LCD_Power(2,i-1)%2); //从高位到低位,取出每一个二进制数字
}
}
(5)独立按键函数
#ifndef _key_h_
#define _key_h_ unsigned char key(); #endif
#include <reg52.h>
#include "delayms.h" sbit key1 = P3^1;
sbit key2 = P3^0;
sbit key3 = P3^2;
sbit key4 = P3^3; /**
* @brief 获取独立按键键码
* @param 无
* @retval 按下按键的键码,范围:0~4,无按键按下时返回值为0
*/ unsigned char key()
{
unsigned char KeyNumber = 0;
if(key1==0){delayms(20);while(key1==0);delayms(20);KeyNumber=1;}
if(key2==0){delayms(20);while(key2==0);delayms(20);KeyNumber=2;}
if(key3==0){delayms(20);while(key3==0);delayms(20);KeyNumber=3;}
if(key4==0){delayms(20);while(key4==0);delayms(20);KeyNumber=4;}
return KeyNumber;
}
(6)延时函数
#ifndef _delayms_h_
#define _delayms_h_ delayms(unsigned int xms); #endif
#include <intrins.h> void delayms(unsigned int xms) //@11.0592MHz
{
unsigned char i, j; while(xms--)
{
_nop_();
i = 2;
j = 199;
do
{
while (--j);
} while (--i);
}
}
AT24C02数据存储+普中51单片机+江科大自化协的更多相关文章
- 67.Android中的数据存储总结
转载:http://mp.weixin.qq.com/s?__biz=MzIzMjE1Njg4Mw==&mid=2650117688&idx=1&sn=d6c73f9f04d0 ...
- android中数据存储
android中数据存储 Android 中存储数据的方式有五种:SQLite数据库.文件存储.内容提供者.网络.SharedPreferences(Key----value)五种存储方式. ...
- 51单片机外部中断INT0实例(汇编程序)
;普中51开发板 ;单片机的P3.2(INT0)引脚与按键K3脚连接 ;用汇编语言实现:按一次K1外部中断INT0响应一次,LED显示值加1(十进制), ;前提是共阴数码LED第一位,需要设定,由P0 ...
- .Net码农学Android---快速了解数据存储
数据存储 Andoid中的数据存储和我们平时见到的不一样,或者说移动设备的存储和平时不一样.Andoid中的存储方式有五种, 单把存储拎出来,是因为我们后续的开发会经常用到,重要性不言而喻,多样的存储 ...
- 【零基础】彻底搞懂51单片机各种型号(ATMEL系列)
零.前言 初学者开始学习51单片机时往往先是一愣,说好51单片机啊,咋个型号是AT89C52,这个S52又是咋回事?上学的时候大都懵懵懂懂就这么用着,但始终没整明白,所以今天我们就彻底搞明白这些“51 ...
- 51单片机RAM 数据存储区学习笔记
转自:http://www.eepw.com.cn/article/216237_2.htm 1.RAM keil C语言编程 RAM是程序运行中存放随机变量的数据空间.在keil中编写程序,如果当前 ...
- [51单片机] Keil C51中变量的使用方法详解
引言 8051内核单片机是一种通用单片机,在国内占有较大的市场份额.在将C语言用于51内核单片机的研究方面,Keil公司做得最为成功.由于51内核单片机的存储结构的特殊性,Keil C51中变量 ...
- sprintf在51单片机中的使用
sprintf在51单片机中的使用 unsigned char ch20_str[4]; unsigned char ch2o_m_str[6]; ch2o = 123; ch2o_m = 23456 ...
- Android编程中的5种数据存储方式
Android编程中的5种数据存储方式 作者:牛奶.不加糖 字体:[增加 减小] 类型:转载 时间:2015-12-03我要评论 这篇文章主要介绍了Android编程中的5种数据存储方式,结合实例形式 ...
- flink04 -----1 kafkaSource 2. kafkaSource的偏移量的存储位置 3 将kafka中的数据写入redis中去 4 将kafka中的数据写入mysql中去
1. kafkaSource 见官方文档 2. kafkaSource的偏移量的存储位置 默认存在kafka的特殊topic中,但也可以设置参数让其不存在kafka的特殊topic中 3 将k ...
随机推荐
- C# 读取类Class注释
https://www.cnblogs.com/shanfeng1000/p/14972515.html 友好的注释能提高代码的可读性,几乎所有的编程语言都支持注释. 在C#中,注释不是可执行代码的一 ...
- Excel:使用powerquery进行多表合并
注:本文原创为:https://www.cnblogs.com/fanyu2019/p/11175827.html,本文在原创的基础上添加修改了一点内容 目录 一. 单工作簿多工作表合并 二. 多工 ...
- 如何从ElasticSearch迁移到OpenSearch?
本文分享自天翼云开发者社区<如何从ElasticSearch迁移到OpenSearch?>,作者:刘****鑫 在云搜索产品的选择中,如果用户倾向于开源软件,并且更喜欢免费提供高级功能的工 ...
- phong模型和blinnphong模型简述
简介 phong 和 blinnphong 都是比较常用的光照模型 参考链接 https://github.com/Richbabe/Phong-BlinnPhong_Unity 非常好讲的 http ...
- Shared_ptr 参考实现
简介 为了防止我们忘记对一个指针对象的释放, C++11出现了shared_ptr. 我们也可以手动实现一个shared_ptr. 参考 https://blog.csdn.net/yanchenzh ...
- raspberry 用户管理
sudo adduser bob增加用户 sudo passwd bob修改用户的密码 sudo visudo 修改用户sudo的权限 bob ALL = NOPASSWD: ALL bob使用sud ...
- 使用RestCloud ETL强大的自定义规则实现自定义数据处理算法
实时数据处理规则有什么作用? 在大数据中的实时数据采集.ETL批量数据传输过程中很多数据处理过程以及数据质量都希望实时进行处理和检测并把不符合要求的脏数据过滤掉或者进行实时的数据质量告警等. 在数据仓 ...
- SciTech-EECS-Manufacturing-Battery:电池 电动车🛵/🚗的功率、行驶里程、电池、BMS、电机 和 控制器
SciTech-EECS-Manufacturing-Battery:电池 电动车/的功率.行驶里程.电池.BMS.电机 和 控制器: 消费者去买电动车,店家广告上 "车能跑100公里不充电 ...
- POLIR-Politics-Political Economics: "零知识" VS "零风险+负成本" : "宣扬'创新'与'极致'"是对组织"最有利"的方式?美国🇺🇸政府不是选最有利的。
POLIR-Politics-Political Economics: 名词解释 零知识: 前人没有的"知识(与经验)" 源于Google运用"AlphaGo(AI人工智 ...
- Angualr响应式表单
由于最近公司框架升级,抛弃了原来手动检验表单的方式,将所有的表单改为响应式,由于之前没用过,在一开始我以为只有我没有用过,了解了小组里的其他同事得知基本都不是很熟悉 后面时间比较紧,没办法只能边做边学 ...