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

摘要:
1.引脚定义P3端口上每个引脚的第二个功能定义标签引脚第二个函数描述P3.010RXD串行输入端口P3.111TXD串行输出端口P3.212INT0(上标)外部中断0P3.313INT1(上标)脉冲P3.717RD(上标)外部数据存储器读取脉冲XTAL1(19针)XTAL2(

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.复位电路

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

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

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

3.晶振

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

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

4.数码管

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

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

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

 1 //共阴极数码管静态显示1
 2 #include <reg52.h>
 3 sbit DUAN = P2^6;
 4 sbit WE = P2^7;
 5 
 6 int main()
 7 {
 8     WE = 1;        //打开WE选信号
 9     P0 = 0xDF;    //选WE6的数码管,给低,其余给高
10     WE = 0;        //关闭WE选信号
11     DUAN = 1;    //打开段选信号
12     P0 = 0x06;    //亮1,即bc接高,其余低
13     DUAN = 0;    //关闭段选信号
14 
15     return 0;
16 }

十天学会单片机Day1点亮数码管(数码管、外部中断、定时器中断)第5张超级亮,但是别的数码管有淡淡的光,以下进行改进

 1 //共阴极数码管静态显示1      防干扰
 2 #include <reg52.h>
 3 sbit DUAN = P2^6;
 4 sbit WE = P2^7;
 5 
 6 int main()
 7 {
 8     WE = 1;
 9     P0 = 0xDF;
10     WE = 0;
11     P0 = 0xFF;      //关闭所有显示,防止打开段选后发生混乱
12     DUAN = 1;
13     P0 = 0x06;
14     DUAN = 0;
15     P0 = 0xFF;       //关闭所有显示,防止打开位选后发生混乱
16 
17     return 0;
18 }

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

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

 1  //共阴极数码管动态显示
 2 #include <reg52.h>
 3 sbit DUAN = P2^6;
 4 sbit WE = P2^7;
 5 unsigned char DuanTable[] = {0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,
 6                               0x7F,0x6F,0x77,0x7C,0x39,0x5E,0x79,0x71};
 7 unsigned char WeTable[]    = {0xFE,0xFD,0xFB,0xF7,0xEF,0xDF};
 8 void delayms(unsigned int n);
 9 int main()
10 {
11     unsigned int i = 0;
12     while(1)
13     {
14         for(i = 0; i < 6; i++) {
15             DUAN = 1;
16             P0 =  DuanTable[i+1];
17             DUAN = 0;
18             P0 = 0xFF;
19             WE = 1;
20             P0 = WeTable[i];
21             WE = 0;
22             P0 = 0xFF;
23             delayms(1);
24         }
25     }
26     return 0;
27 }
28 
29 void delayms(unsigned int n)   //误差 -0.651041666667us
30 {
31     unsigned char a,b;
32     unsigned int i;
33     for(i = 0; i < n; i++) {
34         for(b=4;b>0;b--)
35             for(a=113;a>0;a--);
36     }
37 }

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

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)
 1 //外部中断0 低电平触发
 2 #include <reg52.h>
 3 sbit DUAN = P2^6;
 4 sbit WE = P2^7;
 5 unsigned char DuanTable[] = {0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,
 6                               0x7F,0x6F,0x77,0x7C,0x39,0x5E,0x79,0x71};
 7 unsigned char WeTable[]    = {0xFE,0xFD,0xFB,0xF7,0xEF,0xDF};
 8 void delayms(unsigned int n);
 9 int main()
10 {
11     unsigned int i = 0;
12     EA = 1;//打开总中断
13     EX0 = 1;//打开外部中断0中断
14     //IT0 = 0; 电平触发 由于TCON在复位时自动清零,所以可以省略
15     while(1)
16     {
17         for(i = 0; i < 6; i++) {
18             DUAN = 1;
19             P0 =  DuanTable[i+1];
20             DUAN = 0;
21             P0 = 0xFF;
22             WE = 1;
23             P0 = WeTable[i];
24             WE = 0;
25             P0 = 0xFF;
26             delayms(1);
27         }
28     }
29     return 0;
30 }
31 
32 void delayms(unsigned int n)   //误差 -0.651041666667us
33 {
34     unsigned char a,b;
35     unsigned int i;
36     for(i = 0; i < n; i++) {
37         for(b=4;b>0;b--)
38             for(a=113;a>0;a--);
39     }
40 }
41 
42 void exter0() interrupt 0    //中断函数无需在main前声明     中断全部显示0 P3,2口INT0
43 {
44     int i = 0;
45     for(i = 0; i < 6; i++) {
46         DUAN = 1;
47         P0 =  DuanTable[0];
48         DUAN = 0;
49         P0 = 0xFF;
50         WE = 1;
51         P0 = WeTable[i];
52         WE = 0;
53         P0 = 0xFF;
54         delayms(1);
55     }
56 }

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

 
定时器中断
涉及寄存器IE TMOF TCON (IP) THX TLX (x=0,1)
定时器中断程序初始化
  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循环计时。

 1 //60s倒计时 定时器0中断+数码管显示
 2 #include <reg52.h>
 3 sbit DUAN = P2^6;
 4 sbit WE = P2^7;
 5 unsigned char DuanTable[] = {0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,
 6                               0x7F,0x6F,0x77,0x7C,0x39,0x5E,0x79,0x71};
 7 unsigned char WeTable[]    = {0xFE,0xFD,0xFB,0xF7,0xEF,0xDF};
 8 unsigned int t = 0, num = 59;
 9 void delayms(unsigned int n);
10 int main()
11 {
12     unsigned int i = 0;
13     TMOD = 0x01; //TMOD不能位寻址 定时器0工作方式1
14     TH0 = (65535 - 50000) / 256;
15     TL0 = (65535 - 50000) % 256;
16     EA = 1;//打开总中断
17     ET0 = 1;//打开定时器0中断
18     TR0 = 1;
19     while(1)
20     {
21         //十位数
22         DUAN = 1;
23         P0 =  DuanTable[num/10];
24         DUAN = 0;
25         P0 = 0xFF;
26         WE = 1;
27         P0 = WeTable[4];
28         WE = 0;
29         P0 = 0xFF;
30         delayms(5);
31     
32         //个位数
33         DUAN = 1;
34         P0 =  DuanTable[num%10];
35         DUAN = 0;
36         P0 = 0xFF;
37         WE = 1;
38         P0 = WeTable[5];
39         WE = 0;
40         P0 = 0xFF;
41         delayms(1);
42         
43     }
44     return 0;
45 }
46 
47 void delayms(unsigned int n)   //误差 -0.651041666667us
48 {
49     unsigned char a,b;
50     unsigned int i;
51     for(i = 0; i < n; i++) {
52         for(b=4;b>0;b--)
53             for(a=113;a>0;a--);
54     }
55 }
56 
57 void T0_Time() interrupt 1    //中断函数无需在main前声明     中断全部显示0 P3,2口INT0
58 {
59     TH0 = (65535 - 50000) / 256;
60     TL0 = (65535 - 50000) % 256;
61     t++;
62     if(t >= 20) {
63         num--;
64         t = 0;
65     }
66     
67     if(num == 0)
68         num = 59;    
69 }
 

免责声明:文章转载自《十天学会单片机Day1点亮数码管(数码管、外部中断、定时器中断)》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇windows下的shellcode剖析浅谈[转自看雪]使用Dockerfile制作微服务镜像下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

iOS 几种定时器

//第一种 每一秒执行一次(重复性) double delayInSeconds = 1.0; timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFA...

VS调试技巧

下面有从浅入深的6个问题,您可以尝试回答一下 一个如下的语句for (int i = 0; i < 10; i++){if (i == 5)j = 5;},什么都写在一行,你怎么在j=5前面插入断点 在一个1000次的循环体内部设置断点,你希望当循环进行到900次后中断,怎么才能做到呢? 你有一个表达式在上面循环的某一次发生了变化,你想知道是哪一次...

数据结构基础之memset---有memset 抛出的int 和 char 之间的转换和字节对齐

今天晚上,在做滤波算法时,里面用到很多float 和int 以及char 之间的类型强制转换,后面滤波完发现图片有些区域块,有过度曝光的白光,我就跟踪,以为是char 字符数字数据溢出问题,加了0-255的判断,然后打印,发现强制转换后的int类型数据多处出现负数,很奇怪,后面写了个测试程序,慢慢的问题出来了 : #include <stdio.h&...

esp8266物联网开发四:MQTT再论部控

之前利用点灯科技的库来使小爱同学控制LED的过程中,我们大略提到了一下MQTT的整体流程,由于其MQTT服务器是由点灯科技提供的,所以对其中的很多连接细节,我们并不知道,本节我们准备通过搭建本地的MQTT服务器,然后通过MQTT Client向MQTT服务器发送控制命令,来控制我们的LED灯。 首先,我们需要启动MQTT服务器,启动方式我们就不需要多说了,...

字符串哈希

题目描述 acwing841. 字符串哈希 给定一个长度为n的字符串,再给定m个询问,每个询问包含四个整数l1,r1,l2,r2,请你判断[l1,r1]和[l2,r2]这两个区间所包含的字符串子串是否完全相同。 字符串中只包含大小写英文字母和数字。 输入格式 第一行包含整数n和m,表示字符串长度和询问次数。 第二行包含一个长度为n的字符串,字符串中只包含大...

android 定时器的使用

1、android中通常是使用AlarmManager来定时启动一个单次或重复多次操作的。具体的说就是我们通过AlarmManager设定一个时间和注册一个intent到系统中,然后在该时间到来时,系统为我们发送一个广播,即执行我们设定的Intent(要执行的操作),通常我们使用 PendingIntent来实现“要执行的操作”,PendingIntent...