怎么看懂51单片机电路图与功能实现的C语言编写(2-7入门篇)

提起51单片机,就绕不过B站up江协科技的教学视频:51单片机入门教程

无论什么时候打开,哪怕是现在AIcoding大行其道的2026年,都能看到几百人同时在线观看,可谓经典经久不衰。

本篇为 51 单片机入门实验的个人学习笔记,内容基于 B 站教学视频整理,主要是基于单片机电路图编程的C语言代码笔记。相关代码工程请前往视频源地址自行下载。Up 主讲解逻辑清晰、由浅入深,非常适合入门同学学习,在此强烈推荐给大家。本文仅作为个人学习记录与参考,细节原理与调试过程建议观看原视频学习,相信会有更大收获。

主要是记录个人的单片机电路图学习笔记和代码心得,本篇对应为入门的2-7实验。

2-1点亮一个LED

电路图:

这是一个共阳极接法的 8 路 LED 指示灯电路,核心由三部分组成:8 个 LED 灯(D1~D8)、

2 个 4 位排阻(RP9、RP10,阻值 470Ω)、连接到单片机 P2 口(P2.0~P2.7)的 IO 口。

如果要只点亮D1,则P2=0xFE。

代码:

c 复制代码
#include <REGX52.H>
void main()
{
	P2=0xFE;  //1111 1110
}

现象:仅D1常亮

2-2LED闪烁

主要是通过软件延时计算器生成个延时函数后调用。

代码:

c 复制代码
#include <REGX52.H>
#include <INTRINS.H>

void Delay50ms(void)	//@12.000MHz
{
	unsigned char data i, j;

	i = 98;
	j = 67;
	do
	{
		while (--j);
	} while (--i);
}




void main()
{
	while(1)
	{
		P2=0xFE;
		Delay50ms();
		P2=0xFf;
		Delay50ms();
	}
	
}

现象:仅D1闪烁

2-3LED流水灯

主要是生成了个自定义延时时间的函数。

代码:

c 复制代码
#include <REGX52.H>
#include <INTRINS.H>


void Delayxms(unsigned int xms)		//@12.000MHz
{
	unsigned char i, j;
	while(xms)
	{
	i = 2;        //51单片机晶振执行指令的速度是固定
	j = 239;      //i=2,j=239时,cpu空转的时间正正好是1毫秒
	do
	{
		while (--j);
	} while (--i);
		xms--;  //xms=xms-1
	}
}



void main()
{
	while(1)
	{
	P2=0xFE;  //1111 1110
	Delayxms(25);
	P2=0xFD;  //1111 1101
	Delayxms(25);
	P2=0xFB;  //1111 1011
	Delayxms(25);
	P2=0xF7;  //1111 0111
	Delayxms(25);
	P2=0xEF;  //1110 1111
	Delayxms(25);
	P2=0xDF;  //1101 1111
	Delayxms(2);
	P2=0xBF;  //1011 1111
	Delayxms(25);
	P2=0x7F;  //0111 1111
    Delayxms(25);
	}
}

现象:流水灯效果同时数码管也受影响。

原因:

P22,P23,P24通过74HC138译码器同时控制LED1-8。

流水灯代码直接操作整个 P2 端口,改变了 P2.1/P2.2/P2.3 这三个数码管位选引脚的电平,导致 74HC138 译码器误选通数码管,从而和流水灯效果互相干扰。

3-1独立按键控制LED

实现功能:当K2被按下时,D1常量。

电路图;

K2对应端口P30,只要P30=0,说明被按下,那么这时给P20赋值0。

注意:除了P0端口外,所有端口在不赋值的情况下值都默认是1.

代码:

c 复制代码
#include <REGX52.H>

 
void main()
{
	
	while(1)
	{
		if(P3_0==0)
		{
			P2_0=0;
		}
		else
		{
			P2_0=1;
		}
	}
}

3-2独立按键控制LED状态

思路:如果检测到K2被按下,延时20分钟在检测K2,如果松手了,将P20取反。

代码:

c 复制代码
#include <REGX52.H>

 
void Delay(unsigned int xms)		//@12.000MHz
{
	unsigned char i, j;
	while(xms)
	{
	i = 2;
	j = 239;
	do
	{
		while (--j);
	} while (--i);
	xms--;
	}
}
 
 
void main()
{
	while(1)
	{
		if(P3_1==0)
		{
			Delay(20);  // Keys away shaking
			while(P3_1==0);
			Delay(20);  // Detection of let go
			P2_0=~P2_0;
		}
	}
}

3-3 独立按键控制LED显示二进制

思路:定义一个char,unsigned char 是 51 单片机常用的变量类型,占用 1 个字节(8 位二进制)。LED低电平有效,让他等于char取反。

代码:

c 复制代码
#include <REGX52.H>

 
void Delay(unsigned int xms)		//@12.000MHz
{
	unsigned char i, j;
	while(xms)
	{
	i = 2;
	j = 239;
	do
	{
		while (--j);
	} while (--i);
	xms--;
	}
}
 
void main()
{
	unsigned char LEDNum=0;  // char max num is 255
	while(1)
	{
	if(P3_1==0)
	{
		Delay(20);
		while(P3_1==0);
		Delay(20);
		LEDNum++;
		P2=~LEDNum;
	}
	}
}

3-4独立按键控制LED移位

思路:2MHz 晶振执行一行 C 语言 = 几微秒,人眼能看到的最小时间 = 20ms 以上。我们创建1个char记录K1、K2按的情况,K1按了则减,K2按了则加,然后给P2赋值初值使D1亮,根据char执行移位,P2赋值初值使D1亮只有几微秒,人眼看不到D1亮。

代码;

c 复制代码
#include <REGX52.H>



void Delay(unsigned int xms)		//@12.000MHz
{
	unsigned char i, j;
	while(xms)
	{
	i = 2;
	j = 239;
	do
	{
		while (--j);
	} while (--i);
	xms--;
	}
}




unsigned char LEDNum;  // The global variable

void main()
{
    P2=~0x01; //int P2
	while(1)
	{
		if(P3_0==0)
		{
		Delay(20);
		while(P3_0==0);
		Delay(20);
		LEDNum++;
		if(LEDNum>=8)
			LEDNum=0;
		P2=~(0x01<<LEDNum);  // 0x01 of P2 need shift to the left LEDNum, and get the not
		}
		if(P3_1==0)
		{
		Delay(20);
		while(P3_1==0);
		Delay(20);
		if(LEDNum==0)
			LEDNum=7;
		else
			LEDNum--;
		P2=~(0x01<<LEDNum);
		}
	}
}

4-1静态数码管显示

思路:LED8实际上再物理位置是第一个数码管,所以要点亮第一个数码管实际上是拉低LED8,74HC138译码器输出是低电平有效,使其输入P2_4=1;P2_3=1;P2_2=1;。其他同理创建个函数控制某个数码管显示数字0-9和字幕a-f。

电路图:

代码:这里最后是第三位显示11,即b

c 复制代码
#include <REGX52.H>

 
unsigned char NixieTable[]={
 
0x3f,0x06,0x5b,0x4f,
 
0x66,0x6d,0x7d,0x07,
 
0x7f,0x6f,0x77,0x7c,
 
0x39,0x5e,0x79,0x71, 0x00};
 
 
void Nixie(unsigned char Location,Number)
{
	switch(Location)
	{
		case 1:
			P2_4=1;P2_3=1;P2_2=1;break;
		case 2:
			P2_4=1;P2_3=1;P2_2=0;break;
		case 3:
			P2_4=1;P2_3=0;P2_2=1;break;
		case 4:
			P2_4=1;P2_3=0;P2_2=0;break;
		case 5:
			P2_4=0;P2_3=1;P2_2=1;break;
		case 6:
			P2_4=0;P2_3=1;P2_2=0;break;
		case 7:
			P2_4=0;P2_3=0;P2_2=1;break;
		case 8:
			P2_4=0;P2_3=0;P2_2=0;break;
	}
	P0=NixieTable[Number];
}
 
void main()
{
//	P24=1;  //Controls a nixie tube
//	P23=0;
//	P22=1;
//	P0=0x7D;  //value is 6
	Nixie(2,3);
	Nixie(1,8);
	Nixie(3,10);
	Nixie(3,11);
	while(1)
	{
		
	}
}

4-2动态数码管显示

思路:每隔1ms轮番点亮要点的数码管。

代码:

c 复制代码
#include <REGX52.H>

 
unsigned char NixieTable[]={
 
0x3f,0x06,0x5b,0x4f,
 
0x66,0x6d,0x7d,0x07,
 
0x7f,0x6f,0x77,0x7c,
 
0x39,0x5e,0x79,0x71, 0x00};
 
void Delay(unsigned int xms)		//@12.000MHz
{
	unsigned char i, j;
	while(xms)
	{
	i = 2;
	j = 239;
	do
	{
		while (--j);
	} while (--i);
	xms--;
	}
}
 
void Nixie(unsigned char Location,Number)
{
	switch(Location)
	{
		case 1:
			P2_4=1;P2_3=1;P2_2=1;break;
		case 2:
			P2_4=1;P2_3=1;P2_2=0;break;
		case 3:
			P2_4=1;P2_3=0;P2_2=1;break;
		case 4:
			P2_4=1;P2_3=0;P2_2=0;break;
		case 5:
			P2_4=0;P2_3=1;P2_2=1;break;
		case 6:
			P2_4=0;P2_3=1;P2_2=0;break;
		case 7:
			P2_4=0;P2_3=0;P2_2=1;break;
		case 8:
			P2_4=0;P2_3=0;P2_2=0;break;
	}
	P0=NixieTable[Number];
	Delay(1);  // Shadow elimination
	P0=0x00;  //  reset
}
 
void main()
{
	while(1)
	{
		Nixie(1,1);
		Nixie(2,2);
		Nixie(3,3);
	}
}

5-1模块化编程

功能:模块化编程使8个数码管显示12345678。

思路:编写main使其每个数码管再8ms的周期每隔1ms显示对应数字。调用编写的两个.c子函数。要搭配.h。

代码:

主函数:

c 复制代码
#include <REGX52.H>
#include "Delay.h"  // 使用双引号,有优先查询工作目录
#include "Nixie.h" 
 
void main()
{
	while(1)
	{
		Nixie(1,1);
		Nixie(2,2);
		Nixie(3,3);
		Nixie(4,4);
		Nixie(5,5);
		Nixie(6,6);
		Nixie(7,7);
		Nixie(8,8);
	}
}

Delay.c:

c 复制代码
void Delay(unsigned int xms)		//@12.000MHz
{
	unsigned char i, j;
	while(xms)
	{
	i = 2;
	j = 239;
	do
	{
		while (--j);
	} while (--i);
	xms--;
	}
}

Delay.h:

c 复制代码
#ifndef __DELAY_H__
#define __DELAY_H__
 
void Delay(unsigned int xms);
	
#endif

Nixie.c:

c 复制代码
#include <REGX52.H>
#include "Delay.h"
 
unsigned char NixieTable[]={
 
0x3f,0x06,0x5b,0x4f,
 
0x66,0x6d,0x7d,0x07,
 
0x7f,0x6f,0x77,0x7c,
 
0x39,0x5e,0x79,0x71, 0x00};
 
 
void Nixie(unsigned char Location,Number)
{
	switch(Location)
	{
		case 1:
			P2_4=1;P2_3=1;P2_2=1;break;
		case 2:
			P2_4=1;P2_3=1;P2_2=0;break;
		case 3:
			P2_4=1;P2_3=0;P2_2=1;break;
		case 4:
			P2_4=1;P2_3=0;P2_2=0;break;
		case 5:
			P2_4=0;P2_3=1;P2_2=1;break;
		case 6:
			P2_4=0;P2_3=1;P2_2=0;break;
		case 7:
			P2_4=0;P2_3=0;P2_2=1;break;
		case 8:
			P2_4=0;P2_3=0;P2_2=0;break;
	}
	P0=NixieTable[Number];
	Delay(1);  // Shadow elimination
	P0=0x00;  //  reset
}

Nixie.h:

c 复制代码
#ifndef __NIXIE_H__
#define __NIXIE_H__
 
void Nixie(unsigned char Location,Number);
	
#endif

5-2LCD1602调试工具

思路,通过LCD1602.c实现控制在第几行第几个显示数字,字母等内容。Delay.c和.h可以复制粘贴过来。

功能:实现个在第一行前三个位置显示个三位十进制数,每隔1秒加一。

主函数:

c 复制代码
#include <REGX52.H>
#include "LCD1602.h"
#include "Delay.h"

 
//void main()
//{
//	LCD_Init();
//	LCD_ShowChar(1,1,'B');
//	LCD_ShowString(1,3,"Hello");
//	LCD_ShowNum(1,9,123,3);
//	LCD_ShowSignedNum(1,13,-66,2);
//	LCD_ShowHexNum(2,1,0xA8,2);
//	LCD_ShowBinNum(2,4,0xAA,8);
//	LCD_ShowChar(2,13,'A');
//	while(1)
//	{
//	
//	}
//}


int Result=0;

void main()
{
	LCD_Init();
	while(1)
	{
		Result++;
		Delay(1000);
		LCD_ShowNum(1,1,Result,3);
	}
}	

LCD1602.c:

c 复制代码
#include <REGX52.H>

 
 
//引脚配置:
sbit LCD_RS=P2^6;
sbit LCD_RW=P2^5;
sbit LCD_EN=P2^7;
#define LCD_DataPort P0
 
//函数定义:
/**
  * @brief  LCD1602延时函数,12MHz调用可延时1ms
  * @param  无
  * @retval 无
  */
void LCD_Delay()
{
	unsigned char i, j;
 
	i = 2;
	j = 239;
	do
	{
		while (--j);
	} while (--i);
}
 
/**
  * @brief  LCD1602写命令
  * @param  Command 要写入的命令
  * @retval 无
  */
void LCD_WriteCommand(unsigned char Command)
{
	LCD_RS=0;
	LCD_RW=0;
	LCD_DataPort=Command;
	LCD_EN=1;
	LCD_Delay();
	LCD_EN=0;
	LCD_Delay();
}
 
/**
  * @brief  LCD1602写数据
  * @param  Data 要写入的数据
  * @retval 无
  */
void LCD_WriteData(unsigned char Data)
{
	LCD_RS=1;
	LCD_RW=0;
	LCD_DataPort=Data;
	LCD_EN=1;
	LCD_Delay();
	LCD_EN=0;
	LCD_Delay();
}
 
/**
  * @brief  LCD1602设置光标位置
  * @param  Line 行位置,范围:1~2
  * @param  Column 列位置,范围:1~16
  * @retval 无
  */
void LCD_SetCursor(unsigned char Line,unsigned char Column)
{
	if(Line==1)
	{
		LCD_WriteCommand(0x80|(Column-1));
	}
	else if(Line==2)
	{
		LCD_WriteCommand(0x80|(Column-1+0x40));
	}
}
 
/**
  * @brief  LCD1602初始化函数
  * @param  无
  * @retval 无
  */
void LCD_Init()
{
	LCD_WriteCommand(0x38);//八位数据接口,两行显示,5*7点阵
	LCD_WriteCommand(0x0c);//显示开,光标关,闪烁关
	LCD_WriteCommand(0x06);//数据读写操作后,光标自动加一,画面不动
	LCD_WriteCommand(0x01);//光标复位,清屏
}
 
/**
  * @brief  在LCD1602指定位置上显示一个字符
  * @param  Line 行位置,范围:1~2
  * @param  Column 列位置,范围:1~16
  * @param  Char 要显示的字符
  * @retval 无
  */
void LCD_ShowChar(unsigned char Line,unsigned char Column,char Char)
{
	LCD_SetCursor(Line,Column);
	LCD_WriteData(Char);
}
 
/**
  * @brief  在LCD1602指定位置开始显示所给字符串
  * @param  Line 起始行位置,范围:1~2
  * @param  Column 起始列位置,范围:1~16
  * @param  String 要显示的字符串
  * @retval 无
  */
void LCD_ShowString(unsigned char Line,unsigned char Column,char *String)
{
	unsigned char i;
	LCD_SetCursor(Line,Column);
	for(i=0;String[i]!='\0';i++)
	{
		LCD_WriteData(String[i]);
	}
}
 
/**
  * @brief  返回值=X的Y次方
  */
int LCD_Pow(int X,int Y)
{
	unsigned char i;
	int Result=1;
	for(i=0;i<Y;i++)
	{
		Result*=X;
	}
	return Result;
}
 
/**
  * @brief  在LCD1602指定位置开始显示所给数字
  * @param  Line 起始行位置,范围:1~2
  * @param  Column 起始列位置,范围:1~16
  * @param  Number 要显示的数字,范围:0~65535
  * @param  Length 要显示数字的长度,范围:1~5
  * @retval 无
  */
void LCD_ShowNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length)
{
	unsigned char i;
	LCD_SetCursor(Line,Column);
	for(i=Length;i>0;i--)
	{
		LCD_WriteData(Number/LCD_Pow(10,i-1)%10+'0');
	}
}
 
/**
  * @brief  在LCD1602指定位置开始以有符号十进制显示所给数字
  * @param  Line 起始行位置,范围:1~2
  * @param  Column 起始列位置,范围:1~16
  * @param  Number 要显示的数字,范围:-32768~32767
  * @param  Length 要显示数字的长度,范围:1~5
  * @retval 无
  */
void LCD_ShowSignedNum(unsigned char Line,unsigned char Column,int Number,unsigned char Length)
{
	unsigned char i;
	unsigned int Number1;
	LCD_SetCursor(Line,Column);
	if(Number>=0)
	{
		LCD_WriteData('+');
		Number1=Number;
	}
	else
	{
		LCD_WriteData('-');
		Number1=-Number;
	}
	for(i=Length;i>0;i--)
	{
		LCD_WriteData(Number1/LCD_Pow(10,i-1)%10+'0');
	}
}
 
/**
  * @brief  在LCD1602指定位置开始以十六进制显示所给数字
  * @param  Line 起始行位置,范围:1~2
  * @param  Column 起始列位置,范围:1~16
  * @param  Number 要显示的数字,范围:0~0xFFFF
  * @param  Length 要显示数字的长度,范围:1~4
  * @retval 无
  */
void LCD_ShowHexNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length)
{
	unsigned char i,SingleNumber;
	LCD_SetCursor(Line,Column);
	for(i=Length;i>0;i--)
	{
		SingleNumber=Number/LCD_Pow(16,i-1)%16;
		if(SingleNumber<10)
		{
			LCD_WriteData(SingleNumber+'0');
		}
		else
		{
			LCD_WriteData(SingleNumber-10+'A');
		}
	}
}
 
/**
  * @brief  在LCD1602指定位置开始以二进制显示所给数字
  * @param  Line 起始行位置,范围:1~2
  * @param  Column 起始列位置,范围:1~16
  * @param  Number 要显示的数字,范围:0~1111 1111 1111 1111
  * @param  Length 要显示数字的长度,范围:1~16
  * @retval 无
  */
void LCD_ShowBinNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length)
{
	unsigned char i;
	LCD_SetCursor(Line,Column);
	for(i=Length;i>0;i--)
	{
		LCD_WriteData(Number/LCD_Pow(2,i-1)%2+'0');
	}
}

LCD1602.h:

c 复制代码
#ifndef __LCD1602_H__
#define __LCD1602_H__
 
//用户调用函数:
void LCD_Init();
void LCD_ShowChar(unsigned char Line,unsigned char Column,char Char);
void LCD_ShowString(unsigned char Line,unsigned char Column,char *String);
void LCD_ShowNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length);
void LCD_ShowSignedNum(unsigned char Line,unsigned char Column,int Number,unsigned char Length);
void LCD_ShowHexNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length);
void LCD_ShowBinNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length);
 
#endif

6-1矩阵键盘

电路图:

功能:让显示屏显示哪个按键被按下。

思路,通过MatrixKey获得按下按键编号,通过按列扫描的方法判断哪个按键被按下。

然后在LCE第二行第三列显示,给其两位数空间。同理Delay和LCD1602可以复制过来,这体现了模块化编程优势。

主函数:

c 复制代码
#include <REGX52.H>
#include "LCD1602.h"
#include "Delay.h"
#include "MatrixKey.h"
 
unsigned char KeyNum;
 
void main()
{
	LCD_Init();
//	LCD_ShowChar(1,1,'B');
	LCD_ShowString(1,3,"MatrixKey:");
//	LCD_ShowNum(1,9,123,3);
//	LCD_ShowSignedNum(1,13,-66,2);
//	LCD_ShowHexNum(2,1,0xA8,2);
//	LCD_ShowBinNum(2,4,0xAA,8);
//	LCD_ShowChar(2,13,'A');
	while(1)
	{
		KeyNum=MatrixKey();
		if(KeyNum)
		{
			LCD_ShowNum(2,3,KeyNum,2);
		}
	}
}

MatrixKey.c:

c 复制代码
#include <REGX52.H>
#include "Delay.h"
 
 

	unsigned char MatrixKey()
{
	unsigned char KeyNumber=0;
	P1=0xFF;
	P1_3=0;   // 补全:P1_3
	if(P1_7==0){Delay(20);while(P1_7==0);Delay(20);KeyNumber=1;}
	if(P1_6==0){Delay(20);while(P1_6==0);Delay(20);KeyNumber=5;}
	if(P1_5==0){Delay(20);while(P1_5==0);Delay(20);KeyNumber=9;}
	if(P1_4==0){Delay(20);while(P1_4==0);Delay(20);KeyNumber=13;}
	
	P1=0xFF;
	P1_2=0;   // 补全:P1_2
	if(P1_7==0){Delay(20);while(P1_7==0);Delay(20);KeyNumber=2;}
	if(P1_6==0){Delay(20);while(P1_6==0);Delay(20);KeyNumber=6;}
	if(P1_5==0){Delay(20);while(P1_5==0);Delay(20);KeyNumber=10;}
	if(P1_4==0){Delay(20);while(P1_4==0);Delay(20);KeyNumber=14;}
	
	P1=0xFF;
	P1_1=0;   // 补全:P1_1
	if(P1_7==0){Delay(20);while(P1_7==0);Delay(20);KeyNumber=3;}
	if(P1_6==0){Delay(20);while(P1_6==0);Delay(20);KeyNumber=7;}
	if(P1_5==0){Delay(20);while(P1_5==0);Delay(20);KeyNumber=11;}
	if(P1_4==0){Delay(20);while(P1_4==0);Delay(20);KeyNumber=15;}
	
	P1=0xFF;
	P1_0=0;   // 补全:P1_0
	if(P1_7==0){Delay(20);while(P1_7==0);Delay(20);KeyNumber=4;}
	if(P1_6==0){Delay(20);while(P1_6==0);Delay(20);KeyNumber=8;}
	if(P1_5==0){Delay(20);while(P1_5==0);Delay(20);KeyNumber=12;}
	if(P1_4==0){Delay(20);while(P1_4==0);Delay(20);KeyNumber=16;}

	return KeyNumber;  // 记得返回值!

}

MatrixKey.h:

c 复制代码
#ifndef __MATRIXKEY_H__
#define __MATRIXKEY_H__
 
unsigned char MatrixKey();
	
#endif

6-2矩阵键盘密码锁

实现功能:按键输入密码,按11确认,按12清空输入。

思路:复用之前的Delay,LCD1602,MatrixKey模块。

主函数:

c 复制代码
#include <REGX52.H>
#include "LCD1602.h"
#include "Delay.h"
#include "MatrixKey.h"
 
unsigned char KeyNum;
unsigned int Password, Count;
 
void main()
{
	LCD_Init();
//	LCD_ShowChar(1,1,'B');
	LCD_ShowString(1,1,"Password:");
//	LCD_ShowNum(1,9,123,3);
//	LCD_ShowSignedNum(1,13,-66,2);
//	LCD_ShowHexNum(2,1,0xA8,2);
//	LCD_ShowBinNum(2,4,0xAA,8);
//	LCD_ShowChar(2,13,'A');
	while(1)
	{
		KeyNum=MatrixKey();
		if(KeyNum)
		{
			if(KeyNum<=10)  // 如果S1~S10按键按下,输入密码
			{
				if(Count<4)  // 密码四位数
				{
				Password*=10;  //  密码左移一位,这样就可以依次输入密码
				Password+=KeyNum%10;  // 获取一位密码,加入到原密码,此时10为0
				Count++;
				}
			}
			LCD_ShowNum(2,1,Password,4);
			if(KeyNum==11)  // 确认
			{
				if(Password==4399)
				{
					LCD_ShowString(1,14,"OK ");
					Password=0;
					Count=0;55
					LCD_ShowNum(2,1,Password,4);
				}
				else
				{
					LCD_ShowString(1,14,"ERR");
					Password=0;
					Count=0;
					LCD_ShowNum(2,1,Password,4);
				}
			}
			if(KeyNum==12)  //取消
			{
					Password=0;
					Count=0;
					LCD_ShowString(1,14,"   ");
					LCD_ShowNum(2,1,Password,4);
			}
		}
	}
}

7-1按键控制流水灯模式

思路:编写Key获得按下按键编号,如果K1按键按下则切换流水灯方向。引入中断函数,每个1ms中断检查模式状态,根据模式状态移位控制流水灯。

复用Delay,新建Key和Timer0。

主函数:

c 复制代码
#include <REGX52.H>
#include "Timer0.h"
#include "Key.h"
#include <INTRINS.H>   // 包含_crol_/_cror_循环移位函数

unsigned char KeyNum,LEDMode;


void main()
{
	P2=0xFE;
	Timer0_Init();
	while(1)
	{
		KeyNum=Key();		//获取独立按键键码
		if(KeyNum)			//如果按键按下
		{
			if(KeyNum==1)	//如果K1按键按下
			{
				LEDMode++;	//模式切换,按1下按键是模式1,按2下是模式0,默认模式0
				if(LEDMode>=2)LEDMode=0;
			}
		}
	}
}

void Timer0_Routine() interrupt 1  //中断函数标识,含优先级
{
	static unsigned int T0Count;  //静态变量,拥有局部作用域,全局生命周期
	TL0 = 0x18;		//设置定时初值
	TH0 = 0xFC;		//设置定时初值
	T0Count++;		//T0Count计次,对中断频率进行分频
	if(T0Count>=500)//分频500次,500ms
	{
		T0Count=0;
		if(LEDMode==0)			//模式判断
			P2=_crol_(P2,1);	//LED输出(循环左移函数,即使流水灯循环左移)
		if(LEDMode==1)
			P2=_cror_(P2,1);
	}
}


	



/*    此为按键控制LED代码
void main()
{
	  Timer0_Init();
    while(1)
    {
     KeyNum=Key();
		if (KeyNum)			//如果按键按下
		{
			if (KeyNum==1) P2_1=~P2_1;
			if (KeyNum==2) P2_2=~P2_2;
			if (KeyNum==3) P2_3=~P2_3;
			if (KeyNum==4) P2_4=~P2_4;
		}

    }

}

*/




/*     此为LED1灯每隔1s亮灭
void Timer0_Routine() interrupt 1
{
	static unsigned int T0Count;
	Timer0_Init();    //教程中是用TH0=64535/256;TL0=64535%256;,我选择直接用初始化函数,效果一样
	T0Count++;
	if(T0Count>=1000)
	{
	T0Count=0;
	P2_0=~P2_0;
	}
}
*/

Key.c:

c 复制代码
#include <REGX52.H>
#include "Delay.h"

unsigned char Key()
{
  unsigned	char KeyNumber=0;
	

	
	if(P3_1==0){Delay(20);while(P3_1==0);Delay(20);KeyNumber=1;}
	if(P3_0==0){Delay(20);while(P3_0==0);Delay(20);KeyNumber=2;}
	if(P3_2==0){Delay(20);while(P3_2==0);Delay(20);KeyNumber=3;}
	if(P3_3==0){Delay(20);while(P3_3==0);Delay(20);KeyNumber=4;}


	return KeyNumber;
}

Key.h:

c 复制代码
#ifndef __KEY_H__
#define __KEY_H__

unsigned char Key();

#endif

Timer0.c:

c 复制代码
#include <REGX52.H>



void Timer0_Init()   //
{
//	TMOD=0x01;    //0000 0001
	TMOD=TMOD&0xF0;//把TMOD的低四位清零,高四位保持不变
	TMOD=TMOD|0x01;//把TMOD的最低位置1,高四位保持不变
	TF0=0;
	TR0=1;
	TH0=0xFC;
	TL0=0x18;
	ET0=1;
	EA=1;
	PT0=0;
}

Timer0.h:

c 复制代码
#ifndef __TIMER0_H__
#define __TIMER0_H__

void Timer0_Init(void);

#endif
相关推荐
QiLinkOS4 小时前
《打破“用爱发电”:一种基于 Gitee 与时间戳的开源权益分配机制探索》
c语言·数据结构·c++·科技·算法·gitee·开源
智者知已应修善业5 小时前
【51单片机用T0定时器方式1,实现0.5S的时间间隔实现第一次一个灯亮、第二次二个灯亮,直到全部灯亮,然后重复整个过程】2023-12-29
c++·经验分享·笔记·算法·51单片机
社交怪人5 小时前
【范围判断】信息学奥赛一本通C语言解法(题号2052)
c语言
智者知已应修善业5 小时前
【51单片机4位静态数码管显示1234】2023-11-14
c++·经验分享·笔记·算法·51单片机
项目題供诗5 小时前
STM32-TIM输入捕获(十四)
stm32·单片机·嵌入式硬件
cpsss06816 小时前
Freertos的Systick_Handler重定义
单片机·嵌入式硬件
国产电子元器件7 小时前
电流传感器的输出可以直接接示波器吗?
stm32·单片机·嵌入式硬件
LONGZETECH7 小时前
软硬协同+故障注入:无人机仿真维修与操控仿真底层算法逻辑拆解
大数据·c语言·算法·3d·unity·无人机
zlinear数据采集卡7 小时前
SPI Flash存储电路深度解析:从芯片选型到ZLinear采集卡的实战设计
c语言·嵌入式硬件·自动化·硬件架构