【单片机基础实验】AT89C51 | 红绿灯 | 流水灯 | 单数码管 | 八位数码管显示 | 八位数码管显示学号 | 独立按键 | 矩阵键盘 | 外部中断 | 10秒秒表 | 时分秒 | 串口通信

单片机基础实验

一、红绿灯实验

功能:实现了一个简单的交通灯控制程序,模拟了一个交叉路口的交通信号灯控制系统,通过控制红灯、黄灯和绿灯的亮灭来模拟车辆和行人的通行情况。 

效果: 

红灯亮,绿灯亮

注意:绿灯结束后需要黄灯闪烁,红灯结束直接是绿灯 

二、红绿灯实验(代码) 

代码:

#include<reg51.h>
#define uchar unsigned char
#define uint unsigned int
sbit RED_A=P0^0;	   //东西向灯
sbit YELLOW_A=P0^1;
sbit GREEN_A=P0^2;
sbit RED_B=P0^3;	   //南北向灯
sbit YELLOW_B=P0^4;
sbit GREEN_B=P0^5;
uchar Flash_Count=0,Operation_Type=1; //闪烁次数,操作类型变量
//延时
void DelayMS(uint x)
{
	uchar i;
	while(x--) for(i=0;i<120;i++);
}
//交通灯切换
void Traffic_Light()
{
	switch(Operation_Type)
	{
		case 1:	//东西向绿灯与南北向红灯亮
				RED_A=1;YELLOW_A=1;GREEN_A=0;
				RED_B=0;YELLOW_B=1;GREEN_B=1;
				DelayMS(4000);
				Operation_Type=2;
				break;
		case 2:	//东西向黄灯闪烁,绿灯关闭
				DelayMS(300);
				YELLOW_A=~YELLOW_A;GREEN_A=1;
				if(++Flash_Count!=10) return; //闪烁5次
				Flash_Count=0;
				Operation_Type=3;
				break;
		case 3: //东西向红灯,南北向绿灯亮
			  RED_A=0;YELLOW_A=1;GREEN_A=1;
				RED_B=1;YELLOW_B=1;GREEN_B=0;
				DelayMS(4000);
				Operation_Type=4;
				break;

		case 4: //南北向黄灯闪烁5 次
			  DelayMS(300);
				YELLOW_B=~YELLOW_B;GREEN_B=1`	;
				if(++Flash_Count!=10) return; //闪烁5次
				Flash_Count=0;
				Operation_Type=1;
				break;

	}
}
//主程序
void main()
{
	while(1) Traffic_Light();
}

三、流水灯实验(跑马灯)

功能:实现了一个LED灯从中间向两边亮的效果,通过对P0寄存器的位操作,控制LED灯的亮灭状态。

扫描二维码关注公众号,回复: 17274851 查看本文章

效果:

流水灯从中间向两边亮:

 这个实验最主要的就是对P0口的移位操作

#include<reg51.h>
#include<intrins.h>
#define uchar unsigned char
#define uint unsigned int
sbit p00=P0^0;
sbit p01=P0^1;
sbit p02=P0^2;
sbit p03=P0^3;
sbit p04=P0^4;
sbit p05=P0^5;
sbit p06=P0^6;
sbit p07=P0^7;


//延时函数
void DelayMS(uint x)
{
	uchar i;
	while(x--) for(i=0;i<120;i++);
}

uchar temp,m,n;
uint i;
//中间向两边亮
void main()
{
	m=0xef;
	n=0xf7;
	while(1)
	{
   P0=m&n;
   m=_crol_(m,1);
	 n=_cror_(n,1);
   if(m == 0xfe)
   {
     m=0xef;
     n=0xf7;
	 }
   DelayMS(500);
	 }
	
}

四-1、单数码管显示实验

功能:实现了一个数字显示器的功能,通过循环显示0到F的数字。

效果:

#include<reg51.h>
#define uchar unsigned char
#define uint unsigned int

//共阴极          0     1   2    3    4    5    6     7   8    9    A    B   C     D    E    F
uint table[] = {0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};

//延时
void DelayMS(uint x)
{
	uchar i;
	while(x--) for(i=0;i<120;i++);
}

//主程序
void main()
{
	uchar i;
	while(1)
	{
		for(i=1; i<=16; i++)
		{
			P0 = table[i-1];
			DelayMS(500);
		}
	}
}

四-2、八位数码管滚动显示实验

功能:实现了一个多位数码管显示器的功能,通过循环依次点亮数码管的每一位,并在每一位上显示0到F的数字。

#include<reg51.h>
#include<intrins.h>
#define uchar unsigned char
#define uint unsigned int

//共阴极          0     1   2    3    4    5    6     7   8    9    A    B   C     D    E    F
uint table[] = {0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};
//二极管位    1    2    3    4    5    6    7    8
uint b[] = {0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80};

//延时
void DelayMS(uint x)
{
	uchar i;
	while(x--) for(i=0;i<120;i++);
}

//主程序
void main()
{
	uchar i;
	while(1)
	{
		for(i=1; i<=8; i++)
		{
			P2= b[i-1];
			P0 = ~table[i];
			DelayMS(500);
		}
	}
}

五、八位数码管循环显示十位学号实验

功能:一个基于51单片机的多位数码管显示器控制程序,程序中使用了P0和P2端口来控制数码管的段选和位选,通过循环依次点亮数码管的每一位,并在每一位上显示学号的十位数字。

效果:

#include<reg51.h>
#include<intrins.h>
#define uchar unsigned char
#define uint unsigned int

//共阴极               0     1   2    3    4    5    6     7   8    9    A    B   C     D    E    F
uint code table[] = {0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};
//二极管位         1    2    3    4    5    6    7    8
uint code b[] = {0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80};
//设置位
sbit A8 = P2^0;
sbit A9 = P2^1;

//延时
void DelayMS(uint x)
{
	uchar i;
	while(x--) for(i=0;i<120;i++);
}

void show(uint duanma,uint weima)  //输入位码和段码进行展示
{
	P0=~b[weima];A9=1;A9=0; //锁+位码      -- 哪一位显示
	P0=~table[duanma];A8=1;A8=0; //琐+段码 -- 显示什么字
	DelayMS(500); 
}


//主程序
void main()
{
	P0=~0x00;A9=1;A9=0; //段码
	P0=~0x00;A8=1;A8=0;DelayMS(10); //位码

	while(1)
	{
		uint i,j;
		uchar my_xuehao[]={2,0,2,1,2,1,2,9,8,1};  //十位学号
		for(i=0;i<10;i++)  // 我
		{
			for(j=0;j<9;j++)
			{
				show(my_xuehao[(i*8+j)%10],j);
			}
		}
	}
}

六、独立按键实验

功能:基于51单片机的控制程序,用于控制LED灯的亮灭。程序中使用了P0端口来控制LED灯的亮灭状态,通过独立按键控制LED灯的全亮、全灭、从上往下依次亮。

效果:

#include<reg51.h>
#include<intrins.h>
#define uchar unsigned char
#define uint unsigned int

//共阴极          0     1   2    3    4    5    6     7   8    9    A    B   C     D    E    F
uint code table[] = {0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};
//二极管位    1    2    3    4    5    6    7    8
uint code b[] = {0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80};
//定义按键位
sbit mp30 = P3^0;
sbit mp31 = P3^1;
sbit mp32 = P3^2;

//延时
//void DelayMS(uint x)
//{
	//uchar i;
	//while(x--) for(i=0;i<120;i++);
//}

void updown();

//主程序
void main()
{
	while(1)
	{
		if(mp30 == 0) // 全亮
		{
			P0 =0x00;
		}
		
		if(mp31 == 0) // 全灭
		{
			P0 =0xFF;
		}
		
		if(mp32 == 0) // 从上往下亮
		{
			updown();
		}
	}
}

updown.c 

#include<reg51.h>
#include<intrins.h>
#define uchar unsigned char
#define uint unsigned int

sbit mp30 = P3^0;
sbit mp31 = P3^1;
sbit mp32 = P3^2;

void DelayMS(uint x)
{
	uchar i;
	while(x--) for(i=0;i<120;i++);
}

void updown()
{
	uchar mp0;
	mp0 = 0x01;
	while(1)
	{
		uchar temp = 0xfe;
		uchar i;
		for(i=1; i<=4; i++)
		{
			P0 = temp;
			temp = _crol_(temp,1); //移位
			DelayMS(500);
		}
		if((mp30 == 0)||(mp31 ==0))
	  {
		  break;
	  }
	}
}

七、矩阵键盘实验

功能:基于51单片机的程序,用于实现一个简单的键盘输入并在数码管上显示相应数字的功能,通过矩阵键盘,扫描行列按键

效果:

#include<intrins.h>
#include<reg51.h>
#define uchar unsigned char
#define uint unsigned int

// 共阴极              0     1   2    3    4    5   6     7   8    9    A    B   C     D    E    F
uint code table[] = {0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};
//                     1    2    3    4    5    6    7    8
// uint code wei[] = {0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80};
uchar num_key=17,pre_num_key=17;
// 延时函数
void DelayMS(uint x)
{
	uint i;
	while(x--) for(i=0;i<120;i++);
}

//键盘扫描
void scan_key()
{
	uint temp;
	P1=0Xf0; // 11110000 先行
	DelayMS(5);
	temp=P1^0Xf0;
	if(temp==16)
		num_key=0;
	if(temp==32)
		num_key=1;
	if(temp==64)
		num_key=2;
	if(temp==128)
		num_key=3;
	
	P1=0X0f; // 00001111 再列
		DelayMS(5);
	temp=P1^0X0f;
	if(temp==8)
		num_key+=0;
	if(temp==4)
		num_key+=4;
	if(temp==2)
		num_key+=8;
	if(temp==1)
		num_key+=12;
}
void main()
{ 
	P0=0X00;
	DelayMS(200);
	while(1)
	{
		P1=0XF0;
		if(P1!=0XF0)
		{
			scan_key();
			if(num_key!=pre_num_key)
			{
				P0=table[num_key];
				DelayMS(200);
			}
		}
	}
	}

八、外部中断实验

功能:基于 8051 单片机的程序,实现了一个简单的计数器功能,并使用数码管进行显示,通过计数按键,每按一次个位加一,累计进位,按下清零归零。

效果:

#include<reg51.h>
#define uchar unsigned char
#define uint unsigned int

//共阴极               0     1   2    3    4    5    6     7   8    9   10
uint table[] = {0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x00};

sbit clear_key = P3^6;
uint count = 0;
uchar ge,shi,bai;

// 延时
void DelayMS(uint x)
{
	uchar i;
	while(x--) for(i=0;i<120;i++);
}

//External interrupt0 service routine
void  exint0()  interrupt 0 		//INT0, interrupt 0 (location at 0003H) 自动调用
{
	count++;
}

void main()
{
	P0 = 0;
	P1 = 0;
	P2 = 0;
	DelayMS(200);
	
	IT0 = 1; 					//set INT0 interrupt type (1:Falling 0:Low level) 下降沿触发
	EX0 = 1; 					//enable INT0 interrupt 允许
	EA = 1; 					//open global interrupt switch  中断总允许  -- 两条可以写为一条 IE = 0x81 
	while (1)
	{
		if(clear_key ==0) count =0;
		bai = count / 100;
		shi = count / 10 % 10;
		ge = count % 10;
		if(bai == 0)
		{
			bai = 10;
			if(shi == 0)
			{
				shi = 10;
			}
			
		}
		P0 = table[ge];
	  P1 = table[shi];
	  P2 = table[bai];
		
	}
	
}

九、10秒秒表实验

功能:按下按键开始10秒的计时,再次按下停止秒表,再次按下清零。

效果:

#include<reg51.h>
#include<intrins.h>
#define uchar unsigned char
#define uint unsigned int

// 共阴极7段显示
uchar code table[] = {0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};
sbit K1=P3^7; // 3.7引脚--按键 赋值为K1
uint Timer_count =0; // 定时器中断计数
bit key_state;//按键状态
uint key_flag_idx=0,sec_counter=0;//key_flag_idx-按键的三个状态,初始为0 sec_counter-秒表 

void DelayMS(uint x)
{
	uchar i;
	while(x--)
	{
		for(i=0;i<120;i++);
	}
}


void handle_key()
{
	if(key_state==0) // 按下按钮
	{
		key_flag_idx=(key_flag_idx+1)%3; // 按钮的状态在0-2
		if(key_flag_idx==1) // 按下开启定时器
		{
			TR0=1;
			ET0=1;
			EA=1;
		}
		if(key_flag_idx==2) // 再次按下停止
		{
			TR0=0;
			ET0=0;
			EA=0;
		}
		if(key_flag_idx==0) // 再次按下清零
		{
			sec_counter=0; // 计数清零
			P2=0x3f;  // 显示0
			P0=0x00;
			DelayMS(200);
		}
	}
}

//定时器中断 -- 7段显示器
void Timer0_Rountine(void) interrupt 1
{
	TL0=(65536-50000)%256; // 计数器每50ms产生一次中断
	TH0=(65536-50000)/256; 
	if(Timer_coun % 20 == 0)  // 20 * 50ms = 1秒
	{
		sec_counter++;// 每1秒,sec_counter 显示屏加一
		P2=table[sec_counter%10]; // 显示
		P0=table[sec_counter/10];
		DelayMS(200);
		Timer_coun=0;  // 1秒,定时器中断清0
		if(sec_counter==100)//100s清零
		{
			sec_counter=0;
		}
	}
	Timer_coun++;
}


void main()
{
	P2=0x00;
	P0=0x00;
	TMOD=0X01;
	TL0=(65536-50000)%256;// 定时器寄存器初始化 -- 50ms
	TH0=(65536-50000)/256;
	TR0=0;
	ET0=0;
	EA=0;
	key_state=0; // 初始化按钮状态为0
	while(1)
	{
		if(key_state!=K1) // 按键检测
		{
			DelayMS(5); // 消抖
			key_state=K1; // 按下按键 key_state = K1 = 0
			handle_key();
		}
	}
}

十、时分秒实验

功能:显示 09:30:30 的动态时钟

效果:

#include<reg51.h>
#include<intrins.h>
#define uchar unsigned char
#define uint unsigned int

uchar code table[] = {0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71,0x00}; //段码
uchar  code wei[] = {0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80}; // 位码
sbit A8=P2^0;
sbit A9=P2^1;
sbit A11=P2^3;

uint Timer_count=0; // 定时器计数标志
bit key_state; 
uint shi=9,fen=30,miao=30;

// 延时函数
void DelayMS(uint x)
{
	uchar i;
	while(x--)
	{
		for(i=0;i<120;i++);
	}
}

// 显示函数
void show(uint duanma,uint weima)
{
		P0=wei[weima];A9=1;A9=0;
		P0=table[duanma];A8=1;A8=0;DelayMS(5);
}


// 定时器
void Timer0_Rountine(void) interrupt 1
{
	TR0=0; // 关中断
	TL0=(65536-50000)%256; // 同理定时50ms
	TH0=(65536-50000)/256;
	Timer_count++; // Timer_count定时器
	TR0=1; // 开中断
}


void main()
{
	P0=0x00;
	TMOD=0X01; // 定时器工作在模式1
	TL0=(65536-50000)%256; // 定时器初始化 50 ms
	TH0=(65536-50000)/256;
	TR0=1;
	ET0=1;
	EA=1;
	while(1)
	{
		if(Timer_count==20) // 1秒
	{
		Timer_count=0; // 定时器初始化
		miao++; // 增加秒
		if(miao>=60)
		{
			miao=0; // 秒清零
			fen++; // 60秒增加一分钟
			if(fen>=60) // 60分钟增加一小时
			{
				fen=0; // 分清零
				shi++; // 增加时
				if(shi==24) // 24小时变00:00:00
				{
					shi=0,fen=0,miao=0;
				}
			}
		}
	}
	  show(shi/10,0); // 综合显示 时:分:秒 ,利用显示函数
		show(shi%10,1);
		show(fen/10,3);
		show(fen%10,4);
		show(miao/10,6);
		show(miao%10,7);
		
	}
}

十一、串口通信实验

功能:实现单片机的串口通信,不断打印学号

效果:

#include<reg51.h>
#define uchar unsigned char
#define uint unsigned int

//延时
void DelayMS(uint ms)
{  
  uchar i;
  while(ms--) for(i=0;i<120;i++);
}

//向串口发送字符
void Putc_to_SerialPort(uchar c)
{ 
  SBUF=c;
  while(TI==0);
  TI=0;
}

//向串口发送字符串
void Puts_to_SerialPort(uchar *s)
{	   
   while(*s!='\0')
     {
	    Putc_to_SerialPort(*s);
		s++;
		DelayMS(5);
	}
}

//主程序
void main()
{	
   uchar c = 89, n = 0, i = 0;  // i 用来计数打印的学号个数
	 char xuehao[]="2021212981";
   
	 SCON=0x40; //串口模式1
   TMOD=0x20; //T1 工作模式2
   TH1=0xfd; //波特率9600
   TL1=0xfd;
   PCON=0x00; //波特率不倍增TI=0;
   TR1=1;
   DelayMS(200);
//向主机发送数据
   Puts_to_SerialPort("Receiving From 8051...\r\n");
   Puts_to_SerialPort("-------------------------------\r\n");
	Puts_to_SerialPort("Class: 08052102 Name:WZQ \r\n");
	 Puts_to_SerialPort("-------------------------------\r\n");
   DelayMS(50);
	
   while(1)
   {
		 n = c + i;
		 xuehao[8] = n / 10 + '0'; //将学号转换为字符串
		 xuehao[9] = n % 10 + '0';
    Puts_to_SerialPort(xuehao);
	  DelayMS(100);
		 Putc_to_SerialPort(' ');
		 
	 if(i== 24) //每输出25个学号换行打印一系列--------
	   { 
			 c = 81;  
	    Puts_to_SerialPort("\r\n-------------------------------\r\n");
		  DelayMS(100);
	   }
	   i = (i+1)%25;
		 
	 if(i%5==0) //每输出5个学号后换行
	   {
	      Puts_to_SerialPort("\r\n");
		  DelayMS(100);
		}
	}
}

2023.12.13

渝北仙桃数据谷

猜你喜欢

转载自blog.csdn.net/Akaxi1/article/details/134966162