文章目录

  • 前言
  • 一、硬件特性
  • 二、软件驱动器
    • 1.软件与数码管的接口
    • 2.多路数据块复用器
    • 3. 回到开头的进度条

文章记录一段旅程–使用数码管显示它能显示的任何内容。

前言

  数码管的特点是比较亮,隔老远就能看得清清楚楚,虽然大部分情况它被用来显示数字,但是如果合理拼凑也能显示出各种各样有意思的东西,比如进度条。当然我希望它能显示任何它能力范围内的东西。

一、硬件特性

  其实这个例子我并不是很想研究硬件,但是呢来都来了,就简单看一看吧。

  首先是74HC245芯片,这是一个三态8线双向收发器,也就是数据既可以从A端流向B端也可以反着来,不过它在这个电路的主要是用来驱动数码管的,虽然单片机IO不见得不能直驱数码管,但是需要精心地去设计驱动方式,比如要避免同时点亮所有数码管等等,加了这个东西可以提高系统的稳定裕度,省心。

  然后是74HC138译码器,这是一个三八译码器,8421码转十进制选择线,下图中A管脚的权值为1,B的权值为2,C的权值为4。研究一种特例,CBA=101,换成10进制是5,那么芯片会让“Y5非”标识的那个端口变成0,而其他端口变成1,恰好这个例子用的数码管是共阴的,所以对应的数码管会被选中。

  这个芯片有个好处是正常工况下它永远只有一个输出管脚为0或者所有输出管脚为1,并且由于硬件配置问题,使得在任意时刻有且仅有一位数码管被选中,这可以从设计的角度限制系统功耗。

  总之,要点亮某个数码管的某一段,只要让数码管的共阴位选线为0,阳极段选线为1就能点亮了。本质上这就是在点亮LED灯,可以参考下面软件驱动器小节的第二张图,手绘的那张。

二、软件驱动器

1.软件与数码管的接口

  思路永远从简单的开始。先操作一位数字,也就是下图中红框框起来的基本单元,然后再想办法操作整个数码管。


  上面画的是关于数码管的其中一位的详细信息。要操作它,可以先确定a到dp的值,然后给共阴端口送入逻辑0,当然也可以反着来。得益于研究led点阵驱动器的经验,注意到74HC138与74HC245的传输速度不见得是一样的,如果速度相差过大,那么段数据和位数据先送谁就要关注一下了。转化成代码如下所示。

typedef enum{TUBE1 = 0,TUBE2,TUBE3,TUBE4,TUBE5,    TUBE6,TUBE7,TUBE8,
}tubeIndex_t;void operateOneTube(tubeIndex_t tubeIndex, uint8_t content){switch(tubeIndex){case TUBE1:#error "step1:操作数码管对应位的共阴端为0"break;}#error "step2:为数码管该位的各阳极端口赋值"
}

  操作一个数码管的底层代码,尽量不要做任何多余的动作,只需要指定让哪一个数码管显示什么样的内容即可,尽可能保证这个过程的纯粹性以确保最大限度的可复用性。
  至于要显示什么数字、字母、图形,或者要不要闪烁是上层代码的事情,这些都可以通过逻辑或算法获得数据流,然后让数据流在不同的时间流入operateOneTube函数最终显示出各种各样的内容。

  接下来是要操作整排数码管。动态扫描很好用,直接用这个方法。在点亮一位数码管的基础上进行动态扫描以点亮多个数码管,需要增加延时稳定显示以及消隐操作,这几乎是每一个单片机操作数码管教程都会提的事情。

void operateOneTube(tubeIndex_t tubeIndex, uint8_t content){#error "step1:操作数码管对应位的共阴端为0"#error "step2:为数码管该位的各阳极端口赋值"#error "step3(延时):延时以稳定显示,增加数码管亮度"#error "step4(消隐):清除单片机用于驱动数码管阳极的端口上的值,防止下一位数码管显示当前内容"
}

  操作全部的8位数码管。建立一个缓冲区unsigned char tubeBuf[8],缓冲区共8个字节,每一个字节用于存放指定位的数码管数据。数码管要刷新显示的时候就来缓存里面取数据,其他应用要调用数码管时就向缓存里面写数据,利用缓存,数码管所有的行为都被抽象为随时间变化的数据流,这其中包括完全关闭数码管(全0数据流)。

//数码管数据缓冲,有多少个字符就要有多少缓冲区
unsigned char tubeBuf[8] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
void displayAnythingByAllTube(unsigned char disBuff[]){operateOneTube(TUBE1,disBuff[0]);operateOneTube(TUBE2,disBuff[1]);operateOneTube(TUBE3,disBuff[2]);operateOneTube(TUBE4,disBuff[3]); operateOneTube(TUBE5,disBuff[4]);operateOneTube(TUBE6,disBuff[5]);operateOneTube(TUBE7,disBuff[6]);operateOneTube(TUBE8,disBuff[7]);
}

  突然想起一件事情,那就是上面说的缓存的并发访问问题。假如将数码管刷新函数displayAnythingByAllTube放在一个定时器中断里面以固定数码管刷新率,然后主程序的任意位置可以操作这个缓存,如果主程序操作这个缓存到一半时发生了数码管刷新中断呢?显示的数据就有可能出现乱码,这个事件并不是每时每刻一定会发生,偶发性bug往往是把人搞得焦头烂额的元凶。所以当前想到这个事情就写在提醒自己一下,具体要怎么解决我暂时也不在乎。或许可以使用二级缓存以及互斥锁机制来处理这个事情,然而事情开始变得复杂起来了。

2.多路数据块复用器

  使用这个东西主要是想让数码管的某一位闪烁起来,比如在设置参数的时候,这样搞可以指示目前在设置数字的哪一位。

  下面的机构运行起来有一个前提条件,数码管刷新的速度和复用器运行的速度必须要远大于某个数字闪烁的速度,当然由于单片机的运行速度很快,而且高于30帧的刷新率人眼是瞧不出来的,这个条件可以自然得到保证。

  在前几篇文章(蜂鸣器,led)里面讨论过的多路逻辑复用器的基础上。将复用器的输入输出参数修改为数据块,当然在c里面写程序时指定的是数据块起始地址指针。

typedef struct dataMUX           //数据复用器
{unsigned char selfActionSignal;void* currentOutput;enum{OUT_LINK_TO_CH1 = 0,OUT_LINK_TO_CH2,}linkCH;void* inputChannel1;void* inputChannel2;void (*step)(struct dataMUX* multiplexer);void (*processSignal)(unsigned char signal, unsigned char value, struct dataMUX* multiplexer);
}dataMUX_t;

  然后是主循环和中断代码。由于代码比较冗长,所以只构造伪代码,其中最主要的还是协调各功能模块的运行时间,伪代码足够了。关于上面的多路复用器的运行机制与部分代码,请移步文章《【电子电路基础实验】无源蜂鸣器》。

int main(void){#error "初始化定时器"#error "启动定时器"while(1){#error "step1: 运行数据复用器并装载数码管显示缓存tubeBuf最长时间 = 920us"#error "step2: 刷新数码管时间固定 = 15.6ms"}
}void T0_interrupt(void) interrupt 1 {#error "step1: 重载T0定时器初值以及其他辅助代码段最长时间 = 89us"#error "step2: 运行用于数字闪烁的虚拟定时器最长时间 = 75us"
}

  闹了半天刷新数码管花的时间最多。由于前面讨论过的缓存并发访问的问题,我觉得最直接的方法是把装载tubeBuf的代码与刷新数码管的代码捆在一起,要么都放在中断里面,要么都放在主循环里面,在这个简单的例子里面当然放在哪里都一样,但是工程变得复杂的时候中断里面就不太合适,刷新一次数码管花的时间太长,如果在建的还是个高频采样系统,那这个事情就麻烦了。
  就目前而言,针对上面伪代码的模块分配方式,我觉得下面的时间搭配是一种可行的办法,50ms一次定时器中断可以保证主循环中的数码管数据装载与刷新过程至少能不间断地执行两轮,而定时器中断服务函数至多消耗164us,即使打断数码管刷新函数,实测是看不出来数码管频闪的,并且50ms定时器中断仍然能保证能为数码管闪烁提供足够的时基。

  另外,在采样系统中,数码管的刷新时间就要引起足够的重视,比如使用1kHz的采样率对一个信号持续采样32点用于信号处理,采样间隔要求稳定,显然刷新数码管和采样这两件事情需要精心地去协调,亦或者牺牲成本增加驱动芯片之类的东西来兼得。

3. 回到开头的进度条

  得益于displayAnythingByAllTube函数接收显示内容的任意性,我们可以随意构造、拼凑数码管图形。在构造进度条时,先构造多个静态的显示数据,比如进度为0%时是什么样子,进度为25%时是什么样子,然后让这些数据汇入时间流就构造完成了完整的进度条。

//进度条段选表-高电平使能
const unsigned char code progressBarTubeData[9][8] = {{0x39,0x09,0x09,0x09,0x09,0x09,0x09,0x0F},  //0%{0x79,0x09,0x09,0x09,0x09,0x09,0x09,0x0F},  //12.5%{0x79,0x49,0x09,0x09,0x09,0x09,0x09,0x0F},  //25%  {0x79,0x49,0x49,0x09,0x09,0x09,0x09,0x0F},  //37.5%{0x79,0x49,0x49,0x49,0x09,0x09,0x09,0x0F},  //50%{0x79,0x49,0x49,0x49,0x49,0x09,0x09,0x0F},  //62.5%{0x79,0x49,0x49,0x49,0x49,0x49,0x09,0x0F},  //75%{0x79,0x49,0x49,0x49,0x49,0x49,0x49,0x0F},  //87.5%{0x79,0x49,0x49,0x49,0x49,0x49,0x49,0x4F},  //100%
};

  受限于数码管的位数,本例的进度条最小刻度为12.5%。

【电子电路基础实验】数码管相关推荐

  1. 【电子电路基础实验】无源蜂鸣器

    文章目录 背景 一.硬件驱动器 二.软件驱动器 本文记录一段旅程–控制无源蜂鸣器嗡嗡作响. 背景 小时候,看科幻电影都是瞪大了眼睛,竖直了耳朵,生怕错过了精彩的情节.仙女座星系,宇宙飞船距某颗类地行星 ...

  2. 【电子电路基础实验】LED点阵(上--硬件部分)

    文章目录 背景 主题活动 一. 74HC595和LED点阵之间的电气与数字接口 电气接口 数字接口 记录一段旅程–使用74HC595串转并8位移位寄存器来控制LED点阵. 背景 点亮了一颗led,就会 ...

  3. 【电子电路基础实验】LED闪烁实验

    目录 背景 硬件驱动器 软件驱动器 像航障灯那样闪烁 想怎么闪就怎么闪 本文记录一段旅程–让一颗LED灯闪烁起来. 背景 我随手拿了一块普中的51单片机的开发板,上面恰好有很多led灯,我想让其中一个 ...

  4. 计算机电路基础放大电路实验,计算机电路基础实验报告.doc

    计算机电路基础实验报告 班级姓名学号 实验一戴维南定理的实验 实验一 戴维南定理的实验 71计算公式: 71 计算公式: 一.预习要求 复习戴维南定理的内容,实验前将步骤4计算结果填入表格,并注意思考 ...

  5. 计算机电路基础实验一仪器使用,计算机电路基础实验指导.doc

    计算机电路基础实验指导 <> 实 验 指 导 计算机科学与技术系 2014年4月 课程编码: 教学课时数:学时,其中课堂讲授学时,实验12学时. 学分:学分 适用专业: 开课单位:撰写人: ...

  6. 模拟电子电路基础——放大器理解与梳理

    本文以杭州电子科技大学刘圆圆老师主编的<模拟电子电路基础>为基础,结合清华大学电子学教研组编著的<模拟电子技术基础>进行相关知识的整理理解分析 放大电路 放大电路能够线性或者非 ...

  7. 红警职教智能硬件电子电路基础版教材与配套视频资源即将开发完毕

    经过数月的精心准备,红警智能硬件电路基础与无人机可视化编程视频与在线直播课程即将上线啦~~~! 本系列课程是由公司硬件工程师团队自主开发并分享,适合零基础,电子电路基础等内容,了解智能家居.智能交通. ...

  8. 电子电路基础 (1)——电子电路常识

    一.电子电路常识 原理图 万用表 示波器 1.1 电流 电荷运动称为电流,即电荷在导体内有规律的流动称为电流.电流用I表示,单位为安培,用A表示. 1.2 电子电路 电子电路就是由电阻.线圈.电容.和 ...

  9. 计算机电子电路基础教程视频,电子电路基础详细视频教学(100集)

    本教学视频通过强调电子电路系统设计者所需的实用方法,即对电路的基本原理.经验准则以及大量实用电路设计技巧的全面总结,侧重探讨了电子学及其电路的设计原理与应用.它不仅涵盖了电子学通常研究的全部知识点,还 ...

最新文章

  1. 运维工程师必备之MySQL数据的主从复制、半同步复制和主主复制详解
  2. python画动态图代码-Python使用matplotlib画动态图
  3. 这样写交互说明,开发不会约你去爬山~
  4. 高考前几天我们应该干什么?
  5. 二叉搜索树(创建,插入,删除):基础篇,适合新手观看。
  6. 自定义ui_如何允许用户自定义UI
  7. restTemplate使用和踩坑总结
  8. SQL Server含逗号分隔的数据匹配维表
  9. Springboot06配制拦截器
  10. HDU 2224 The shortest path
  11. UVa 10806 Dijkstra,Dijkstra(最小费用最大流)
  12. JAVA生产者消费者的实现
  13. VMware Workstation Pro 无法在Windows上运行的解决方法
  14. VMProtect修复导入表的插件
  15. linux arm sbus,嵌入式ARM系列linux2.4配置makefile完全注释(2)
  16. 位图字体的制作与使用
  17. java 仓库管理系统源码
  18. Linux中vim的安装和使用
  19. 鱼雷武器控制系统半实物仿真系统ETest设计与实现
  20. LabWindows/CVI(一):各文件类型的含义及初始项目的搭建

热门文章

  1. C5t:函数求长方形的周长和面积
  2. gnome3 修改gtk主题,鼠标主题,窗口主题
  3. Swagger框架学习分享
  4. LeetCode题解(0594):计算最长和谐子序列(Python)
  5. java基于Springboot+vue 的在线药品销售商城购药管理系统 elementui
  6. 2021年1月6日订阅朋友的问题与解决方案汇总
  7. Tableau培训学习笔记3:空间数据分析——科比投篮以及新冠肺炎分析(带数据)
  8. Discriminative Correlation Filters (DCF)
  9. MySql 自定义函数,存储过程,游标的使用
  10. 用Scratch 巧解奥数题