资源描述
MCS-51单片机实验源程序
仅供参考。没有最好,只有更好!希望大家设计出更好的程序来。
软件实验一 求一组数据的最大(小)值
/*软件实验的目的:熟悉单片机常用的基本程序(算法),调试时观察变量(含数组)值的变化,从而理解程序的功能,了解变量(含数组)在单片机存储器中的具体位置。*/
int a[]={-1,2,-30,40,-500,600,-7000,8000,-32750,32765}; //任意给出10个int型数(范围:-32768~+32767),放在数组a中
void main()
{
unsigned char i;
int max,min;
max=min=a[0]; //max,min先取该组数据的第一个
for(i=1;i<10;i++)
{
if(a[i]>max) max=a[i];
if(a[i]<min) min=a[i];
}
while(1); //没有什么要做了,则用该语句作为main函数的结尾,无限循环
}
附调试截图:
注意:由于是纯软件实验(单片机没有进行实际的输入与输出),有些变量要声明为全局变量(如上面的数组a),否则可能会被Keil软件编译时优化掉(即:一些语句没有真正生成执行代码),导致无法观察到正确结果。
软件实验二 二进制(十六进制)数转换为BCD数
//按流程图,编写程序如下:
#define uchar unsigned char
void main()
{
uchar x=0xA5; //设二进制数为1010 0101,在Keil中只能用十六进制0xA5或十进制165(不能直接用二进制形式)
uchar a[3];
a[2]=x/100;
x=x%100;
a[1]=x/10;
x=x%10;
a[0]=x;
while(1);
}
//或者用for循环语句,先取出个位
#define uchar unsigned char
void main()
{
uchar x=0xA5;
uchar i,a[3];
for(i=0;i<3;i++)
{
a[i]=x%10;
x=x/10;
}
while(1);
}
软件实验三 二进制(十六进制)数转换为ASCII码
//将0-9、A-F的ASCII码做成表格(数组)放到程序存储器ROM中
#define uchar unsigned char
uchar code ascii[]={"0123456789ABCDEF"}; //ASCII码表放ROM中
/*上句赋值也可写成{0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39, 0x41,0x42,0x43,0x44,0x45,0x46} */
/* 还可写成{48,49,50,51,52,53,54,55,56,57,65,66,67,68,69,70} */
/* 还可写成{'0','1','2','3','4','5','6','7','8','9','A','B','C','D', 'E','F'} */
void main()
{
uchar x=0x5A; //设二进制数为0101 1010,在Keil中只能用十六进制0x5A或十进制90(不能直接用二进制形式)
uchar cc,a[2];
cc=x & 0x0f; //取x的低4位1010(即A)
a[0]=ascii[cc]; //查表,a[0]存x低4位对应十六进制数(即A)的ASCII码
cc=(x>>4)& 0x0f; //取x的高4位0101(即5)
a[1]=ascii[cc]; //查表,a[1]存x高4位对应十六进制数(即5)的ASCII码
while(1);
}
硬件实验一 并行口输入、输出
//P2做输出口,接8只LED,编写程序,使LED循环点亮(流水灯)
#include<reg51.h>
#include<intrins.h> //内部函数_crol_,_cror_等的头文件
void Delay(unsigned int x) //延时函数,在12MHz晶振下,延时约x ms
{unsigned char i;
while(x--)
for(i=0;i<123;i++);
}
void main()
{
char a=0xfe;
while(1)
{
P2=a;
Delay(500); //在12MHz晶振下,延时约500ms
a=_crol_(a,1); //循环左移,_cror_为循环右移
}
}
//P3.2和P3.3做输入口,分别接两个拨动开关到GND;P2.7~P2.4做输出口,接4只LED,用来指示两个开关的闭合状态组合
#include<reg51.h>
void main()
{
char a;
while(1)
{
a=P3; //读入P3口状态
a=a&0x0C; //a中只保留P3.3、P3.2的值,其余位清零
if(a==0x0C) P2=0x7F; //P3.3=1开,P3.2=1开,则P2.7=0亮
if(a==0x08) P2=0xbF; //P3.3=1开,P3.2=0合,则P2.6=0亮
if(a==0x04) P2=0xdF; //P3.3=0合,P3.2=1开,则P2.5=0亮
if(a==0x00) P2=0xEF; //P3.3=0合,P3.2=0合,则P2.4=0亮
}
}
//用一个共阳七段数码管循环显示0-9和A-F,每个数显示0.5s
#include<reg51.h>
sbit P1_0=P1^0;
char code TABLE[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,
0x80,0x90,0x88,0x83,0xc6,0xa1,0x86,0x8e}; //共阳数码管段码(放在程序存储器ROM中)
void Delay(unsigned int x) //延时函数,在12MHz晶振下,延时约x ms
{unsigned char i;
while(x--)
for(i=0;i<123;i++);
}
void main()
{ char j;
P1_0=0; //位选信号
while(1)
{
for(j=0;j<16;j++)
{
P0=TABLE[j];
Delay(500);
}
}
}
硬件实验二 外部中断
//通过外部中断0(下降沿触发),启动或关闭流水灯,即上电复位时不亮,按一次INT0(P3.2)引脚的按钮,流水灯开启,再按一次,灯熄灭
#include<reg51.h>
#include<intrins.h> //内部函数_crol_,_cror_等的头文件
bit LED=0; //位变量LED用于记录流水灯的状态,0为关闭,1为开启
void Delay(unsigned int x) //延时函数,在12MHz晶振下,延时约x ms
{unsigned char i;
while(x--)
for(i=0;i<123;i++);
}
void INT0_srv(void) interrupt 0 //INT0中断号为0
{
Delay(10); //延时10ms,去抖动
if(INT0==0) LED=!LED; //每次中断时切换LED开启或关闭
}
void main()
{
char a=0xfe;
IT0=1; //下降沿触发
EX0=1; //允许INT0中断
EA=1;
while(1)
{
if(LED) //开启
{
P2=a;
Delay(500); //在12MHz晶振下,延时约500ms
a=_crol_(a,1); //循环左移,_cror_为循环右移
}
else //关闭
{P2=0xff;}
}
}
//通过外部中断0(低电平触发),启动或关闭流水灯,即上电复位时不亮,按一次INT0(P3.2)引脚的按钮,流水灯开启,再按一次,灯熄灭
#include<reg51.h>
#include<intrins.h> //内部函数_crol_,_cror_等的头文件
bit LED=0; //位变量LED用于记录流水灯的状态,0为关闭,1为开启
void Delay(unsigned int x) //延时函数,在12MHz晶振下,延时约x ms
{unsigned char i;
while(x--)
for(i=0;i<123;i++);
}
void INT0_srv(void) interrupt 0 //INT0中断号为0
{
Delay(10); //延时10ms,去抖动
if(INT0==0) LED=!LED; //每次中断时切换LED开启或关闭
while(INT0==0); //如P3.2(INT0)还是0,则等待,变为1后才从中断返回
}
void main()
{
char a=0xfe;
IT0=0; //低电平触发
EX0=1; //允许INT0中断
EA=1;
while(1)
{
if(LED) //开启
{
P2=a;
Delay(500); //在12MHz晶振下,延时约500ms
a=_crol_(a,1); //循环左移,_cror_为循环右移
}
else //关闭
{P2=0xff;}
}
}
硬件实验三 定时计数器
//用单片机内部定时器方式计时,实现每一秒钟P2口输出状态发生一次反转。
//设置定时器溢出时间为50ms,溢出20次则为1s
//12MHz晶振下,内部每个计数脉冲为1ms,50ms则需要50000个脉冲
//在定时器方式1下初值为65536-50000
//中断法
#include<reg51.h>
unsigned char count=20; //定时溢出次数
void T0_int(void) interrupt 1 //T0中断号为1
{
TH0=(65536-50000)/256; //每次溢出重新置初值
TL0=(65536-50000)%256;
count--;
if(count==0) //溢出20次,即1s
{
count=20;
P2=~P2;
}
}
void main()
{
TMOD=0x01; //T0内部定时,方式1
TH0=(65536-50000)/256; //置初值
TL0=(65536-50000)%256;
ET0=1; //允许T0中断
EA=1;
TR0=1; //启动T0
while(1); //循环等待
}
//查询法
#include<reg51.h>
unsigned char count=20; //定时溢出次数
void main()
{
TMOD=0x01; //T0内部定时,方式1,由TR0启动
TH0=(65536-50000)/256; //置初值
TL0=(65536-50000)%256;
TR0=1; //启动T0
while(1)
{
while(!TF0); //等待定时溢出
TF0=0; //溢出标志清零
TH0=(65536-50000)/256; //溢出重新置初值
TL0=(65536-50000)%256;
count--;
if(count==0) //溢出20次,即1s
{
count=20;
P2=~P2;
}
}
}
//单片机对从P3.4(T0)输入的脉冲信号计数,T0工作于方式1,将计数结果送至P2口显示(二进制形式)
//由于输出低电平时LED亮,故需反转后输出
#include<reg51.h>
void main()
{
TMOD=0x05; //T0外部计数,方式1,由TR0启动
TH0=TL0=0; //置初值(可省略)
TR0=1; //启动T0
while(1)
{
P2=~TL0; //将计数值实时送P2口显示,未考虑TH0
}
}
//单片机对从P3.4(T0)输入的脉冲信号计数,T0工作于方式1,将计数结果用4位共阳数码管动态扫描显示(P0口输出段码,P1.0~P1.3分别选择千、百、十、个位,参见实验板原理图)
#include<reg51.h>
char code SEG[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90}; //共阳数码管0~9的段码(放在程序存储器ROM中)
char code bit_sel[]={0xf7,0xfb,0xfd,0xfe}; //个、十、百、千 位选信号
void Delay(unsigned int x) //延时函数,在12MHz晶振下,延时约x ms
{unsigned char i;
while(x--)
for(i=0;i<123;i++);
}
void main()
{
unsigned int count;
unsigned char k;
TMOD=0x05; //T0外部计数,方式1,由TR0启动
TH0=TL0=0; //置初值(可省略)
TR0=1; //启动T0
while(1)
{
count=TH0*256+TL0; //将计数值送count
for(k=0;k<4;k++) //动态扫描显示
{
P1=bit_sel[k]; //输出位选信号
P0=SEG[count%10]; //输出段码
Delay(5);
count=count/10;
}
}
}
硬件实验四 串行通信
//单片机甲用于串行发送,单片机乙用于接收。甲向乙发送0-9和A-F共16个数。
//乙接收这16个数存放到数组,然后依次用一个接在P0口的共阳七段数码管显示出来,每个数显示时间约0.5s
//单片机甲发送程序(查询方式) Keil中需单独建一个项目
#include <reg51.h>
#define uchar unsigned char
void main()
{
uchar i=0;
TMOD=0x20; /*设置定时器T1为方式2*/
TH1=TL1=0xfd; /*波特率9600*/
SCON=0x40; /*串口方式1只发送,不接收*/
TR1=1; /*启动T1*/
for(i=0;i<16;i++) //循环16次,依次发送0-F
{
SBUF=i; /*数据送串行口发送缓冲器*/
while(TI==0); /*如果TI=0,未发送完,循环等待*/
TI=0; /*已发送完,再把TI清0*/
}
while(1);
}
//单片机乙接收程序(中断方式) Keil中需单独建一个项目
#include <reg51.h>
sbit P1_0=P1^0;
#define uchar unsigned char
uchar sc=0,a[16]; //数组a存放接收到的数据,sc为数组下标
char code TABLE[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,
0x80,0x90,0x88,0x83,0xc6,0xa1,0x86,0x8e}; //共阳数码管段码
void Delay(unsigned int x) //延时函数
{unsigned char i;
while(x--)
for(i=0;i<123;i++);
}
void SI_int(void) interrupt 4 //串行口中断号为4
{
if(RI) //接收到一帧数据
{
a[sc]=SBUF;
RI=0;
sc++;
}
}
void main()
{
uchar i=0;
TMOD=0x20; /*设置定时器T1为方式2*/
TH1=TL1=0xfd; /*波特率9600*/
SCON=0x50; /*串口方式1,允许接收*/
TR1=1; /*启动T1*/
ES=EA=1; /*允许串行口中断*/
P1_0=0; //数码管位选信号
while(1)
{if(sc>=16) //接收到16个数后,循环显示
{
for(i=0;i<16;i++) //循环16次,依次显示a[0]-a[15]
{
P0= TABLE[a[i]];
Delay(500);
}
}
}
}
//发生外部中断0(下降沿触发)时,单片机从串行口输出字符串"Hello";
//发生外部中断1(下降沿触发)时,单片机从串行口输出字符串"SCUT!"。
#include <reg51.h>
char sa[]="Hello",sb[]="SCUT!";
void INT0_srv(void) interrupt 0 //INT0中断号为0
{ char i;
for(i=0;i<5;i++) //循环5次,依次发送各字符
{
SBUF=sa[i]; /*数据送串行口发送缓冲器*/
while(TI==0); /*如果TI=0,未发送完,循环等待*/
TI=0; /*已发送完,再把TI清0*/
}
}
void INT1_srv(void) interrupt 2 //INT1中断号为2
{ char i;
for(i=0;i<5;i++) //循环5次,依次发送各字符
{
SBUF=sb[i]; /*数据送串行口发送缓冲器*/
while(TI==0); /*如果TI=0,未发送完,循环等待*/
TI=0; /*已发送完,再把TI清0*/
}
}
void main()
{
TMOD=0x20; /*设置定时器T1为方式2*/
TH1=TL1=0xfd; /*波特率9600*/
SCON=0x40; /*串口方式1只发送,不接收*/
TR1=1; /*启动T1*/
IT0=IT1=1; //INT0,INT1下降沿触发
EX0=EX1=EA=1; //允许INT0,INT1中断
while(1);
}
展开阅读全文