当前位置:文档之家› 《单片机的C语言程序设计与运用(第2版)》期末复习题及答案2

《单片机的C语言程序设计与运用(第2版)》期末复习题及答案2

第四章中断类例4-1 P104假设外部中断0和外部中断1均为下降沿触发,当外部中断0发生时,P0端口的电平反向,当外部中断1发生时,P1端口的电平反向。

#include<reg51.h>void IS0(void) interrupt 0{ P0=~P0;} //P0端口反向void IS1(void) interrupt 2{ P1=~P1;} //P1端口反向void main( ){ P0=0x00; P1=0xFF;IT0=1; IT1=1;EX0=1; EX1=1; EA=1;while(1);}【例4-9】外部中断示例在本实例中,首先通过P1.7口点亮发光二极管D1,然后外部输入一脉冲串,则发光二极管D1亮、暗交替。

#include<reg51.h>sbit P1_7=P1^7;void interrupt0( ) interrupt 0 using 2 //外部中断0 { P1_7=!P1_7;}void main( ){ EA=1; //开中断IT0=1; //外部中断0脉冲触发EX0=1; //外部中断0P1_7=0;do{ }while(1);}如果有3个脉冲,则灯亮、暗交替一次,可如下面编程:#include<reg51.h>Sbit P17=P1^7;unsigned char i=3;void main( ){ EA=1; IT0=1; EX0=1;P17=0;do{ }while(1); }void interrupt0( ) interrupt 0{ 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<reg51.h>sbit P32=P3^2;void delay(unsigned int d) //定义延时子函数{ while(--d>0);}void main( ){ P0=0xFF; //熄灭LEDIT0=1; IT1=1; //外中断0、1脉冲触发方式EA=1; EX0=1; EX1=1; //开中断for( ; ; ) //延时等待中断发生{;}}void INT0_ISR( ) interrupt 0//外中断0中断服务函数{ P0=0x00;}void INT1_ISR( ) interrupt 2//外中断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,计数器的计数初值为65 536-1000,TH0=(65536-1000)/256,TL0=(65 536-1000)%256。

①采用查询方式程序如下:#include<reg51.h>sbit P1_0=P1^0;void main(void){ TMOD=0x01;TR0=1;for(;;){ TH0=(65536-1000)/256;TL0=(65536-1000)%256;do{ }while(!TF0);P1_0=!P1_0;TF0=0;}}②采用中断方式程序如下:#include<reg51.h>sbit P1_0=P1^0;void timer0(void) interrupt 1 using 1 { P1_0=!P1_0;TH0=(65536-1000)/256;TL0=(65536-1000)%256;}void main(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,方式控制字为00000001B(01H),则初值X为X=65 536-10 000。

#include<reg51.h>sbit P1_1=P1^1;unsigned char i; //定义计数变量void main( ){ i=0; //初始化TMOD=0x01;TH0=(65536-10000)/256;TL0=(65536-10000)%256;EA=1;ET0=1;TR0=1;while(1);}void time0_int(void) interrupt 1 //中断服务程序{ 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,定时方式,则这时方式控制字为01100001B (61H)。

定时/计数器T0和T1都采用中断方式工作。

#include<reg51.h>sbit P1_1=P1^1;sbit P1_0=P1^0;void main( ){ 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);}void time0_int(void) interrupt 1 //T0中断服务程序{ TH0=(65536-10000)/256; //重载初始值TL0=(65536-10000)%256; //重载初始值P1_0=!P1_0;}void time1_int(void) interrupt 3 //T1中断服务程序{ P1_1=!P1_1; }【例4-18】设系统时钟频率为12MHz,编程实现:P1.1引脚上输出周期为1s,占空比为20%的脉冲信号根据输出要求,脉冲信号在一个周期内高电平占0.2s,低电平占0.8s,超出了定时器的最大定时间隔,因此利用定时器0产生一个基准定时配合软件计数来实现。

取50ms作为基准定时,采用工作方式1,这样这个周期需要20个基准定时,其中高电平占4个基准定时。

#include<reg51.h>sbit P1_1=P1^1;unsigned char i; //定义计数变量void main( ){ i=0; //初始化TMOD=0x01;TH0=(65536-50000)/256;TL0=(65536-50000)%256;EA=1; ET0=1;TR0=1;while(1);}void time0_int(void) interrupt 1 //中断服务程序{ TH0=(65536-50000)/256; //重载初始值TL0=(65536-50000)%256;i=i+1;if(i==4) P1_1=0; //高电平时间到变低else if(i==20) //周期时间到变高{ P1_1=1;i=0; //计数变量清零}}第五章【例5-9】串行口自发自收#include<reg51.h>#define uchar unsigned char #define uint unsigned int void main( ){ uchar i=0x55;uint j=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<reg51.h>#define uint unsigned int#define uchar unsigned charvoid main( ){ uchar i;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<reg51.h>#define uint unsigned int#define uchar unsigned charvoid main( ){ uchar i=0;TMOD=0x20; TH1=TL1=0xff;SCON=0x50; PCON=0x80;TR1=1;while(1){ while(RI==0){;}RI=0;i=SBUF;P1=i;}}两个单片机串行通信2C51源程序代码如下:#include<reg51.h>#define uchar unsigned char#define TR 1 //TR=1,发送uchar idata buf[10];uchar pf;void main( ){ int( ); //串行口初始化子函数if(TR==0){send(buf);} //发送else{receive(buf);} //接收}/*串口初始化子函数*/void init(void){ TMOD=0x20; //T1工作于方式2TH0=0xE8;TL0=0xE8;TR1=1;SCON=0X50; //串行口工作于方式1,REN=1}/*发送子函数*/void send(uchar idata*d){ uchar i;do{ SBUF=0xAA; //发送联络信号while(TI= =0); //等待一帧发送完毕TI=0; //发送完毕,标志位清0while (RI= =0); //等待乙机应答信号RI=0;} while (SBUF^0xBB!=0); //乙机未准备好,继续联络do{ pf=0; //校验和变量清0for(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); //回答出错,则重新发送}/*接收函数*/void receive(uchar idata*d){uchar i;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;} //校验和相等,发0x00else{SBUF=0xFF; //校验和不相等,发0Xffwhile(TI= =0);TI=0;}}}第六章静态:【例6-1】利用单片机的并行口作为静态显示的输出口的示例静态轮流显示“12”、“- -”和“AB”的C51源程序如下:#include<reg51.h>#define uchar unsigned charuchar data dis_buf[2];//显示缓冲区uchar code able[18]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x3 9,0x5e,0x79,0x71,0x40,0x00}; //显示的代码表void dl( ){ unsigned int i;for(i=0;i<40000;i++);}void display(void) //显示函数{ uchar segcode;segcode=dis_buf[0];//P0口显示segcode=table[segcode];P0=segcode;segcode=dis_buf[1]; //P3口显示segcode=table[segcode];P3=segcode;}void main(void) //主函数{ while(1){ dis_buf[0]=1;dis_buf[1]=2; //显示12display( ); dl();dis_buf[0]=16;dis_buf[1]=16;//显示- -display( ); dl( );dis_buf[0]=10;dis_buf[1]=11;//显示ABdisplay( ); dl( );}}示例中的显示函数display( )可以再简单一些,如下面程序段:void display(void){ P0=table[dis_buf[0]]; //P0口显示P3=table[dis_buf[1]]; //P3口显示}动态:【例6-3】利用MCS-51单片机的并行口作为动态显示的段口与位口的示例6位数码管动态显示“123456”的C51源程序如下1)随机调用#include<reg51.h>#define uchar unsigned charuchar data dis_buf[6];//显示缓冲区uchar code table[18]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71,0x40,0x00};//代码表void dl_ms() //延时1ms函数{ unsigned int j;for(j=0;j<200;j++) ;}void display(void)//显示函数{ uchar segcode, 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;}}void main(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),定时时间到来调用显示函数。

相关主题