实验6-单片机扩展RAM6264实验
之前做的一次实验,51单片机扩展RAM6264实验。如有问题欢迎指正。
实验目的:
掌握单片机扩展芯片的方法;掌握RAM6264的写入和读取;
实验内容:
单片机、74LS573,82C55(A口和B口作为输出,C口作为输入)、8个数码管、按键信息从C口输入,端口地址A~控制寄存器依次为 ff7c,ff7d,ff7e,ff7cf(可以使用RAM6264)。按键做成4x4的矩阵按键,显示内容为你做实验的日期:例如: 2020.05.13。
实验环境:
MDK-ARM V5.21a、Proteus 8.6
Proteus原理图
暂停仿真开始观察RAN区
选择元器件:
DEVICES | 说明 |
---|---|
7SEG-MPX8-CC-BLUE | 八位共阴数码管 |
74HC573 | 锁存器 |
74LS373 | 锁存器 |
6264 | RAM |
AT89C51 | MCU |
BUTTON | 按键 |
CAP | 普通电容 |
CAP-ELEC | 电解电容 |
CRYSTAL | 晶振 |
RES | 电阻 |
RESPACK-8 | 排阻 |
51单片机的P0口做IO口使用时是漏极开路输出,其引脚一般需要在片外接一定阻值的上拉电阻,此时端口不存在高阻抗的悬浮状态,因此它是一个准双向口。同时,P0口每一位的驱动能力是P1~P3口的两倍,每位可以驱动8个LSTTL(Low-power Schottky TTL,即低功耗肖特基TTL)输入,89C51等单片机任何一个端口想要获得较大的驱动能力,必须采用低电平输出。
时钟晶体振荡频率为
f
o
s
c
=
11.0592
M
H
Z
f_{osc}=11.0592MHZ
fosc=11.0592MHZ
时钟周期相当于
T
o
s
c
=
1
f
o
s
c
≈
90.42
n
s
T_{osc}=\frac{1}{f_{osc}} \approx 90.42ns
Tosc=fosc1≈90.42ns
复位电路的话通过给89C51等单片机的复位引脚RST加上大于2个机器周期的高电平(即24个时钟振荡周期)就可以使单片机复位。
KEIL工程:
1.鉴于51单片机的端口可能不够,我采用了两片74hc573芯片来进行数码管段码和位码的锁存,P2^ 5控制段选,P2^ 6控制位选。其中数码管使用共阴极数码管,注意数码管的二重消隐。
2.单片机外部扩展1片外部数据存储器RAM6264。
3.使用定时器t0工作方式1,在中断函数中对数码管进行扫描。
4.键盘扫描使用矩阵反转扫描,并有与之匹配的按键处理函数。
5.通过按下矩阵键盘,输入本次实验的日期,将本次日期写入RAM6264,并在数码管上显示。其中,为了节省端口,数码管采用两片74HC573;按键输入时,数码管会从右到左移位,当按第9次时输入无效,用来清屏。
6.本程序有两种写入方式,一种是直接写入RAM6264在数码管显示,一种是按键输入,为了符合要求,我选择了后者。
头文件以及宏定义等:
#include "reg52.h"
#include "absacc.h"//定义地址所需的头文件
#define uchar unsigned char
#define uint unsigned int
#define KeyPort P1
#define DataPort P0
#define TIME 1000 /*延时常量(ms)*/
#define SHAKING_TIME 10 /*消抖时间(ms)*/
sbit LATCH1=P2^5;//定义锁存使能端口 段锁存
sbit LATCH2=P2^6;// 位锁存
uchar code Duanma[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};/*0123456789abcdef*/
uchar code Weima[] ={0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f};/*自左向右*/
uchar code Mydate[]={0x5b,0x3f,0x5b,0x3f,0x3f,0x7d,0x06,0x6f}; //用来事先直接写入RAM
uchar TempData[8];
sbit LED=P2^7;
uchar num;//按键返回值
主函数:
void main()
{
uint i,j;
uchar temp[8];
Init_Timer0();
/*1:直接写入RAM*/
// LED=1;
// /*在RAM6264写入数据*/
// for(i=0;i<8;i++) //向6264的0x0000地址开始写入实验日期:20200619
// {
// XBYTE[i]=Mydate[i];
// delayMs(150);
// }
// LED=0; //写入完毕,LED灯亮起
// /*读取RAM数据到数码管段码数据缓存数组*/
// for(i=0;i<8;i++)
// {
// TempData[i]=XBYTE[i]; //读取数据
// }
// while(1)
// {
// Display(0,8);
// }
/*2:按键输入写入RAM*/
while (1) //主循环
{
num=KeyPro();
if(num!=0xff)
{
if(i==0)
{
for(j=0;j<8;j++)//清屏
TempData[j]=0;
}
if(i<8)
{
XBYTE[i]=temp[i]=Duanma[num]; //把按键值输入到临时数组中,并写入RAM
for(j=0;j<=i;j++) //把临时数组中的值赋值到显示缓冲区,从右往左输入
TempData[7-i+j]=temp[j];
}
i++; //输入数值累加
if(i==9) //按的第9次用于清屏,此时按键不做输入值
{
i=0;
for(j=0;j<8;j++)
{
TempData[j]=0;//清屏
/*此处可以修改RAM:eg.XBYTE[i]=0;如果不修改,在下次输入时相当于覆盖0x0000~0x0008原来的值*/
}
}
}
}
}
中断初始化及子函数:
void Init_Timer0(void)
{
TMOD |= 0x01; //使用模式1,16位定时器,使用"|"符号可以在使用多个定时器时不受影响
//TH0=0x00; //给定初值
//TL0=0x00;
EA=1; //总中断打开
ET0=1; //定时器中断打开
TR0=1; //定时器开关打开
}
void Timer0_isr(void) interrupt 1
{
TH0=(65536-2000)/256; //重新赋值 2ms
TL0=(65536-2000)%256;
Display(0,8); //调用数码管扫描
}
显示函数:
void Display(uchar FirstBit,uchar Num)
{
static uchar i=0;
DataPort=0; //清空数据,防止有交替重影
LATCH1=1; //段锁存
LATCH1=0;
DataPort=Weima[i+FirstBit]; //取位码
LATCH2=1; //位锁存
LATCH2=0;
DataPort=TempData[i]; //取显示数据,段码
LATCH1=1; //段锁存
LATCH1=0;
i++;
if(i==Num)
i=0;
}
键盘扫描函数:
/*键盘扫描函数,使用行列反转扫描法*/
uchar KeyScan(void)
{
unsigned char cord_h,cord_l;//行列值中间变量
KeyPort=0x0f; //行线输出全为0
cord_h=KeyPort&0x0f; //读入列线值
if(cord_h!=0x0f) //先检测有无按键按下
{
delayMs(SHAKING_TIME); //去抖
if((KeyPort&0x0f)!=0x0f)
{
cord_h=KeyPort&0x0f; //读入列线值
KeyPort=cord_h|0xf0; //输出当前列线值
cord_l=KeyPort&0xf0; //读入行线值
while((KeyPort&0xf0)!=0xf0);//等待松开并输出
return(cord_h+cord_l);//键盘最后组合码值
}
}return(0xff); //返回该值
}
按键处理函数:
/*按键处理函数,返回键值*/
uchar KeyPro(void)
{
switch(KeyScan())
{
case 0x7e:return 0;break;//0 按下相应的键显示相对应的码值
case 0x7d:return 4;break;//4
case 0x7b:return 8;break;//8
case 0x77:return 12;break;//c
case 0xbe:return 1;break;//1
case 0xbd:return 5;break;//5
case 0xbb:return 9;break;//9
case 0xb7:return 13;break;//d
case 0xde:return 2;break;//2
case 0xdd:return 6;break;//6
case 0xdb:return 10;break;//a
case 0xd7:return 14;break;//e
case 0xee:return 3;break;//3
case 0xed:return 7;break;//7
case 0xeb:return 11;break;//b
case 0xe7:return 15;break;//f
default:return 0xff;break;
}
}
/*uS级延时函数*/
void DelayUs2x(uchar t)
{
while(--t);
}
/*MS级延时函数*/
void delayMs(uchar t)
{
while(t--)
{
//大致延时1mS
DelayUs2x(245);
DelayUs2x(245);
}
}
更新补充
关于RAM数据的查看
参考文献
1.《单片机原理与接口技术》张毅刚
资源