proteus工程文件及实验报告:XiaoBai1103/MCU-Experiment-Report: 单片机实验报告 (github.com)
实验1 单片机环境认识实验
编程实现在片内 50H~5FH 单元中建立 0~FH 字符串,将其移至片外数据区 8000H 开始处;然后将 8000H 开始处的各字节取反后送回片内 60H~6FH 单元。
#include"reg51.h"
#define uchar unsigned char
uchar data *dp1; //直接寻址片内RAM低128B
uchar xdata *dp2; //片外RAM,0x0000-0xffff
uchar data *dp3;
void main(void){
char i;
dp1=0x50;
dp2=0x8000;
dp3=0x60;
for(i=0;i<16;i++)
{
*(dp1+i)=i;
}
for(i=0;i<16;i++)
{
*(dp2+i)=*(dp1+i);
}
for(i=0;i<16;i++)
{
*(dp3+i)=~(*(dp2+i));
}
while(1);
}
编程将片内 50H 单元开始 10 字节的内容初始化为 0~9,然后移至 55H 开始的各单元中。
#include"reg51.h"
#define uchar unsigned char
uchar data *dp1;
uchar data *dp2;
void main(void){
char i;
dp1=0x50;
dp2=0x5e;//55+9=5e
for(i=0;i<10;i++)
{
*(dp1+i)=i;
}
for(i=0;i<10;i++)
{
*(dp2-i)=*(dp1-i+9);
}
while(1);
}
设 Number=0xABCD,将其转换为 BCD 码, 存入 Result 数组。Number 单元地址为片内 0x60。Result 单元地址为片内 0x70。
#include"reg51.h"
#include"intrins.h"
#define uchar unsigned char
#define uint unsigned int
data unsigned int num _at_ 0x60;
data unsigned char Result[5] _at_ 0x70;
void main(void){
num=0xABCD;
Result[0]=(num/10000)%10;
Result[1]=(num/1000)%10;
Result[2]=(num/100)%10;
Result[3]=(num/10)%10;
Result[4]=num%10;
while(1);
}
实验2 PROTUES 认识实验
1. 编程实现 LED 流水灯,从上往下流水再从下往上流水。
#include<reg51.h>
#include<intrins.h>
#define uchar unsigned char
#define uint unsigned int
void DelayMS(uint x) //延时函数
{
uchar i;
while(x--)
{
for(i=0;i<120;i++);
}
}
void main()
{
uchar i;
P0=0xFE; //点亮第一个灯
DelayMS(150);
while(1)
{
for(i=0;i<7;i++)
{
P0=_crol_(P0,1); //循环左移,使得灯向下移动
DelayMS(150);
}
for(i=0;i<7;i++)
{
P0=_cror_(P0,1); //循环右移,使得灯向上移动
DelayMS(150);
}
}
}
2. 编程实现堆叠流水灯效果:从上往下 1 盏灯亮、2 盏灯亮、3 盏灯亮….8 盏灯亮,再从下往上 1 盏灯灭、2 盏灯灭、3 盏灯灭….8 盏灯灭,周而复始。
#include<reg51.h>
#include<intrins.h>
#define uchar unsigned char
#define uint unsigned int
void DelayMS(uint x) //延时函数
{
uchar i;
while(x--)
{
for(i=0;i<120;i++);
}
}
void LED(uint x) //灯全部的状态
{
switch(x)
{
case 0:P0=0xFF;
break;
case 1:P0=0xFE; //1111 1110
break;
case 2:P0=0xFC; //1111 1100
break;
case 3:P0=0xF8; //1111 1000
break;
case 4:P0=0xF0; //1111 0000
break;
case 5:P0=0xE0; //1110 0000
break;
case 6:P0=0xC0; //1100 0000
break;
case 7:P0=0x80; //1000 0000
break;
case 8:P0=0x00; //1000 0000
break;
}
}
void main()
{
uchar i;
while(1)
{
for(i=0;i<=8;i++)
{
LED(i);
DelayMS(150);
}
for(i=8;i>0;i--)
{
LED(i);
DelayMS(150);
}
}
}
3. 编程实现, 上电时 LED 灯全亮。按下 K1 时, LED 上移一位;按下 K2, LED 下移一位。
#include<reg51.h>
#include<intrins.h>
#define uchar unsigned char
#define uint unsigned int
void DelayMS(uint x)
{
uchar i;
while(x--)
for(i=0;i<120;i++);
}
void Move_LED()
{
if ((P1&0x01)==0) P0=_cror_(P0,1); //K1
else if((P1&0x02)==0) P0=_crol_(P0,1); //K2
}
void main()
{
uchar Recent_Key; //最近按键
P0=0xfe;
P1=0xff;
Recent_Key=0xff;
while(1)
{
if(Recent_Key!=P1)
{
Recent_Key=P1; //保存最近按键
Move_LED();
DelayMS(10);
}
}
}
4. 更改电路:将图 1 中的 2 个按键开关改为单刀单掷开关(switch),实现:K2K1=10 时,
出现实验 2 的效果;K2K1=01 时,出现实验 3 的效果;K2K1=00 时,实现闪烁效果;
K2K1=11 时,灯全灭。
#include<reg51.h>
#include<intrins.h>
#define uchar unsigned char
#define uint unsigned int
void DelayMS(uint x)
{
uchar i;
while(x--)
for(i=0;i<120;i++);
}
void LED(uint x)
{
switch(x)
{
case 0:P0=0xFF;
break;
case 1:P0=0xFE; //1111 1110
break;
case 2:P0=0xFC; //1111 1100
break;
case 3:P0=0xF8; //1111 1000
break;
case 4:P0=0xF0; //1111 0000
break;
case 5:P0=0xE0; //1110 0000
break;
case 6:P0=0xC0; //1100 0000
break;
case 7:P0=0x80; //1000 0000
break;
case 8:P0=0x00; //1000 0000
break;
}
}
void Move_LED()
{
if ((P1&0x04)==0) P0=_cror_(P0,1); //K1
else if((P1&0x08)==0) P0=_crol_(P0,1); //K2
}
void main()
{
uchar a=0;
P0=0xfe;
P1=0xff;
while(1)
{
if(((P1&0x01)==0)&&((P1&0x02)==0))//00
{
P0=0xff;
DelayMS(150);
P0=0x00;
DelayMS(150);
a=0;
}
else if(((P1&0x01)==1)&&((P1&0x02)==2))//11
{
P0=0xff;
a=0;
}
else if(((P1&0x01)==1)&&((P1&0x02)==0))//10:实验 2
{uchar i;
a=0;
for(i=0;i<=8;i++)
{
LED(i);
DelayMS(150);
}
for(i=8;i>0;i--)
{
LED(i);
DelayMS(150);
}
}
else if(((P1&0x01)==0)&&((P1&0x02)==2))//01:实验 3
{
uchar Recent_Key; //最近按键
if(a==0)
{
P0=0xfe;
P1=0xff;
Recent_Key=0xff;
a=1;
}
if((Recent_Key!=P1)&&(a==1))
{
Recent_Key=P1; //保存最近按键
Move_LED();
DelayMS(10);
}
}
}
}
实验3 按键-LED数码管设计
1.LED循环显示字符0~7
#include <reg51.h>
#include <intrins.h>
#define uchar unsigned char
#define uint unsigned int
//段码表
uchar code dis_code[]={0x3f,0x06,0x5b,0x4f,//0 1 2 3
0x66,0x6d,0x7d,0x07,
0x7f,0x6f,0x77,0x7c,
0x39,0x5e,0x79,0x71,0x40};
//延时
void delay(unsigned int x)
{
unsigned char i;
while(x--)
{
for(i=0;i<120;i++);
}
}
//数码管显示
shownum(m)
{
unsigned char k;
for(k = 0;k < 8;k++) //循环8次
{
//P2 = 0x00; //每显示一位都要关闭位选端口一次
m=_crol_(m,1); //循环左移
P2=m; //每次选通一个位选端口
P0=dis_code[k]; //段码送P0口
delay(2);
}
}
//键盘扫描程序
scankey()//键盘扫描程序
{
uchar KeyNo=16,Tmp;
delay(20);
P3=0x0f; //高4位置零,低四位置1
Tmp=P3;
Tmp=Tmp&0x0f;//低4位数
switch(Tmp) //判断哪行被按下,并为按键赋行初始值
{
case (0x0e): KeyNo=0;break; //0000 1110
case (0x0d): KeyNo=4;break; //0000 1101
default:KeyNo=16; //无键按下
}
P3=0xf0; //高4位置1,低四位置0
Tmp=P3;
Tmp=Tmp&0xf0;//低4位数
switch(Tmp) //判断哪列被按下,并加上对行初始值的偏移量
{
case (0xe0): KeyNo+=0;break; //1110 0000
case (0xd0): KeyNo+=1;break; //1101 0000
case (0xb0): KeyNo+=2;break; //1011 0000
case (0x70): KeyNo+=3;break; //0111 0000
}
return KeyNo;
}
//主函数
void main()
{
uchar m=0x7f;
P0 = 0xff; //先关闭数码管
P2 = 0x00; //
while(1)
{
uchar key;
key=scankey();
if(key==0)
{
delay(200);
m=_crol_(m,1);
}
if(key==1)
{
delay(200);
m=_cror_(m,1);
}
if(key==2)
{
delay(200);
m=0x7f;
}
shownum(m);
}
}
2.LED按键数值显示
#include <reg51.h>
#include <intrins.h>
#define uchar unsigned char
#define uint unsigned int
//段码表
uchar code dis_code[]={0x3f,0x06,0x5b,0x4f,//0 1 2 3
0x66,0x6d,0x7d,0x07,
0x7f,0x6f,0x77,0x7c,
0x39,0x5e,0x79,0x71,0x40};
//延时
void delay(unsigned int x)
{
unsigned char i;
while(x--)
{
for(i=0;i<120;i++);
}
}
//数码管显示
shownum(k)
{
uchar m=0x7f;
P2=m; //每次选通一个位选端口
P0=dis_code[k]; //段码送P0口
delay(2);
}
//键盘扫描程序
scankey()//键盘扫描程序
{
uchar KeyNo=16,Tmp;
delay(20);
P3=0x0f; //高4位置零,低四位置1
Tmp=P3;
Tmp=Tmp&0x0f;//低4位数
switch(Tmp) //判断哪行被按下,并为按键赋行初始值
{
case (0x0e): KeyNo=0;break; //0000 1110
case (0x0d): KeyNo=4;break; //0000 1101
case (0x0b): KeyNo=8;break; //0000 1011
case (0x07): KeyNo=12;break; //0000 0111
default:KeyNo=16; //无键按下
}
P3=0xf0; //高4位置1,低四位置0
Tmp=P3;
Tmp=Tmp&0xf0;//低4位数
switch(Tmp) //判断哪列被按下,并加上对行初始值的偏移量
{
case (0xe0): KeyNo+=0;break; //1110 0000
case (0xd0): KeyNo+=1;break; //1101 0000
case (0xb0): KeyNo+=2;break; //1011 0000
case (0x70): KeyNo+=3;break; //0111 0000
}
return KeyNo;
}
//主函数
void main()
{
while(1)
{
uchar key;
key=scankey();
if(key!=16)//16为无按键返回标志
shownum(key);
}
}
3.LED数字右移
#include <reg51.h>
#include <intrins.h>
#define uchar unsigned char
#define uint unsigned int
//段码表
uchar code dis_code[]={0x3f,0x06,0x5b,0x4f,//0 1 2 3
0x66,0x6d,0x7d,0x07,
0x7f,0x6f,0x77,0x7c,
0x39,0x5e,0x79,0x71,0x40};
//延时
void delay(unsigned int x)
{
unsigned char i;
while(x--)
{
for(i=0;i<120;i++);
}
}
//数码管显示
shownum(uchar cache[8])
{
uchar m=0x7f;
uchar k;
for(k = 0;k < 8;k++) //循环8次
{
//P2 = 0x00; //每显示一位都要关闭位选端口一次
m=_crol_(m,1); //循环左移
P2=m; //每次选通一个位选端口
P0=dis_code[cache[k]]; //段码送P0口
delay(2);
}
}
//键盘扫描程序
scankey()//键盘扫描程序
{
uchar KeyNo=16,Tmp;
delay(20);
P3=0x0f; //高4位置零,低四位置1
Tmp=P3;
Tmp=Tmp&0x0f;//低4位数
switch(Tmp) //判断哪行被按下,并为按键赋行初始值
{
case (0x0e): KeyNo=0;break; //0000 1110
case (0x0d): KeyNo=4;break; //0000 1101
case (0x0b): KeyNo=8;break; //0000 1011
case (0x07): KeyNo=12;break; //0000 0111
default:KeyNo=16; //无键按下
}
P3=0xf0; //高4位置1,低四位置0
Tmp=P3;
Tmp=Tmp&0xf0;//低4位数
switch(Tmp) //判断哪列被按下,并加上对行初始值的偏移量
{
case (0xe0): KeyNo+=0;break; //1110 0000
case (0xd0): KeyNo+=1;break; //1101 0000
case (0xb0): KeyNo+=2;break; //1011 0000
case (0x70): KeyNo+=3;break; //0111 0000
}
return KeyNo;
}
//主函数
void main()
{
uchar cache[8]={0,1,2,3,4,5,6,7};
uchar cache1[8];
uchar i;
while(1)
{
uchar key;
key=scankey();
if(key!=16)//16为无按键返回标志
{
delay(200);
for(i=6;i>0;i--)
{
cache[i+1]=cache[i];
}
cache[1]=cache[0];
cache[0]=key;
}
shownum(cache);
}
}
参考资料
基于proteus的51单片机仿真实例六十、8位数码管显示实例:CSDN博主「老马识途单片机」链接:https://blog.csdn.net/tian_maer/article/details/71436045
实验4 定时计数器设计实验
实验1
用定时计数器编程实现:每隔1s点亮1只发光二极管。要求分别用查询方式和中断方式
//查询方法
#include<reg51.h>
#include<intrins.h>
#define uchar unsigned char
#define uint unsigned int
void LED(uchar x) //灯全部的状态
{
switch(x)
{
case 0:P0=0xFF;
break;
case 1:P0=0xFE; //1111 1110
break;
case 2:P0=0xFC; //1111 1100
break;
case 3:P0=0xF8; //1111 1000
break;
case 4:P0=0xF0; //1111 0000
break;
case 5:P0=0xE0; //1110 0000
break;
case 6:P0=0xC0; //1100 0000
break;
case 7:P0=0x80; //1000 0000
break;
case 8:P0=0x00; //1000 0000
break;
}
}
void Init_T0 (void) //定时器初始化
{
TMOD = 0x01;//T0工作方式1
TH0 = (65536-1000) /256;
TL0 = (65536-1000) %256;//12M机器周期是1us 定时1ms:65536-10^(-3)/10^(-6)
TR0=1;
}
void Main()
{
uint i=0;
uchar count=1;
P0=0xFF;//开始灯全灭
Init_T0 ();
while(1)
{
if(TF0) //查询中断标志
{
TH0 = (65536-1000) /256;
TL0 = (65536-1000) %256;
TF0=0;
i++;
if(i==1000)
{
i=0;
LED(count);
count++;
if(count==9)
{
count=0;
}
}
}
}
}
//中断方法
#include<reg51.h>
#include<intrins.h>
#define uchar unsigned char
#define uint unsigned int
bit flag=0;
void LED(uchar x) //灯全部的状态
{
switch(x)
{
case 0:P0=0xFF;
break;
case 1:P0=0xFE; //1111 1110
break;
case 2:P0=0xFC; //1111 1100
break;
case 3:P0=0xF8; //1111 1000
break;
case 4:P0=0xF0; //1111 0000
break;
case 5:P0=0xE0; //1110 0000
break;
case 6:P0=0xC0; //1100 0000
break;
case 7:P0=0x80; //1000 0000
break;
case 8:P0=0x00; //1000 0000
break;
}
}
void Init_T0 (void) //定时器初始化
{
TMOD = 0x01;//T0工作方式1
TH0 = (65536-1000) /256;
TL0 = (65536-1000) %256;//12M机器周期是1us 定时1ms:65536-10^(-3)/10^(-6)
TR0=1;
}
void Time0_Int() interrupt 1 //中断处理函数
{
flag=1;
}
void Main()
{
uint i=0;
uchar count=1;
EA=1;//中断允许
ET0=1;//定时器0中断允许
P0=0xFF;//开始灯全灭
Init_T0 ();
while(1)
{
if(flag) //中断被触发
{
TH0 = (65536-1000) /256;
TL0 = (65536-1000) %256;
i++;
flag=0;
if(i==1000)
{
i=0;
LED(count);
count++;
if(count==9)
{
count=0;
}
}
}
}
}
实验2
定时器T0每接收3个脉冲,流水灯下移一位。
#include<reg51.h>
#include<intrins.h>
#define uchar unsigned char
#define uint unsigned int
void Init_T0 (void) //定时器初始化
{
TMOD=0x06; /工作方式2
TH0 =0;
TL0 =0;
TR0=1;
}
void Main()
{
P0=0xFE;
Init_T0 ();
while(1)
{
if(TL0==0x03) //计到3,初值重新置0
{
P0=_crol_(P0,1);
TL0=0;
}
}
}
实验3
设计电路并编程实现电子钟:24小时制,显示格式XX-XX-XX,由左到右分别为时分秒。初值为23-59-59.
#include<reg51.h>
#include<intrins.h>
#define uchar unsigned char
#define uint unsigned int
//断码表
uchar code dis_code[]={
0x3f,0x06,0x5b,0x4f,
0x66,0x6d,0x7d,0x07,
0x7f,0x6f,0x77,0x7c,
0x39,0x5e,0x79,0x71,0x40};
uint ms = 0,s = 59,min = 59,h = 23;//ms,s,min,h分别是毫秒,秒,分,时。
uchar num[8]; //数码管时钟显示内容
//定时器初始化
void Init_T0 (void)
{
TMOD=0x01;//定时器方式1
TH0 = (65536-1000) /256;
TL0 = (65536-1000) %256;
TR0=1;
ET0=1;
EA=1;
}
void delay(unsigned int x)
{
uchar i;
while(x--)
{
for(i=0;i<120;i++);
}
}
//数码管显示
shownum()
{
uchar m=0x7f;
uchar k;
for(k = 0;k < 8;k++) //循环8次
{
m=_crol_(m,1); //循环左移
P2=m; //每次选通一个位选端口
P0=dis_code[num[k]]; //段码送P0口
delay(2);
}
}
void main(){
Init_T0 () ;
while(1){
shownum();
}
}
void TimeInt0() interrupt 1{ //1ms触发中断
TH0 = 0xfc;
TL0 = 0x18;
ms++;
if(ms == 1000) // 中断1000次,即1s
{
ms = 0;
s++;
if(s == 60)//60s归零
{
s = 0;
min++;
}
}
if(min == 60)//60min归零
{
min = 0;
h++;
if(h == 24)//24h归零)
h = 0;
}
num[7] = s % 10;
num[6] = s / 10;
num[5]=16;
num[4] = min % 10;
num[3] = min / 10;
num[2]=16;
num[1] = h % 10;
num[0] = h / 10;
}
实验5 中断定时计数器综合
1&2
#include<reg51.h>
#define uchar unsigned char
#define uint unsigned int
#define ulong unsigned long
uchar code DIS_CODE[12] = {0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90,0xFF,0x0C};
ulong num; //计数值
void delay(unsigned int x)
{
uchar i;
while(x--)
{
for(i=0;i<120;i++);
}
}
void shounum(ulong num)
{
uchar num_1; //个位
uchar num_2; //十位
uchar num_3; //百位
uchar num_4; //千位
num_1 = num%10;
num_2 = num%100/10;
num_3 = num%1000/100;
num_4 = num%10000/1000;
P2 = 0x01;
P0 = DIS_CODE[num_4];
delay(5);
P2 = 0x02;
P0 = DIS_CODE[num_3];
delay(5);
P2 = 0x04;
P0 = DIS_CODE[num_2];
delay(5);
P2 = 0x08;
P0 = DIS_CODE[num_1];
}
void int0() interrupt 0//外中断0
{
num++;
}
void main (void)
{
num = 0; //要显示的变量初始化
P0 = 0xFF;
P2 = 0xFF;
P3 = 0xFF;
IT0 = 1; //下降沿触发
EX0 = 1; //允许Int0中断
EA = 1; //允许中断
while(1)
{
if(num<=9999)
{
P1=~(num%256);//实验内容2部分
shounum(num);
}
else
num=0;
}
}
3
#include<reg51.h>
#include<intrins.h>
#define uchar unsigned char
#define uint unsigned int
#define ulong unsigned long
uchar code dis_code[]={
0x3f,0x06,0x5b,0x4f,
0x66,0x6d,0x7d,0x07,
0x7f,0x6f,0x77,0x7c,
0x39,0x5e,0x79,0x71,0x40};
uint num;//计数值
uchar num_LED[8]; //数码管显示内容
void delay(unsigned int x)
{
unsigned char i;
while(x--)
{
for(i=0;i<120;i++);
}
}
shownum()
{
uchar m=0x7f;
uchar k;
for(k = 0;k < 8;k++)
{
m=_crol_(m,1); //循环左移
P2=m; //每次选通一个位选端口
P0=dis_code[num_LED[k]]; //段码送P0口
delay(2);
}
}
void Init_T0 (void) //定时器初始化
{
TMOD=0x05; //工作方式1(16位)
TH0 =0;
TL0 =0;
TR0=1;
}
void main (void)
{
uchar i;
num = 0;
Init_T0 ();
for(i=0;i<8;i++)
{
num_LED[i]=0;
}
while(1)
{
num=TL0+TH0*256;
num_LED[7]=num%10;
num_LED[6]=num%100/10;
num_LED[5]=num%1000/100;
num_LED[4]=num%10000/1000;
num_LED[3]=num%100000/10000;
num_LED[2]=0; //计数器最大值65535,因此最多用到5位数码管
num_LED[1]=0;
num_LED[0]=0;
P1=~(num%256);
shownum();
}
}
实验6 串口通信实验
1.甲、乙双机串行通信,甲机 P1 口接 8 个开关,乙机 P1 口接8 个发光二极管,要求读入甲机的 8 个开关状态后,通过串行口发送到乙机,乙机将接收到的数据送发光二极管的显示。双方晶振均采用11.0592MHz,波特率9600,串口工作方式采用方式 1。参考电路见图 1,补齐晶振电路。
/*甲机串行发送*/
#include <reg51.h>
#define uchar unsigned char
#define uint unsigned int
void main()
{
uchar temp=0;
TMOD=0x20;
TR1=1;
TH1=0xfd;/*波特率9600*/
TL1=0xfd;
SCON=0x40; /*方式1*/
PCON=0x00;
TR1=1;
P1=0xff;
ES = 1;
EA = 1;
while(1)
{
temp=P1;
SBUF=temp;
while(TI==0);
TI=0;
}
}
/*乙机串行接收*/
#include <reg51.h>
#define uchar unsigned char
#define uint unsigned int
void main( )
{
uchar temp=0;
TMOD=0x20; /*定时器T1为方式2*/
TR1=1;
TH1=0xfd; /*波特率9600*/
TL1=0xfd;
SCON = 0x50; /*方式1接收,REN=1*/
PCON = 0x00;
RI=1;
ES = 1;
EA = 1;
while(1)
{
while(RI==0);
RI=0;
temp=SBUF;
P1=temp;
}
}
2.甲、乙双机串行通信,乙机 P1 口接 8 个发光二极管,甲机通过串口发送数据给乙机,点亮 8 个发光二极管,晶振均采用 11.0592MHz,波特率 9600,串口工作方式采用方式 3。参考电路见图 2,补齐晶振和复位电路。
/*甲机串行发送*/
#include <reg51.h>
#define uchar unsigned char
#define uint unsigned int
sbit p=PSW^0; /* p位定义为PSW 寄存器的第0位,即奇偶校验位*/
void Send(unsigned char dat )
{ ACC=dat;
TB8=p;
SBUF=dat;
while(TI==0);
TI=0;
}
void Delay(unsigned int x)
{
uchar i;
while(x--)
{
for(i=0;i<250;i++);
}
}
void main(void)
{
unsigned char i;
TMOD=0x20;
TR1=1;
TH1=0xfd; /*波特率设置为9600*/
TL1=0xfd;
SCON=0xc0; /*串口方式3*/
PCON=0x00;
TR1=1;
RI=1;
ES = 1;
EA = 1;
while(1)
{
Send(0x00);
Delay(100);
Send(0xff);
Delay(100);
}
}
/*乙机串行接收*/
#include <reg51.h>
#define uchar unsigned char
#define uint unsigned int
unsigned char Receive(void) /*接收一个字节数据的函数*/
{
unsigned char dat;
while(RI==0);
RI=0;
ACC=SBUF;
if(RB8==P)
{
dat=ACC;
return dat;
}
}
void main(void)
{
TMOD=0x20; /*T1为方式2*/
TR1=1;
TH1=0xfd; /*波特率9600*/
TL1=0xfd;
SCON=0xd0; /*串口方式3*/
PCON=0x00;
TR1=1;
RI=1;
ES = 1;
EA = 1;
while(1)
P1= Receive( );
}
3.在实验 2 的基础上,每隔 1s 甲机发送 1 次数据给乙机,即乙机的流水灯是每隔 1s 流水 1 次。
/*甲机串行发送*/
#include <reg51.h>
#define uchar unsigned char
#define uint unsigned int
sbit p=PSW^0; /* p位定义为PSW 寄存器的第0位,即奇偶校验位*/
unsigned char code Tab[]= {0xfe , 0xfd , 0xfb , 0xf7 , 0xef , 0xdf , 0xbf , 0x7f};
/*控制流水灯显示数据,数组被定义为全局变量*/
void Send(unsigned char dat ) /* 发送一个字节数据的函数*/
{ ACC=dat;
TB8=p; /* 将奇偶校验位写入TB8*/
SBUF=dat; /* 将待发送的数据写入发送缓冲器*/
while(TI==0); /* 检测发送标志位TI, TI=0,未发送完*/
TI=0; /* 一个字节发送完,TI清0*/
}
void main(void)
{
unsigned char i=0;
uchar count=0;
TMOD=0x21; //设置定时器T1为方式2 T0工作方式1
TH1=0xfd; /*波特率设置为9600*/
TL1=0xfd;
TH0= (19456)/256;
TL0= (19456)%256;
TR1=1;//打开定时器1
TR0=1;//打开定时器1
SCON=0xc0; /*设置串口为方式3*/
PCON=0x00; /*SMOD=0*/
//RI=1;//启动T1*/ RI=1表示收到数据
/*中断*/
ES = 1; //允许串行中断
EA = 1; //允许中断
while(1)
{
if(TF0) //查询中断标志
{
TH0 = (19456) /256;
TL0 = (19456) %256;
TF0=0;
count++;
if(count==20)
{
count=0;
if(i<8)
{
Send(Tab[i]);
i++;
}
else
{
i=0;
}
}
}
}
}
实验7 键盘-串口通信综合实验
1.甲、乙双机串行通信,甲机 P1 口接 8 个按键开关,乙机 P1口接 1 个 LED 数码管,要求读入甲机的开关状态,通过串行口发送到乙机,乙机在 LED 数码管上显示 0~F。双方晶振均采用 11.0592MHz,波特率 2400,采用串口工作方式 1。
/*甲机串行发送*/
#include <reg51.h>
#define uchar unsigned char
#define uint unsigned int
void main()
{
uchar temp=0;
/*定时器1初始化*/
TMOD=0x20; //设置定时器T1为方式2
TR1=1;//打开定时器
TH1=0xf4;//波特率2400
TL1=0xf4;
/*串口初始化*/
SCON=0x40; //方式1只发送,不接收
PCON=0x00;
P1=0xff; //P1口为输入
/*中断*/
ES = 1; //允许串口中断
EA = 1; //允许中断
while(1)
{
temp=P1; //读入P1口开关的状态数据
SBUF=temp; //数据送串行口发送
while(TI==0); //如果TI=0,未发送完,循环等待
TI=0; //已发送完,再把TI清0
}
}
/*乙机串行接收*/
#include <reg51.h>
#define uchar unsigned char
#define uint unsigned int
uchar code seg[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0x88,0x83,0xc6,0xa1,0x86,0x8e};
void main( )
{
uchar temp=0;
/*定时器1初始化*/
TMOD=0x20; //设置定时器T1为方式2
TR1=1;//打开定时器
TH1=0xf4; //波特率2400
TL1=0xf4;
/*串口初始化*/
SCON = 0x50; //串行口控制寄存器设置串口为方式1接收,REN=1
PCON = 0x00; //串行口控制寄存器 SMOD=0
RI=1;//启动T1
/*中断*/
ES = 1; //允许Int0中断
EA = 1; //允许中断
while(1)
{
while(RI==0);//若RI为0,未接收到数据
RI=0;//接收到数据,则把RI清0
temp=SBUF; //读取数据存入temp中
temp=temp&0x0f;
P1=seg[temp];
//temp; //接收数据送P1口控制8个LED的亮与灭
}
}
甲、乙双机串行通信。甲机接键盘和 LED 数码管,按键显示1~9,甲机外中断 0 接键盘扫描,每当有键按下,触发 1 次中断,外中断 1 接按键开关,开关触发 1 次,甲机的数据传给乙机显示。双方晶振均采用 11.0592MHz,波特率 2400,采用串口工作方式 1。
/*甲机串行发送*/
#include <reg51.h>
#define uchar unsigned char
#define uint unsigned int
uchar code seg[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0xbf,0xc0,0x8c};
uchar key,num;
void delayms(uint x)
{
uchar i;
while(x--)
{
for(i=0;i<250;i++);
}
}
uchar scan(void)
{
uchar k=13,m,n,in;//k=13无按键按下标志
delayms(10);
P1=0x07;
if((P1&0x07)!=0x07)//有按键被按下
{
for(m=0;m<4;m++)//行扫描
{
P1=~(0x01<<(m+3));//行扫描
for(n=0;n<3;n++)
{
in=P1;
in=in>>n;//in右移n位 非循环移位
if((in&0x01)==0)//列判断
{
if((in&0x01)==0)
{
k=n+m*3+1;//行数+列数
break;
}
}
}
if(k!=13)
break;
}
}
return(k);
}
void ext0()interrupt 0//外中断0 用于扫描键盘
{
EX0=0;//外中断0禁止
key=scan();
if(key!=13)
num=key;
EX0=1;//外中断0允许
}
void ext1()interrupt 2//外中断2 发送按钮
{
SBUF=num;
while(TI==0); //如果TI=0,未发送完,循环等待
TI=0;
}
void main(void)
{
TMOD=0X20; //设置定时器1工作在方式2
TH1=0xf4;//波特率2400
TL1=0xf4;
TR1=1;
SCON=0X40; //串口工作在方式1
PCON=0X00;
EA=1;
ES=1;
EX1=1;
EX0=1;
while(1)
{
P1=0x07;
P2=seg[num];
}
}
/*乙机串行接收*/
#include <reg51.h>
#define uchar unsigned char
#define uint unsigned int
uchar code seg[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0xbf,0xc0,0x8c};
void main( )
{
uchar temp;
/*定时器1初始化*/
TMOD=0x20; //设置定时器T1为方式2
TR1=1;//打开定时器
TH1=0xf4; //波特率9600
TL1=0xf4;
/*串口初始化*/
SCON = 0x50; //串行口控制寄存器设置串口为方式1接收,REN=1
PCON = 0x00; //串行口控制寄存器 SMOD=0
RI=1;//启动T1
/*中断*/
ES = 1; //允许Int0中断
EA = 1; //允许中断
while(1)
{
while(RI==0);//若RI为0,未接收到数据
RI=0;//接收到数据,则把RI清0
temp=SBUF; //读取数据存入temp中
P1=seg[temp];
}
}
实验 8 单片机系统扩展实验
1.实验内容 1:扩展一片 RAM6264,实现:(1)片外 00 地址开始 16 个单元赋初值,0~F;(2)片外 00 地址开始 16 个单元取反后送 80H~8FH;(3)片外 80H~8FH 的值点亮 P1 口灯。
#include "reg52.h"
#include "absacc.h"
#define uchar unsigned char
#define uint unsigned int
uchar code data_write []={0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f};
sbit LED=P2^7;
void delayms(uint j)
{
uchar i;
for(;j>0;j--)
{i=250;
while(--i);
i=249;
while(--i);
}
}
void main(void)
{
uchar i,j;
LED=1;
for(i=0;i<16;i++)
{
XBYTE[i]= data_write [i];
delayms(50);
}
for(i=0;i<=16;i++)
{
j=i+128;//80H-8FH 128~143
XBYTE[j]=~XBYTE[i];
delayms(50);
}
LED=0;//写入完毕,LED灯亮起
while(1){
for(i=128;i<=143;i++)
{
P1=XBYTE[i];
delayms(300);
}
}
}
- 实验内容 2:用 8255A 扩展 51 单片机并口,如图 2 所示,要求读入开关状态,送灯显示。
#include "reg51.h"
#include "absacc.h"
#define uchar unsigned char
#define uint unsigned int
#define con_8255 XBYTE[0x7f03] //控制口地址
#define pb_8255 XBYTE[0x7f01] //PB口地址
#define pa_8255 XBYTE[0x7f00] //PA口地址
sbit rst_8255=P3^5;
void delayms(uint j)
{
uchar i;
for(;j>0;j--)
{i=250;
while(--i);
i=249;
while(--i);
}
}
void main(void)
{
uchar temp;
rst_8255=1;
delayms(1);
rst_8255=0;
con_8255=0x82;//PB口输入,PA口输出
while(1)
{
temp=pb_8255; //读PB口值
pa_8255=temp; //写PA口
}
}
- 使用定时器 T0,在 P1.7 输出频率为 100Hz,占空比为 70%的矩形波。要求 P1.7 引脚接虚拟示波器,观察波形,如图 3 所示。假设 fosc=6MHz。
#include<reg51.h>
#include<intrins.h>
#define uchar unsigned char
#define uint unsigned int
sbit output=P1^7;//示波器接口
void Init_T0 (void) //定时器初始化
{
TMOD = 0x01;//T0工作方式1
TH0 = (65536-500) /256;
TL0 = (65536-500) %256;
TR0=1;
}
void Main()
{
uint i=0;
uchar count=1;
output=1;
Init_T0 ();
while(1)
{
if(TF0)
{
TH0 = (65536-500) /256;
TL0 = (65536-500) %256;
TF0=0;
i++;
if(i==3)
output=1;
if(i==10)
{
output=0;
i=0;
}
}
}
}
实验 9 DA接口设计实验
1.设计 51 单片机与 DAC0832 的接口电路,DAC0832 的地址 为 8000H,参考电压为 5V。编程实现矩形波,要求:波形占空比为 20%,高电 平时电压为 2.5V,低电平时电压为 1.25V。
#include<absacc.h>
#include<reg51.h>
#define DAC0832 XBYTE[0x8000]
#define uchar unsigned char
#define uint unsigned int
void delay(uint x)
{
uchar i;
while(x--)
{
for(i=0;i<50;i++);
}
}
void main()
{
uchar i=0;
while(1) {
if(i<2)
{
DAC0832=0x80;//高电平 2.5V 2.5*256=D*5 D=128=80h
delay(1);
i++;
}
else
{
DAC0832=0x40;//低电平 1.25V 1.25*256=D*5 D=64=40h
delay(1);
i++;
if(i==10)
i=0;
}
}
}
2. 实验内容 2:DAC0832 用作波形发生器,分别产生锯齿波、三角波、正弦 波和矩形波,能够用按键选择波形。芯片地址 7FFFH。实验参考图如图 1 所示。
#include<reg51.h>
#include<absacc.h>
sbit CS=P2^7;
sbit WR12=P3^6;
sbit sin=P1^0;
sbit square=P1^1;
sbit triangle=P1^2;
sbit sawtooth=P1^3;
#define DAC0832 XBYTE[0x7FFF]
#define uchar unsigned char
#define uint unsigned int
unsigned char const code sin_code[256]={0x80,0x83,0x86,0x89,0x8d,0x90,0x93,0x96,0x99,0x9c,0x9f,
0xa2,0xa5,0xa8,0xab,0xae,0xb1,0xb4,0xb7,0xba,0xbc,0xbf,0xc2,0xc5 ,
0xc7,0xca,0xcc,0xcf,0xd1,0xd4,0xd6,0xd8,0xda,0xdd,0xdf,0xe1,0xe3,
0xe5,0xe7,0xe9,0xea,0xec,0xee,0xef,0xf1,0xf2,0xf4,0xf5 ,0xf6,0xf7,
0xf8,0xf9,0xfa,0xfb,0xfc,0xfd,0xfd,0xfe,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xfd ,0xfd,0xfc,0xfb,0xfa,
0xf9,0xf8,0xf7,0xf6,0xf5,0xf4,0xf2,0xf1,0xef,0xee,0xec,0xea,0xe9,
0xe7,0xe5,0xe3,0xe1,0xde,0xdd,0xda ,0xd8,0xd6,0xd4,0xd1,0xcf,0xcc,
0xca,0xc7,0xc5,0xc2,0xbf,0xbc,0xba,0xb7,0xb4,0xb1,0xae,0xab,0xa8,
0xa5,0xa2,0x9f,0x9c,0x99 ,0x96,0x93,0x90,0x8d,0x89,0x86,0x83,0x80,
0x80,0x7c,0x79,0x76,0x72,0x6f,0x6c,0x69,0x66,0x63,0x60,0x5d,0x5a,
0x57,0x55,0x51 ,0x4e,0x4c,0x48,0x45,0x43,0x40,0x3d,0x3a,0x38,0x35,
0x33,0x30,0x2e,0x2b,0x29,0x27,0x25,0x22,0x20,0x1e,0x1c,0x1a,0x18,
0x16 ,0x15,0x13,0x11,0x10,0x0e,0x0d,0x0b,0x0a,0x09,0x08,0x07,0x06,
0x05,0x04,0x03,0x02,0x02,0x01,0x00,0x00,0x00,0x00,0x00,0x00 ,0x00,
0x00,0x00,0x00,0x00,0x00,0x01,0x02 ,0x02,0x03,0x04,0x05,0x06,0x07,
0x08,0x09,0x0a,0x0b,0x0d,0x0e,0x10,0x11,0x13,0x15 ,0x16,0x18,0x1a,
0x1c,0x1e,0x20,0x22,0x25,0x27,0x29,0x2b,0x2e,0x30,0x33,0x35,0x38,
0x3a,0x3d,0x40,0x43,0x45,0x48,0x4c,0x4e ,0x51,0x55,0x57,0x5a,0x5d,
0x60,0x63,0x66 ,0x69,0x6c,0x6f,0x72,0x76,0x79,0x7c,0x80 };
void delay(uint x)
{
uchar i;
while(x--)
{
for(i=0;i<50;i++);
}
}
void main(void)
{
uint i,j;
CS=0;
WR12=0;
P1=0xff;
while(1)
{
if(sin==0) //正弦波
{
while(!sin)
{
for(i=0;i<255;i++)
DAC0832=sin_code[i];
}
}
if(square==0) //方波
{
DAC0832=0xff;
delay(1);
DAC0832=0x00;
delay(1);
}
if(triangle==0)//三角波
{
for(i=0;i<0xff;i++)
{
DAC0832=i;
delay(1);
}
for(i=0xff;i>0;i--)
{
DAC0832=i;
delay(1);
}
}
if(sawtooth==0) //锯齿波
{
for(i=0;i<=0xff;i++)
DAC0832=i;
delay(1);
}
}
3.查阅资料,了解呼吸灯的概念,设计呼吸灯实验
#include<absacc.h>
#include<reg51.h>
#define DAC0832 XBYTE[0x8000]
#define uchar unsigned char
#define uint unsigned int
void delay(uint x)
{
uchar i;
while(x--)
{
for(i=0;i<50;i++);
}
}
void main()
{
uchar i=0,j=1;
while(1) {
for(j=1;j<255;j++)
{
if(i<j)
{
DAC0832=0xff;
i++;
}
else
{
DAC0832=0x00;
i++;
if(i==255)
i=0;
}
}
}
}
实验 10 AD 接口设计实验
1. 单片机控制 ADC0809 进行 A/D 转换的接口与程序设计。参考图 1,采用查询方式控制 ADC0809 进行 A/D 转换,电位器 RV1 调节输入给ADC0809 的模拟电压,ADC0809 转换结果由 P1 口输出,通过控制发光二极管的亮与灭,来显示转换结果的二进制数字量。
#include "reg51.h"
#define uchar unsigned char
#define uint unsigned int
#define led P0
#define out P1
sbit start=P2^1;
sbit oe=P2^7;
sbit eoc=P2^3;
sbit clock=P2^0;
sbit add_a=P2^4;
sbit add_b=P2^5;
sbit add_c=P2^6;
void main(void)
{
uchar temp;
add_a=0;add_b=0;add_c=0; //选择ADC0808的通道0
while(1)
{
start=0;
start=1;
start=0; //启动转换
while(1){clock=!clock;if(eoc==1)break;}//等待转换结束
oe=1; //允许输出
temp=out; //暂存转换结果
oe=0; //关闭输出
led=temp; //采样结果输出到LED
}
}
2. 利用单片机 AT89S51 与 ADC0809 设计一个数字电压表,能够测量 0-5V 之间的直流电压值,四位数码显示。
#include <reg51.H>
#define uchar unsigned char
#define uint unsigned int
uchar code dispcode[4]={0x08,0x04,0x02,0x00};//LED显示的控制代码
uchar code codevalue[10]={0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90}; //0~9共阳极字段码
uint temp; //存储ADC0808转换后处理过程中的临时数值
uchar temp_int;
uchar dispbuf[4]; //存储十进制值
sbit ST=P3^0;
sbit OE=P3^1;
sbit EOC=P3^2;
sbit CLK=P3^7;
uchar count; //LED显示位控制
uchar getdata; //ADC0808转换后的数值
void delay(uchar m) //延时
{ while(m--)
{}
}
void main(void)
{
ET0=1;
ET1=1;
EA=1;
TMOD=0x12; //0工作在模式2,T1工作在模式1
TH0=246;
TL0=246;
TH1=(65536-10000)/256;
TL1=(65536-10000)%256;
TR1=1;
TR0=1;
while(1)
{
ST=0;
ST=1; //产生启动转换的正脉冲信号
ST=0;
while(EOC==0) {;} //等待转换结束
OE=1;
getdata=P0;
OE=0;
temp=getdata*19.5; //转换为电压 量程为5V 分辩率为8位 5/256=19.5mV,即1代表19.5mV
dispbuf[2]=temp/1000;//1V
dispbuf[1]=temp/100%10;//0.1V
dispbuf[0]=temp/10%10;//0.01V
}
}
void T0X(void)interrupt 1 using 0 //定时/计数器0中断,产生转换时钟 50KHz
{
CLK=~CLK;
}
void T1X(void) interrupt 3 using 0 //定时/计数器1中断,数码管显示
{
TH0=(65536-10000)/256;
TL0=(65536-10000)%256;
for(count=0;count<3;count++)
{
if(count==2)
{
P2=dispcode[count];//LED显示的控制代码
P1=(codevalue[dispbuf[count]])&(0x7f); //加小数点
}
else
{
P2=dispcode[count];
P1=codevalue[dispbuf[count]]; //输出字段码
}
delay(255);
}
}
3. 将实验 1 改为中断方式
#include "reg51.h"
#define uchar unsigned char
#define uint unsigned int
#define led P0
#define out P1
sbit start=P2^1;
sbit oe=P2^7;
sbit clock=P2^0;
sbit add_a=P2^4;
sbit add_b=P2^5;
sbit add_c=P2^6;
uchar temp;
void main(void)
{
add_a=0;add_b=0;add_c=0; //选择ADC0808的通道0
EA=1;
EX0=1;
start=0;
start=1;
start=0; //启动转换
while(1){
clock=!clock;
}
}
void output(void) interrupt 0
{
oe=1; //允许输出
temp=out; //暂存转换结果
oe=0; //关闭输出
led=temp; //采样结果输出到LED
start=0;
start=1;
start=0; //启动转换
}
Comments | NOTHING