
天祥STC89C52学习笔记
STC89C52单片机名称含义
STC:表示芯片为STC公司生产的产品
8:表示该芯片为8051内核芯片
9:表示内部含 FlashE²PROM 寄存器
C:表示该器件为CMOS产品
52:5固定不变,2表示存储空间的大小(1为4KB,2为8KB,以此类推)
点亮第一个LED
#include <REGX51.H> //51单片机头文件
//主函数,程序的入口
void main() {
P1=0xFE; //P1端口,0xFE是一个十六进制数
}
进制表:1—15数字进制表
电路板上有8个LED,0xFE
十六进制值,转换为二进制是11111110
,在这个二进制中0
表示低电平,而1表示高电平,P1端口连接了8个LED灯,对应的LED如果是低电平会亮,高电平会灭。
LED闪烁
#include <REGX52.H> //51单片机头文件
#include <INTRINS.H> //用于定义_nop_函数
void Delay500ms() //@11.0592MHz
{
unsigned char i, j, k;
_nop_(); //空函数,没有任何作用,纯消耗时间
_nop_();
i = 22;
j = 3;
k = 227;
do
{
do
{
while (--k);
} while (--j);
} while (--i);
}
//主函数,程序的入口
void main()
{
while(1) //死循环
{
P1=0xFE; //二进制1111 1110
Delay500ms(); //调用Delay500ms函数(延时函数)
P1=0xFF; //二进制1111 1111
Delay500ms();
}
}
注意点:如果不加延迟或延迟太低,会导致LED闪烁过快,使肉眼无法看到闪烁(出现依旧常亮的情况)
自定义延迟
正常情况可以依靠STC-ISP工具里的软件延时计算器生成对应的延迟时长的代码,但是如果不同时间的延迟过多,那种方法会导致代码不简洁且难维护,这时候就需要一个自定义延时的函数来完成这个任务
#include <REGX52.H>
#include <INTRINS.H>
//其他头文件...
void Delay1ms(unsigned int xms); //函数声明,如果函数在主函数之前,可以不声明
void Delay1ms(unsigned int xms) //@11.0592MHz
{
unsigned char i, j;
while(xms)
{
_nop_();
_nop_();
i = 2;
j = 15;
do
{
while (--j);
} while (--i);
xms--;
}
}
//其他代码
调用方法:
Delay1ms(1000); //1000代表延迟1000毫秒,循环执行1ms函数1000次
大概原理:Delay1ms
函数中,每执行一次约1毫秒,用while
来实现循环执行,每执行一次变量xms
自减,直到变量xms
的值为零,循环结束。
注意点:注意声明函数的位置
LED流水灯
#include <REGX52.H>
#include <INTRINS.H>
void Delay500ms() //@11.0592MHz
{
unsigned char i, j, k;
_nop_();
_nop_();
i = 22;
j = 3;
k = 227;
do
{
do
{
while (--k);
} while (--j);
} while (--i);
}
void main()
{
while(1)
{
P1=0xFE;//1111 1110
Delay500ms();
P1=0xFD;//1111 1101
Delay500ms();
P1=0xFB;//1111 1011
Delay500ms();
P1=0xF7;//1111 0111
Delay500ms();
P1=0xEF;//1110 1111
Delay500ms();
P1=0xDF;//1101 1111
Delay500ms();
P1=0xBF;//1011 1111
Delay500ms();
P1=0x7F;//0111 1111
Delay500ms();
}
}
和LED闪烁代码差不多,只不过是延时后的十六进制数发生改变
独立按键控制LED亮灭
#include <REGX52.H>
#include <INTRINS.H>
sbit key_1 = P3^4; //设定声明开关
sbit led_1 = P1^1; //设定声明led
void Delay1ms(unsigned int xms) //@11.0592MHz(自定义延时函数)
{
unsigned char i, j;
while(xms)
{
_nop_();
_nop_();
i = 2;
j = 15;
do
{
while (--j);
} while (--i);
xms--;
}
}
int key()
{
if(key_1 == 0) //判断按钮是否被按下
{
Delay1ms(100); //延时100ms
if(key_1 == 0) //再判定一次是否被按下(防止短时间的点击)
{
led_1 = !led_1; //led取反,设定led的亮灭
while(!key_1); //按键取反,中断读取(防止出现led闪烁)
}
}
}
void main()
{
while(1)
{
key(); //调用key函数
}
}
按键控制LED灯位移
#include <REGX52.H>
#include <INTRINS.H>
sbit key_1 = P3^4;
sbit key_2 = P3^5;
sbit led = P1^1;
void Delay1ms(unsigned int xms) //@11.0592MHz
{
unsigned char i, j;
while(xms)
{
_nop_();
_nop_();
i = 2;
j = 15;
do
{
while (--j);
} while (--i);
xms--;
}
}
int key()
{
if(key_1 == 0)
{
Delay1ms(100);
if(key_1 == 0)
{
P1 = _crol_(P1,1); //左移1个led
while(!key_1);
}
}
if(key_2 == 0)
{
Delay1ms(100);
if(key_2 == 0)
{
P1 = _cror_(P1,1); //右移1个led
while(!key_2);
}
}
}
void main()
{
led = 0; //初始化led
while(1)
{
key();
}
}
_crol_
函数控制向左位移,_cror_
函数控制向右位移。
静态数码管显示
编码表:共阴极数码管编码表
#include <REGX52.H>
sbit w = P2^7; //定义位选
sbit d = P2^6; //定义段选
int main()
{
w=1; //开启位选
P0=0xfe; //1111 1110
w=0; //锁定位选
d=1; //开启段选
P0=0x71; //数码管显示F(对应见编码表)
d=0; //锁定段选
while(1); //停止(死循环)
}
数码管位选数组
uchar wtab[] = {0xC0, 0xFE, 0xFD, 0xFB, 0xF7, 0xEF, 0xDF}; // 0为全部,其余依次选中第1~6位数码管
数码管段选数组
uchar dtab[]={
0x3f,0x06,0x5b,0x4f,
0x66,0x6d,0x7d,0x07,
0x7f,0x6f,0x77,0x7c,
0x39,0x5e,0x79,0x71};
数组每个值的含义可参考上方的 共阴极数码管编码表
段选和位选需要记忆的数值过多时,使用数组可以方便我们的调用,一定程度上减少记忆的成本。
数组使用方法示例:
P0=tab[1]; //表示使用上面数组中第二个值,设定为数码管的值
上面演示使用的
tab
需要替换成你需要调用的数组名,如上面位选的wtab
或段选的dtab
例如
P0=wtab[1];
等于位选数组的第二个值,代码意思与P0=0xFE;
相同
本文是原创文章,采用 CC BY-NC-ND 4.0 协议,完整转载请注明来自 小白初梦