//C51_将按键次数写入AT24C02,再读出送LCD显示
//这篇文章较为详细介绍了AT24C02,感谢!
//开发版在连接AT24C02千万别连错,视力不好的近视的连好了仔细检查
//思路:1.利用以前编写的LCD显示函数(直接copy)
2.消抖程序确认按键按下(电平改变,直接copy)
3.计数程序
4.AT24C02的相关程序
#code
#include<reg51.h>
#include<intrins.h> //包含_nop_()函数的头文件
/*LCD模块与单片机引脚连接确定*/
sbit RS=P1^0;//RS为寄存选择位,引脚根据自己的电路图定义
sbit RW=P1^1;//读写选择位
sbit E=P1^2;//LCD模块使能端
sbit BF=P0^7;//1602字符型LCD设置的忙碌标志位BF连接在8位双向数据线的D7位上根据单片机原理图我对应于P0^7引脚
sbit S=P1^4; //开关
#define OP_READ 0xa1 // 宏 全局定义
#define OP_WRITE 0xa0
sbit SDA=P3^4; //SDA根据原理图设置引脚
sbit SCL=P3^3;
unsigned char code digit[ ]={"0123456789"}; //
/*LCD设置*/
/***************************************************
延时基函数:设置目的为根据所需时间随意改变谁让这是1ms
***************************************************/
void delay1ms()
{
unsigned char i,j;
for(i=0;i<10;i++)
for(j=0;j<33;j++)//time~=3*(i*j)
;
}
/*****************************************************
延时自定义函数:根据基变量1ms来自定义定延迟时间函数
***************************************************/
void delaynms(unsigned char n)
{
unsigned char i;
for(i=0;i<n;i++)
delay1ms();
}
/*****************************************************
LCD模块状态检测>>>LCD模块是慢显示器>>>在写每一条指令前需要检测
忙碌状态,忙等,不忙在执行。
***************************************************/
unsigned char BusyTest(void)
{
bit result;
RS=0;
//RS是寄存器选择,RS=0为选择了指令寄存器>>>检查是否忙碌跟指令相关
RW=1;
//RW为读写选择,RW=1为读LCD的忙碌状况>>>检查是要去读状态
E=1;
//E是模块使能端,负跳变时E=1,LCD模块开始执行命令
_nop_(); //一个空的机器周期(记住就OK啦!)
_nop_();
_nop_();
_nop_(); //4个机器周期,让硬件有充足反应时间>>>LCD是一个慢显示器
result=BF; //把BF的状态给result返回传达忙碌状态
E=0; //不得进行读/写操作
return result;//result=1 busy;result=0 rest
}
/*****************************************************
写入指令:将模式设置指令或显示地址写入LCD模块
写指令RS=0;RW=0;E=0>>>E=1>>>E=0(高脉冲,过程才能写入dictate)
***************************************************/
void WriteInstruction (unsigned char dictate)
{
while(BusyTest()==1); //检查LCD是否忙碌是则空操作等待至位0
RS=0; //选择指令寄存器
RW=0; //选择进行写入操作
E=0; //脉冲开始
_nop_();
_nop_(); //老年人多体谅给点反应时间
P0=dictate;
//把dictate(指令或地址)送入P0口即写入指令或地址
_nop_();
_nop_();
_nop_();
_nop_(); //4个机器周期用于硬件处理
E=1; //高电平,产生跳变>>>进行读写操作
_nop_();
_nop_();
_nop_();
_nop_(); //就是如此无语的慢
E=0;
//负跳变完成一个脉冲。LCD模块开始执行dictate。
}
/*****************************************************
指定字符显示地址:跟据1602字符型LCD
确定位置的方法80H+地址码知道输出实际地址
***************************************************/
void WriteAddress(unsigned char x)
{
WriteInstruction(x|0x80);
//通过WriteInstruction函数将指令写入
}
/*****************************************************
写数据:将数据(想在LCD上输出的字符标准ASCII码/电脑会将A等自动转为ASCII码/)写入LCD模块
***************************************************/
void WriteData(unsigned char y)
{
while(BusyTest()==1);
RS=1; //选择数据寄存器
RW=0; //写数据
E=0; //高脉冲
P0=y; //将数据送入P0口,将数据写入液晶模块
_nop_();
_nop_();
_nop_();
_nop_();
E=1;
_nop_();
_nop_();
_nop_();
_nop_();
E=0;
}
/*****************************************************
LCD初始化
***************************************************/
void LcdInitiate(void)
{
delaynms(15); //首次写指令延时>>>充足反应时间
WriteInstruction(0x38);
//显示模式:16*2显示,5*7点阵,8位数据接口
delaynms(5);
WriteInstruction(0x38);
delaynms(5);
WriteInstruction(0x38); //确保成功
delaynms(5);
WriteInstruction(0x0c); //显示模式:显示开,有光标,光标闪烁
delaynms(5);
WriteInstruction(0x06); //显示模式:光标移动,字符不动
delaynms(5);
WriteInstruction(0x01); //清屏指令
delaynms(5);
}
/***************************************************
***************************************************/
void Display(unsigned char x)
{
unsigned char i,j;
i=x/10;
j=x%10;
WriteAddress(0x44);
WriteData(digit[i]);
WriteData(digit[j]);
}
/******************AT24C02的操作******************/
/***************************************************
AT24C02开始信号
***************************************************/
void start()
// 开始传输数据
{
SDA = 1; //串行数据/地址线高电平
SCL = 1; //串行时钟线高电平
_nop_(); //机器周期>>>反应时间
_nop_();
SDA = 0; //开始传输数据标志SDA负跳变,SCL尚处于高电平
_nop_();
_nop_();
_nop_();
_nop_();
SCL = 0; //SCL为低电平时,SDA上的数据才允许变化即允许以后数据传输
}
/***************************************************
AT24C02停止信号
***************************************************/
void stop()
// 停止传输数据
{
SDA = 0; //结束出初期SDA为低电平
_nop_();
_nop_();
SCL = 1; //高电平,不允许数据传输
_nop_();
_nop_();
_nop_();
_nop_();
SDA = 1; //最终SDA变为高电平
}
/*以上两步的图解可以参考度娘上的便于理解*/
/***************************************************
从AT24C02读取数据
***************************************************/
unsigned char ReadData()
//将AT24C02数据给MCU
{
unsigned char i;
unsigned char x; //存储从AT24C02中读出的数据
for(i = 0; i < 8; i++)
{
SCL = 1; //SCL置为高电平
x<<=1; //将x中二进制向左移动一位
x|=(unsigned char)SDA;
//将SDA中的数据通过按位或运算存入x中
SCL = 0; //在SCL下降时读出数据
}
return(x);
}
/***************************************************
向AT24C02当前地址写入数据
***************************************************/
//因为要用到start函数,so SCL=0
bit WriteCurrent(unsigned char y)
{
unsigned char i;
bit ack_bit; //存储应答位
for(i = 0; i < 8; i++) //循环移入8个位
{
SDA = (bit)(y&0x80); //按位与运算将最高位数据送到S
//传递时高位在前低位在后
_nop_();
SCL = 1; //上升时将数据写入AT24C02
_nop_();
_nop_();
SCL = 0; //置零为为循环准备
y <<= 1;
}
SDA = 1; // 主机在时钟脉冲的高电平期间释放SDA
//ÒÔÈÃSDAÏßתÓɽÓÊÕÉ豸(AT24Cxx)¿ØÖÆ
_nop_();
_nop_();
SCL = 1;
_nop_();
_nop_();
_nop_();
_nop_();
ack_bit = SDA; //表示AT24C02向SDA输送低电平表示已经接收到了第一个字节
//若为高电平则异常
SCL = 0; //SCL位低电平SDA才允许数据变化即允许后续数据传输
return ack_bit; //返回AT24C02的应答位
}
/***************************************************
向AT24C02中指定地址写入数据
add为存储指定地址,dat为存储待写入数据
***************************************************/
void WriteSet(unsigned char add, unsigned char dat)
// 在指定地址addr处写入数据WriteCurrent
{
start(); //开始传递
WriteCurrent(OP_WRITE); //选择要操作的芯片,并告知要对其写入数据
WriteCurrent(add); //写入指定地址
WriteCurrent(dat); //向上面指定地址写入数据
stop(); //停止数据传递
delaynms(4);
}
/***************************************************
从当前地址读取数据
***************************************************/
unsigned char ReadCurrent()
{
unsigned char x;
start();
WriteCurrent(OP_READ); //选择要操作的芯片,并告知要对其写入数据
x=ReadData();
stop();
return x;
}
/***************************************************
在指定地址读取数据
***************************************************/
unsigned char ReadSet(unsigned char set_add)
// 在指定地址读取
{
start();
WriteCurrent(OP_WRITE);
WriteCurrent(set_add);
return(ReadCurrent()); //从指定地址读出数据并返回
}
void main(void)
{
unsigned char sum;
unsigned char x; //存储从AT24C02读出数值
LcdInitiate();
sum=0;
while(1)
{
if(S==0)
{
delaynms(80);
if(S==0)
sum++;
if(sum==99)
sum=0;
}
WriteSet(0x01,sum);
x=ReadSet(0x01);
Display(x);
}
}