发光二极管,简称为LED,是一种常用的发光器件,具有单向导通,节能,响应速度快等特性。一般10mA,1.7v就可以使得LED导通
共阳极,高电平驱动
由AD的绘图我们知道,相同的网络标号代表相同的电气连接,再C51的A4板中,LED灯与P2口产生电气连接。在以后的编写中注意对IO口连接其他模块时不要与其正在使用的板载外设冲突
#include"reg52.h"
sbit LED0=P2^0;
void main()
{
LED0 = 0;
while(1);
}
头文件相当于一个目录的作用,可以调用在此文件中定义的函数.
为什么要分多个文件编程?
1.防止找错找崩溃
2.方便代码移植
void delay(int a)
{
while(a--);
}
void flow()
{
char i;
LED = 0x01;
delay(60000);
while(1)
{
for(i=0;i<8;i++)
{
LED=0x01<<i;//LED=_crol_(LED,1) ;
delay(50000);
}
}
}
其中delay()函数是占用CPU进行减一操作从而进行延时,之后会介绍更好的延时方式
.
LED数码管的本质即为8个发光二极管,控制方法与之前的LED相同,可用于一些简单的数字显示
与LED一样,存在共阴和共阳两种接法,在C51中动态的8位数码管是共阴型,静态数码管是共阳极。
74HC245是兼容TTL器件引脚的高速CMOS总线收发器,典型的CMOS型三态缓冲门电路,八路信号收发器,。由于单片机或CPU的数据/地址/控制总线端口都有一定的负载能力,如果负载超过其负载能力,一般应加驱动器。主要应用于大屏显示,以及其它的消费类电子产品中增加驱动。在C51中给数码管
DIR:高电平传输方向是A->B输出,低电平传输方向是B->A
74HC138的主要功能是用来控制点亮哪一位数码管,通过3位输入来控制8位输出,从而达成节约IO口的目的;
3位IO口输入就相当于3位2进制数,从而得以控制2^3=8个输出IO口
void main()
{
P0=0x79;;
while(1);
}
由原理图可以知道每个LED所对应的管脚。
如果我们想显示一个E,则需要点亮”a,f,g,e,d”,由所对应的IO口可得P0=0x79
void display()
{
int i;
for(i=0;i<8;i++)
{
switch(i)
{
case(7):
a=0;b=0;c=0; break;
case(6):
a=1;b=0;c=0; break;
case(5):
a=0;b=1;c=0; break;
case(4):
a=1;b=1;c=0; break;
case(3):
a=0;b=0;c=1; break;
case(2):
a=1;b=0;c=1; break;
case(1):
a=0;b=1;c=1; break;
case(0):
a=1;b=1;c=1; break;
}
P0=0x79;
delay(60000);
P0=0x00;
}
}
通过改变38译码器的3位断选来控制其8位位选的值,从而达成点亮不同数码管的目的。
按键是一种简单的电子开关,使用时,按下按钮可以使得开关接通,通过读取IO口的电平判断开关是否接通,由于单片机的各个引脚都接了上拉电阻,所以默认为高电平,当检测到低电平时表示引脚本按下。
由于人手的抖动可能会使得按键在断开和闭合的状态来回切换,导致检测不准,所以要对按键进行消抖处理
1.硬件消抖
通过电容充放电的时间差来规避一开始和刚结束时候的按键抖动
通过单片机的延时来规避一开始和刚结束时候的按键抖动
int keylong()
{
int sign=0,i=0;
if(k1==0)
{
delay(1000);
if(k1==0)
{
P1=0X11;
}
}
}
通过逐行逐列的扫描来判断按键是否被按下。
例如先给P17-P14高电平,P13-P10低电平,若测到P14也为低电平,则可知第四行导通。
然后再给P17-P14低电平,P13-P10高电平,若测到P13也为低电平,则可知第一列导通。
综上,S13导通。
int press()
{
int sign=0;
key=0x0f;
if(key!=0x0f)
delay(1000);
if(key!=0x0f)
{
key=0x0f;
switch(key)
{
case(0x07): sign=0;break;
case(0x0b): sign=1;break;
case(0x0d): sign=2;break;
case(0x0e): sign=3;break;
}
key=0xf0;
switch(key)
{
case(0x70): sign=sign+1;break;
case(0xb0): sign=sign+5;break;
case(0xd0): sign=sign+9;break;
case(0xe0): sign=sign+13;break;
}
}
delay(1000);
while(key==0x0f);
return sign;
}
通过函数的不同的返回值来判断按下了哪个按键``
int keylong()
{
int sign=0,i=0;
if(k1==0)
{
delay(1000);
if(k1==0)
{
for(i=0;i<50;i++)
{
if(k1)
return 1;
delay(1000);
}
while(!k1);
return 2;
}
}
return 3;
}
大约每10ms对按键进行一次扫描,看按键是否弹起,若50次扫描后按键均没有弹起,则识别为此次为长按,否则则为短按。
PWM周期:一个完整波形的时间
占空比:高电平时间占一个周期的比例
重要作用:可以将单片机只能输出0和1的数字信号变成模拟信号输出
假设高电平为5V 低电平则为0V 那么我们要输出不同的模拟电压,就要用到PWM,通过改变IO口输出的方波的占空比从而获得使用数字信号模拟成的模拟电压信号
在单片机应用的设计上,很多方案都会用到蜂鸣器,大部分都是使用蜂鸣器来做提示或报警,比如按键按下、开始工作、工作结束或是故障等等。
有源蜂鸣器:直流电压驱动,不需要利用交流信号进行驱动,只需对驱动口输出驱动电平并通过放大电路放大驱动电流就能使蜂鸣器发出声音,非常简单。
无源蜂鸣器:无震荡电路,需要输入一定频率的交流电,才可以发声。
1.改变单片机引脚输出波形的频率,就可以调整控制蜂鸣器音调,产生各种不同音色、音调的声音。
2.改变输出电平的高低电平占空比,则可以控制蜂鸣器的声音大小。
无源蜂鸣器需要一个交流信号才能发声,PWM可以模拟交流信号使蜂鸣器发声
改变PWM波周期T可以改变声音频率
改变PWM波占空比可以改变声音大小
void main()
{
u16 t = 50,T=100;
while(1)
{
beep = 0;
delay(t);
beep = 1;
delay(T-t);
}
}
89C51/52的中断系统有5个中断源 ,2个优先级,可实现二级中断嵌套 。
1)CPU同时接受到多个中断时,首先响应优先级别最高的中断请求。
2)正在进行的中断过程不能被新的同级或低优先级的中断请求所中断。
3)正在进行的低优先级中断服务,能被高优先级中断请求所中断。
1.检测对应中断源标志位
2.检测对应中断开关是否打开
3.检测总中断是否打开
4.查询是否有优先级更高或同优先级或低优先级中断正在执行
5.有更高优先级或同级,等待执行完毕进行中断,无高优先级和同级,直接进行中断,或者有低优先级,则直接进入中断,完成以后返回原低优先级中断(即嵌套中断)
1)设置外部中断触发模式
2)打开外部中断允许位
3)打开总中断允许位
4)写对应中断的服务函数
下面是一个用按键触发外部中断来使LED翻转的部分代码
void Int0Init()
{
IT0=1;//跳变沿触发方式(下降沿)
EX0=1;//打开 INT0 的中断允许。
EA=1;//打开总中断
}
void Int0() interrupt 0 //外部中断 0 的中断服务函数
{
delay(1000); //延时消抖
if(k3==0)
{
led=~led;
}
while(!k3);
}
void main()
{
Int0Init(); // 设置外部中断 0
while(1);
}
工作模式0:
定时器/计数器的工作方式0称之为13位定时/计数方式。它由TL(1/0)的低5位和TH(1/0)的8位构成13位的计数器,此时TL(1/0)的高3位未用。
工作模式1:
工作方式1是16位的定时/计数方式,将M1M0设为01即可,其它特性与工作方式0相同。
工作模式2:
工作方式1是8位的自动重装载定时/计数方式,其它特性与工作方式0相同,一般用于串口波特率的设置。
工作模式3:
T1被禁用,T0变成一个双8位计数器。
一、时钟周期
1、时钟周期也称为振荡周期,就是单片机外接晶振频率的倒数,例如12M的晶振,它的时间周期就是1/12 us,是计算机中最基本的、最小的时间单位。
2、在一个时钟周期内,CPU仅完成一个最基本的动作。对于某种单片机,若采用了1MHZ的时钟频率,则时钟周期为1us;显然,对同一种机型的计算机,时钟频率越高,计算机的工作速度就越快。常用的8051单片机的时钟范围是1.2MHz-12MHz。
二、机器周期
1、机器周期:完成一个基本操作所需要的时间称为机器周期。
2、8051系列单片机的一个机器周期由12个时钟周期组成。
三、指令周期
1、指令周期是执行一条指令所需要的时间,一般由若干个机器周期组成。指令不同,所需的机器周期数也不同。对于一些简单的的单字节指令,在取指令周期中,指令取出到指令寄存器后,立即译码执行,不再需要其它的机器周期。对于一些比较复杂的指令,则需要两个或者两个以上的机器周期。综上:如果你的晶振频率为f,那么一个时钟周期为1/f,机器周期为12*1/f。
1)设置定时器/计数器工作模式
2)设置定时器初值
2)打开定时器中断允许位
3)打开总中断允许位
4)打开定时器中断运行控制位
5)写对应中断的服务函数
下面是一个用定时器控制灯闪烁的部分代码
void Timer0Init()
{
TMOD|=0X01;//选择为定时器0,工作方式1,仅用TR0打开启动。
TH0=(65536-1000)/256;//给定时器赋初值,定时1000us
TL0=(65536-1000)%256;
ET0=1;//打开定时器0中断允许
EA=1;//打开总中断
TR0=1;//打开定时器
}
void Timer0() interrupt 1
{
TH0=(65536-1000)/256;//重装初值
TL0=(65536-1000)%256;
i++;
if(i==1000)
{
led=~led;
i=0;
}
}