1.07k likes | 1.21k Views
操作实验 1 用单片机控制一个灯. 教学目标: 学习用 Proteus 仿真设计电路,掌握与 Kril c51 联合调试的方法。. 电路图:. C 程序:. #include<reg51.h> // 包含 51 单片机寄存器定义的头文件 void main(void) { P1=0xfe; //P1=1111 1110B ,即 P1.0 输出低电平 }. 将上题改成控制一个灯的闪烁:. #include<reg51.h> // 包含单片机寄存器的头文件
E N D
操作实验1 用单片机控制一个灯 教学目标:学习用Proteus仿真设计电路,掌握与Kril c51联合调试的方法。
C程序: #include<reg51.h> //包含51单片机寄存器定义的头文件 void main(void) { P1=0xfe; //P1=1111 1110B,即P1.0输出低电平 } 将上题改成控制一个灯的闪烁:
#include<reg51.h> //包含单片机寄存器的头文件 void delay(void) //两个void意思分别为无需返回值,没有参数传递 { unsigned int i; //定义无符号整数,最大取值范围65535 for(i=0;i<20000;i++) //做20000次空循环 ; //什么也不做,等待一个机器周期 } void main(void) { while(1) //无限循环 { P1=0xfe; //P1=1111 1110B, P1.0输出低电平 delay(); //延时一段时间 P1=0xff; //P1=1111 1111B, P1.0输出高电平 delay(); //延时一段时间 } }
void main(void) { while(1) { P1=0xfe; //第一个灯亮 delay(); //调用延时函数 P1=0xfd; //第二个灯亮 delay(); //调用延时函数 P1=0xfb; //第三个灯亮 delay(); //调用延时函数 P1=0xf7; //第四个灯亮 delay(); //调用延时函数 P1=0xef; //第五个灯亮 delay(); //调用延时函数 P1=0xdf; //第六个灯亮 delay(); //调用延时函数 P1=0xbf; //第七个灯亮 delay(); //调用延时函数 P1=0x7f; //第八个灯亮 delay(); //调用延时函数 } } 1 用顺序方式编程实现: #include<reg51.h> void delay(void) { unsigned char i,j; for(i=0;i<250;i++) for(j=0;j<250;j++) ; } 2 请用查表方式编程实现:
利用查表的方法,使端口P1做单一灯的变化:左移2次,右移2次,闪烁2次(延时的时间0.2秒)。利用查表的方法,使端口P1做单一灯的变化:左移2次,右移2次,闪烁2次(延时的时间0.2秒)。
# include<reg51.h> unsigned char code table[]={0xfe,0xfd,0xfb,0xf7, 0xef,0xdf,0xbf,0x7f, 0xfe,0xfd,0xfb,0xf7, 0xef,0xdf,0xbf,0x7f, 0x7f,0xbf,0xdf,0xef, 0xf7,0xfb,0xfd,0xfe, 0x7f,0xbf,0xdf,0xef, 0xf7,0xfb,0xfd,0xfe, 0x00,0xff,0x00,0xff, 0x01}; unsigned char i=0; void delay(void) { unsigned char m,n,s; for(m=20;m>0;m--) for(n=20;n>0;n--) for(s=248;s>0;s--); } void main(void) { while(1) { if(table[i]!=0x01) { P1=table[i]; i++; delay(); } else { i=0; } } }
中断方式编程: void time0_int(void) interrupt 1 TH0 = (65536-50000)/256; TL0 = (65536-50000)%256; j++; if (j= =10) { if(table[i]!=0x01) { P1=table[i]; i++; delay(); } else { i=0; } } # include<reg51.h> unsigned char code table[]={0xfe,0xfd,0xfb,0xf7, 0xef,0xdf,0xbf,0x7f, 0xfe,0xfd,0xfb,0xf7, 0xef,0xdf,0xbf,0x7f, 0x7f,0xbf,0xdf,0xef, 0xf7,0xfb,0xfd,0xfe, 0x7f,0xbf,0xdf,0xef, 0xf7,0xfb,0xfd,0xfe, 0x00,0xff,0x00,0xff, 0x01}; unsigned char I,j; void main(void) {TMOD=0x01; TH0 = (65536-50000)/256; TL0 = (65536-50000)%256; EA=1;ET0=1; i=0;j=0; TR0=1; while(1); }
实验一 输入/输出端口的基本应用 点亮与单片机P1.0口相连的发光二极管,延时约0.2S,然后熄灭,再延时约0.2S,再点亮,如此循环下去。(使用定时器和中断方式) 参考流程图:
#include<reg51.h> // 包含51单片机寄存器定义的头文件 sbit D1=P1^0; //将D1位定义为P2.0引脚 /************************************************************** 函数功能:主函数 **************************************************************/ void main(void) { EA=1; //开总中断 ET0=1; //定时器T0中断允许 TMOD=0x01; //使用定时器T0的模式1 TH0=(65536-46083)/256; TL0=(65536-46083)%256; TR0=1; //启动定时器T0 while(1) //无限循环等待中断 ; } /************************************* 函数功能:定时器T0的中断服务程序 *************************************/ void Time0(void) interrupt 1 using 0 { D1=~D1; TH0=(65536-46083)/256; TL0=(65536-46083)%256; }
设计作业: (1)如果P1口接8个LED,如何让8个LED一起闪烁? (2)编程实现单片机P1口相连的8个发光二极管中的一个循环移位点亮。
Tcy 振荡器 12 S2 C/T 中断请求 TLx (低5位) THx (高8位) S1 TFx Tx TRx 与 GATE 或 INTx 定时/计数器工作方式 ⒈ 工作方式0 13位计数器,由TL0低5位和TH0 8位组成,TL0低5位计数满时不向TL0第6位进位,而是向TH0进位,13位计满溢出,TF0置“1”。最大计数值213 = 8192。
⒉ 工作方式1 16位计数器,最大计数值为216 = 65536。 方式1的结构与方式0结构相同,只是把13位变成16位, 16位的加法计数器被全部用上。 ⒊ 工作方式2 8位计数器,仅用TL0计数,最大计数值为28= 256,计满溢出后,一方面进位TF0,使溢出标志TF0 = 1;另一方面,使原来装在TH0中的初值装入TL0。 优点:定时初值可自动恢复;缺点:计数范围小。 适用于需要重复定时,而定时范围不大的应用场合。
Tcy 振荡器 12 S2 C/T 中断请求 TLx (8位) S1 TFx Tx 重装初值 TRx 与 8 GATE THx (8位) 或 INTx
⒋ 工作方式3 方式3仅适用于T0,T1无方式3。 ⑴ T0方式3 在方式3情况下,T0被拆成二个独立的8位计数器TH0、TL0。 ① TL0使用T0原有的控制寄存器资源:TF0,TR0,GATE,C/T,INT0,组成一个8位的定时/计数器; ② TH0借用T1的中断溢出标志TF1,运行控制开关TR1,只能对片内机周脉冲计数,组成另一个8位定时器(不能用作计数器)。 ⑵ T0方式3情况下的T1 T1由于其TF1、TR1被T0的TH0占用,计数器溢出时,只能将输出信号送至串行口,即用作串行口波特率发生器。
Tcy 振荡器 12 S2 C/T 中断请求 TL0 (8位) S1 TF0 T0 TR0 与 GATE 或 S2 INT0 中断请求 TH0 (8位) Fosc/12 TF1 TR1
操作实验3:定时器的应用 例1:用定时器控制单片机发出1KHZ的音频
#include<reg51.h> // 包含51单片机寄存器定义的头文件 sbit sound=P3^7; //将sound位定义为P3.7引脚 void main(void) { TMOD=0x10; //使用定时器T1的模式1 TH1=(65536-921)/256; TL1=(65536-921)%256; TR1=1; //启动定时器T1 TF1=0; while(1)//无限循环等待查询 { while(TF1==0) ; TF1=0; sound=~sound; TH1=(65536-921)/256; TL1=(65536-921)%256; } }
中断方式编程 /*************************************** 函数功能:定时器T1的中断服务程序 **************************************/ void Time1(void) interrupt 3 using 0 { sound=~sound; TH1=(65536-921)/256; TL1=(65536-921)%256; } #include<reg51.h> sbit sound=P3^7; /**************************** 函数功能:主函数 *****************************/ void main(void) { EA=1; //开总中断 ET1=1; //定时器T1中断允许 TMOD=0x10; TH1=(65536-921)/256; TL1=(65536-921)%256; TR1=1; //启动定时器T1 while(1); //无限循环等待中断 }
例2:设计蜂鸣器鸣笛报警程序 /**************************************** 函数功能:主函数 ****************************************/ void main(void) { unsigned int i; while(1) { for(i=0;i<830;i++) { sound=0; //P3.7输出低电平 delay1600(); sound=1; //P3.7输出高电平 delay1600(); } for(i=0;i<200;i++) { sound=0; //P3.7输出低电平 delay800(); sound=1; //P3.7输出高电平 delay800(); } } } #include<reg51.h> sbit sound=P3^7; /**************************************** 函数功能:延时形成1600Hz音频 ****************************************/ void delay1600(void) { unsigned char n; for(n=0;n<100;n++) ; } /**************************************** 函数功能:延时形成800Hz音频 ****************************************/ void delay800(void) { unsigned char n; for(n=0;n<200;n++) ; }
例3:用定时器的方式控制两个LED以不同周期闪烁例3:用定时器的方式控制两个LED以不同周期闪烁 用T1定时器的中断来控制P1.0、P1.1的两个LED分别以200ms和800ms的周期闪烁。 实现方法: 通过给定时器T1赋适当的初值,设置为50ms产生1次中断。由于控制两个LED以不同的周期闪烁,第一个LED亮、灭周期为100ms,第二个LED亮、灭周期为400ms,所以,需设置两个变量countor1和countor2来分别统计中断次数。
/******************************************** 函数功能:定时器T1的中断服务程序 *******************************************/ void Time1(void) interrupt 3 using 0 { Countor1++; //Countor1自加1 Countor2++; //Countor2自加1 if(Countor1==2) //若累计满2次,即计时满100ms { D1=~D1; Countor1=0; //将Countor1清0,重新从0开始计数 } if(Countor2==8) //若累计满8次,即计时满400ms { D2=~D2; Countor2=0; //将Countor1清0,重新从0开始计数 } TH1=(65536-46083)/256; TL1=(65536-46083)%256; } #include<reg51.h> sbit D1=P1^0; sbit D2=P1^1; unsigned char Countor1; unsigned char Countor2; /************************************* 函数功能:主函数 ***************************************/ void main(void) { EA=1; //开总中断 ET1=1; //定时器T1中断允许 TMOD=0x10; //使用定时器T1的模式1 TH1=(65536-46083)/256; TL1=(65536-46083)%256; TR1=1; //启动定时器T1 Countor1=0; //从0开始累计中断次数 Countor2=0; //从0开始累计中断次数 while(1) ; //无限循环等待中断 }
实验二:定时/计数器的基本应用 实验内容 利用定时器T0工作在方式3,用TL0计数器对应的8位定时器实现一个发光管以1s闪烁, 用TH0计数器对应的8位定时器实现另一个发光管以0.5s闪烁。 实验电路 :
while(1) //程序停止在这里等待中断发生 { if(num1>=3686)//如果到了3686次,说明1秒时间到 { num1=0; //然后把num1清0重新再计3686次 led1=~led1; //让发光管状态取反 } if(num2>=1843)//如果到了1843次,说明半秒时间到 { num2=0;//然后把num2清0重新再计1843次 led2=~led2; //让发光管状态取反 } } } #include <reg51.h> #define uchar unsigned char #define uint unsigned int sbit led1=P1^0; sbit led2=P1^1; uint num1,num2; void main() { TMOD=0x03; //设置定时器0为工作方式3 TH0=6; //装初值 TL0=6; EA=1; //开总中断 ET0=1; //开定时器0中断 ET1=1; //开定时器1中断 TR0=1; //启动定时器0 TR1=1; //启动定时器0的高8位计数器
void TL0_time() interrupt 1 { TL0=6; //重装初值 num1++; } void TH0_time() interrupt 3 { TH0=6; //重装初值 num2++; }
实验三:中断系统实验 (用外中断0的中断方式进行数据采集) 用外中断0控制P1口LED亮灭状态。按下S键8灯亮,再按下8灯灭,如此循环。
#include<reg51.h> sbit S=P3^2; //将S位定义为P3.2, /******************************************* 函数功能:主函数 ******************************************/ void main(void) { EA=1; //开放总中断 EX0=1; //允许使用外中断 IT0=1; //选择负跳变来触发外中断 P1=0xff; while(1) ; //无限循环, 防止程序跑飞 } /************************************************************** 函数功能:外中断T0的中断服务程序 **************************************************************/ void int0(void) interrupt 0 using 0 //外中断0的中断编号为0 { P1=~P1; //每产生一次中断请求,P1取反一次。 }
练习: 用外中断INT0测量负跳变信号累计数。结果在P1口的8个LED上显示(设100个脉冲)。
Countor=0; for(i=0;i<100;i++) //输出100个负跳变 { u=1; delay30ms(); u=0; delay30ms(); } while(1) ; //无限循环, 防止程序跑飞 } /************************************** 函数功能:外中断T0的中断服务程序 ************************************/ void int0(void) interrupt 0 using 0 { Countor++; P1=Countor; } #include<reg51.h> sbit u=P3^0; unsigned char Countor; /************************************************* 函数功能:延时约30ms (3*100*100=30 000μs =30ms) *************************************************/ void delay30ms(void) { unsigned char m,n; for(m=0;m<100;m++) for(n=0;n<100;n++) ; } /******************************************* 函数功能:主函数 ******************************************/ void main(void) { unsigned char i; EA=1; //开放总中断 EX0=1; //允许使用外中断 IT0=1; //选择负跳变来触发外中断
将上题改成用数码管显示0~9个外中断计数(共阳)。将上题改成用数码管显示0~9个外中断计数(共阳)。
参考程序: void main(void) { unsigned char i; P2=0xfe; EA=1; //开放总中断 EX0=1; //允许使用外中断 IT0=1; //选择负跳变来触发外中断 Countor=0; for(i=0;i<9;i++) //输出9个负跳变 { u=1; delay120ms(); u=0; delay120ms(); } while(1) ; } void int0(void) interrupt 0 using 0 { Countor++; P0=tab[Countor]; } #include<reg51.h> sbit u=P3^0; unsigned char Countor; unsigned char tab[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90}; /************************************************* 函数功能:延时约120ms (3*200*200=30 000μs 120ms) *************************************************/ void delay120ms(void) { unsigned char m,n; for(m=0;m<200;m++) for(n=0;n<200;n++) ; }
用外中断0的中断测量外部负脉冲宽度。 实现方法:先设计一个单片机的P1.4脚输出负脉冲(设200us),由第2片单片机的外中断0(P3.2脚)接收并检测负脉冲宽度,结果由P1口8位LED显示。
测量负脉冲宽度的程序设计 产生200us方波 #include<reg51.h> sbit u=P3^2; //将u位定义为P3.2 void main(void) { TMOD=0x02; EA=1; //开放总中断 EX0=1; //允许使用外中断 IT0=1; //选择负跳变来触发外中断 ET0=1; //允许定时器T0中断 TH0=0; //定时器T0赋初值0 TL0=0; //定时器T0赋初值0 TR0=0; //先关闭T0 while(1) ; //无限循环, 不停检测输入负脉冲宽度 } void int0(void) interrupt 0 using 0 { TR0=1; //外中断一到来,即启动T0计时 TL0=0; //从0开始计时 while(u==0) ; //低电平时,等待T0计时 P1=TL0; //将结果送P1口显示 TR0=0; //关闭T0 } #include<reg51.h> sbit u=P1^4; void main(void) { TMOD=0x02; EA=1; //开总中断 ET0=1; //定时器T0中断允许 TH0=256-56; //定时器T0的高8位赋初值 TL0=256-200; //定时器T0的高8位赋初值 TR0=1; //启动定时器T0 while(1) //无限循环,等待中断 ; } void Time0(void) interrupt 1 using 0 { u=~u; //将P1.4引脚输出电平取反,产生方波 }
串行口应用串行控制寄存器SCON ① SM0 SM1 —— 串行口工作方式选择位。 ② SM2 —— 多机通信控制位。 ③ REN —— 允许接收控制位。REN=1,允许接收。 ④ TB8 —— 方式2和方式3中要发送的第9位数据。 ⑤ RB8 —— 方式2和方式3中要接收的第9位数据。 ⑥ TI —— 发送中断标志。 ⑦ RI —— 接收中断标志。 3、电源控制寄存器PCON SMOD=1,串行口波特率加倍。PCON寄存器不能进行位寻址。
SM0、SM1:串行口工作方式选择位。用于选择四种工作方式SM0、SM1:串行口工作方式选择位。用于选择四种工作方式
实验四 单片机串口通信实验 • 基于方式1的单工通信 • 单片机U1通过串行口TXD端将一段流水灯控制码以方式一发送至单片机U2的RXD,U2再利用该控制码点亮P1口的8位数码管。
发送程序 void main(void) { unsigned char i; TMOD=0x20; SCON=0x40; PCON=0x00; //PCON=0000 0000B,波特率9600 TH1=0xfd; //根据规定给定时器T1赋初值 TL1=0xfd; //根据规定给定时器T1赋初值 TR1=1; //启动定时器T1 while(1) { for(i=0;i<8;i++) //模拟检测数据 { Send(Tab[i]); //发送数据i delay(); //50ms发送一次检测数据 } } } #include<reg51.h> unsigned char code Tab[ ]={0xFE,0xFD,0xFB,0xF7,0xEF,0xDF,0xBF,0x7F}; void Send(unsigned char dat) { SBUF=dat; while(TI==0) ; TI=0; } void delay(void) { unsigned char m,n; for(m=0;m<200;m++) for(n=0;n<250;n++) ; }
void main(void) { TMOD=0x20; SCON=0x50; 允许接收(REN=1) PCON=0x00; //PCON=0000 0000B,波特率9600 TH1=0xfd; //根据规定给定时器T1赋初值 TL1=0xfd; //根据规定给定时器T1赋初值 TR1=1; //启动定时器T1 while(1) { P1=Receive(); //将接收到的数据送P1口显示 } } 数据接收程序 #include<reg51.h> unsigned char Receive(void) { unsigned char dat; while(RI==0) //只要接收中断标志位RI没有被置“1” ; //等待,直至接收完毕(RI=1) RI=0; dat=SBUF; return dat; }
[例] 设U1为甲机发送,U2为乙机接收。试编程通过串行口将甲机上的一段流水灯控制码以方式1发送给乙机,乙机再利用该段控制码流水点亮其P1口的8位LED.加奇偶校验。
#include<reg51.h> //包含单片机寄存器的头文件 sbit p=PSW^0; unsigned char code Tab[ ]={0xFE,0xFD,0xFB,0xF7,0xEF,0xDF,0xBF,0x7F}; //流水灯控制码,该数组被定义为全局变量 /***************************************************** 函数功能:向PC发送一个字节数据 ***************************************************/ void Send(unsigned char dat) { ACC=dat; TB8=p; SBUF=dat; while(TI==0) ; TI=0; }
void delay(void) { unsigned char m,n; for(m=0;m<200;m++) for(n=0;n<250;n++); } void main(void) { unsigned char i; TMOD=0x20; //TMOD=0010 0000B,定时器T1工作于方式2 SCON=0xc0; //SCON=1100 0000B,串口工作方式3, //SM2置0,不使用多机通信,TB8置0 PCON=0x00; //PCON=0000 0000B,波特率9600 TH1=0xfd; //根据规定给定时器T1赋初值 TL1=0xfd; //根据规定给定时器T1赋初值 TR1=1; //启动定时器T1 while(1) { for(i=0;i<8;i++) //模拟检测数据 { Send(Tab[i]); //发送数据i delay(); } } } //50ms发送一次检测数据
解:程序如下: #include<reg51.h> sbit p=PSW^0; unsigned char receive(void) { unsigned char dat; while(RI==0) ; RI=0; ACC=SBUF; //将接收缓冲器中的数据存于dat if(RB8==p) { dat=ACC; return dat; } }
void main(void) { TMOD=0x20; //定时器T1工作于方式2 SCON=0xd0; //SCON=1101 0000B,串口工作方式3,允许接收(REN=1) PCON=0x00; //PCON=0000 0000B,波特率9600 TH1=0xfd; //根据规定给定时器T1赋初值 TL1=0xfd; //根据规定给定时器T1赋初值 TR1=1; //启动定时器T1 REN=1; //允许接收 while(1) { P1=receive(); //将接收到的数据送P1口显示 } }
实验五 单片机显示实验 电路:
#include<reg51.h> // 包含51单片机寄存器定义的头文件 void main(void) { P2=0xfe; //P2.0引脚输出低电平,数码显示器接通电源准备点亮 P0=0x92; //让P0口输出数字"5"的段码92H }
例:循环显示0~9 while(1) //无限循环 { for(i=0;i<10;i++) { P0=Tab[i]; delay(); } } } #include<reg51.h> void delay(void) { unsigned char i,j; for(i=0;i<255;i++) for(j=0;j<255;j++) ; } void main(void) { unsigned char i; unsigned char code Tab[10]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90}; //数码管显示0~9的//段码表,程序运行中当数组值不发生变 //化时,前面加关键字code ,可以大大节//约单片机的存储空间 P2=0xfe; //P2.0引脚输出低电平,数码显示器DS0接通电源工作
例:用串行口扩展并行口软件译码静态显示电路:例:用串行口扩展并行口软件译码静态显示电路: