《单片机的C语言程序设计与运用第2版》期末复习题及答案2.docx
《《单片机的C语言程序设计与运用第2版》期末复习题及答案2.docx》由会员分享,可在线阅读,更多相关《《单片机的C语言程序设计与运用第2版》期末复习题及答案2.docx(42页珍藏版)》请在冰豆网上搜索。
《单片机的C语言程序设计与运用第2版》期末复习题及答案2
第四章
中断类
例4-1P104
假设外部中断0和外部中断1均为下降沿触发,当外部中断0发生时,P0端口的电平反向,当外部中断1发生时,P1端口的电平反向。
#include
voidIS0(void)interrupt0
{P0=~P0;}//P0端口反向
voidIS1(void)interrupt2
{P1=~P1;}//P1端口反向
voidmain()
{P0=0x00;P1=0xFF;
IT0=1;IT1=1;
EX0=1;EX1=1;EA=1;
while
(1);
}
【例4-9】外部中断示例
在本实例中,首先通过P1.7口点亮发光二极管D1,然后外部输入一脉冲串,则发光二极管D1亮、暗交替。
#include
sbitP1_7=P1^7;
voidinterrupt0()interrupt0using2//外部中断0
{P1_7=!
P1_7;}
voidmain()
{EA=1;//开中断
IT0=1;//外部中断0脉冲触发
EX0=1;//外部中断0
P1_7=0;
do{}while
(1);
}
如果有3个脉冲,则灯亮、暗交替一次,可如下面编程:
#include
SbitP17=P1^7;
unsignedchari=3;
voidmain()
{EA=1;IT0=1;EX0=1;
P17=0;
do{}while
(1);}
voidinterrupt0()interrupt0
{i=i-1;
if(i==0)
{P17=!
P17;i=3;
}
}
【例4-10】如图4-18所示,8只LED阴极接至单片机P0口,两开关S0、S1分别接至单片机引脚P3.2()和P3.3()。
编写程序控制LED状态。
按下S0后,点亮8只LED;按下S1后,变为闪烁状态。
#include
sbitP32=P3^2;
voiddelay(unsignedintd)//定义延时子函数
{while(--d>0);
}
voidmain()
{P0=0xFF;//熄灭LED
IT0=1;IT1=1;//外中断0、1脉冲触发方式
EA=1;EX0=1;EX1=1;//开中断
for(;;)//延时等待中断发生
{;}
}
voidINT0_ISR()interrupt0//外中断0中断服务函数
{P0=0x00;
}
voidINT1_ISR()interrupt2//外中断1中断服务函数
{while(P32!
=0)//如果有外部中断0,则退出
{delay(5000);
P0=0x00;
delay(5000);
P0=0xFF;
}
}
定时类
【例4-16】设单片机的fosc=12MHz,要求在P1.0上产生周期为2ms的方波。
要在P1.0上产生周期为2ms的方波,定时器应产生1ms的周期性定时,定时到对P1.0取反。
要产生1ms的定时,应选择方式1,定时器方式。
TMOD的确定:
选择定时器/计数器T0,定时器方式。
方式1,GATE不起作用,高4位为0000,TMOD=01H。
TH、TL的确定:
单片机的fosc=12MHz,则单片机的机器周期为1ms,1ms=1000ms,计数器的计数初值为65536-1000,TH0=(65536-1000)/256,TL0=(65536-1000)%256。
①采用查询方式
程序如下:
#include
sbitP1_0=P1^0;
voidmain(void)
{TMOD=0x01;
TR0=1;
for(;;)
{TH0=(65536-1000)/256;
TL0=(65536-1000)%256;
do{}while(!
TF0);
P1_0=!
P1_0;
TF0=0;
}
}
②采用中断方式
程序如下:
#include
sbitP1_0=P1^0;
voidtimer0(void)interrupt1using1
{P1_0=!
P1_0;
TH0=(65536-1000)/256;
TL0=(65536-1000)%256;
}
voidmain(void)
{TMOD=0x01;
P1_0=0;
TH0=(65536-1000)/256;
TL0=(65536-1000)%256;
EA=1;ET0=1;
TR0=1;
do{}while
(1);
}
【例4-17】设系统时钟频率为12MHz,编程实现从P1.1输出周期为1s的方波。
要输出周期为1s的方波,应产生500ms的周期性定时,定时到则对P1.1取反即可实现。
由于定时时间较长,一个定时器/计数器不能直接实现,一个定时器/计数器最长定时时间为65ms多一点,可以用以下两种方法实现。
(1)方法一
用定时/计数器T0产生周期性为10ms的定时,然后用一个变量对10ms计数50次。
系统时钟为12MHz,定时/计数器T0定时10ms,计数值N为10000,选方式1,方式控制字为B(01H),则初值X为X=65536-10000。
#include
sbitP1_1=P1^1;
unsignedchari;//定义计数变量
voidmain()
{i=0;//初始化
TMOD=0x01;
TH0=(65536-10000)/256;
TL0=(65536-10000)%256;
EA=1;
ET0=1;
TR0=1;
while
(1);
}
voidtime0_int(void)interrupt1//中断服务程序
{TH0=(65536-10000)/256;//重载初始值
TL0=(65536-10000)%256;//重载初始值
i++;//每发生一次中断,计数变量加1
if(i==50)//发生50次中断,定时0.5ms
{P1_1=!
P1_1;
i=0;//计数变量清零
}
}
(2)方法二
用定时/计数器T1计数实现,对10ms计数50次。
定时/计数器T1工作于计数方式时,计数脉冲通过T1(P3.5)输入。
设定时/计数器T0定时时间到对P1.0取反一次,则T1(P3.5)每10ms产生一个计数脉冲,那么定时500ms只需计数25次,设定时/计数器T1工作于方式2,初值X=256-25=231,TH1=TL1=231。
因为定时/计数器T0工作于方式1,定时方式,则这时方式控制字为B(61H)。
定时/计数器T0和T1都采用中断方式工作。
#include
sbitP1_1=P1^1;
sbitP1_0=P1^0;
voidmain()
{TMOD=0x61;//初始化
TH0=(65536-10000)/256;
TL0=(65536-10000)%256;
TH1=231;TL1=231;
EA=1;
ET0=1;ET1=1;
TR0=1;TR1=1;
while
(1);
}
voidtime0_int(void)interrupt1//T0中断服务程序
{TH0=(65536-10000)/256;//重载初始值
TL0=(65536-10000)%256;//重载初始值
P1_0=!
P1_0;
}
voidtime1_int(void)interrupt3//T1中断服务程序
{P1_1=!
P1_1;}
【例4-18】设系统时钟频率为12MHz,编程实现:
P1.1引脚上输出周期为1s,占空比为20%的脉冲信号
根据输出要求,脉冲信号在一个周期内高电平占0.2s,低电平占0.8s,超出了定时器的最大定时间隔,因此利用定时器0产生一个基准定时配合软件计数来实现。
取50ms作为基准定时,采用工作方式1,这样这个周期需要20个基准定时,其中高电平占4个基准定时。
#include
sbitP1_1=P1^1;
unsignedchari;//定义计数变量
voidmain()
{i=0;//初始化
TMOD=0x01;
TH0=(65536-50000)/256;
TL0=(65536-50000)%256;
EA=1;ET0=1;
TR0=1;
while
(1);
}
voidtime0_int(void)interrupt1//中断服务程序
{TH0=(65536-50000)/256;//重载初始值
TL0=(65536-50000)%256;
i=i+1;
if(i==4)P1_1=0;//高电平时间到变低
elseif(i==20)//周期时间到变高
{P1_1=1;
i=0;//计数变量清零
}
}
第五章
【例5-9】串行口自发自收
#include
#defineucharunsignedchar
#defineuintunsignedint
voidmain()
{uchari=0x55;
uintj=0;
TMOD=0X20;//设定定时器1模式2
TL1=TH1=0XF4;
PCON=0X00;
SCON=0X50;
TR1=1;
while
(1)
{SBUF=i;//发送数据
do()while(!
RI)
RI=0;
TI=0;
i=SBUF;//读取接收数据
P1=i;
i=~i;//将发送数据取反
for(j=0;j<12500;j++);
}
}
【例5-10】两个单片机串行通信1
单片机1的C51源程序代码:
#include
#defineuintunsignedint
#defineucharunsignedchar
voidmain()
{uchari;
TMOD=0x20;TH1=TL1=0xff;
SCON=0x50;PCON=0x80;
TR1=1;
P1=0xff;
while
(1)
{P1=0xff;
i=P1;SBUF=i;
while(TI==0)
{;}
TI=0;
}
}
单片机2的C51源程序:
#include
#defineuintunsignedint
#defineucharunsignedchar
voidmain()
{uchari=0;
TMOD=0x20;TH1=TL1=0xff;
SCON=0x50;PCON=0x80;
TR1=1;
while
(1)
{while(RI==0){;}
RI=0;
i=SBUF;
P1=i;
}
}
两个单片机串行通信2
C51源程序代码如下:
#include
#defineucharunsignedchar
#defineTR1//TR=1,发送
ucharidatabuf[10];
ucharpf;
voidmain()
{int();//串行口初始化子函数
if(TR==0)
{send(buf);}//发送
else
{receive(buf);}//接收
}
/*串口初始化子函数*/
voidinit(void)
{TMOD=0x20;//T1工作于方式2
TH0=0xE8;
TL0=0xE8;
TR1=1;
SCON=0X50;//串行口工作于方式1,REN=1
}
/*发送子函数*/
voidsend(ucharidata*d)
{uchari;
do
{SBUF=0xAA;//发送联络信号
while(TI==0);//等待一帧发送完毕
TI=0;//发送完毕,标志位清0
while(RI==0);//等待乙机应答信号
RI=0;
}while(SBUF^0xBB!
=0);//乙机未准备好,继续联络
do
{pf=0;//校验和变量清0
for(i=0;i<10;i++){
SBUF=d[i];//发送一个数据
pf+=d[i];//计算校验和
while(TI==0);
TI=0;}
SBUF=pf;//发送校验和
while(TI==0);TI=0;
while(RI==0);RI=0;//等待乙机应答
}while(SBUF!
=0);//回答出错,则重新发送
}
/*接收函数*/
voidreceive(ucharidata*d)
{uchari;
do
{while(RI==0);RI=0;
}while(SBUF^0xAA)!
=0);//判断甲机是否请求
SBUF=0xBB;//发应答信号
while(TI==0);TI=0;
while
(1){
pf=0;//清校验和
for(i=0;i<10;i++){
d[i]=SBUF;//接收数据
pf+=d[i];}//计算校验和
while(RI==0);RI=0;//接收甲校验和
If((SBUF^pf)==0){//比较校验和
SBUF=0x00;break;}//校验和相等,发0x00
else{
SBUF=0xFF;//校验和不相等,发0Xff
while(TI==0);TI=0;
}
}
}
第六章
静态:
【例6-1】利用单片机的并行口作为静态显示的输出口的示例
静态轮流显示“12”、“--”和“AB”的C51源程序如下:
#include
#defineucharunsignedchar
uchardatadis_buf[2];//显示缓冲区
ucharcodeable[18]=
{0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71,0x40,0x00};//显示的代码表
voiddl()
{unsignedinti;
for(i=0;i<40000;i++);
}
voiddisplay(void)//显示函数
{ucharsegcode;
segcode=dis_buf[0];//P0口显示
segcode=table[segcode];
P0=segcode;
segcode=dis_buf[1];//P3口显示
segcode=table[segcode];
P3=segcode;
}
voidmain(void)//主函数
{while
(1)
{dis_buf[0]=1;dis_buf[1]=2;//显示12
display();dl();
dis_buf[0]=16;dis_buf[1]=16;//显示--
display();dl();
dis_buf[0]=10;dis_buf[1]=11;//显示AB
display();dl();
}
}
示例中的显示函数display()可以再简单一些,如下面程序段:
voiddisplay(void)
{P0=table[dis_buf[0]];//P0口显示
P3=table[dis_buf[1]];//P3口显示
}
动态:
【例6-3】利用MCS-51单片机的并行口作为动态显示的段口与位口的示例
6位数码管动态显示“”的C51源程序如下
1)随机调用
#include
#defineucharunsignedchar
uchardatadis_buf[6];//显示缓冲区
ucharcodetable[18]=
{0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,
0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71,0x40,0x00};//代码表
voiddl_ms()//延时1ms函数
{unsignedintj;
for(j=0;j<200;j++);
}
voiddisplay(void)//显示函数
{ucharsegcode,bitcode,i;
bitcode=0xfe;//位码赋初值
for(i=0;i<6;i++)
{segcode=dis_buf[i];//显示缓冲器内容查表
P0=table[segcode];P3=bitcode;dl_ms();
P3=0xff;//关闭显示
bitcode=bitcode<<1;//调整位码
bitcode=bitcode|0x01;
}
}
voidmain(void)
{dis_buf[0]=1;dis_buf[1]=2;
dis_buf[2]=3;dis_buf[3]=4;
dis_buf[4]=5;dis_buf[5]=6;
while
(1)
{display();
}
}
(2)定时调用
定时调用是通过定时器/计数器的定时功能来定时一定的时间(如20ms),定时时间到来调用显示函数。
voidmain(void)//定时调用
{TMOD=0x01;
TH0=-20000/256;TL0=-2000%256;
EA=1;ET0=1;
TR0=1;
dis_buf[0]=1;dis_buf[1]=2;dis_buf[2]=3;
voidtime0_int()interrupt1
{TH0=-20000/256;
TL0=-2000%256;
display();
}
dis_buf[3]=4;dis_buf[4]=5;dis_buf[5]=6;
while
(1);
}
【例6-6】独立式按键示例
C51源程序如下:
#include
#defineucharunsignedchar
#defineuintunsignedint
uchardatakey2;
codeuchardirtab[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80};
voiddl_6()
{uinti;
for(i=0;i<600;i++);
}
voidkey()
{ucharkey1;
P1=0xff;
key1=P1;
if(key1!
=0xff)
{dl_6();P1=0xff;key1=P1;
if(key1!
=0xff)
{key1=P1;
switch(key1)
{case0xff:
key2=8;break;
case0xfe:
key2=0;break;
case0xfd:
key2=1;break;
case0xfb:
key2=2;break;
case0xf7:
key2=3;break;
case0xef:
key2=4;break;
case0xdf:
key2=5;break;
case0xbf:
key2=6;break;
case0x7f:
key2=7;break;
default:
break;
}
}
}
}
voidmain()
{
key2=8;
while
(1)
{
key();
P3=dirtab[key2];
}
}
【例6-7】4×4矩阵键盘示例
#include
#defineucharunsignedchar
#defineuintunsignedint
uchardatadir_buf;
codeuchardirtab[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,
0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71,0x40};
codeucharkeytab[]={0xee,0xed,0xeb,0xe7,0xde,0xdd,0xdb,0xd7,
0xbe,0xbd,0xbb,0xb7,0x7e,0x7d,0x7b,0x77};
voiddelay(void);
voidkeyscan();
voiddir();
ucharkey;
voidmain(void)
{dir_buf=16;
while
(1)
{keyscan();
dir();
}
}
voiddir()
{P2=dirtab[dir_buf];}
voiddelay(void)
{uchari;
for(i=0;i<200;i++);
}
voidkeyscan()
{ucharcode_h,code_l,i1,i2;
P1=0xf0;//所有的行输出0
code_l=P1;//读列值
code_l=code_l&0xf0;//屏蔽掉高4位
if(code_l!
=0xf0)
{delay();
//P1=0xf0;
code_l=P1;
code_l=code_l&0xf0;
if(code_l!
=0xf0)
{code_h=0xfe;
for(i1=0;i1<4;i1++)
{kk:
P1=code_h;
code_l=P1;
code_l=code_l&0xf0;
if(code_l==0xf0)
{code_h=(code_h<<1)|0x01;gotokk;
}
gotoll;
}//for
}
ll:
code_h=code_h&0x0f;
key=code_h+code_l;
for(i2=0;i2<16;i2++)
{if(key==key