单片机课后答案9 下载本文

习题9

1. 某系统片外RAM的片选电路如图9-38所示:RAM共7路,有2K×8位和1K×8位两种芯片,其片选信号都是低电平有效。请为各路RAM芯片注明它的容量和地址范围。

A15A14E3E1E274LS138A13A12A11A10Y0Y1Y2Y4Y5第一路片选端第二路片选端第三路片选端≥1≥1≥1≥1第四路片选端第五路片选端第六路片选端第七路片选端CBA

图9-38 第1题图

解:第一路芯片的地址为8000H-87FFH;

第二路芯片的地址为8800H-8FFFH; 第三路芯片的地址为9000H-97FFH; 第四路芯片的地址为A000H-A3FFH; 第五路芯片的地址为A400H-A7FFH; 第六路芯片的地址为A800H-ABFFH; 第七路芯片的地址为AC00H-AFFFH。

2. 对AT89C51单片机外扩4片静态RAM62128芯片,请画出硬件电路图,写出每片芯片的地址。 解:

GP2.7P2.6P2.0-P2.5ALEAT89C51G74LS373Q0-Q7D0-D7OE8P0.0-P0.78WRRDY3Y2B74LS139Y1AY0688A0-A7A8-A1362128(1)CED0-D7OE8WE6868686EAA0-A7A8-A1362128(2)CED0-D7OE8WEA0-A7A8-A1362128(3)CED0-D7OE8WEA0-A7A8-A1362128(4)CED0-D7OE8WE62128(1):0000H-3FFFH,62128(2):4000H-7FFFH,62128(3):8000H-BFFFH, 62128(4):C000H-FFFFH

3. 8255A有几种工作方式?如何进行选择?

解:8255A共有三种工作方式,用方式控制字来选择。

4. 现有一片AT89C51单片机,扩展了一片8255A,若把8255A的B口用作输入,每一位接一个开关,A口用作输出,每一位接一个发光二极管,请用proteus软件画出电路原理图,并编写出B口某一位开关接低电平时,A口相应位发光二极管被点亮的程序。 解:电路如下图:

程序如下: #include #include #include #define uint unsigned int #define uchar unsigned char

//PA,PB,PC及命令端口地址定义 #define PA XBYTE[0x0000] #define PB XBYTE[0x0001] #define PC XBYTE[0x0002] #define COM XBYTE[0x0003]

void main() {

uchar k;

COM=0x82;//控制字 while(1)

}

{ k = PB; PA = k; }

5. 按照图9-18所示8255与AT89C52的连接图,用8255C口的PC3引脚向外输出连续的正方波信号,频率为500Hz。试编程,并用proteus仿真验证。

解:利用定时器0,每1ms中断一次,在中断服务程序中改变PC3的状态。 程序如下: #include #include #define PA8255

XBYTE[0xe000] /* 定义8255A口地址 */

#define PB8255 XBYTE[0xe001] /* 定义8255B口地址 */ #define PC8255 XBYTE[0xe002] /* 定义8255C口地址 */ #define COM8255 void timer0init(); bit k;

unsigned char aa; void init8255(void) ; void main (void) {

timer0init(); init8255();

XBYTE[0xe003] /* 定义8255控制寄存器地址 */

COM8255=0x07; /*PC3置1*/ k=0; }

void init8255(void) { }

void timer0init() {

TMOD=0x01; //设置T0为定时器模式,工作在方式1

COM8255=0x80;/*工作方式选择字送入8255控制寄存器,设置A、B、C口为基本I/O输出方式 */

while (1);

}

TH0=(65536-1000)/256; TL0=(65536-1000)%6; ET0=1; //允许T0中断 TR0=1; // 启动T0

EA=1; //开总中断

void timer0() interrupt 1//定时器0每1ms中断一次 {

TH0=(65536-1000)/256; TL0=(65536-1000)%6;

if(k==0) {

COM8255=0x06;/*PC3清0*/ k=~k; } else {

COM8255=0x07;/*PC3置1*/ k=~k; } }

6. 为什么要进行按键消抖?按键消抖的方法有几种?

解:按键是利用机械触点的合、断来实现键的闭合与释放,由于弹性作用,机械触点在闭合及断开瞬间会有抖动的过程,从而使键输入电压的信号也存在抖动现象。

去除抖动的方法一般有硬件和软件两种。硬件方法就是在按键输出通道上添加去抖动电路,从根本上避免电压抖动的产生,去抖动电路可以是单稳态电路或者滤波电路。软件方法通常是在检测到有键按下时延迟10~20ms的时间,待抖动期过去后,再次检测按键的状态,如果仍然为闭合状态,才认为是有键按下,否则认为是一个扰动信号。按键释放的过程与此相同,都要利用延时进行消抖处理。由于人的按键速度与单片机的运行速度相比要慢很多,所以,软件延时的方法简单可行,而且不需要增加硬件电路,成本低,因而被广泛采用。

7. 按键输入程序应具备哪些功能? 解:具有下列功能:

(1) 确定键是否闭合;(2)按键消抖处理;(3)确定闭合键的位置;(4)确定按键是否上访;(5) 对按键进行处理。

8. 利用LED显示器设计一个统计按键次数的系统,能够实时将当前按键次数以十进制形式显示在2位LED显示器上。

(1)所设计的 Proteus仿真电路如图5-13所示。

图5-13 计数器的仿真电路与效果图

两位数码管与单片机相连时,可以采用静态显示方式,也可以采用动态显示方式。这里采用动态显示方式,将两个数码管的段码连接到单片机的P0口,P0口通过470Ω的上拉电阻接+5V,两个数码管的位选由P2.6和P2.7选中。图5-13中数码管是共阴极的。 (2) 程序设计如下:

#include #define uchar unsigned char sbit key=P3^0; sbit ge= P2^7; sbit shi=P2^6;

uchar dd; // dd为显示的数字

uchar f0; // f0为键按下过的标志 uchar time=0,count=0;

uchar code dis[] ={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};//段码 /*************延时程序*************/ void delay(uchar N) {

uchar i,j; for(i=0;i

/***************显示程序*************/ void display(void) {

P0=dis[dd];

//显示个位

ge=0; delay(3); ge=1;

P0=dis[dd/10]; //显示十位 shi=0; delay(3); shi=1; }

/****************主程序***************/ void main() {

dd=0; //开始显示的数字为0

f0=1; //f0为按下过键的标志位,如果按下过键,f0=0,否则f0=1 while(1) {

while (key==1)//键未按下,显示

{

display();

if (f0==0)

{ dd=dd+1; f0=1; }

}

while (key==0)//键按下,显示,标志f0=0 { } } (3) 仿真效果

0~99计数器的仿真效果图如图5-13所示,图中显示的是23。

9. LCD1602与AT89C52单片机连接的仿真电路如图9-36所示。用C语言编程,实现第一行从右侧移入“Hello everyone”,同时第二行从右侧移入“Welcome to here!”,移入速度自定,然后停留在屏幕上。

display(); f0=0;

}

解:程序设计如下:程序如下: #include #define uchar unsigned char #define uint unsigned int

uchar code table[]=%uchar code table1[]=\sbit lcden=P3^4;//液晶使能端

sbit lcdrs=P3^5; //液晶数据命令选择端 uchar num;

void delay(uint z)//延时子程序 { uint x,y; for(x=z;x>0;x--) for(y=110;y>0;y--); }

void write_com(uchar com)//写命令函数 {

lcdrs=0;//选择写命令模式

P0=com;//将要写的命令字送到数据总线上 delay(5);//稍微做延时以待数据稳定

lcden=1;//使能端给一个高脉冲,因为初始化函数中已将lcden置为0 delay(5);//稍做延时

lcden=0;//将使能端置0以完成高脉冲 }

void write_data(uchar date) { lcdrs=1; P0=date; delay(5);

lcden=1; delay(5); lcden=0; } void init() { lcden=0;

write_com(0x38);//设置16×2显示,5×7点阵,8位数据接口 write_com(0x0f); //设置开显示,不显示光标 write_com(0x06);//写一个字符后地址指针加1 write_com(0x01);//显示清0,数据指针清0 }

void main() { init();

write_com(0x80+0x10);//先将数据指针定位到第一行第一个字处 for(num=0;num<15;num++)//做简短延时 {

write_data(table[num]); delay(5); }

write_com(0x80+0x50);//写第二行时重新定位数据指针 for(num=0;num<16;num++) {

write_data(table1[num]); delay(20); }

for(num=0;num<16;num++) {

}

write_com(0x1c); delay(100);

while(1); }