(1)点亮第一颗LED灯
LED原理图
*如果直接通过VCC流过LED,不加电阻的话,可能会将LED击穿
流水灯的实现
方法一:
#include"reg52.h"
sbit led1 =P2^0;
sbit led2 =P2^1;
sbit led3 =P2^2;
sbit led4 =P2^3;
sbit led5 =P2^4;
sbit led6 =P2^5;
sbit led7 =P2^6;
sbit led8 =P2^7;
void delay(long num)
{
long i = num * 1000;
while(i--);
}
void main()
{
while(1)
{
led1 = 0;
delay(5);
led2 = 0;
led1 = 1;
delay(5);
led3 = 0;
led2 = 1;
delay(5);
led4 = 0;
led3 = 1;
delay(5);
led5 = 0;
led4 = 1;
delay(5);
led6 = 0;
led5 = 1;
delay(5);
led7 = 0;
led6 = 1;
delay(5);
led8 = 0;
led7 = 1;
delay(5);
led8 = 1;
delay(5);
}
}
方法二:因为C52的寄存器是可位寻址的,所以可以用16进制直接调用整个P2口
*相关知识:
- PO = 0XFE;也就是二进制的1111 1110,对不对?0x01取反等价于~0X01也就是0XFE,&是什么作用呢?让某一位清零,也就是最低位清零,而其他位保持不变,|呢?让某一位置1,其他保持不变,但是为什么要这样用呢?以后如果你有机会同时用到了两个定时器(特指51),比如说TMOD这个寄存器,他是不能进行单独的位操作的,一次必须操作整个8位数据,如果你只用到了定时器0或者是定时器1,那么你设置TMOD = 0X01;也对,但是已经影响到了定时器1的设置了,定时器1不用还好,如果用的话,就容易出错,所以你应该这样写TMOD &= 0XF0;即低四位清零,高四位不变,TMOD |= 0X01;最低位置1,高7位不改变,这就达到了互不干扰的目的。
- 电源为VCC, Vpd是备用电源,当主电源Vcc发生故障,降低到某一固定的低电平时,Vpd自动接入RST端,提供备用电源,以保证片内ROM不丢失,从而使得单片机复位后能正常工作
(2)通过按钮控制LED的亮与按
demo1:按下时亮,松开时暗
#include"reg52.h"
typedef unsigned int u16;
typedef unsigned char u8;
sbit led = P2^0;
sbit button = P3^1;
void delay(u16 num)
{
while(num--);
}
void method()
{
//如果按钮按下了,则点亮
if(button == 0)
{
//消抖,100us
delay(1000);
if(button == 0)
{
led = 0;
}
while(!button);//检测按键是否松开
}else
{
delay(1000);
if(button == 1)
{
led = 1;
}
}
}
void main()
{
while(1)
{
method();
}
}
demo2:通过单击调整亮暗
#include"reg52.h"
typedef unsigned int u16;
typedef unsigned char u8;
sbit led = P2^0;
sbit button = P3^1;
u16 count = 0;
void delay(u16 num)
{
while(num--);
}
void method()
{
//如果按钮按下了,则点亮
if(button == 0)
{
//消抖,100us
delay(1000);
if(count % 2 ==0)
{
led = 0;
}else
{
led = 1;
}
while(!button);//检测按键是否松开
count++;
}
}
void main()
{
while(1)
{
method();
}
}
代码优化:led = ~led;
(3)蜂鸣器的使用
蜂鸣器的端口:P2^5 P2^6;
原理图
demo:
#include"reg52.h"
typedef unsigned int u16;
typedef unsigned char u8;
sbit beep = P2^5;
sbit button = P3^1;
void delay(u16 num)
{
while(num--);
}
void main()
{
while(1)
{
if(button == 0)
{
delay(1000);
if(button ==0)
{
beep = ~beep;
}
}
}
}
(4)数码管的使用
数组集合如下:
u8 code arr[17] = {0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71,0x00}
*数组要保存到CODE里面
*位选和段选:位选是选择哪一位,段选是选择那一位数字中的哪一个片段(a b c d e f g )
*动态显示的原理,让数码管快速的显示单个数字
demo:显示1和2
demo:
#include"reg52.h"
typedef unsigned int u16;
typedef unsigned char u8;
/*
实现数码管显示数字
12345678
*/
//定义138译码器的引脚
sbit LSA = P2^2;
sbit LSB = P2^3;
sbit LSC = P2^4;
u8 code arr[17]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71,0x00};
//延时函数
void delay(u16 num)
{
while(num--);
}
void main()
{
while(1)
{
LSA = 1;
LSB = 1;
LSC = 1;
P0 = arr[1];
delay(100);
P0 = 0x00;
LSA = 0;
P0 = arr[2];
delay(100);
P0 = 0x00;
}
}
*要注意消隐(消除阴影)
delay(100);
P0 = 0x00;
(5)LCD1602
这里的LCD底层已经被封装好了,我们直接调用方法就可以了,想要源代码的点击下列文章:
LCD1602代码封装
DEMO:显示QQ帐号
#include"reg52.h"
#include"LCD1602.H"
void main()
{
LCD_init();
while(1)
{
LCD_ShowNum(1,1,28701,5);
LCD_ShowNum(1,6,7217,4);
}
}
(6)定时器
时钟周期:单片机时序中的最小单位,具体的计算方法是时钟源分之一
机器周期:单片机完成一个操作的最短时间
*一个机器周期=12个时钟周期
定时器:打开定时器后,定时器“存储寄存器”的值经过一个机器周期自动加1,也就是说机器周期是定时器的计数周期
定时器的组成:控制寄存器和工作模式寄存器
定时器/计数器控制寄存器TCON time count ON的功能
*寄存器控制电路,尝试把它当成处理器\
定时器/计数器工作模式寄存器TMOD的功能
demo:1s记录一次
#include"reg52.h"
sbit led = P2^0;
sbit led1 = P2^1;
void delay(unsigned int num)
{
while(num--);
}
//定义定时器0
void Timer0_init()
{
//TMOD = TMOD&0xf0;//高四位保持不变,低四位清零
TMOD |= 0x01; //工作模式寄存器0000 0001:表示16位定时器,表示高四位保持不变,最低位置为0001
TF0 = 0; //中断溢出标志位,溢出时TF0变成1
TR0 = 1; //运行控制位,TR0 = 1的时候开始计数
//初始值设定,如果设定64535
//则计数1000ms相应一次,也就是1ms
TH0 = 64535/256; //寄存机由高低两个拼接而成,因此要分成两部分计数
TL0 = 64535%256; //低8位
ET0 = 1;
EA = 1;
PT0 = 0;
}
void main()
{
Timer0_init();
while(1)
{
}
}
unsigned int count = 0;
//中断服务程序
void Time0_Routine() interrupt 1
{
//寄存器重新赋值,因为1ms后已经溢出了
TH0 = 64535/256;
TL0 = 64535%256;
count++;
if(count >= 1000)
{
led = ~led;
count = 0;
}
}
*注意TMOD的配置
*可以在ISP中直接配置定时器,但是AUXR代码要删去,因为默认是12T模式
再加上中断:
ET0 = 0;
EA = 1;
PT0 = 0;