C51实现LED流水灯:完美的DIY电子项目!
🐋 前言:本实验基于STC89C52RC芯片集成的51单片机,根据电路原理图点亮led灯,同时实现led灯的走马灯效果。由于51系列单片机结构大同小异,读者可根据此博客举一反三,实现所需完成的功能。
🐬 目录:
🐇 实验所选单片机及结构展示(以普中C51为例,其他大同小异),本实验所操作led模块位于图中⑤位置
🐇 实验效果
一、背景知识
🐪 单片机:是一种集成电路芯片,是采用超大规模集成电路技术把具有数据处理能力的中央处理器CPU、随机存储器RAM、只读存储器ROM等功能集成到一块硅片上构成的一个小而完善的微型计算机系统
🐪 若要使系统正常运行,必须确保单片机的最小系统稳定工作。51 单片机的最 小系统由以下几部分组成: (1)晶振电路(晶振电路提供时钟给单片机工作,犹如人的心脏)(2)复位电路 (3)电源电路
🐪 芯片引脚分类:
(1)电源引脚:上图中的VCC、GND都属于电源引脚
(2)晶振引脚:上图中的XTAL1、XTAL@都属于晶振引脚
(3)复位引脚:上图中的RST/VPD属于复位引脚
(4)通信引脚:51单片机串口功能引脚(TXD、RXD)
(5)GPIO引脚:上图中带有Px.x等字样的属于GPIO引脚,共32个,分为4组,每组8个IO
🐺P0 口是漏极开路,要使其输出高电平,必须外接上拉电阻,通常选择 4.7K~10K 阻值。
🐺P0、P1、P2 几乎都用作普通 I/O 口使用,既可作为输入,又可作为输出。
🐺 P3 口既可用作普通 I/O 口,又可作为第二功能使用,比如串口、外部中 断、计数器等。
二、环境搭建(keil4)
新建工程->选择CPU型号(Atmel(AT89C52))->给工程添加文件->配置输出文件hex
三、点亮一个led灯
💌 3.1 查看电路原理图
通过观察开发板的线路连接图可以观察到:
☁️ 1.D1阴极连接到单片机的P2.0引脚(线编号相同表示连接在一起P20)、D2连接到单片机P2.1引脚………
☁️ 2.当单片机P2.0输出低电平0,则与电源连接的D1形成通路,D1灯亮。P2.X输出0,其他灯亦然。
因此,要想使得D1等亮,需要编程并将程序烧录到单片机中,使得P2.0端口输出低电平,
💌 3.2 编写代码并烧录
☁️ 3.2.1 导入reg52.h头文件,预编译时会将头文件中的内容加载到文件中,reg52.h头文件中内容如下:
#ifndef __REG52_H__
#define __REG52_H__
/* BYTE Registers */
sfr P0 = 0x80;
sfr P1 = 0x90;
sfr P2 = 0xA0;
sfr P3 = 0xB0;
sfr PSW = 0xD0;
sfr ACC = 0xE0;
sfr B = 0xF0;
sfr SP = 0x81;
sfr DPL = 0x82;
sfr DPH = 0x83;
sfr PCON = 0x87;
sfr TCON = 0x88;
sfr TMOD = 0x89;
sfr TL0 = 0x8A;
sfr TL1 = 0x8B;
sfr TH0 = 0x8C;
sfr TH1 = 0x8D;
sfr IE = 0xA8;
sfr IP = 0xB8;
sfr SCON = 0x98;
sfr SBUF = 0x99;
/* 8052 Extensions */
sfr T2CON = 0xC8;
sfr RCAP2L = 0xCA;
sfr RCAP2H = 0xCB;
sfr TL2 = 0xCC;
sfr TH2 = 0xCD;
/* BIT Registers */
/* PSW */
sbit CY = PSW^7;
sbit AC = PSW^6;
sbit F0 = PSW^5;
sbit RS1 = PSW^4;
sbit RS0 = PSW^3;
sbit OV = PSW^2;
sbit P = PSW^0; //8052 only
/* TCON */
sbit TF1 = TCON^7;
sbit TR1 = TCON^6;
sbit TF0 = TCON^5;
sbit TR0 = TCON^4;
sbit IE1 = TCON^3;
sbit IT1 = TCON^2;
sbit IE0 = TCON^1;
sbit IT0 = TCON^0;
/* IE */
sbit EA = IE^7;
sbit ET2 = IE^5; //8052 only
sbit ES = IE^4;
sbit ET1 = IE^3;
sbit EX1 = IE^2;
sbit ET0 = IE^1;
sbit EX0 = IE^0;
/* IP */
sbit PT2 = IP^5;
sbit PS = IP^4;
sbit PT1 = IP^3;
sbit PX1 = IP^2;
sbit PT0 = IP^1;
sbit PX0 = IP^0;
/* P3 */
sbit RD = P3^7;
sbit WR = P3^6;
sbit T1 = P3^5;
sbit T0 = P3^4;
sbit INT1 = P3^3;
sbit INT0 = P3^2;
sbit TXD = P3^1;
sbit RXD = P3^0;
/* SCON */
sbit SM0 = SCON^7;
sbit SM1 = SCON^6;
sbit SM2 = SCON^5;
sbit REN = SCON^4;
sbit TB8 = SCON^3;
sbit RB8 = SCON^2;
sbit TI = SCON^1;
sbit RI = SCON^0;
/* P1 */
sbit T2EX = P1^1; // 8052 only
sbit T2 = P1^0; // 8052 only
/* T2CON */
sbit TF2 = T2CON^7;
sbit EXF2 = T2CON^6;
sbit RCLK = T2CON^5;
sbit TCLK = T2CON^4;
sbit EXEN2 = T2CON^3;
sbit TR2 = T2CON^2;
sbit C_T2 = T2CON^1;
sbit CP_RL2 = T2CON^0;
#endif
从上面代码中可以看到,该头文件中定义了 52 系列单片机内部所有的功能 寄存器。其中sbit
、sfr
为C51扩充数据类型。C51扩充数据类型主要如下:
ssfr P2 = 0xA0;
声明一个8位的特殊功能寄存器,它的起始地址为0xA0
sbit LED1 = P2^0
P2是一个8位寄存器,P2^0表示这个8位寄存器的最低位。该语句的功能就是将P2寄存器的最低位声明为LED1,以后若是要对P2寄存器最低位操作,则可直接操作LED1
☁️ 3.2.2 编写程序
使用while(1)死循环,使得程序一直运行,这样能保证led灯一直亮着。
main.c
#include "reg52.h"
sbit LED1=P2^0; //将P2.0管脚定义为LED1
void main()
{
LED1=0; //将寄存器P2的最低位赋低电平
while(1)
{
}
}
四、实现led灯闪烁
📟 当单片机P2.0引脚输出高电平时,led等两侧无电位差,因此没有电流通过,led灯熄灭。实现程序如下:
#include "reg52.h"
typedef unsigned int u16; //对系统默认数据类型进行重定义
typedef unsigned char u8;
sbit LED1=P2^0; //将P2.0管脚定义为LED1
/*******************************************************************************
*函数名 : delay_10us
* 函数功能 : 延时函数,ten_us=1时,大约延时10us
*******************************************************************************/
void delay_10us(u16 ten_us)
{
while(ten_us--);
}
void main()
{
while(1)
{
LED1=0; //点亮
delay_10us(50000); //点亮500ms
LED1=1; //熄灭
delay_10us(50000);
}
}
五、实现led流水灯
🐙 本实验通过两种方式实现led走马灯效果,一种是通过循环+移位完成对P2寄存器各位轮流赋低电平。第二种是使用intrins,h头文件中定义的外部方法 _crol_
与_cror_
分别实现按位的移动
#include "reg52.h"
#include "intrins.h"
typedef unsigned int u16; //对系统默认数据类型进行重定义
typedef unsigned char u8;
#define LED_PORT P2 //使用宏定义P2端口寄存器
/*******************************************************************************
* 函数名: : delay_10us
* 函数功能 : 延时函数,ten_us=1时,大约延时10us
*******************************************************************************/
void delay_10us(u16 ten_us)
{
while(ten_us--);
}
void main()
{
u8 i=0;
LED_PORT=~0x01; //给P2寄存器各位赋值,即给寄存器最低位赋低电平
delay_10us(50000);
while(1)
{
//方式一:通过移位+循环实现流水灯
for(i=0;i<8;i++)
{
LED_PORT=~(0x01<<i); //给P2寄存器最低位到最高位依次赋低电平,循环8次后继续循环
delay_10us(50000);
}
//方式2:使用循环+_crol_或_cror_函数实现流水灯
// for(i=0;i<7;i++) //将led左移一位
// {
// LED_PORT=_crol_(LED_PORT,1);
// delay_10us(50000);
// }
// for(i=0;i<7;i++) //将led右移一位
// {
// LED_PORT=_cror_(LED_PORT,1);
// delay_10us(50000);
// }
}
}