目录
本节内容我们学习如何控制数码管,先尝试点亮一个数码管,并实现倒计时效果。
数码管的英文为Nixie Tube,又称辉光管或LED数码管。其基本单元由LED组成,单个数码管的概念图如左图所示,一般可以分为七段数码管和八段数码管两种。八段比七段多一个小数点,应用更为广泛。
除此之外,单个数码管只能显示一个数字(字母),功能受限。所以常常将多个数码管封装起来,如右图所示,常用的为4位数码管。
图1 八段数码管 |
图2 多位数码管
|
数码管的发光颜色由管中充的低压气体决定,一般为氖加上一些汞或氩,一般为橙色或绿色。
数码管的电路原理图如下:

按LED的连接方式可以分为共阴极数码管和共阳极数码管。
共阴极需要单片机IO给高电平,对应的段(LED)才能点亮,而单片机的IO引脚电流输出能力不足,往往需要借助驱动芯片(如74HC245芯片)才可以点亮数码管。而共阳极只需要单片机IO给低电平,故共阳极数码管应用更加广泛。
在数码管中有段选和位选两个概念,现阐释如下:
仔细观察数码管的段选顺序,按 a、b、c、d、e、f、g、h 逆时针排列,依次对应字节的低位至高位。因此,我们可以给出共阴极数码管的字形码编码表。(有些字母不易表示,缺省)
| 字形码 | dp g f e d c b a | 十六进制 |
|---|---|---|
| 0 | 0011 1111 | 0x3f |
| 1 | 0000 0110 | 0x06 |
| 2 | 0101 1011 | 0x5b |
| 3 | 0100 1111 | 0x4f |
| 4 | 0110 0110 | 0x66 |
| 5 | 0110 1101 | 0x6d |
| 6 | 0111 1101 | 0x7d |
| 7 | 0000 0111 | 0x07 |
| 8 | 0111 1111 | 0x7f |
| 9 | 0110 1111 | 0x6f |
| A | 0111 0111 | 0x77 |
| b | 0111 1100 | 0x7c |
| c | 0101 1000 | 0x58 |
| d | 0101 1110 | 0x5e |
| E | 0111 1001 | 0x79 |
| F | 0111 0001 | 0x71 |
| G | - | - |
| H | 0111 0110 | 0x76 |
| I | 0011 0000 | 0x30 |
| J | 0000 1110 | 0x0e |
| K | - | - |
| L | 0011 1000 | 0x38 |
| M | - | - |
| n | 0101 0100 | 0x54 |
| o | 0101 1100 | 0x5c |
| p | 0111 0011 | 0x73 |
| q | 0110 0111 | 0x67 |
| r | 0101 0000 | 0x50 |
| s | 0110 1101 | 0x6d |
| t | - | - |
| U | 0011 1110 | 0x3e |
| v | 0001 1100 | 0x1c |
| w | - | - |
| x | - | - |
| y | 0110 1110 | 0x6e |
| z | - | - |
如果是共阳极,其编码表刚好是共阴极的按位取反(~)。其实可以看出,数码管对显示字母并不友好,一般用于显示数字,在电梯楼层显示,计算器显示中应用广泛。
从上述一些系列分析中我们可以感觉到,数码管相当于LED的堆叠,它对IO口资源的消耗是巨大的。如果要同时显示多个数字,除了采用芯片(如38译码器)来节约IO口,还可以采用不同的显示方式实现。数码管有两种驱动显示方式:静态显示和动态显示。
2个4位共阴极数码管和74HC138芯片(38译码器)原理图如下:
2个4位共阴极数码管 |
38译码器
|
将各数码管相同的段选连在一起,由 P0 统一控制,这样每个数码管显示的字符都是一样的。如何使不同数码管显示不同的字符?只需要给出位选信号指定不同的数码管点亮即可。
虽然位选端共有8个引脚,但实际上我们只需要每次点亮一个数码管,即只有8种情况,那么完全可以用3个引脚来控制这8种输出,这就是38译码器的实现机理。
观察38译码器原理图。其中, G 1 G1 G1、 G 2 ‾ \overline{G2} G2、 G 3 ‾ \overline{G3} G3 为使能端,其中G1高电平有效,G2、G3低电平有效(即上横线的含义)。38译码器的真值表为
| A0 | A1 | A2 | Y0 | Y1 | Y2 | Y3 | Y4 | Y5 | Y6 | Y7 |
|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 0 | 0 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 |
| 0 | 0 | 1 | 1 | 0 | 1 | 1 | 1 | 1 | 1 | 1 |
| 0 | 1 | 0 | 1 | 1 | 0 | 1 | 1 | 1 | 1 | 1 |
| 0 | 1 | 1 | 1 | 1 | 1 | 0 | 1 | 1 | 1 | 1 |
| 1 | 0 | 0 | 1 | 1 | 1 | 1 | 0 | 1 | 1 | 1 |
| 1 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 0 | 1 | 1 |
| 1 | 1 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 0 | 1 |
| 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 |
因为是共阴极数码管,所以Y端口为低电平时该数码管被点亮。

主要用于提升单片机IO口的驱动电流。一般IO口的输出电流为20mA,这个电流大小仅仅点亮一颗LED是没有问题的,但对于驱动数码管、点阵等多负载模块就力不从心了。
74HC245芯片可以将输出电流提升至70-80mA左右,具有8路输入和8路输出,可输出低电平、高电平、高阻态三态。其中DIR引脚用于控制输入输出方向,高电平(A => B)、低电平(B => A)。 O E ‾ \overline{OE} OE为使能引脚,低电平输出有效。
#include "reg52.h"
#define SMG_PORT P0
//重定义数据类型
typedef unsigned char u8;
typedef unsigned int u16;
//共阴极数码管字形码编码
u8 code smgduan[] = {0x3f,0x06,0x5b,0x4f,0x66, //0 1 2 3 4
0x6d,0x7d,0x07,0x7f,0x6f, //5 6 7 8 9
0x77,0x7c,0x58,0x5e,0x79, //A b c d E
0x71,0x76,0x30,0x0e,0x38, //F H I J L
0x54,0x5c,0x73,0x67,0x50, //n o p q r
0x6d,0x3e,0x1c,0x6e}; //s U v y
void main()
{
//P0口控制数码管显示字符
SMG_PORT = smgduan[14]; //E
while(1);
}
定义共阴极数码管字形码编码,注意这里的定义中使用了code关键字,这是C51中拓展的存储器类型。在标准C中,变量的定义格式为
[存储类别] 数据类型 变量名 = 初值;
| 存储类别 | 含义 | 特点 |
|---|---|---|
| auto | 自动变量 | 默认类型。(生存期)属于动态局部变量,调用时临时分配内存,函数调用结束即释放。(初值分配)在调用时赋初值,未赋初值则初值不确定。(作用域)仅在函数体内可调用。 |
| static | 静态变量 | (生存期) 属于静态局部(全局)变量,调用结束后保留当前值。(初值分配)只在编译时赋初值,默认赋0或'\0'。 (作用域)静态局部变量仅在函数体内可调用,静态全局变量在本文件中可调用。 |
| extern | 外部变量 | 外部声明,数据类型可省略。扩展变量作用域,实现跨文件调用。 |
| register | 寄存器变量 | 将变量存储在CPU的寄存器中,减小内存开销。 |
但在C51中,变量的完整定义格式为
[存储类别] 数据类型 [存储器类型] 变量名 = 初值;
| 存储器类型 | 特点 |
|---|---|
| code | 变量放在ROM(程序存储器,64KB),不可更改 |
| data | 变量放在可直接寻址片内RAM(数据存储器,低128B),访问速度快 |
| xdata | 变量放在间接寻址片外RAM(数据存储器,全64KB) |
| bdata | 变量放在可位寻址片内RAM(数据存储器,20H~2FH,16B) |
| idata | 变量放在间接寻址片内RAM(数据存储器,全256B) |
| pdata | 变量放在间接寻址片外RAM(数据存储器,低128B) |
代码如下:
#include <REGX52.H>
#define SMG_PORT P0
typedef unsigned char u8;
typedef unsigned int u16;
void delay(u16 t){
while(t--);
}
void main(){
//定义共阴数码管字形码编码
u8 smg_array[] = {0x3f,0x06,0x5b,0x4f,0x66, //0 1 2 3 4
0x6d,0x7d,0x07,0x7f,0x6f}; //5 6 7 8 9
while(1){
int i;
for(i=0;i<10;i++){
SMG_PORT = smg_array[9-i];
delay(50000);
}
delay(60000);
}
}
效果图如下:

下面,我们通过动态驱动显示的原理来显示字符I LOVE YOU
#include <REGX52.H>
#define SMG_SELECT_PORT P2 //位选端口
#define SMG_PORT P0
typedef unsigned char u8;
typedef unsigned int u16;
//共阴数码管码表(I LOVE YOU)
u8 code smg_array[] = {0x30,0x38,0x3f,0x3e,0x79,0x6e,0x3f,0x3e};
sbit A0 = SMG_SELECT_PORT^2;
sbit A1 = SMG_SELECT_PORT^3;
sbit A2 = SMG_SELECT_PORT^4;
void delay(u16 t){
while(t--);
}
//位选码,利用十进制取余
void Dec2Bin(u8 i){
A0 = i % 2;
i /= 2;
A1 = i % 2;
i /= 2;
A2 = i % 2;
}
void main(){
u8 i;
while(1){
for(i=0;i<8;i++){
Dec2Bin(i); //给38译码器赋值
SMG_PORT = smg_array[7-i];
delay(100); //1ms,实验测试5ms以上能察觉出闪烁
SMG_PORT = 0x00; //消除重影
}
}
}
硬件电路中,位选信号由P2.2、P2.3、P2.4控制,借助38译码器,控制8位COM端。
在程序中,我通过取余运算得到位选信号的取值,并依次赋值给各端口。当然,你也可以通过Switch语句,分别讨论8种取值情况。
比较重要的是,数码管的动态显示存在重影的问题。重影产生的本质是当位选信号发生改变时,上个数码管的段选信号在这一瞬间还未发生改变,但因为这个时间极短,因此只会留下淡淡的残影。如何消影呢,只要在下个数码管被点亮前,将段选信号清除即可(熄灭)。
最终效果图如下:

delay.h
#ifndef _DELAY_H_
#define _DELAY_H_
#include <regx52.h>
typedef unsigned char u8;
typedef unsigned int u16;
void delay_10us(u16);
void delay_ms(u16);
#endif
delay.c
#include "delay.h"
/**
* @brief 延时函数(10us)
* @param t:0~65535,循环一次约10us
* @retval 无
*/
void delay_10us(u16 t){
while(t--);
}
/**
* @brief 延时函数(ms)
* @param t:0~65535,单位ms
* @retval 无
*/
void delay_ms(u16 t){
while(t--){
delay_10us(100);
}
}
smg.h
#ifndef _SMG_H_
#define _SMG_H_
#include "delay.h"
void smg_showChar(u8,u8);
void smg_showString(u8*, u8);
#endif
smg.c
#include "smg.h"
//共阴极数码管字形码编码
u8 code smgduan[] = {0x3f,0x06,0x5b,0x4f,0x66, //0 1 2 3 4
0x6d,0x7d,0x07,0x7f,0x6f, //5 6 7 8 9
0x77,0x7c,0x58,0x5e,0x79, //A b c d E
0x71,0x76,0x30,0x0e,0x38, //F H I J L
0x54,0x3f,0x73,0x67,0x50, //n o p q r
0x6d,0x3e,0x3e,0x6e}; //s U v y
// 段选引脚
#define SMG_PORT P0
// 位选引脚,与38译码器相连
sbit A1 = P2^2;
sbit A2 = P2^3;
sbit A3 = P2^4;
/**
* @brief 指定第几个数码管点亮,38译码器控制位选(不对外声明)
* @param pos:从左至右,数码管位置 1~8
* @retval 无
*/
void select_38(u8 pos){
u8 temp_pos = 8 - pos; // 0~7
A1 = temp_pos % 2; //高位
temp_pos /= 2;
A2 = temp_pos % 2;
temp_pos /= 2;
A3 = temp_pos % 2; //低位
}
/**
* @brief 解析数据并取得相应数码管字形码编码(不对外声明)
* @param dat:想要显示的字符
* @retval 对应字形码编码值
*/
u8 parse_data(u8 dat){
switch(dat){
case 0:
case 1:
case 2:
case 3:
case 4:
case 5:
case 6:
case 7:
case 8:
case 9:return smgduan[dat];
case 'a':
case 'A':return smgduan[10];
case 'b':
case 'B':return smgduan[11];
case 'c':
case 'C':return smgduan[12];
case 'd':
case 'D':return smgduan[13];
case 'e':
case 'E':return smgduan[14];
case 'f':
case 'F':return smgduan[15];
case 'h':
case 'H':return smgduan[16];
case 'i':
case 'I':return smgduan[17];
case 'j':
case 'J':return smgduan[18];
case 'l':
case 'L':return smgduan[19];
case 'n':
case 'N':return smgduan[20];
case 'o':
case 'O':return smgduan[21];
case 'p':
case 'P':return smgduan[22];
case 'q':
case 'Q':return smgduan[23];
case 'r':
case 'R':return smgduan[24];
case 's':
case 'S':return smgduan[25];
case 'u':
case 'U':return smgduan[26];
case 'v':
case 'V':return smgduan[27];
case 'y':
case 'Y':return smgduan[28];
default:return 0x00; //不显示
}
}
/**
* @brief 显示一个字符(1字节)
* @param dat:字符数据
* @param pos:显示位置 1~8
* @retval 无
*/
void smg_showChar(u8 dat, u8 pos){
// 解析点亮哪一个数码管
select_38(pos);
// 解析数据
SMG_PORT = parse_data(dat);
}
/**
* @brief 显示字符串(动态显示)
* @param
* @retval
*/
void smg_showString(u8 dat[], u8 pos){
u8 i;
// 超出部分直接截断
for(i=0;(i<9-pos )&&(dat[i]!='\0');i++){
smg_showChar(dat[i], pos+i);
delay_10us(100); //延时1ms
SMG_PORT = 0x00; //消影
}
}
main.c
#include "smg.h"
/**
* @brief 仅提供一个调用demo
* @author Qiu
* @date 2023.3.10
*/
void main(){
//smg_showChar('a',7); //单字符显示示例
while(1){
smg_showString("Iloveyou",1); //字符串显示示例
}
}
数码管本质就是发光二极管的封装,所以有了LED基础之后,本节内容并不难理解。继续加油吧!
当我在Rails控制台中按向上或向左箭头时,出现此错误:irb(main):001:0>/Users/me/.rvm/gems/ruby-2.0.0-p247/gems/rb-readline-0.4.2/lib/rbreadline.rb:4269:in`blockin_rl_dispatch_subseq':invalidbytesequenceinUTF-8(ArgumentError)我使用rvm来管理我的ruby安装。我正在使用=>ruby-2.0.0-p247[x86_64]我使用bundle来管理我的gem,并且我有rb-readline(0.4.2)(人们推荐的最少
我正在使用Ruby2.1.1和Rails4.1.0.rc1。当执行railsc时,它被锁定了。使用Ctrl-C停止,我得到以下错误日志:~/.rvm/gems/ruby-2.1.1/gems/spring-1.1.2/lib/spring/client/run.rb:47:in`gets':Interruptfrom~/.rvm/gems/ruby-2.1.1/gems/spring-1.1.2/lib/spring/client/run.rb:47:in`verify_server_version'from~/.rvm/gems/ruby-2.1.1/gems/spring-1.1.
我将我的Rails应用程序部署到OpenShift,它运行良好,但我无法在生产服务器上运行“Rails控制台”。它给了我这个错误。我该如何解决这个问题?我尝试更新rubygems,但它也给出了权限被拒绝的错误,我也无法做到。railsc错误:Warning:You'reusingRubygems1.8.24withSpring.UpgradetoatleastRubygems2.1.0andrun`gempristine--all`forbetterstartupperformance./opt/rh/ruby193/root/usr/share/rubygems/rubygems
?博客主页:https://xiaoy.blog.csdn.net?本文由呆呆敲代码的小Y原创,首发于CSDN??学习专栏推荐:Unity系统学习专栏?游戏制作专栏推荐:游戏制作?Unity实战100例专栏推荐:Unity实战100例教程?欢迎点赞?收藏⭐留言?如有错误敬请指正!?未来很长,值得我们全力奔赴更美好的生活✨------------------❤️分割线❤️-------------------------
说在前面这部分我本来是合为一篇来写的,因为目的是一样的,都是通过独立按键来控制LED闪灭本质上是起到开关的作用,即调用函数和中断函数。但是写一篇太累了,我还是决定分为两篇写,这篇是调用函数篇。在本篇中你主要看到这些东西!!!1.调用函数的方法(主要讲语法和格式)2.独立按键如何控制LED亮灭3.程序中的一些细节(软件消抖等)1.调用函数的方法思路还是比较清晰地,就是通过按下按键来控制LED闪灭,即每按下一次,LED取反一次。重要的是,把按键与LED联系在一起。我打算用K1来作为开关,看了一下开发板原理图,K1连接的是单片机的P31口,当按下K1时,P31是与GND相连的,也就是说,当我按下去时
目录前言滤波电路科普主要分类实际情况单位的概念常用评价参数函数型滤波器简单分析滤波电路构成低通滤波器RC低通滤波器RL低通滤波器高通滤波器RC高通滤波器RL高通滤波器部分摘自《LC滤波器设计与制作》,侵权删。前言最近需要学习放大电路和滤波电路,但是由于只在之前做音乐频谱分析仪的时候简单了解过一点点运放,所以也是相当从零开始学习了。滤波电路科普主要分类滤波器:主要是从不同频率的成分中提取出特定频率的信号。有源滤波器:由RC元件与运算放大器组成的滤波器。可滤除某一次或多次谐波,最普通易于采用的无源滤波器结构是将电感与电容串联,可对主要次谐波(3、5、7)构成低阻抗旁路。无源滤波器:无源滤波器,又称
注意:本文主要掌握DCN自研无线产品的基本配置方法和注意事项,能够进行一般的项目实施、调试与运维AP基本配置命令AP登录用户名和密码均为:adminAP默认IP地址为:192.168.1.10AP默认情况下DHCP开启AP静态地址配置:setmanagementstatic-ip192.168.10.1AP开启/关闭DHCP功能:setmanagementdhcp-statusup/downAP设置默认网关:setstatic-ip-routegeteway192.168.10.254查看AP基本信息:getsystemgetmanagementgetmanaged-apgetrouteAP配
项目介绍随着我国经济迅速发展,人们对手机的需求越来越大,各种手机软件也都在被广泛应用,但是对于手机进行数据信息管理,对于手机的各种软件也是备受用户的喜爱小学生兴趣延时班预约小程序的设计与开发被用户普遍使用,为方便用户能够可以随时进行小学生兴趣延时班预约小程序的设计与开发的数据信息管理,特开发了小程序的设计与开发的管理系统。小学生兴趣延时班预约小程序的设计与开发的开发利用现有的成熟技术参考,以源代码为模板,分析功能调整与小学生兴趣延时班预约小程序的设计与开发的实际需求相结合,讨论了小学生兴趣延时班预约小程序的设计与开发的使用。开发环境开发说明:前端使用微信微信小程序开发工具:后端使用ssm:VU
Rails相对较新。我正在尝试调用一个API,它应该向我返回一个唯一的URL。我的应用程序中捆绑了HTTParty。我已经创建了一个UniqueNumberController,并且我已经阅读了几个HTTParty指南,直到我想要什么,但也许我只是有点迷路,真的不知道该怎么做。基本上,我需要做的就是调用API,获取它返回的URL,然后将该URL插入到用户的数据库中。谁能给我指出正确的方向或与我分享一些代码? 最佳答案 假设API为JSON格式并返回如下数据:{"url":"http://example.com/unique-url"
在我的Character模型中,我添加了:字符.rbbefore_savedoself.profile_picture_url=asset_path('icon.png')end但是,对于数据库中已存在的所有角色,它们的profile_picture_url为nil。因此,我想进入控制台并遍历所有这些并进行设置。在我试过的控制台中:Character.find_eachdo|c|c.profile_picture_url=asset_path('icon.png')end但这给出了错误:NoMethodError:undefinedmethod`asset_path'formain:O