找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 3414|回复: 3
打印 上一主题 下一主题
收起左侧

24C02放不下的情结绕不过的坎

  [复制链接]
跳转到指定楼层
楼主
ID:474670 发表于 2019-2-2 13:11 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
第一课  写入一个字节到24c02 中
24c02 是一个非挥发eeprom 存储器器件,采用的IIC 总线技术。24c02 在许多试验
中都有出现。24c02 的应用,主要在存储一些掉电后还要保存数据的场合,在上次运行
时,保存的数据,在下一次运行时还能够调出。24c02 采用的IIC 总线,是一种2 线
总线,我们在试验中用IO 来模拟这种总线,至于总线的时序和原理,请参考相关资料。
如果您不想研究, 也没有关系, 我们在程序中已经为你写好了,现在和今后您都可以只调用
就是,不必花时间和精力去研究。一块24c02 中有256 个字节的存储空间。我们将
24c02 的两条总线接在了P26 和P27 上,因此,必须先定义:
sbit SCL=P2^7;
sbit SDA=P2^6;
在这个试验中,我们写入了一个字节数值0x88 到24c02 的0x02 的位置。
写入完成后, P10 灯会亮起,我们再在下一颗来读出这个字节来验证结果。
―――――――――――――
#define uchar unsigned char// 定义一下方便使用
#define uint unsigned int
#define ulong unsigned long
#include <reg52.h> //包括一个52 标准内核的头文件
// 本课试验写入一个字节到24c02 中
char code dx516[3] _at_0x003b;// 这是为了仿真设置的
#define WriteDeviceAddress0xa0 // 定义器件在IIC 总线中的地址
#define ReadDviceAddress0xa1
sbit SCL=P2^7;
sbit SDA=P2^6;
sbit P10=P1^0;
// 定时函数
void DelayMs(uint number)
{
uchar temp;
for(;number!=0;number--)
{
for(temp=112;temp!=0;temp--);
}
}
// 开始总线
void Start()
{
SDA=1;
SCL=1;
SDA=0;
SCL=0;
}
// 结束总线
void Stop()
{
SCL=0;
SDA=0;
SCL=1;
SDA=1;
}
// 测试ACK
bit TestAck()
{
bit ErrorBit;
SDA=1;
SCL=1;
ErrorBit=SDA;
SCL=0;
return(ErrorBit);
}
// 写入8 个bit 到24c02
Write8Bit(uchar input)
{
uchar temp;
for(temp=8;temp!=0;temp--)
{
SDA=(bit)(input&0x80);
SCL=1;
SCL=0;
input=input<<1;
}
}
// 写入一个字节到24c02 中
void Write24c02(uchar ch,uchar address)
{
Start();
Write8Bit(WriteDeviceAddress);
TestAck();
Write8Bit(address);
TestAck();
Write8Bit(ch);
TestAck();
Stop();
DelayMs(10);
}
void main(void) // 主程序
{
Write24c02(0x88,0x02);// 将0x88 写入到24c02 的第2 个地址空间
P10=0; // 指示运行完毕
while(1); // 程序挂起
}
―――――――――――――――――
【24C02放不下的情结绕不过的坎】
第二课  写入一个字节到24c02 并读出来
本课的程序已经包含了上一颗的内容,增加了读24c02 的函数,请看程序:
―――――――――――――――――――――――――――――
#define uchar unsigned char// 定义一下方便使用
#define uint unsigned int
#define ulong unsigned long
#include <reg52.h> //包括一个52 标准内核的头文件
char code dx516[3] _at_0x003b;// 这是为了仿真设置的
#define WriteDeviceAddress0xa0 // 定义器件在IIC 总线中的地址
#define ReadDviceAddress0xa1
sbit SCL=P2^7;
sbit SDA=P2^6;
sbit P10=P1^0;
// 定时函数
void DelayMs(unsigned intnumber)
{
unsigned char temp;
for(;number!=0;number--)
{
for(temp=112;temp!=0;temp--);
}
}
// 开始总线
void Start()
{
SDA=1;
SCL=1;
SDA=0;
SCL=0;
}
// 结束总线
void Stop()
{
SCL=0;
SDA=0;
SCL=1;
SDA=1;
}
// 发ACK0
void NoAck()
{
SDA=1;
SCL=1;
SCL=0;
}
// 测试ACK
bit TestAck()
{
bit ErrorBit;
SDA=1;
SCL=1;
ErrorBit=SDA;
SCL=0;
return(ErrorBit);
}
// 写入8 个bit 到24c02
Write8Bit(unsigned charinput)
{
unsigned char temp;
for(temp=8;temp!=0;temp--)
{
SDA=(bit)(input&0x80);
SCL=1;
SCL=0;
input=input<<1;
}
}
// 写入一个字节到24c02 中
void Write24c02(uchar ch,uchar address)
{
Start();
Write8Bit(WriteDeviceAddress);
TestAck();
Write8Bit(address);
TestAck();
Write8Bit(ch);
TestAck();
Stop();
DelayMs(10);
}
// 从24c02 中读出8 个bit
uchar Read8Bit()
{
unsigned char temp,rbyte=0;
for(temp=8;temp!=0;temp--)
{
SCL=1;
rbyte=rbyte<<1;
rbyte=rbyte|((unsignedchar)(SDA))
SCL=0;
}
return(rbyte);
}
// 从24c02 中读出1 个字节
uchar Read24c02(uchar address)
{
uchar ch;
Start();
Write8Bit(WriteDeviceAddress);
TestAck();
Write8Bit(address);
TestAck();
Start();
Write8Bit(ReadDviceAddress);
TestAck();
ch=Read8Bit();
NoAck();
Stop();
return(ch);
}
void main(void) // 主程序
{
uchar c1,c2;
c1=Read24c02(0x02);
Write24c02(0x99,0x03);
c2=Read24c02(0x03);
P10=0;
while(1); // 程序挂起
}
――――――――――――――――
在主程序中,我们将上一课写入的0x02 位置的数据读出来放在c1 中,新写了一个数
据0x99 在0x03 位置中,并立即将它读出来放在c2 中。
【24C02放不下的情结绕不过的坎】
第三课  写入按键次数到24c02 ,并读出来显示在4 个LED 上
#define uchar unsigned char// 定义一下方便使用
#define uint unsigned int
#define ulong unsigned long
#include <reg52.h> //包括一个52 标准内核的头文件
char code dx516[3] _at_0x003b;// 这是为了仿真设置的
#define WriteDeviceAddress0xa0 // 定义器件在IIC 总线中的地址
#define ReadDviceAddress0xa1
sbit SCL=P2^7;
sbit SDA=P2^6;
sbit P10=P1^0;
sbit K1=P3^2;
// 定时函数
void DelayMs(unsigned intnumber)
{
unsigned char temp;
for(;number!=0;number--)
{
for(temp=112;temp!=0;temp--);
}
}
// 开始总线
void Start()
{
SDA=1;
SCL=1;
SDA=0;
SCL=0;
}
// 结束总线
void Stop()
{
SCL=0;
SDA=0;
SCL=1;
SDA=1;
}
// 发ACK0
void NoAck()
{
SDA=1;
SCL=1;
SCL=0;
}
// 测试ACK
bit TestAck()
{
bit ErrorBit;
SDA=1;
SCL=1;
ErrorBit=SDA;
SCL=0;
return(ErrorBit);
}
// 写入8 个bit 到24c02
Write8Bit(unsigned charinput)
{
unsigned char temp;
for(temp=8;temp!=0;temp--)
{
SDA=(bit)(input&0x80);
SCL=1;
SCL=0;
input=input<<1;
}
}
// 写入一个字节到24c02 中
void Write24c02(uchar ch,uchar address)
{
Start();
Write8Bit(WriteDeviceAddress);
TestAck();
Write8Bit(address);
TestAck();
Write8Bit(ch);
TestAck();
Stop();
DelayMs(10);
}
// 从24c02 中读出8 个bit
uchar Read8Bit()
{
unsigned char temp,rbyte=0;
for(temp=8;temp!=0;temp--)
{
SCL=1;
rbyte=rbyte<<1;
rbyte=rbyte|((unsignedchar)(SDA));
SCL=0;
}
return(rbyte);
}
// 从24c02 中读出1 个字节
uchar Read24c02(uchar address)
{
uchar ch;
Start();
Write8Bit(WriteDeviceAddress);
TestAck();
Write8Bit(address);
TestAck();
Start();
Write8Bit(ReadDviceAddress);
TestAck();
ch=Read8Bit();
NoAck();
Stop();
return(ch);
}
void main(void) // 主程序
{
uchar c1,c2;
while(1)
{
c1=Read24c02(0x01); // 读出24c02 第一个地址数据
P1=c1; // 显示在P1 口的4 个LED 上
if(!K1) // 按键处理
{
c1++; // 值加1
Write24c02(c1,0x01); // 重新写入24c02
while(!K1); // 等待按键松开
for(c2=0;c2<250;c2++);// 松开按键去抖
}
}
}
【24C02放不下的情结绕不过的坎】
第四课  把乐谱全部写入到了24c02 中
前面我们只学习过写入一个字节到24c02 中。在这一课中,我们将一首乐谱全部写入
到24c02 中。在下一课时,我们将会读出24c02 中的乐谱播放。
这种工作方式,可以比作一个简单的mp3 ,将乐曲写在可以重复写入的存储器中,播
放时,读出来再播放。这样,只要换一个存有新的音乐的存储器,或者从外部将新的乐曲写
入到存储器中,就可以播放新的乐曲,而单片机的程序并没有改变。
――――――――――――――――――――――――――――
#define uchar unsigned char// 定义一下方便使用
#define uint unsigned int
#define ulong unsigned long
#include <reg52.h> //包括一个52 标准内核的头文件
// 本课试验写入一个字节到24c02 中
char code dx516[3] _at_0x003b;// 这是为了仿真设置的
#define WriteDeviceAddress0xa0 // 定义器件在IIC 总线中的地址
#define ReadDviceAddress0xa1
sbit SCL=P2^7;
sbit SDA=P2^6;
sbit P10=P1^0;
// 定时函数
void DelayMs(uint number)
{
uchar temp;
for(;number!=0;number--)
{
for(temp=112;temp!=0;temp--);
}
}
// 开始总线
void Start()
{
SDA=1;
SCL=1;
SDA=0;
SCL=0;
}
// 结束总线
void Stop()
{
SCL=0;
SDA=0;
SCL=1;
SDA=1;
}
// 测试ACK
bit TestAck()
{
bit ErrorBit;
SDA=1;
SCL=1;
ErrorBit=SDA;
SCL=0;
return(ErrorBit);
}
// 写入8 个bit 到24c02
Write8Bit(uchar input)
{
uchar temp;
for(temp=8;temp!=0;temp--)
{
SDA=(bit)(input&0x80);
SCL=1;
SCL=0;
input=input<<1;
}
}
// 写入一个字节到24c02 中
void Write24c02(uchar ch,uchar address)
{
Start();
Write8Bit(WriteDeviceAddress);
TestAck();
Write8Bit(address);
TestAck();
Write8Bit(ch);
TestAck();
Stop();
DelayMs(10);
}
// 老鼠爱大米
uchar code dami[]={
"321-|3.2_1-|3231|3_6.5-|3_5_665|65-3_2_|122_3_2|12--|"
};
// 本课试验写老鼠爱大米的乐谱到24c02 中
void main(void) // 主程序
{
uchar i;
for(i=0;dami!=0;i++)
{
Write24c02(dami,i);// 逐个写入到24c02 的中
}
Write24c02(0x00,i); // 写入最后一个0
P10=0; // 指示运行完毕
while(1); // 程序挂起
}
――――――――――――――――――――――――
通过一个for 循环,我们就把乐谱全部写入到了24c02 中。看到for 循环的条件是
dami!=0 ,这是因为字符串的最后一个字符是0,可以作为结束的判断,这个方法在前面
的音乐播放等例子中已经见到。
【24C02放不下的情结绕不过的坎】
第五课  从24c02 中读出音乐来并播放音乐
这一课,我们学会从24C02 中读出音乐,并实现单片机播放音乐。
main.c
―――――――――――――――――――――――
#define uchar unsigned char// 定义一下方便使用
#define uint unsigned int
#define ulong unsigned long
#include <reg52.h> //包括一个52 标准内核的头文件
extern uchar Read24c02(uchar address); // 声明外部的读24c02 函数
extern void play(uchar*songdata); // 声明外部的音乐播放函数
char code dx516[3] _at_0x003b;// 这是为了仿真设置的
sbit P10=P1^0;
sbit K1= P3^2;
sbit K2=P3^5;
sbit K3= P2^4;
sbit K4= P2^5;
void main(void) // 主程序
{
uchar i;
uchar xdata yinyue[256]; //设立一个缓冲区
TMOD = 0x01; // 使用定时器0 的16 位工作模式
TR0 = 0;
ET0 = 1; // 定时器0 中断
EA = 1; // 打开总中断
for(i=0;yinyue!=0;i++) // 读出音乐来放到缓冲中
{
yinyue=Read24c02(i);
}
yinyue=0;
while(1)
{
play(yinyue); // 播放音乐
}
}
――――――――――――――――――――――――――
24c02.c
―――――――――――――――――――――――
#define uchar unsigned char// 定义一下方便使用
#define uint unsigned int
#define ulong unsigned long
#include <reg52.h> //包括一个52 标准内核的头文件
#define WriteDeviceAddress0xa0 // 定义器件在IIC 总线中的地址
#define ReadDviceAddress0xa1
sbit SCL=P2^7;
sbit SDA=P2^6;
sbit P10=P1^0;
/*
// 定时函数
void DelayMs(unsigned intnumber)
{
unsigned char temp;
for(;number!=0;number--)
{
for(temp=112;temp!=0;temp--);
}
}
*/
// 开始总线
void Start()
{
SDA=1;
SCL=1;
SDA=0;
SCL=0;
}
// 结束总线
void Stop()
{
SCL=0;
SDA=0;
SCL=1;
SDA=1;
}
// 发ACK0
void NoAck()
{
SDA=1;
SCL=1;
SCL=0;
}
// 测试ACK
bit TestAck()
{
bit ErrorBit;
SDA=1;
SCL=1;
ErrorBit=SDA;
SCL=0;
return(ErrorBit);
}
// 写入8 个bit 到24c02
Write8Bit(unsigned charinput)
{
unsigned char temp;
for(temp=8;temp!=0;temp--)
{
SDA=(bit)(input&0x80);
SCL=1;
SCL=0;
input=input<<1;
}
}
/*
// 写入一个字节到24c02 中
void Write24c02(uchar ch,uchar address)
{
Start();
Write8Bit(WriteDeviceAddress);
TestAck();
Write8Bit(address);
TestAck();
Write8Bit(ch);
TestAck();
Stop();
DelayMs(10);
}
*/
// 从24c02 中读出8 个bit
uchar Read8Bit()
{
unsigned char temp,rbyte=0;
for(temp=8;temp!=0;temp--)
{
SCL=1;
rbyte=rbyte<<1;
rbyte=rbyte|((unsignedchar)(SDA));
SCL=0;
}
return(rbyte);
}
// 从24c02 中读出1 个字节
uchar Read24c02(uchar address)
{
uchar ch;
Start();
Write8Bit(WriteDeviceAddress);
TestAck();
Write8Bit(address);
TestAck();
Start();
Write8Bit(ReadDviceAddress);
TestAck();
ch=Read8Bit();
NoAck();
Stop();
return(ch);
}
――――――――――――――――――――――――――
music.c
――――――――――――――――――
#define uchar unsigned char// 定义一下方便使用
#define uint unsigned int
#define ulong unsigned long
#include <reg52.h> //包括一个52 标准内核的头文
sbit BEEP=P1^7; // 喇叭输出脚
sbit K1= P3^2;
sbit K2=P3^5;
sbit K3= P2^4;
sbit K4= P2^5;
uchar th0_f; // 在中断中装载的T0 的值高8 位
uchar tl0_f; // 在中断中装载的T0 的值低8 位
//T0 的值,及输出频率对照表
uchar code freq[36*2]={
0xA9,0xEF,//00220HZ ,1 //0
0x93,0xF0,//00233HZ ,1#
0x73,0xF1,//00247HZ ,2
0x49,0xF2,//00262HZ ,2#
0x07,0xF3,//00277HZ ,3
0xC8,0xF3,//00294HZ ,4
0x73,0xF4,//00311HZ ,4#
0x1E,0xF5,//00330HZ ,5
0xB6,0xF5,//00349HZ ,5#
0x4C,0xF6,//00370HZ ,6
0xD7,0xF6,//00392HZ ,6#
0x5A,0xF7,//00415HZ ,7
0xD8,0xF7,//00440HZ 1 //12
0x4D,0xF8,//00466HZ 1# //13
0xBD,0xF8,//00494HZ 2 //14
0x24,0xF9,//00523HZ 2# //15
0x87,0xF9,//00554HZ 3 //16
0xE4,0xF9,//00587HZ 4 //17
0x3D,0xFA,//00622HZ 4# //18
0x90,0xFA,//00659HZ 5 //19
0xDE,0xFA,//00698HZ 5# //20
0x29,0xFB,//00740HZ 6 //21
0x6F,0xFB,//00784HZ 6# //22
0xB1,0xFB,//00831HZ 7 //23
0xEF,0xFB,//00880HZ `1
0x2A,0xFC,//00932HZ `1#
0x62,0xFC,//00988HZ `2
0x95,0xFC,//01046HZ `2#
0xC7,0xFC,//01109HZ `3
0xF6,0xFC,//01175HZ `4
0x22,0xFD,//01244HZ `4#
0x4B,0xFD,//01318HZ `5
0x73,0xFD,//01397HZ `5#
0x98,0xFD,//01480HZ `6
0xBB,0xFD,//01568HZ `6#
0xDC,0xFD,//01661HZ `7 //35
};
// 定时中断0, 用于产生唱歌频率
timer0() interrupt 1
{
TL0=tl0_f;TH0=th0_f; // 调入预定时值
BEEP=~BEEP; // 取反音乐输出IO
}
//******************************
// 音乐符号串解释函数
// 入口: 要解释的音乐符号串, 输出的音调串,输出的时长串
changedata(uchar*song,uchar *diao,uchar *jie)
{
uchar i,i1,j;
char gaodi; // 高低+/-12 音阶
uchar banyin;// 有没有半个升音阶
uchar yinchang;// 音长
uchar codejie7[8]={0,12,14,16,17,19,21,23}; //C 调的
*diao=*song;
for(i=0,i1=0;;)
{
gaodi=0; // 高低=0
banyin=0;// 半音=0
yinchang=4;// 音长1 拍
if((*(song+i)=='|') ||(*(song+i)==' ')) i++;
// 拍子间隔和一个空格过滤
switch(*(song+i))
{
case ',': gaodi=-12;i++;// 低音
break;
case '`': gaodi=12;i++; // 高音
break;
}
if(*(song+i)==0) // 遇到0 结束
{
*(diao+i1)=0; // 加入结束标志0
*(jie+i1)=0;
return;
}
j=*(song+i)-0x30; i++; // 取出基准音
j=jie7[j]+gaodi; // 加上高低音
yinc: switch(*(song+i))
{
case '#': // 有半音j 加一个音阶
i++;j++;
goto yinc;
case '-': // 有一个音节加长
yinchang+=4;
i++;
goto yinc;
case '_': // 有一个音节缩短
yinchang/=2;
i++;
goto yinc;
case '.': // 有一个加半拍
yinchang=yinchang+yinchang/2;
i++;
goto yinc;
}
*(diao+i1)=j; // 记录音符
*(jie+i1)=yinchang; // 记录音长
i1++;
}
}
//******************************************
// 奏乐函数
// 入口: 要演奏的音乐符号串
void play(uchar *songdata)
{
uchar i,c,j=0;
uint n;
uchar xdata diaodata[112];// 音调缓冲
uchar xdata jiedata[112];// 音长缓冲
changedata(songdata,diaodata,jiedata);// 解释音乐符号串
TR0=1;
for(i=0;diaodata!=0;i++) //逐个符号演奏
{
tl0_f=freq[diaodata*2]; // 取出对应的定时值送给T0
th0_f=freq[diaodata*2+1];
for(c=0;c<jiedata;c++)// 按照音长延时
{
for(n=0;n<32000;n++);
if((!K1)||(!K2)||(!K3)||(!K4))//发现按键,立即退出播放
{
TR0=0;
return;
}
}
TR0=0;
for(n=0;n<500;n++); // 音符间延时
TR0=1;
}
TR0=0;
}



评分

参与人数 7黑币 +194 收起 理由
春风十里吹 + 12
zhengchong60 + 15
jinsheng7533967 + 35
areyouok + 35
钻牛尖滴刘尖尖 + 12
shuisheng60 + 35
admin + 50 共享资料的黑币奖励!

查看全部评分

分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏1 分享淘帖 顶 踩
回复

使用道具 举报

沙发
ID:236982 发表于 2019-2-2 16:43 | 只看该作者
精彩,有料,不错的IIC读写24C02教程
回复

使用道具 举报

板凳
ID:472242 发表于 2019-2-4 18:59 | 只看该作者
不错不错,分享可贵!

评分

参与人数 7黑币 +205 收起 理由
sheng7533967 + 15
钻牛尖滴刘尖尖 + 35 赞一个!
刀刀见红 + 35
jinsheng7533967 + 35
areyouok + 35
Sawardeakar + 35
#include51.h + 15 很给力!

查看全部评分

回复

使用道具 举报

地板
ID:473186 发表于 2019-3-7 23:07 | 只看该作者
值得学习与探讨
回复

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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