24c02.c
来自「自己单片机板c程序」· C语言 代码 · 共 343 行
C
343 行
/*EEPROM24C02,程序将对存储器进行读和写,因此涉及到键盘程序,比较复杂,耐心学,*/
#include <reg51.h>
#include <intrins.h>
#define W24C02 0xA0 //存储器的写地址
#define R24C02 0xA1 //存储器的读地址
#define MSB 0x80 //8位二进制最高位置1
#define LSB 0x01 //8位二进制最低位置1
/********************/
sbit SDA=P3^6; //AT24C02串行数据 5脚
sbit SCL=P3^7; //AT24C02串行时钟 6脚
sbit SPK=P3^4; //蜂鸣器,按键用时蜂鸣
void I2C_write(unsigned char tmp); //向I2C总线写数据
unsigned char I2C_read(); //向I2C总线读数据
void I2C_ACK(bit tmp); //ACK应答
void I2C_start(void); //I2C传送数据的开始
void I2C_stop(void); //I2C传送数据的结束
void _24c02menu(void); //当我们按下按键进入处理I2C数据时用的函数
void _24c02wdate(unsigned char tmp); //当我们对24C02存储器进行写数据用到的函数
void display(unsigned char *lp,unsigned char lc);//显示,在键盘程序里用过
void displaystr(unsigned char *lp,unsigned char lc);//字符的显示函数,同上
void delay();//延时子函数
void ReadKey(void); //扫描键盘 获取键值
unsigned char l_key=0xFF; //定义变量,存放键值
unsigned char l_keyold=0; //做为按键松开否的凭证
code unsigned char l_24C02[5]={0x5b,0x66,0x39,0x3f,0x5b};//定义数组常量在数码管上显示24C02
unsigned char l_address=0; //读24C02的地址变量
unsigned char l_tmpdate[6]={0,0,0x10,0,0,0}; //数组变量
code unsigned char table[]=
{0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,
0x77,0x7c,0x39,0x5e,0x79,0x71,0x40};
//共阴数码管 0-9 a-f - 表
code unsigned char key_tab[17]={0xed,0x7e,0x7d,0x7b,
0xbe,0xbd,0xbb,0xde,
0xdd,0xdb,0x77,0xb7,
0xee,0xd7,0xeb,0xe7,0XFF};//========================此数组为键盘编码,
// 1 2 3 a
// 4 5 6 b
// 7 8 9 e
// * 0 # f
void main(void) //入口函数
{
EA=1; //首先开启总中断
EX0=1; //开启外部中断 0
IT0=1; // 设置成 下降沿触发方式
P0=0xf0; //P0口高位输高电平,经过74HC21四输入与门,连接外中断0,有键按下调用中断函数
while(1){
displaystr(l_24C02,5); //用这个函数显示5个字符
if(l_key==0x0e){
l_key=0xff; //按下#键调用
_24c02menu(); //此函数
}
}
}
//以下一部份在键盘程序里有说明,此处不在讲述
void key_scan() interrupt 0 //外部中断 0 0的优先级最高
{
EX0=0;
TMOD&=0XF1;
TH0=0X2E;
TL0=0X00;
ET0=1;
TR0=1;
}
void timer0_isr(void) interrupt 1 //定时器0的中断函数
{
TR0=0;
ReadKey();
}
void ReadKey(void) //读键盘值
{
unsigned char i,j,key;
j=0xfe;
key=0xff;
for (i=0;i<4;i++){
P0=j;
if ((P0&0xf0)!=0xf0){
key=P0;
break;
}
j=_crol_(j,1);
}
if (key==0xff){
l_keyold=0xff;
P0=0xf0;
EX0=1;
SPK=1;
return;
}
SPK=0;
if(l_keyold==key){
TH0=0X2E;
TL0=0;
TR0=1;
return;
}
TH0=0X2E;
TL0=0;
TR0=1;
l_keyold=key;
for(i=0;i<17;i++){
if (key==key_tab[i]){
l_key=i;
break;
}
}
}
void display(unsigned char *lp,unsigned char lc)//显示
{
unsigned char i;
P2=0;
P1=P1&0xF8;
for(i=0;i<lc;i++){
P2=table[lp[i]];
delay();
if(i==7)
break;
P2=0;
P1++;
}
}
void displaystr(unsigned char *lp,unsigned char lc)//显示
{
unsigned char i;
P2=0;
P1=P1&0xF8;
for(i=0;i<lc;i++){
P2=lp[i];
delay();
P2=0;
if(i==7)
break;
P1++;
}
}
void delay(void) //空5个指令
{
unsigned char i=10;
while(i)
i--;
}
void _24c02menu(void) //处理I2C数据时用的函数
{
unsigned char tmp,tmp2;
P2=0; //数码管显示清0
l_key=0xfe; //进入存储器处理程序先读取0地址的数据
while (1){
if(l_key==0x0c){ //如果按下*号键退出循环,即退出回到主函数
l_key=0xff;
break;
}
switch(l_key){ //扫描键盘做相应处理
case 0x0a: //按下0X0A键,我们可将它理解为上翻键
l_key=0xff;
if(l_address>0){
l_address--; //将地址减1
l_key=0xfe; //读取数据
}
break;
case 0x0b: //按下0X0A键,我们可将它理解为下翻键
l_key=0xff;
if(l_address<255){
l_address++; //将地址加1
l_key=0xfe; ////读取数据
}
break;
case 0x0e: //如果按下#号键,调用写存储器函数
l_key=0xff;
_24c02wdate(tmp);
l_key=0xfe;
break;
case 0xfe: //此按值是在键盘是没有的,我们有内部给他增加做为读数据处理
l_key=0xff;
I2C_start(); //I2C读数据的开始,到下面的结束是读一地址的整个过程,
I2C_write(W24C02); //向I2C总线发出读取24C02的地址
I2C_ACK(0); //下面就得你们自己结合I2C串口协议进行,先看看24C02数据手册是怎么讲I2C协议的
I2C_write(l_address);//先写入地址,
I2C_ACK(1);
I2C_stop();
I2C_start(); //再开始读取数据
I2C_write(R24C02);
I2C_ACK(0);
tmp=I2C_read();
I2C_ACK(1);
I2C_stop(); //读取一个地址的数据结束
l_tmpdate[0]=l_address/16; //数码管前两位显示地址(以16进制显示)
l_tmpdate[1]=l_address%16; //将地址变量分开用两位数据
l_tmpdate[3]=tmp/100; //后面用10进制数显示数据,中间用"-"隔开,数组l_tmpdate[2]
tmp2=tmp%100; //8位二进制最大十进制为255,所以我们也将它分开三位显示
l_tmpdate[4]=tmp2/10;
l_tmpdate[5]=tmp2%10;
break;
}
display(l_tmpdate,6);
}
}
void _24c02wdate(unsigned char tmp)//对24C02的写数据处理函数
{
unsigned char tmp2=0;
while(1){
if (l_key==0x0c){ //如果按下*号键退出循环,即退出回到上一极函数
l_key=0xff;
break;
}
if(l_key==0x0e){ //如果按下#号键,将更改的数据写入24C02存储器
l_key=0xff;
I2C_start(); //下面是写一地址数据的过程
I2C_write(W24C02); //先向总线发出写24C02的地址
I2C_ACK(0);
I2C_write(l_address); //写入地址
I2C_ACK(0);
I2C_write(tmp); //然后写入数据
I2C_ACK(1);
I2C_stop();
break;
}
switch(l_key){ //下面是对数据的处理
case 0x01: //如果按下1键,数据百位加1
l_key=0xff;
if(tmp<155)
tmp+=100;
break;
case 0x02: //如果按下2键,数据十位加1
l_key=0xff;
if(tmp<245)
tmp+=10;
break;
case 0x03: //如果按下3键,数据个位加1
l_key=0xff;
if(tmp<255)
tmp++;
break;
case 0x04: //如果按下4键,数据百位减1
l_key=0xff;
if(tmp>=100)
tmp-=100;
break;
case 0x05: //如果按下5键,数据十位减1
l_key=0xff;
if(tmp>=10)
tmp-=10;
break;
case 0x06: //如果按下6键,数据个位减1
l_key=0xff;
if(tmp>0)
tmp--;
break;
}
l_tmpdate[3]=tmp/100; //地址不变我们不用修改,更改数据显示即可
tmp2=tmp%100;
l_tmpdate[4]=tmp2/10;
l_tmpdate[5]=tmp2%10;
display(l_tmpdate,6);
}
}
void I2C_write(unsigned char tmp)//I2C写入一个8位二进制数,高位在前低位在后
{
unsigned char i;
for(i=0;i<8;i++){
SCL=0;
_nop_();
_nop_();
_nop_();
SDA=(bit)(tmp&0x80);
tmp<<=1;
_nop_();_nop_();_nop_();_nop_();_nop_();
SCL=1;
_nop_();_nop_();_nop_();_nop_();_nop_();
}
SCL=0;
}
unsigned char I2C_read(void)////I2C读取一个8位二进制数,也是高位在前低位在后
{
unsigned char i,tmp;
tmp=0;
for(i=0;i<8;i++){
SCL=0;
_nop_();
_nop_();
_nop_(); //加入空指令增加稳定性,这关系到频率问题
SDA=1;
_nop_();_nop_();_nop_();_nop_();_nop_();
SCL=1;
_nop_();_nop_();_nop_();_nop_();_nop_();
tmp<<=1;
if(SDA==1)
tmp++;
}
SCL=0;
return tmp;
}
void I2C_ACK(bit tmp) //根据tmp的1、0来决定应答信号
{
SDA=tmp;
_nop_();_nop_();_nop_();_nop_();_nop_();
SCL=1;
_nop_();_nop_();_nop_();_nop_();_nop_();
SCL=0;
}
void I2C_start(void) //看看I2C开始的波形,再对应SDA、SCL的输出
{
SDA=1;
_nop_();
SCL=1;
_nop_();
SDA=0;
_nop_();
SCL=0;
_nop_();
}
/*********/
void I2C_stop(void) //I2C结束
{
SDA=0;
_nop_();
SCL=1;
_nop_();
SDA=1;
_nop_();
SCL=0;
_nop_();
}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?