单片机控制技术配套实验程序.docx
《单片机控制技术配套实验程序.docx》由会员分享,可在线阅读,更多相关《单片机控制技术配套实验程序.docx(188页珍藏版)》请在冰豆网上搜索。
单片机控制技术配套实验程序
单片机控制技术配套实验程序
数据类型
C语言的数据结构是以数据类型出现的,数据类型可分为基本数据型和复杂数据类型,复杂数据类型由基本数据类型构造而成。
C语言中的基本数据类型有char、int、short、long、float和double六种。
对于C51编译器来说,short类型与int类型相同,double类型与float类型相同。
#include//预处理命令
voidmain(void)//主函数名
{
unsignedinta;//定义变量a为unsignedint类型
unsignedcharb;//定义变量b为unsignedchar类型
do
{//dowhile组成循环
for(a=0;a<65535;a++)
P1_0=0;//65535次设P1.0口为低电平,点亮LED
P1_0=1;//设P1.0口为高电平,熄灭LED
for(a=0;a<30000;a++);//空循环
for(b=0;b<255;b++)
P1_1=0;//255次设P1.1口为低电平,点亮LED
P1_1=1;//设P1.1口为高电平,熄灭LED
for(a=0;a<30000;a++);//空循环
}
while
(1);
}
bit位标量
bit位标量是C51编译器的一种扩充数据类型,利用它可定义一个位标量,但不能定义位指针,也不能定义位数组。
它的值是一个二进制位,不是0就是1,类似一些高级语言中的Boolean类型中的True和False。
7.sfr特殊功能寄存器
sfr也是一种扩充数据类型,占用一个内存单元,值域为0~255。
利用它可以访问51单片机内部的所有特殊功能寄存器。
如用sfrP1=0x90这一句定P1为P1端口在片内的寄存器,在后面的语句中我们用以用P1=255(对P1端口的所有引脚置高电平)之类的语句来操作特殊功能寄存器。
8.sfr1616位特殊功能寄存器
sfr16占用两个内存单元,值域为0~65535。
sfr16和sfr一样用于操作特殊功能寄存器,所不同的是它用于操作占两个字节的寄存器,如定时器T0和T1。
9.sbit可录址位
sbit同样是C51中的一种扩充数据类型,利用它可以访问芯片内部的RAM中的可寻址位或特殊功能寄存器中的可寻址位。
如先前我们定义了
sfrP1=0x90;//因P1端口的寄存器是可位寻址的,所以我们可以定义
sbitP1_1=P1^1; //P1_1为P1中的P1.1引脚
//同样我们可以用P1.1的地址去写,如sbitP1_1=0x91;
这样我们在以后的程序语句中就可以用P1_1来对P1.1引脚进行读写操作了。
通常这些可以直接使用系统提供的预处理文件,里面已定义好各特殊功能寄存器的简单名字,直接引用可以省去一点时间,我自己是一直用的。
当然您也可以自己写自己的定义文件,用您认为好记的名字。
sfrP1=0x90;//这里没有使用预定义文件,
sbitP1_0=P1^0;//而是自己定义特殊寄存器
sbitP1_7=0x90^7;//之前我们使用的预定义文件其实就是这个作用
sbitP1_1=0x91;//这里分别定义P1端口和P10,P11,P17引脚
voidmain(void)
{
unsignedinta;
unsignedcharb;
do{
for(a=0;a<50000;a++)
P1_0=0;//点亮P1_0
for(a=0;a<50000;a++)
P1_7=0;//点亮P1_7
for(b=0;b<255;b++)
{
for(a=0;a<10000;a++)
P1=b;//用b的值来做跑马灯的花样
}
P1=255;//熄灭P1上的LED
for(b=0;b<255;b++)
{
for(a=0;a<10000;a++)//P1_1闪烁
P1_1=0;
for(a=0;a<10000;a++)
P1_1=1;
}
}while
(1);
}
常量
常量又称为标量,它的值在程序执行过程中不能改变。
常量的数据类型有整型、浮点型、字符型和字符串型等
#include//预处理文件里面定义了特殊寄存器的名称如P1口定义为P1
voidmain(void)
{
//定义花样数据
unsignedchardesign[32]={0xFF,0xFE,0xFD,0xFB,0xF7,0xEF,0xDF,0xBF,0x7F,
0x7F,0xBF,0xDF,0xEF,0xF7,0xFB,0xFD,0xFE,0xFF,
0xFF,0xFE,0xFC,0xF8,0xF0,0xE0,0xC0,0x80,0x0,
0xE7,0xDB,0xBD,0x7E,0xFF};
unsignedinta;//定义循环用的变量
unsignedcharb;//在C51编程中因内存有限尽可能注意变量类型的使用
//尽可能使用少字节的类型,在大型的程序中很受用
do{
for(b=0;b<32;b++)
{
for(a=0;a<30000;a++);//延时一段时间
P1=design[b];//读已定义的花样数据并写花样数据到P1口
}
}while
(1);
}
运算符与表达式
条件语句
条件语句又称为分支语句,是用关键字if构成的。
C语言提供了三种形式的条件语句:
①.if(条件表达式)语句
其含义为:
若条件表达式的结果为真(非0值),就执行后面的语句;反之,就不执行后面的语句。
这里的语句也可以是复合语句。
②.if(条件表达式)语句1
else语句2
其含义为:
若条件表达式的结果为真(非0值),就执行语句1;反之,就执行语句2。
这里的语句1和语句2均可以是复合语句。
#include
sbitK1=P3^0;
sbitL1=P1^0;
voidmain(void)
{
while
(1)
{
if(K1==0)
{
L1=0;//灯亮
}
else
{
L1=1;//灯灭
}
}
}
开关语句
开关语句也是一种用来实现多方向条件分支的语句。
虽然采用条件语句也可以实现多方向条件分支,但是当分支较多时,会使条件语句的嵌套层次太多,程序冗长,可读性降低。
开关语句直接处理多分支选择,使程序结构清晰,使用方便。
开关语句是用关键字switch构成的,一般形式如下:
switch(表达式)
{
case常量表达式1:
语句1
break;
case常量表达式2:
语句2
break;
……
case常量表达式n:
语句n
break;
default:
语句d
}
开关SP1接在P3.7/RD管脚上,在AT89S51单片机的P1端口接有四个发光二极管,上电的时候,L1接在P1.0管脚上的发光二极管在闪烁,当每一次按下开关SP1的时候,L2接在P1.1管脚上的发光二极管在闪烁,再按下开关SP1的时候,L3接在P1.2管脚上的发光二极管在闪烁,再按下开关SP1的时候,L4接在P1.3管脚上的发光二极管在闪烁,再按下开关SP1的时候,又轮到L1在闪烁了,如此轮流下去。
#include
unsignedcharID;
voiddelay10ms(void)
{
unsignedchari,j;
for(i=20;i>0;i--)
for(j=248;j>0;j--);
}
voiddelay02s(void)
{
unsignedchari;
for(i=20;i>0;i--)
{delay10ms();
}
}
voidmain(void)
{while
(1)
{if(P3_7==0)
{delay10ms();
if(P3_7==0)
{
ID++;
if(ID==4)
{
ID=0;
}
while(P3_7==0);
}
}
switch(ID)
{case0:
P1_0=~P1_0;
delay02s();
break;
case1:
P1_1=~P1_1;
delay02s();
break;
case2:
P1_2=~P1_2;
delay02s();
break;
case3:
P1_3=~P1_3;
delay02s();
break;
}
}
函数的定义
从用户的角度来看,有两种函数:
标准库函数和用户自定义函数。
标准库函数是C51编译器提供的,不需要用户进行定义,可以直接调用。
用户自定义函数是用户根据自己需要编写的能实现特定功能的函数,必须先定义之后才能调用
#include
sbitL1=P1^0;
voiddelay02s(void)//延时0.2秒子程序
{
unsignedchari,j,k;
for(i=20;i>0;i--)
for(j=20;j>0;j--)
for(k=248;k>0;k--);
}
voidmain(void)
{
while
(1)
{
L1=0;
delay02s();
L1=1;
delay02s();
}
}
多路开关状态指示
#include
unsignedchartemp;
voidmain(void)
{
while
(1)
{
temp=P1>>4;
temp=temp|0xf0;
P1=temp;
}
}
#include
voidmain(void)
{
while
(1)
{
if(P1_4==0)
{
P1_0=0;
}
else
{
P1_0=1;
}
if(P1_5==0)
{
P1_1=0;
}
else
{
P1_1=1;
}
if(P1_6==0)
{
P1_2=0;
}
else
{
P1_2=1;
}
if(P1_7==0)
{
P1_3=0;
}
else
{
P1_3=1;
}
}
}
广告灯的左移右移
#include
unsignedchari;
unsignedchartemp;
unsignedchara,b;
voiddelay(void)
{
unsignedcharm,n,s;
for(m=20;m>0;m--)
for(n=20;n>0;n--)
for(s=248;s>0;s--);
}
voidmain(void)
{
while
(1)
{
temp=0xfe;
P1=temp;
delay();
for(i=1;i<8;i++)
{
a=temp<
b=temp>>(8-i);
P1=a|b;
delay();
}
for(i=1;i<8;i++)
{
a=temp>>i;
b=temp<<(8-i);
P1=a|b;
delay();
}
}
}
广告灯(利用取表方式)
1. 实验任务
利用取表的方法,使端口P1做单一灯的变化:
左移2次,右移2次,闪烁2次(延时的时间0.2秒)。
#include
unsignedcharcodetable[]={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};
unsignedchari;
voiddelay(void)
{
unsignedcharm,n,s;
for(m=20;m>0;m--)
for(n=20;n>0;n--)
for(s=248;s>0;s--);
}
voidmain(void)
{
while
(1)
{
if(table[i]!
=0x01)
{
P1=table[i];
i++;
delay();
}
else
{
i=0;
}
}
}
报警产生器
1.实验任务
用P1.0输出bHz和500Hz的音频信号驱动扬声器,作报警信号,要求1KHz信号响100ms,500Hz信号响200ms,交替进行,P1.7接一开关进行控制,当开关合上响报警信号,当开关断开告警信号停止,编出程序。
C语言源程序
#include
#include
bitflag;
unsignedcharcount;
voiddely500(void)
{
unsignedchari;
for(i=250;i>0;i--)
{
_nop_();
}
}
voidmain(void)
{
while
(1)
{
if(P1_7==0)
{
for(count=200;count>0;count--)
{
P1_0=~P1_0;
dely500();
}
for(count=200;count>0;count--)
{
P1_0=~P1_0;
dely500();
dely500();
}
}
}
}
世上只有妈妈好
#include
sbitspeaker=P3^3;//接音频放大电路,
//sbitspeaker=P3^2;
//电后位后,sw合上后就开始放音乐,灯开始闪动,sw断开,音乐停止,灯也同时停止闪动
unsignedchartimer0h,timer0l,time,led=1,j=0;
unsignedcharflagd=0;
//世上只有妈妈好数据表
codeunsignedcharsszymmh[]={6,2,3,5,2,1,3,2,2,5,2,2,1,3,2,6,2,1,5,2,1,
6,2,4,3,2,2,5,2,1,6,2,1,5,2,2,3,2,2,1,2,1,
6,1,1,5,2,1,3,2,1,2,2,4,2,2,3,3,2,1,5,2,2,
5,2,1,6,2,1,3,2,2,2,2,2,1,2,4,5,2,3,3,2,1,
2,2,1,1,2,1,6,1,1,1,2,1,5,1,6,0,0,0
};
//音阶频率表高八位
codeunsignedcharFREQH[]={
0xF2,0xF3,0xF5,0xF5,0xF6,0xF7,0xF8,
0xF9,0xF9,0xFA,0xFA,0xFB,0xFB,0xFC,0xFC,//1,2,3,4,5,6,7,8,i
0xFC,0xFD,0xFD,0xFD,0xFD,0xFE,
0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFF,
};
//音阶频率表低八位
codeunsignedcharFREQL[]={
0x42,0xC1,0x17,0xB6,0xD0,0xD1,0xB6,
0x21,0xE1,0x8C,0xD8,0x68,0xE9,0x5B,0x8F,//1,2,3,4,5,6,7,8,i
0xEE,0x44,0x6B,0xB4,0xF4,0x2D,
0x47,0x77,0xA2,0xB6,0xDA,0xFA,0x16,
};
voiddelay(unsignedchart)
{
unsignedchart1;
unsignedlongt2;
for(t1=0;t1{
for(t2=0;t2<8000;t2++)
{
;
}
}
TR0=0;
}
voidt0int()interrupt1
{
TR0=0;
speaker=!
speaker;
TH0=timer0h;
TL0=timer0l;
TR0=1;
}
voidsong()
{
TH0=timer0h;
TL0=timer0l;
TR0=1;
delay(time);
}
voidmain(void)
{
unsignedchark,i;
TMOD=1;//置CT0定时工作方式1
EA=1;ET0=1;//IE=0x82//CPU开中断,CT0开中断
while
(1)
{
i=0;
time=1;
while(time)
{
if(j==8)
{
//led=1;
j=0;flagd=~flagd;
if(flagd)
{
led=0x80;
}
else
{
led=1;
}
}
else
{
P1=~led;
if(flagd)
{
led=led>>1;
}
else
{
led=led<<1;
}
j++;
}
k=sszymmh[i]+7*sszymmh[i+1]-1;
timer0h=FREQH[k];
timer0l=FREQL[k];
time=sszymmh[i+2];
i=i+3;
song();
}
}
}
用外中断方式读按键,控制灯的亮灭
外中断的用法。
也就是外部IO的中断INT0,和INT1。
对应的引脚是P32和P33。
在我们的电路图中,P32也就是接在K1的引脚。
所以当我们按下P32接到地的时候,可以触发一个INT0中断,当然,必须预先初始化才会启动。
这种中断方式的按键,可以实现按键的立即响应。
对于需要快速响应的场合是很有用的。
外部IO中断还常用在用IO模拟通讯的场合,可以对数据的到来立即响应。
下面请看代码:
―――――――――――――――――
#defineucharunsignedchar//定义一下方便使用
#defineuintunsignedint
#defineulongunsignedlong
#include//包括一个52标准内核的头文件
sbitP10=P1^0;//头文件中没有定义的IO就要自己来定义了
sbitP11=P1^1;
sbitP12=P1^2;
sbitP13=P1^3;
sbitK1=P3^2;
bitldelay=0;//长定时溢出标记,预置是0
ucharspeed=10;//设置一个变量保存默认的跑马灯的移动速度
ucharspeedlever=0;//保存当前的速度档次
//用外中断方式读按键K1,点亮一个LED
voidmain(void)//主程序
{
IT0=1;//外中断跳变产生中断
EX0=1;
EA=1;//打开总中断
while
(1)//主程序循环
{
}
}
//外中断0
int0()interrupt0
{
P10=0;//在中断里点亮LED
}作业:
用中断方式的按键K1,控制一个LED灯的亮和灭两种状态
提示:
需要去抖操作,否则按键抖动会引起多种中断。
定时/计数器结构
⏹定时/计数器简称定时器,89C51单片机有2个16位的定时/计数器:
定时器0(T0)和定时器1(T1)。
它们都有定时器或事件计数的功能,可用于定时控制、延时、对外部事件计数和检测等场合。
⏹T0由2个特殊功能寄存器TH0和TL0构成,T1则由TH1和TL1构成。
作计数器时,通过引脚T0(P3.4)和T1(P3.5)对外部脉冲信号计数,当输入脉冲信号从1到0的负跳变时,计数器就自动加1。
计数的最高频率一般为振荡频率的1/24。
定时/计数器工作方式
⏹每个定时/计数器还有4种工作模式,也就是每个定时器可构成4种电路结构模式。
⏹在模式0、1和2,T0和T1的工作模式相同,在模式3,两个定时器的模式不同。
下面以T1为例,分述各种工作模式的特点和用法。
⏹
定时/计数器控制寄存器
⏹定时器共有2个控制寄存器TMOD和TCON,由软件写入TMOD和TCON两个8位寄存器,设置各个定时器的操作模式和控制功能。
二、定时器的结构
初学者不必去深入研究单片机的内部硬件电路,只要掌握单片机的使用方法,通过实际编程,充分发挥单片机的特定功能即可。
与定时器有关的特殊功能寄存器之间的信号关系示于图1。
图中,TLO、THO、TL1、TH1以及TMOD和TCON都是单片机的特殊功能寄存器。
TLO和THO组成16位的定时/计数器(T0),TL1和TH1组成16位的定时/计数器(T1),TMOD是T0和T1的工作方式控制寄存器,TCON是T0和T1的运行状态控制寄存器,这些寄存器在程序2中已多次出现。
在实际应用时,应首先根据需要对这些寄存器进行初始化,即设置T0和T1的工作方式并对T0和T1定时器装入初始值以得到精确的定时时间。
T0和T1的工作方式及运行状态是由TMOD和TCON两个特殊功能寄存器控制的,而TMOD和TCON是由用户所编的程序控制的。
因此,学好用好定时/计数器必须掌握这些寄存器的功能及使用方法。
三、TMOD
TMOD是定时器的工作方式控制寄存器,其格式见表1。
表1定时器工作方式寄存器格式
TMOD是8位的控制寄存器,低4位控制T0的工作方式,高4位控