您的位置:首页 > 其它

十天学会单片机Day1点亮数码管(数码管、外部中断、定时器中断)

2016-03-30 20:59 645 查看
1.引脚定义

P3口各引脚第二功能定义

标号引脚第二功能说明
P3.010RXD串行输入口
P3.111TXD串行输出口
P3.212INT0(上划线)外部中断0
P3.313INT1(上划线)外部中断1
P3.414T0定时器/计数器0 外部输入端
P3.515T1定时器/计数器1 外部输入端
P3.616WR(上划线)外部数据存储器写脉冲
P3.717RD(上划线)外部数据存储器读脉冲
XTAL1(19脚) XTAL2(18脚):外接时钟引脚。XTAL1为片内震荡电路的输入端,XTAL2为片内震荡电路的输出端。

              8051时钟两种方式:①片内时钟震荡,两引脚外接晶振和震荡电容。

                        ②外部时钟方式,XTAL1接地,外部时钟信号从XTAL2脚输入。

RST(9脚):单片机复位引脚。当输入连续两个机器周期以上高电平时为有效。复位后程序计数器PC=0000H,读取第一条指令码。即从头开始执行程序。

ALE(30脚):在没有外部存储器期间,ALE以1/6振荡周期频率输出(6分频),当访问外部存储器时,以1/12振荡周期输出(12分频)。

EA(上划线)(31脚):接高电平时,单片机读取内部程序存储器。接低电平,单片机直接读取外部(ROM)。(板子上直接接高)

P0口(39~32脚):双向8位三态I/O口,早期51芯片内部无上拉电阻,为高阻态,需外部接上拉电阻。

P1口(1~8脚):准双向8位I/O口,之所以称它为"准双向",是因为改口作为输入使用前,要先向该口进行写1操作,有个"准"备过程,称为准双向口。

P2口(21~28脚):准双向8位I/O口。

P3口(10~17脚):准双向8位I/O口。

2.复位电路



按键按下,RST=5V,按键时长大于两个时钟周期,则复位。

上电自动复位:上电瞬间,电容充电,之后电容放电,τ = √(RC) >两个时钟周期 ,自动复位。

3.晶振



非极性电容,上电帮助晶振起振。12M左右 30pf,6M左右20pf。具体参考厂家提供的晶振要求负载电容选值。(Day0有详细介绍)

4.数码管





开发板中用的为共阴极。即WE选信号给低,则导通(WE提供一个GND作用)。

利用74HC573锁存器的锁存功能。(详细见Day0 ⑤锁存器),先控制位选信号P2.7口高,选定哪个数码管,后P2.7低锁存。再控制段选信号P2.6高,亮什么数字后,P2.6低锁存。

//共阴极数码管静态显示1
#include <reg52.h>
sbit DUAN = P2^6;
sbit WE = P2^7;

int main()
{
WE = 1;        //打开WE选信号
P0 = 0xDF;    //选WE6的数码管,给低,其余给高
WE = 0;        //关闭WE选信号
DUAN = 1;    //打开段选信号
P0 = 0x06;    //亮1,即bc接高,其余低
DUAN = 0;    //关闭段选信号

return 0;
}



超级亮,但是别的数码管有淡淡的光,以下进行改进

//共阴极数码管静态显示1      防干扰
#include <reg52.h>
sbit DUAN = P2^6;
sbit WE = P2^7;

int main()
{
WE = 1;
P0 = 0xDF;
WE = 0;
P0 = 0xFF;      //关闭所有显示,防止打开段选后发生混乱
DUAN = 1;
P0 = 0x06;
DUAN = 0;
P0 = 0xFF;       //关闭所有显示,防止打开位选后发生混乱

return 0;
}




接下来是数码管的动态扫描,其实是一个个显示,由于频率太快,人眼无法识别,达到目的。

//共阴极数码管动态显示
#include <reg52.h>
sbit DUAN = P2^6;
sbit WE = P2^7;
unsigned char DuanTable[] = {0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,
0x7F,0x6F,0x77,0x7C,0x39,0x5E,0x79,0x71};
unsigned char WeTable[]    = {0xFE,0xFD,0xFB,0xF7,0xEF,0xDF};
void delayms(unsigned int n);
int main()
{
unsigned int i = 0;
while(1)
{
for(i = 0; i < 6; i++) {
DUAN = 1;
P0 =  DuanTable[i+1];
DUAN = 0;
P0 = 0xFF;
WE = 1;
P0 = WeTable[i];
WE = 0;
P0 = 0xFF;
delayms(1);
}
}
return 0;
}

void delayms(unsigned int n)   //误差 -0.651041666667us
{
unsigned char a,b;
unsigned int i;
for(i = 0; i < n; i++) {
for(b=4;b>0;b--)
for(a=113;a>0;a--);
}
}




5.中断

52单片机共有6个中断源

INT0:外部中断0.由P3.2端口线引入,低电平或下降沿引起。

INT1:外部中断1.由P3.3端口线引入,低电平或下降沿引起。

T0:定时器/计数器0中断,由T0计数器计满回零引起。

T1:定时器/计数器1中断,由T1计数器计满回零引起。

T2:定时器/计数器2中断,由T2计数器计满回零引起。

TI/RI:串行口中断,串行端口完成一帧字符发送/接收后引起。

52单片机中断级别

中断源默认中断级别序号(C语言用)入口地址(汇编语言用)
INT0 外部中断0最高00003H
T0 定时器/计数器0中断第21000BH
INT1 外部中断1第320013H
T1 定时器/计数器1中断第43001BH
TI/RI 串行口中断第540023H
T2 定时器/计数器2中断最低5002BH
中断允许寄存器IE  (1为开 0为关)

位序号
D7
D6
D5
D4
D3
D2
D1
D0
说明
全局中断位
无效位
定时/计数2
(52单片机)
串行口中断
定时/计数1
外部中断1
定时/计数0
外部中断0
位符号(写程序时可直接引用)
EA
--
ET2
ES
ET1
EX1
ET0
EX0
位地址
AFH
--
ADH
ACH
ABH
AAH
A9H
A8H
单片机复位时全部清零。可进行位寻址,即可对该寄存器每一位进行单独操作。
只有打开全局开关,其它各位的开关才可以开启。
每个位开关赋值为1则开,赋值为0则关。
使用方法
  ①整体赋值:IE=0x81;(开启全局中断,打开外部中断0)
  ②单独赋值:EA=1;EX0=1;(开启全局中断,打开外部中断0)

中断优先级寄存器IP

位序号D7D6D5D4D3D2D1D0
说明无效位无效位无效位串行口中断优先级控制位定时器/计数器1中断优先级控制位外部中断1中断优先级控制位定时器/计数器0中断优先级控制位外部中断0中断优先级控制位
位符号------PSPT1PX1PT0PX0
位地址------BCHBBHBAHB9HB8H
单片机复位时全部清零。可进行位寻址。
每个位赋值为1,将对应中断定义为高优先级中断;赋值0,则定义为低优先级中断。
在没有设置中断优先级情况下,按照默认中断级别响应中断,设置后,则按设置顺序确定相应的先后顺序。

定时器/计数器工作方式寄存器TMOD

位序号D7D6D5D4D3D2D1D0
位符号GATEC/T(上划线)M1M0GATEC/T(上划线)M1M0
定时器1定时器0
单片机复位时全部清零。不可进行位寻址。

GATE:

GATE = 0 定时器/计数器启动与停止仅受TCON寄存器中TRX(X=0,1)来控制。

  当TR0=1,启动定时器T0。
  当TR1=1,启动定时器T1。
GATE = 1 定时器/计数器启动与停止由TCON寄存器中TRX(X=0,1)和外部中断引脚(INT0 或 INT1)上的电平状态共同控制。

  当INT0引脚为高电平时且TR0置位,TR0=1;启动定时器T0。
  当INT1引脚为高电平时且TR1置位,TR1=1;启动定时器T1。

C/T(上划线):定时器模式和计数器模式选择位

  C/T=0时为定时模式: 加1计数器对脉冲f进行计数,每来一个脉冲,计数器加1,直到计时器TFx满溢出。

  C/T=1时为计数模式: 加1计数器对来自输入引脚T0(P3.4)和T1(P3.5)的外信号脉冲进行计数,每来一个脉冲,计数器加1,直到计时器TFx满溢出。

M1M0:方式选择功能

定时器/计数器的4种工作方式

M1
M0
工作方式
功能说明
0
0
方式0
13位定时器/计数器
0
1
方式1
16位定时器/计数器
1
0
方式2
自动重载8位定时器/计数器
1
1
方式3
T0分为2个8位独立计数器,T1无方式3
控制寄存器TCON

位序号D7D6D5D4D3D2D1D0
位符号TF1TR1TF0TR0IE1IT1IE0IT0
位地址8FH8EH8DH8CH8BH8AH89H88H
定时器/计数器控制外部中断控制
单片机复位时全部清零。可进行位寻址。
TF1:定时器1溢出标志位。当定时器1计满溢出时,由硬件使TF1置“1”,并且申请中断。进入中断服务程序后,由硬件自动清“0”,在查询方式下用软件清“0”。
TR1:定时器1运行控制位。由软件清“0”关闭定时器1。当GATE=1,且/INT1为高电平时,TR1置“1”启动定时器1;当GATE=0,TR1置“1”启动定时器1。
TF0:定时器0溢出标志。其功能及操作情况同TF1。
TR0:定时器0运行控制位。其功能及操作情况同TR1。
IE1:外部中断1请求标志位。
IT1:外部中断1触发方式选择位。当IT1=0,为低电平触发方式;当IT1=1,为下降沿触发方式。
IE0:外部中断0请求标志位。
IT0:外部中断0触发方式选择位。 当IT0=0,为低电平触发方式;当IT0=1,为下降沿触发方式。

中断响应条件
  ①CPU开中断(EA=1)
  ②此中断允许位为1
  ③中断源有中断请求

中断服务程序格式
void 函数名() interrupt 中断号 using 工作组
{
}

//using 工作组 指这个中断函数使用单片机内存中4组工作寄存器中哪一组,C51编译器在编译程序时会自动分配工作组,因此最后这句话可以省略不写。
//中断号见前 52单片机中断级别 表格

外部中断
涉及寄存器IE TCON (IP)

//外部中断0 低电平触发
#include <reg52.h>
sbit DUAN = P2^6;
sbit WE = P2^7;
unsigned char DuanTable[] = {0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,
0x7F,0x6F,0x77,0x7C,0x39,0x5E,0x79,0x71};
unsigned char WeTable[]    = {0xFE,0xFD,0xFB,0xF7,0xEF,0xDF};
void delayms(unsigned int n);
int main()
{
unsigned int i = 0;
EA = 1;//打开总中断
EX0 = 1;//打开外部中断0中断
//IT0 = 0; 电平触发 由于TCON在复位时自动清零,所以可以省略
while(1)
{
for(i = 0; i < 6; i++) {
DUAN = 1;
P0 =  DuanTable[i+1];
DUAN = 0;
P0 = 0xFF;
WE = 1;
P0 = WeTable[i];
WE = 0;
P0 = 0xFF;
delayms(1);
}
}
return 0;
}

void delayms(unsigned int n)   //误差 -0.651041666667us
{
unsigned char a,b;
unsigned int i;
for(i = 0; i < n; i++) {
for(b=4;b>0;b--)
for(a=113;a>0;a--);
}
}

void exter0() interrupt 0    //中断函数无需在main前声明     中断全部显示0 P3,2口INT0
{
int i = 0;
for(i = 0; i < 6; i++) {
DUAN = 1;
P0 =  DuanTable[0];
DUAN = 0;
P0 = 0xFF;
WE = 1;
P0 = WeTable[i];
WE = 0;
P0 = 0xFF;
delayms(1);
}
}



中断ing

定时器中断
[b]涉及寄存器IE TMOF TCON (IP) THX TLX (x=0,1)[/b]
定时器中断程序初始化
  1.对TMOD赋值,以确定T0和T1的工作方式
  2.计算初值,并将初值写入TH0、TL0 或 TH1、TL1
  3.中断方式时,则对IE赋值,开发中断
  4.使TR0或TR1置位,启动定时器/计数器定时或计数(TCON)

定时器初值问题:
  假设时钟频率为12MHZ,12个时钟周期为一个机器周期,那么此时机器周期为1us。计满TH0、TL0需要2^16-1个数,再来一个脉冲计数器溢出,向CPU请求中断。例如要定时50ms
要给TH0和TL0装初值,在初值基础上计数50000后溢出,中断。若要定时1s,则产生20次50ms中断即可。
结论:用定时器方式1是,机器周期为Tcy,定时器产生一次中断时间为t,那么需要计数的个数N= t/Tcy.
  THX = (65535 -N) / 256
  TLX = (65535 - N) % 256

//定时器0中断 方式1  中断显示0
#include <reg52.h>
sbit DUAN = P2^6;
sbit WE = P2^7;
unsigned char DuanTable[] = {0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,
0x7F,0x6F,0x77,0x7C,0x39,0x5E,0x79,0x71};
unsigned char WeTable[]    = {0xFE,0xFD,0xFB,0xF7,0xEF,0xDF};
unsigned int t = 0;
void delayms(unsigned int n);
int main()
{
unsigned int i = 0;
TMOD = 0x01; //TMOD不能位寻址 定时器0工作方式1
TH0 = (65535 - 50000) / 256;
TL0 = (65535 - 50000) % 256;
EA = 1;//打开总中断
ET0 = 1;//打开定时器0中断
TR0 = 1;
while(1)
{
for(i = 0; i < 6; i++) {
DUAN = 1;
P0 =  DuanTable[i+1];
DUAN = 0;
P0 = 0xFF;
WE = 1;
P0 = WeTable[i];
WE = 0;
P0 = 0xFF;
delayms(1);
}
if(t >= 100) {
for(i = 0; i < 6; i++) {
DUAN = 1;
P0 =  DuanTable[0];
DUAN = 0;
P0 = 0xFF;
WE = 1;
P0 = WeTable[i];
WE = 0;
P0 = 0xFF;
delayms(1);
}
if(t >= 250)
t = 0;
}
}
return 0;
}

void delayms(unsigned int n)   //误差 -0.651041666667us
{
unsigned char a,b;
unsigned int i;
for(i = 0; i < n; i++) {
for(b=4;b>0;b--)
for(a=113;a>0;a--);
}
}

void T0_Time() interrupt 1    //中断函数无需在main前声明     中断全部显示0 P3,2口INT0
{
TH0 = (65535 - 50000) / 256;
TL0 = (65535 - 50000) % 256;
t++;
}


practice:

59s循环计时。

//60s倒计时 定时器0中断+数码管显示
#include <reg52.h>
sbit DUAN = P2^6;
sbit WE = P2^7;
unsigned char DuanTable[] = {0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,
0x7F,0x6F,0x77,0x7C,0x39,0x5E,0x79,0x71};
unsigned char WeTable[]    = {0xFE,0xFD,0xFB,0xF7,0xEF,0xDF};
unsigned int t = 0, num = 59;
void delayms(unsigned int n);
int main()
{
unsigned int i = 0;
TMOD = 0x01; //TMOD不能位寻址 定时器0工作方式1
TH0 = (65535 - 50000) / 256;
TL0 = (65535 - 50000) % 256;
EA = 1;//打开总中断
ET0 = 1;//打开定时器0中断
TR0 = 1;
while(1)
{
//十位数
DUAN = 1;
P0 =  DuanTable[num/10];
DUAN = 0;
P0 = 0xFF;
WE = 1;
P0 = WeTable[4];
WE = 0;
P0 = 0xFF;
delayms(5);

//个位数
DUAN = 1;
P0 =  DuanTable[num%10];
DUAN = 0;
P0 = 0xFF;
WE = 1;
P0 = WeTable[5];
WE = 0;
P0 = 0xFF;
delayms(1);

}
return 0;
}

void delayms(unsigned int n)   //误差 -0.651041666667us
{
unsigned char a,b;
unsigned int i;
for(i = 0; i < n; i++) {
for(b=4;b>0;b--)
for(a=113;a>0;a--);
}
}

void T0_Time() interrupt 1    //中断函数无需在main前声明     中断全部显示0 P3,2口INT0
{
TH0 = (65535 - 50000) / 256;
TL0 = (65535 - 50000) % 256;
t++;
if(t >= 20) {
num--;
t = 0;
}

if(num == 0)
num = 59;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: