zoukankan      html  css  js  c++  java
  • 十天学会单片机Day1点亮数码管(数码管、外部中断、定时器中断)

    1.引脚定义

    P3口各引脚第二功能定义
    标号 引脚 第二功能 说明
    P3.0 10 RXD 串行输入口
    P3.1 11 TXD 串行输出口
    P3.2 12 INT0(上划线) 外部中断0
    P3.3 13 INT1(上划线) 外部中断1
    P3.4 14 T0 定时器/计数器0 外部输入端
    P3.5 15 T1 定时器/计数器1 外部输入端
    P3.6 16 WR(上划线) 外部数据存储器写脉冲
    P3.7 17 RD(上划线) 外部数据存储器读脉冲

    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 //共阴极数码管静态显示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 }

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

     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 }

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

     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 }

    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 最高 0 0003H
    T0 定时器/计数器0中断 第2 1 000BH
    INT1 外部中断1 第3 2 0013H
    T1 定时器/计数器1中断 第4 3 001BH
    TI/RI 串行口中断 第5 4 0023H
    T2 定时器/计数器2中断 最低 5 002BH
    中断允许寄存器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
    位序号 D7 D6 D5 D4 D3 D2 D1 D0
    说明 无效位 无效位 无效位 串行口中断优先级控制位 定时器/计数器1中断优先级控制位 外部中断1中断优先级控制位 定时器/计数器0中断优先级控制位 外部中断0中断优先级控制位
    位符号 -- -- -- PS PT1 PX1 PT0 PX0
    位地址 -- -- -- BCH BBH BAH B9H B8H
     
     
     
     
     
     
     
     
     
     
    单片机复位时全部清零。可进行位寻址。
    每个位赋值为1,将对应中断定义为高优先级中;赋值0,则定义为低优先级中断。
    在没有设置中断优先级情况下,按照默认中断级别响应中断,设置后,则按设置顺序确定相应的先后顺序。
     
    定时器/计数器工作方式寄存器TMOD
    位序号 D7 D6 D5 D4 D3 D2 D1 D0
    位符号 GATE C/T(上划线) M1 M0 GATE C/T(上划线) M1 M0
      定时器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
    位序号 D7 D6 D5 D4 D3 D2 D1 D0
    位符号 TF1 TR1 TF0 TR0 IE1 IT1 IE0 IT0
    位地址 8FH 8EH 8DH 8CH 8BH 8AH 89H 88H
      定时器/计数器控制 外部中断控制
     
     
     
     
     
     
    单片机复位时全部清零。可进行位寻址。
    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 }

    中断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 }
     
  • 相关阅读:
    SQL Server 执行参数化脚本时的一个性能问题
    2021 年终总结
    循序渐进——NAnt构建实例
    用C#实现单链表(创建单链表,在头部插入)
    用C#实现单链表(插入,在第i个前插,在第i个后插)
    用C#实现单链表(merge两个有序单链表)
    用C#实现单链表(取第i个结点元素,删除第i个结点)
    播放器03:以文件夹的形式添加整个文件夹里面的文件到播放列表,播放刚加进来的第一首歌曲,默认顺序播放
    用C#实现单链表(初始化数据,返回链表元素个数)
    ObjectiveC中创建单例方法的步骤
  • 原文地址:https://www.cnblogs.com/kuotian/p/5338862.html
Copyright © 2011-2022 走看看