一、 单片机IO实验
自律 学习 坚强 ,拒绝迷茫。
作者:行走的皮卡丘
时间:2021/03/23
喜欢就去追,这个红灯等不到,说不定下一个红灯等到了,嘻嘻!!!!!!!
文章目录
一、实验目的
-
1、掌握AT89C51 单片机IO 口的输入输出。
-
2、掌握用查表方式实现AT89C51 单片机IO 口的控制。
-
3、练习单片机简单延时子程序的编写。
-
4、熟练运用Proteus 设计、仿真AT89C51 系统。
-
5、使用单片机开发试验仪来验证实验结果。
二、实验原理
1、 单片机最小系统由单片机芯片、时钟电路以及复位电路构成。
2、I/O 口
P0 口:8 位双向I/O 口。在访问外部存储器时,P0 口可用于分时传送低8 位地址总线和8 位数据总线。能驱动8 个LSTTL 门。
P1 口:8 位准双向I/O 口(“准双向”是指该口内部有固定的上拉电阻)。能驱动4 个LSTTL门。
P2 口:8 位准双向I/O 口。在访问外部存储器时,P2 口可用于高8 位地址总线。能驱动4 个LSTTL 门。
P3 口:8 位准双向I/O 口。能驱动4 个LSTTL 门。P3 口还有第二功能。
P1 口作为输出口时与一般的双向口使用方法相同。当P1口用为输入口时,必须先对它置1。若不先对它置1,读入的数据可能是不正确的。
三、设计步骤:
【PROTEUS电路设计】
在ISIS 中进行电路图设计,发光二极管流水灯实验装置电路原理图如下图所示。
图一
- 1、按照元件清单从PROTEUS 库中选取元器件,进行第2、3、4、5、6 步,完成原理图。
元件名称 | 所属类 | 所属子类 |
---|---|---|
AT89C51(单片机) | Microprocessor ICs | 8051 Family |
RES(电阻) | Resistors | Generic |
LED-YELLOW(黄色发光二极管) | Optoelectronics | LEDs |
CAP(电容) | Capacitors | Generic |
CAP-ELEC(电解电容) | Capacitors | Generic |
CRYSTAL(晶振) | Miscellaneous | – |
SWITCH(按键) | Switich&relays | Switchs |
-
2、放置元器件;
-
3、放置电源和地;
-
4、连线;
-
5、参照原理图进行元件属性设置;
-
6、电气检查。
【实验程序设计】
-
1、流程图:
-
2、在KeilC 中进行源程序设计:
-
3、编译、生成目标代码
【PROTUES 仿真】
-
1、在AT89C51 属性页中加载KeilC 中生成的目标代码;
-
2、仿真、调试代码
-
3、注意使用观察窗口
四、实验内容
1、见图一。通过AT89C51 单片机控制8 个发光二极管发光,实现亮点以由上到下循环移动,间隔时间为0.1S。
电路连接图:
代码:
#include "reg52.h"
#include "intrins.h"
#define uint unsigned int //无符号整型
#define uchar unsigned char //无符号字符型
#define led P1 //对整个P2端口进行操作
uchar temp;
//ms
void delay(uint z)
{
int x,y;
for(x = 0; x < z; x++)
for(y=0;y<110;y++);
}
void Led_Pipeline_1() //先左再右逐个亮起,不熄灭;再从右到左逐个熄灭;
{
//方法五:
led = 0XFF;
delay(1);
led = 0XFE; //1
delay(1);
led = 0XFD; //2
delay(1);
led = 0XFB; //3
delay(1);
led = 0XF7; //4
delay(1);
led = 0XEF; //5
delay(1);
led = 0XDF; //6
delay(1);
led = 0XBF; //7
delay(1);
led = 0X7F; //8
delay(1);
led = 0XFF;
delay(1);
}
void Led_Pipeline_2() //先左再右逐个亮起,不熄灭;再从右到左逐个熄灭;
{
// 方法六:
P1 = temp;
delay(1);
temp = _crol_(temp,1);
}
void main()
{
temp = 0xfe;
while(1)
{
Led_Pipeline_1();
Led_Pipeline_2();
}
}
实验效果图:
2、见图一。通过AT89C51 单片机控制8 个发光二极管发光,循环实现亮点由上到下移动1 次(间隔时间为0.2S),由下到上移动1 次(间隔时间为0.2S),闪烁1 次(即先全亮0.1S,再全灭0.1S)。
电路连接图:
代码:
#include "reg52.h"
#include "intrins.h"
#define uint unsigned int //无符号整型
#define uchar unsigned char //无符号字符型
#define led P1 //对整个P2端口进行操作
uchar temp;
//ms
void delay(uint z)
{
int x,y;
for(x = 0; x < z; x++)
for(y=0;y<110;y++);
}
void Led_Pipeline_1() //先左再右逐个亮起,不熄灭;再从右到左逐个熄灭;
{
// 方法六:
int i;
for(i=0;i<7;i++)
{
P1 = temp;
delay(100);
temp = _crol_(temp,1);
}
for(i=0;i<7;i++)
{
P1 = temp;
delay(100);
temp = _cror_(temp,1);
}
}
void main()
{
temp = 0xfe;
while(1)
{
Led_Pipeline_1();
}
}
实验效果图:
3、用蜂鸣器发出固定电话回音声音。见图三。
固定电话回音声音:450Hz,通1秒断4秒。(1秒时间内,输出频率450Hz信号;另外四秒无声音)
电路连接图:
流程图:
代码:
#include "reg52.h"
#define uchar unsigned char
#define uint unsigned int
sbit BUZZ = P1^5;
void OpenBuzz(uint freq);
void StopBuzz();
void delay_ms(uint xms);
uint reload; //计算所需定时器重载值
void main()
{
TMOD|=0x01;
EA=1;
while(1)
{
OpenBuzz(450); //以4KHZ频率启动蜂鸣器
delay_ms(1000);
StopBuzz(); //停止蜂鸣器
delay_ms(4000);
}
}
void OpenBuzz(uint freq)
{
reload = 65536 - (11059200/12)/(freq*2);
TH0 = reload/256;
TL0 = reload%256;
ET0 = 1;
TR0 = 1;
}
void StopBuzz()
{
ET0 = 0;
TR0 = 0;
}
void Timer0() interrupt 1
{
TH0 = reload/256;
TL0 = reload%256;
BUZZ = ~BUZZ;
}
void delay_ms(uint xms)
{
uint i,j;
for(i=xms;i>0;i--)
for(j=110;j>0;j--);
}
实验效果图:
4、 简易模拟交通灯****(********自己作图********)****
说明:东西向绿灯亮10秒,黄灯闪烁3次后红灯亮, 红灯亮后,南北向由红灯变为绿灯,15秒后南北向黄灯闪烁3次后变红灯,东西向变绿灯,如此重复。
电路连接图:
流程图:
代码:
#include "reg52.h"
#define uint unsigned int //无符号整型
#define uchar unsigned char //无符号字符型
sbit red1 = P0^0;
sbit yellow1 = P0^1;
sbit green1 = P0^2;
sbit red2 = P0^3;
sbit yellow2 = P0^4;
sbit green2 = P0^5;
//ms
void delay_ms(uint z)
{
int x,y;
for(x = 0; x < z; x++)
for(y=0;y<110;y++);
}
void main()
{
P1 = 0XFF;
while(1)
{
// P1 = 0XFF;
// delay_ms(1000);
// P1 = 0;
// delay_ms(1000);
red2=0;
red1=1;
green1 = 0;
delay_ms(1000);
delay_ms(1000);
delay_ms(1000);
delay_ms(1000);
delay_ms(1000);
delay_ms(1000);
delay_ms(1000);
delay_ms(1000);
delay_ms(1000);
green1 = 1;
yellow1=0;
delay_ms(100);
yellow1=1;
delay_ms(100);
yellow1=0;
delay_ms(100);
yellow1=1;
delay_ms(100);
yellow1=0;
delay_ms(100);
yellow1=1;
delay_ms(100);
red1=0;
red2=1;
green2 = 0;
delay_ms(1000);
delay_ms(1000);
delay_ms(1000);
delay_ms(1000);
delay_ms(1000);
delay_ms(1000);
delay_ms(1000);
delay_ms(1000);
delay_ms(1000);
green2 = 1;
yellow2=0;
delay_ms(100);
yellow2=1;
delay_ms(100);
yellow2=0;
delay_ms(100);
yellow2=1;
delay_ms(100);
yellow2=0;
delay_ms(100);
yellow2=1;
delay_ms(100);
}
}
实验效果图:
五、提交实验报告写作内容要
请写出实验过程中曾出现的问题和你的解决方法,你对实验有何感想和体会?
一开始自我拟了一道题:做一个十字路口交通灯,带倒计时功能,有暂停功能,绿灯时长控制功能。且暂停时倒计时灯熄灭,十字路口红灯全亮;绿灯时长的控制由另一个单片机进行控制(串口通信)。
实验时:
①我先通过Proteus搭建一个只有十字路口交通灯的电路。搭建完电路后,通过代码编程,实现基本的交通灯功能。具体为按照四个路口方向逐次亮起红灯24秒,绿灯5秒,黄灯3秒。
②搞完交通灯的显示问题后,我去proteus中继续添加一部分电路,用于实现十字路口交通灯的倒计时的显示。这时发现单片机引脚不太够用,毕竟交通灯就占了12个引脚,若倒计时的显示全部直接用单片机的引脚作为控制,则要用到16个引脚。这明显(12+16=28)会用到P3口的引脚。但我又不想用P3口来做这些事,P3口我打算用于功能按键的控制。这时我想起动态数码管的位选其实可以用138译码器来进行,这样只需3个端口用于选择地址,而剩下的5个端口则省下来了。相关电路添加完毕后,我继续通过代码编程,实现基本的交通灯功能+倒计时功能。
③在单片机A中,加了个外部中断0,并在proteus中修改了对应电路。并通过在while(1)死循环中,用if….else….进行分支选择,成功把交通灯暂停功能添加上去了。
④在单片机B中,通过两个按键,并在代码中,实现了绿灯时长的加减,且通过串口发送给了单片机A中。至此完成了自拟题目的功能要求。
最后的最后就是,修改了一些小bug,例如增加了绿灯、红灯时长范围,防止绿灯时间过长等。并且在不影响功能的前提下,优化了下代码,尽量节约单片机的内存空间(虽说是实验而已,没必要,但还是要有一个好习惯),简化代码,使之既层次分明、通俗易懂,又简单直了。