0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

第7章 变量进阶与点阵LED(7.1 7.2)

137933yu 来源:137933yu 作者:137933yu 2025-12-10 16:25 次阅读
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

走在马路上的时候,经常会看到马路两侧有一些LED点阵的广告牌,这些广告牌看起来绚烂夺目,非常吸引人,而且还会变化很多种不同的显示方式。本章就会学习到点阵LED的控制方式,同时也会学习C语言变量的进阶知识——变量的作用域和存储类别。
7.1变量的作用域
所谓的作用域就是指变量起作用的范围,也是变量的有效范围。变量按他的作用域可以分为局部变量和全局变量。
7.1.1局部变量
在一个函数内部声明的变量是内部变量,它只在本函数内有效,在本函数以外是不能使用的,这样的变量就是局部变量。此外,函数的形参也是局部变量,形参会在后面讲解函数的时候再详细解释。
比如第6章程序中定义的unsigned long sec这个变量,它是定义在main函数内部的,所以只能由main函数使用,中断函数就不能使用这个变量。同理,如果在中断函数内部定义的变量,在main函数中也是不能使用的。
7.1.2全局变量
在函数外声明的变量就是全局变量。一个源程序文件可以包含一个或者多个函数,全局变量的作用范围是从它开始声明的位置一直到程序结束。
比如第6章程序中定义的unsigned char LedBuff[6]这个数组,它的作用域就是从开始定义的位置一直到程序结束,不管是main函数,还是中断函数InterruptTimer0,都可以直接使用这个数组。
局部变量只有在声明它的函数范围内可以使用,而全局变量可以被作用域内的所有的函数使用。所以在一个函数内既可以使用本函数内声明的局部变量,也可以使用全局变量。从编程规范上讲,一个程序文件内所有的全局变量都应定义在文件的开头部分,在文件中所有函数之前。
由于C语言函数只有一个返回值,但是却经常会希望一个函数可以提供或影响多个结果值,这时就可以利用全局变量来实现。但是考虑到全局变量的一些特征,应该限制全局变量的使用,过多使用全局变量也会带来一些问题。
1、全局变量可以被作用域内所有的函数直接引用,可以增加函数间数据联系的途径,但同时加强了函数模块之间的数据联系,使这些函数的独立性降低,对其中任何一个函数的修改都可能会影响到其它函数的执行结果,函数之间过于紧密的联系不利于程序的维护。
2、全局变量的应用会降低函数的通用性,函数在执行的时候过多依赖于全局变量,不利于函数的重复利用。目前编写的程序还都比较简单,就一个.c文件,但以后要学到一个程序中有多个.c文件,当一个函数被另外一个.c文件调用的时候,必须将这个全局变量的变量值一起移植,而全局变量不只被一个函数调用,这样会引起一些不可预见的后果。
3、过多使用全局变量会降低程序的清晰度,使程序的可读性下降。在各个函数执行的时候都可能改变全局变量值,往往难以清楚的判断出每个时刻各个全局变量的值。
4、定义全局变量会永久占用单片机的内存单元,而局部变量只有进入定义局部变量的函数时才会占用内存单元,函数退出后会自动释放所占用的内存。所以大量的全局变量会额外增加内存消耗。
综上所述之原因,在编程规范上有一条原则,就是尽量减少全局变量的使用,能用局部变量代替的就不用全局变量。
还有一种特殊情况,在看别人程序的时候请注意,C语言是允许局部变量和全局变量同名的,它们定义后在内存中占有不同的内存单元。如果在同一源文件中,全局变量和局部变量同名,在局部变量作用域范围内,只有局部变量有效,全局变量不起作用,也就是说局部变量具有更高优先级。但是从编程规范上讲,是要避免全局变量与局部变量重名的,从而避免不必要的误解和误操作。
7.2变量的存储类别
变量的存储类别分为自动、静态、寄存器和外部这四种。其中后两种暂不介绍,主要介绍自动变量和静态变量这两种。
函数中的局部变量,如果不加static这个关键字来修饰,都属于自动变量,也叫做动态存储变量。这种存储类别的变量,在调用该函数的时候系统会给他们分配存储空间,在函数调用结束后会自动释放这些存储空间。动态存储变量的关键字是auto,但是这个关键字是可以省略的。
与动态变量对应的就是静态变量。首先,全局变量均是静态变量,此外,还有一种特殊的局部变量也是静态变量。即在定义局部变量时前边加上static这个关键字,加上这个关键字的变量就称之为静态局部变量,它的特点是,在整个生存期中只赋一次初值,在第一次执行该函数时,它的值就是给定的那个初值,而之后在该函数所有的执行次数中,它的值都是上一次函数执行结束后的值,即它可以保持前次的执行结果。
有这样一种情况,某个变量只在一个函数中使用,但是却想在函数多次调用期间保持住这个变量的值而不丢失,也就是说在该函数的本次调用中该变量值的改变要依赖与上一次调用函数时的值,而不能每次都从初值开始。如果使用局部动态变量的话,每次进入函数后上一次的值就丢失了,它每次都从初值开始,如果定义成全局变量的话,又违背了上面提到的尽量减少全局变量的使用这条原则,那么此时,局部静态变量就是最好的解决方案了。
比如第6章最后的例程中有一个控制数码管动态扫描显示用的索引变量i和实现秒定时的计数变量cnt,当时就是定义成了全局变量,现在就可以改成局部静态变量来试试。
#include

sbit ADDR0 = P1^0;
sbit ADDR1 = P1^1;
sbit ADDR2 = P1^2;
sbit ADDR3 = P1^3;
sbit ENLED = P1^4;

unsigned char code LedChar[] = { //数码管显示字符转换表
0xC0, 0xF9, 0xA4, 0xB0, 0x99, 0x92, 0x82, 0xF8,
0x80, 0x90, 0x88, 0x83, 0xC6, 0xA1, 0x86, 0x8E
};
unsigned char LedBuff[6] = { //数码管显示缓冲区,初值0xFF确保启动时都不亮
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
};
unsigned char flag1s = 0; //1秒定时标志

void main()
{
unsigned long sec = 0; //记录经过的秒数

EA = 1; //使能总中断
ENLED = 0; //使能U3,选择控制数码管
ADDR3 = 1; //因为需要动态改变ADDR0-2的值,所以不需要再初始化了
TMOD = 0x01; //设置T0为模式1
TH0 = 0xFC; //为T0赋初值0xFC67,定时1ms
TL0 = 0x67;
ET0 = 1; //使能T0中断
TR0 = 1; //启动T0

while (1)
{
if (flag1s == 1) //判断1秒定时标志
{
flag1s = 0; //1秒定时标志清零
sec++; //秒计数自加1
//以下代码将sec按十进制位从低到高依次提取并转为数码管显示字符
LedBuff[0] = LedChar[sec%10];
LedBuff[1] = LedChar[sec/10%10];
LedBuff[2] = LedChar[sec/100%10];
LedBuff[3] = LedChar[sec/1000%10];
LedBuff[4] = LedChar[sec/10000%10];
LedBuff[5] = LedChar[sec/100000%10];
}
}
}
/* 定时器0中断服务函数 */
void InterruptTimer0() interrupt 1
{
static unsigned char i = 0; //动态扫描的索引,定义为局部静态变量
static unsigned int cnt = 0; //记录T0中断次数,定义为局部静态变量

TH0 = 0xFC; //重新加载初值
TL0 = 0x67;
cnt++; //中断次数计数值加1
if (cnt >= 1000) //中断1000次即1秒
{
cnt = 0; //清零计数值以重新开始下1秒计时
flag1s = 1; //设置1秒定时标志为1
}
//以下代码完成数码管动态扫描刷新
P0 = 0xFF; //显示消隐
switch (i)
{
case 0: ADDR2=0; ADDR1=0; ADDR0=0; i++; P0=LedBuff[0]; break;
case 1: ADDR2=0; ADDR1=0; ADDR0=1; i++; P0=LedBuff[1]; break;
case 2: ADDR2=0; ADDR1=1; ADDR0=0; i++; P0=LedBuff[2]; break;
case 3: ADDR2=0; ADDR1=1; ADDR0=1; i++; P0=LedBuff[3]; break;
case 4: ADDR2=1; ADDR1=0; ADDR0=0; i++; P0=LedBuff[4]; break;
case 5: ADDR2=1; ADDR1=0; ADDR0=1; i=0; P0=LedBuff[5]; break;
default: break;
}
}
注意看程序中中断函数里的局部变量i,为其加上了static关键字来修饰,就成为了静态局部变量。它的初始化i = 0操作只进行一次,程序执行代码中会进行i++等操作,那么下次再进入中断函数的时候,i会保持上次中断函数执行完毕后的值。如果去掉static这个关键字,那么每次进入中断函数后,i都会被初始化成0,可以自己修改程序看一下实际效果是否和理论相符。

审核编辑 黄宇

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • led
    led
    +关注

    关注

    243

    文章

    24445

    浏览量

    687550
收藏 人收藏
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

    评论

    相关推荐
    热点推荐

    FZH367 具有独立自动呼吸功能的LED(12×16)点阵驱动芯片 原厂技术支持

    概述 型号:FZH367FZH367是一种具有独立自动呼吸功能的LED(12×16)点阵驱动芯片。芯片通过I2C协议控制每个LED实现 3 种自动呼吸模式及PMW模式的切换控制。此外,芯片具备
    发表于 11-18 09:18

    原厂 FZH365 具有独立自动呼吸功能的LED(12×12)点阵驱动芯片

    是一种具有独立自动呼吸功能的LED(12×12)点阵驱动芯片。芯片通过I2C协议控制每个 LED实现 3 种自动呼吸模式及PMW模式的切换控制。此外,芯片具备对每一个LED的开短路检
    发表于 11-17 09:38

    原厂 FZH364 一款8×8点阵恒流LED驱动芯片

    )FZH364是一款8×8点阵恒流LED驱动芯片。可广泛应用于各种单色调光LED显示系统,或RGB 全彩LED显示系统。每颗LED都可以通过
    发表于 11-17 09:34

    点阵数码管显示芯片高抗干扰数显IC芯片VK1S68C

    接口、数据锁存器、LED驱 动、键盘扫描等电路。SEG脚接LED阳极,GRID脚接LED阴极,可支13SEG×4GRID、12SEG×5GRID、11SEG×6GRID、10SEG×7
    发表于 11-06 17:45

    2 点亮你的LED(2.5)

    程序5个步骤: 1步:芯片型号,选择STC89C52RC系列下的STC89C52RC/LE52RC,一定不能选错。 2步:扫描串口,根据查到的
    的头像 发表于 10-16 10:58 311次阅读
    <b class='flag-5'>第</b>2<b class='flag-5'>章</b> 点亮你的<b class='flag-5'>LED</b>(2.5)

    2 点亮你的LED(2.3 2.4)

    2.3 LED小灯 LED(light-emitting diode),即发光二极管,俗称LED小灯,它的种类很多,参数也不尽相同,Kingst51开发板上用的是普通的贴片发光二极管。这种二极管通常
    的头像 发表于 10-15 14:37 635次阅读
    <b class='flag-5'>第</b>2<b class='flag-5'>章</b> 点亮你的<b class='flag-5'>LED</b>(2.3 2.4)

    2 点亮你的LED

    本章的标题是点亮LED,虽然任务很简单,但是需要了解的单片机基础知识却很多,特别是对于初学者,刚开始要在头脑中建立一个单片机的概念,然后通过点亮一个LED小灯来增加初学者对单片机的兴趣和自信
    的头像 发表于 10-13 15:52 317次阅读
    <b class='flag-5'>第</b>2<b class='flag-5'>章</b>  点亮你的<b class='flag-5'>LED</b>

    Texas Instruments TPS92402 LED点阵控制器数据手册

    Texas Instruments TPS92402 LED点阵控制器支持8通道独立照明解决方案,提供高达2.5A像素级LED调光控制,具有4.5V至65V的宽输入范围。该器件包括一串八个串联的集成
    的头像 发表于 07-17 15:56 534次阅读
    Texas Instruments TPS92402 <b class='flag-5'>LED</b><b class='flag-5'>点阵</b>控制器数据手册

    Texas Instruments TPS92401 LED点阵控制器数据手册

    FET为单个LED提供PWM调光功能。TPS92401点阵控制器包含一个用于系统时钟的内部振荡器,可支持高达16位的集成PWM 发生器,其可编程PWM频率高达60kHz。这些LED点阵
    的头像 发表于 07-14 14:38 532次阅读
    Texas Instruments TPS92401 <b class='flag-5'>LED</b><b class='flag-5'>点阵</b>控制器数据手册

    RK3568驱动指南|第十二篇 GPIO子系统-130 GPIO的调试方法

    RK3568驱动指南|第十二篇 GPIO子系统-130 GPIO的调试方法
    的头像 发表于 06-03 11:32 997次阅读
    RK3568驱动指南|第十二篇 GPIO子系统-<b class='flag-5'>第</b>130<b class='flag-5'>章</b> GPIO的调试方法

    RK3568驱动指南|驱动基础进阶篇-进阶7 向系统中添加一个系统调用

    RK3568驱动指南|驱动基础进阶篇-进阶7 向系统中添加一个系统调用
    的头像 发表于 05-21 14:15 558次阅读
    RK3568驱动指南|驱动基础<b class='flag-5'>进阶</b>篇-<b class='flag-5'>进阶</b><b class='flag-5'>7</b> 向系统中添加一个系统调用

    单片机外围电路设计 (2版)

    及智能传感器的接口技术。4阐述单片机测控系统的设计。5阐述数据采集系统及新颖检测电路的设计。6
    发表于 04-18 16:16

    RK3568驱动指南|第三篇-并发与竞争-19 并发与竞争实验

    RK3568驱动指南|第三篇-并发与竞争-19 并发与竞争实验
    的头像 发表于 02-24 16:26 856次阅读
    RK3568驱动指南|第三篇-并发与竞争-<b class='flag-5'>第</b>19<b class='flag-5'>章</b> 并发与竞争实验

    点阵数码管驱动抗干扰数显数码管芯片VK1616

    驱动等电路。 SEG脚接LED阳极,GRID脚接LED阴极,可支持7SEGx4GRID的点阵LED显示面板。采用SOP16/DIP16的封
    发表于 02-14 17:00

    VK1618 SOP18/DIP18抗干扰LED数码管驱动/点阵LED驱动控制专用芯片

    8SEGx4GRID、7SEGx5GRID、6SEGx6GRID、5SEGx7GRID的点阵LED显示面 板,最大支持5x1按键。适用于要求可靠、稳定和抗干扰能力强的产品。 LJQ36
    的头像 发表于 12-12 16:25 905次阅读
    VK1618 SOP18/DIP18抗干扰<b class='flag-5'>LED</b>数码管驱动/<b class='flag-5'>点阵</b><b class='flag-5'>LED</b>驱动控制专用芯片