ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

零基础蓝桥杯单片机学习_第四章_数码管显示

零基础蓝桥杯单片机学习_第四章_数码管显示

看到板子上一大块暗着的像时钟一样的数码管吗?今天让我们给他点起。

一、原理图讲解

如图是数码管模块的原理图,可以看到,最下面的数码管有左右两边端口。随便挑一个,不难发现,左边的控制一个’8’中哪一横亮(A’->a),右边则控制哪个’8’亮(COM1->DP1)。

那么就有问题了,数码管一次只能亮一个’8’,怎么做到同时显示数字?只要让每个’8’以极短的时间显示就行。

想要显示数码管,这就是关键:每2ms切换一根数码管显示。

二、要求提出

  1. 每2ms切换数码管显示
  • 数码管的显示不能干扰正常循环代码,否则可能导致阻塞。
  • 三、代码编写

    前情提要:这块数码管是共阳极,即低电平点亮。(CA,Common Anode 阳极共同连接,阴极相互独立。与之相反的是CC,Common Cathode)

    1.让我们先用while函数点亮一根数码管。

    比如先点亮原理图左边数码管的左边第二个‘8’的bc,使其显示“1”(COM2-c)

    基本思路:

    1.将P0改为指向COM2(P0= 0000 0010),_74HC138函数选中Y6

    2.将P0改为指向bc,即~0000 0110(0xF9),_74HC138函数选中Y7

    于是就有了下面代码

    (待填充)

    2.数组存储

    每次都写0xF9等十六进制太麻烦了,这里我们引入数组,做到输入一个数,就能代替一个十六进制。

    数组的语法如下:

    需要注意的是,在大多数的编程语言,0是作为数组的开端的。所以如果我希望取0xF8,尽管它在第8个,但我得取数组的第七位。

    当我需要取数组内数时,只需写nixie_table[n]即可,n是0-9的正整数。

    当需要修改数组内数字时,只需写nixie_table[n]=x即可,n是0-9的正整数,x是任意0-255的数(在任何进制下,x范围随定义的数组输出数字类型决定)


    广告:

    不想一个个推?打开“SEG_TABLE_对应断码.pdf”文件,找到你的专属十六进制断码!(笑)

    PS:部分考纲要求的显示还是要自己推的,但减了不少麻烦。


    3.定时器

    想要2ms运行一次代码还不阻塞main循环,我们就需要引入一个定时器。

    如果我们初始化一段2ms的定时器,并为定时器赋予一串代码,软件就会这样跑:(黑为main,红为定时器。实际上红段会小很多,此处仅是为了理解。)

    可以看到,即使只有一个核心,单片机也会在规定时间运行要执行的代码,并且不阻塞源代码的持续。

    在ISC中,我们可以直接生成定时器代码,具体步骤如下。

    在软件界面打开“定时器计算器”,调整以下参数:
    1.时钟频率:12.0000Hz(考纲要求)
    2.定时长度:1毫秒(便于计量计算)
    3.选中“使能定时器中断”
    点击"生成C代码"并复制

    你会得到这串代码,相关注释已经放在旁边

    void Timer0_Isr(void) interrupt 1 { //这里就是红线部分 } void Timer0_Init(void) //1毫秒@12.000MHz { AUXR |= 0x80; //定时器时钟1T模式 TMOD &= 0xF0; //设置定时器模式 TL0 = 0x20; //设置定时初始值 TH0 = 0xD1; //设置定时初始值 TF0 = 0; //清除TF0标志 TR0 = 1; //定时器0开始计时 ET0 = 1; //使能定时器0中断EA = 1; //使计时器开启(这段要自己写,否则开不了) }

    将它直接放到main.c里面,于是就有

    //main.c #include <STC15F2K60S2.H> #include "_74HC138.h" #include "Led.h" void Timer0_Init(void) //计时器 { AUXR |= 0x80; TMOD &= 0xF0; TL0 = 0x20; TH0 = 0xD1; TF0 = 0; TR0 = 1; ET0 = 1; EA = 1; } void Timer0_Isr(void) interrupt 1 { //红线部分 } void main() { //刚上电的运行 while(1) { //初始化后的总循环(蓝线部分) } }

    好,定时器到这里就结束了,后面我们将用计时器直接使灯循环亮起。

    4.开始编写

    请读者建立一个意识,数码管的循环显示与更改需要解耦,占据更小的运行时间,同时还使代码更易编写。

    没看懂上面的话?翻译一下,就是我们可以将用数组保存数码管需要显示的数字,
    并创建一个全新的,使数码管按照数组点亮的函数循环2ms运行。

    如图,右边扫描函数一直运行,一直使数码管亮起,左边while函数只需修改数组。

    如此,我们就需要创建三个函数:

    让单个数码管‘8’亮起的函数,让数码管一直循环亮的扫描函数,与修改数组的函数。

    //nixie,c // #include <STC15F2K60S2.H> #include "_74HC138.h" #include "nixie.h"code1unsigned char nixie_table[11] = {0xC0, 0xF9, 0xA4, 0xB0, 0x99, 0x92, 0x82, 0xF8, 0x80, 0x90, 0xFF}; //0 1 2 3 4 5 6 7 8 9 Null unsigned char nixie_display[9] ={10,10,10,10,10,10,10,10,10}; //让单个数码管‘8’亮起的函数 void nixie(unsigned char Location, display) // { P0 = 0xFF; //对P0改为0xFF,为所有数码管置零做准备,避免不必要的显示 _74HC138_init(7); //选中Y7,更改数码管显示为全暗 P0 = 0x01 << (Location-1); //使用P0预选中相对应'8',为点亮做准备 _74HC138_init(6); //选中Y6,结合P0选中相对应的'8' P0 = display; //指明对应数码管的显示 _74HC138_init(7); //选中Y7,更改数码管的显示 } //让数码管一直循环亮的扫描函数 void nixie_loop() {static2unsigned char n = 1; //声明一个char,作为每次刷新的位置记录 nixie(n,nixie_table[nixie_display[n]]); //每次char刷新后,执行一个'8'的点亮 n++; //每次数码管点亮后,自动将位置后移一格 if(n >= 9){n = 1;} //当n超过8了,自动回到1 } //修改数组的函数 void set_nixie_display(unsigned char Location, display){ nixie_display[Location] = display; //将显示数组调整成需要的数 }

    那么这个时候,就可以使用定时器让数码管点亮了,此处我直接把代码贴出来并做出注释。

    //main.c #include <STC15F2K60S2.H> #include "_74HC138.h" #include "nixie.h" void Timer0_Init(void) { AUXR &= 0x7F; TMOD &= 0xF0; TL0 = 0x18; TH0 = 0xFC; TF0 = 0; TR0 = 1; ET0 = 1; EA = 1; //这一段别忘了加 } void Timer0_Isr(void) interrupt 1 { static unsigned char count1 = 0; //从软件开始的一刻,设定一个1ms自动加1的数,方便计时。 count1++; if(count1 >= 2) //如果2ms了 { nixie_loop(); //执行一次循环,让所有'8'亮一下 count1 = 0; //置零,到了下一次2ms可以循环 } } void main() { _74HC138_init_all(); //初始化所有74HC138下的硬件 Timer0_Init(); //初始化并开启定时器 while(1) //软件主循环 { set_nixie_display(1,2); //设置第一个灯管亮“2”这个数字 } }

    此处省略关于头文件的书写与74HC138选中的函数,有需要可以查看上一章节,也可以直接下载文档并导入。

    文档链接:https://hkpanel.sakurarun.vip/s/G5zirAY7sBE5E?operateNode=local

    那么到现在,我们就完成了数码管灯的点亮,是时候留点思考题了!!!

    在所有灯(电源灯除外)熄灭的前提下,编写一个20s的计时器,当最后3s时,LED灯4号亮起,0s后,一直保持0s(不要求数字在哪里显示)【可能用到的计算:{'/'除得商,12/10=1},{'%'除得余,12%10=2}】
    //main.c #include <STC15F2K60S2.H> #include "_74HC138.h" #include "nixie.h" #include "LED.h"

    void Timer0_Init(void)
    {
    AUXR &= 0x7F;
    TMOD &= 0xF0;
    TL0 = 0x18;
    TH0 = 0xFC;
    TF0 = 0;
    TR0 = 1;
    ET0 = 1;
    EA = 1; //这里记得补充。
    }

    static char time = 21;
    //此处使用21,因为count2运行时先减1再显示
    void Timer0_Isr(void) interrupt 1
    {
    static unsigned char count1 = 0;
    static unsigned int count2 = 0;
    //设置一个count2,方便以秒计时
    count1++;
    count2++;
    if(count1 >= 2)
    {
    nixie_loop();
    count1 = 0;
    }
    if(count2 >= 1000){ //如果1s之后
    if(time>0){ //且20s倒计时还没到0s
    time–; //先减1s
    set_nixie_display(1,time/10); //再将十位调到时间与10整除得到的商
    set_nixie_display(2,time%10); //再将个位跳到时间与10整除得到的余
    if(time<=3) //如果时间小于或等于3s
    {LED(4);} //把4号LED亮起来
    count2 = 0;} //并置零count2,等待下一个1s

    }
    }

    void main()
    {
    _74HC138_init_all();
    Timer0_Init(); //这里记得初始化函数,不要让定时器开不了。
    while(1)
    {

    }
    }

返回列表