RAM : 易失性存储器 (高速存储)
- SRAM:静态RAM,电脑中的CPU,高速缓存,容量少,成本高
- DRAM:动态RAM,使用电容存储,电容容值小,需要补电能,成本相较于SRAM更低,容量更大
ROM:非易失性存储器
- Mask ROM(掩膜ROM),只能读,不能写
- PROM:可编程ROM,可以写,但是只能写入一次
- EPROM:可擦除可编程ROM,可以编程,也可以清除(30分钟紫外线)
- E2PROM: 电可擦除可编程ROM,5V电可擦除,掉电不丢失
- Flash(闪存):
- 硬盘、软盘、光盘等:磁介质、光信号
单片机烧录的由来:早期通过编程储存数据,实际上是将特殊的二极管击穿,相当于“烧毁”(PROM)。
AT24C02介绍
I2C总线介绍:
为什么要开漏输出模式?
- 输出端浮空,电平易受外界干扰,不稳定
![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/a446e82c166b462bb6128a982ee637da.png
I2C不同的流程模块:
- 起始条件
- 中止条件
- 发送一个字节
- 接收一个字节
- 接收应答
- 发送应答
实验: 给AT24C02写入数据
实验现象:AT24C02掉电不丢失
代码:
#include <REGX52.H>
#include "LCD1602.h"
#include "Key.h"
#include "AT24C02.h"
#include "Delay.h"
unsigned char Data;
void main()
{
LCD_Init();
LCD_ShowString(1,1,"Hello World");
//AT24C02_WriteByte(1,123);
Delay(5);//AT21C02写一个序列的有效停止条件开始至内部写周期结束的时间
Data=AT24C02_ReadByte(1);
LCD_ShowNum(2,1,Data,3);
while(1)
{
}
}
完善代码:
#include <REGX52.H>
#include "LCD1602.h"
#include "Key.h"
#include "AT24C02.h"
#include "Delay.h"
unsigned char KeyNum;
//unsigned char Num; 这里要用到整型
unsigned int Num;
void main()
{
LCD_Init();
LCD_ShowNum(1,1,Num,5);
while(1)
{
KeyNum=Key();
if(KeyNum==1)
{
Num++;
LCD_ShowNum(1,1,Num,5);
}
if(KeyNum==2)
{
Num--;
LCD_ShowNum(1,1,Num,5);
}
if(KeyNum==3)
{
AT24C02_WriteByte(0,Num%256);//低八位
Delay(5);
AT24C02_WriteByte(1,Num/256);//高八位
Delay(5);
LCD_ShowString(2,1,"Write OK");//完成写入数据,提示
Delay(1000);
LCD_ShowString(2,1," ");//延时清除
}
if(KeyNum==4)//读的时候不需要Delay
{
Num=AT24C02_ReadByte(0);
Num|=AT24C02_ReadByte(1)<<8;
LCD_ShowNum(1,1,Num,5);
LCD_ShowString(2,1,"Read OK");//完成读取数据,提示
Delay(1000);
LCD_ShowString(2,1," ");//延时清除
}
}
}
为什么要写?
AT24C02_WriteByte(0,Num%256);//低八位
Delay(5);
AT24C02_WriteByte(1,Num/256);//高八位
因为:int类型最高65535,对应的二进制为16位
实验:定时器按键扫描实例1
实验结果:如果直接让Nixie在判断键码后显示Keynum值,只能显示一瞬间,数码管的显示方式不同于LCD1602,所以需要一个缓存量Temp
Temp=Key();
if(KeyNum)//显示结果只在一瞬间显示
{
Nixie(1,KeyNum);
}
if(Temp)
{
KeyNum=Temp;
}
Nixie(1,KeyNum);
实验:定时器按键扫描实列2
#include <REGX52.H>
#include "Key.h"
#include "AT24C02.h"
#include "Timer0.h"
#include "Nixie.h"
#include "Delay.h"
unsigned char KeyNum;
void main()
{
Timer0_Init();
while(1)
{
KeyNum=Key();
if(KeyNum)
{
Nixie_SetBuf(1,KeyNum);
Nixie_SetBuf(2,KeyNum);
Nixie_SetBuf(3,KeyNum);
Delay(1000);
}
}
}
void Timer0_Routine() interrupt 1 //中断子程序
{
static unsigned int T0Count1,T0Count2;//静态局部变量,保证退出函数之后不销毁
TL0 = 0x66; //设置定时初始值
TH0 = 0xFC; //设置定时初始值
T0Count1++;//每次进入中断子程序,秒控制器自加一
if(T0Count1>=20)//每隔20ms,按键函数会被调用一次
{
T0Count1=0;
Key_Loop();
}
T0Count2++;
if(T0Count2>=2)
{
T0Count2=0;
Nixie_Loop();
}
}
实验结果:
这时,按下按键,数码管显示会延时一秒改变,可见,使用定时器扫描按键,不会被延时函数影响,相较于延时函数使单片机的工作更具有可靠性
秒表源代码:
操作方式:
- 按键1暂停
- 按键2清零
- 按键3通过AT24C02写入数据
- 按键4通过AT24C02读取数据
#include <REGX52.H>
#include "Key.h"
#include "AT24C02.h"
#include "Timer0.h"
#include "Nixie.h"
#include "Delay.h"
unsigned char KeyNum;
unsigned char Min,Sec,MiniSec;//单位:分,秒,1/100s=10ms
unsigned char RunFlag;//启动暂定标志位
void main()
{
P2_5=0;//蜂鸣器关闭
Timer0_Init();
while(1)
{
KeyNum=Key();
if(KeyNum==1)
{
RunFlag=!RunFlag;
}
if(KeyNum==2)
{
Min=0;Sec=0;MiniSec=0;
}
if(KeyNum==3)
{
AT24C02_WriteByte(0,Min);
Delay(5);
AT24C02_WriteByte(1,Sec);
Delay(5);
AT24C02_WriteByte(2,MiniSec);
Delay(5);
}
if(KeyNum==4)
{
Min=AT24C02_ReadByte(0);
Sec=AT24C02_ReadByte(1);
MiniSec=AT24C02_ReadByte(2);
}
Nixie_SetBuf(1,Min/10);
Nixie_SetBuf(2,Min%10);
Nixie_SetBuf(3,11);
Nixie_SetBuf(4,Sec/10);
Nixie_SetBuf(5,Sec%10);
Nixie_SetBuf(6,11);
Nixie_SetBuf(7,MiniSec/10);
Nixie_SetBuf(8,MiniSec%10);
}
}
void Sec_Loop(void)
{
if(RunFlag)
{
MiniSec++;
if(MiniSec>=100)
{
MiniSec=0;
Sec++;
}
if(Sec>=60)
{
Sec=0;
Min++;
}
if(Min>=60)
{
Min=0;
}
}
}
void Timer0_Routine() interrupt 1 //中断子程序
{
static unsigned int T0Count1,T0Count2,T0Count3;//静态局部变量,保证退出函数之后不销毁
TL0 = 0x66; //设置定时初始值
TH0 = 0xFC; //设置定时初始值
T0Count1++;//每次进入中断子程序,秒控制器自加一
if(T0Count1>=20)//每隔20ms,按键函数会被调用一次
{
T0Count1=0;
Key_Loop();
}
T0Count2++;
if(T0Count2>=2)
{
T0Count2=0;
Nixie_Loop();
}
T0Count3++;
if(T0Count3>=10)//10ms
{
T0Count3=0;
Sec_Loop();
}
}
- 题外话: 6-1矩阵键盘密码锁:为什么密码不能设置为0开头?
因为0开头代表八进制,比如0123实际上对应的十进制数是83