爆款云主机2核4G限时秒杀,88元/年起!
查看详情

活动

天翼云最新优惠活动,涵盖免费试用,产品折扣等,助您降本增效!
热门活动
  • 618智算钜惠季 爆款云主机2核4G限时秒杀,88元/年起!
  • 免费体验DeepSeek,上天翼云息壤 NEW 新老用户均可免费体验2500万Tokens,限时两周
  • 云上钜惠 HOT 爆款云主机全场特惠,更有万元锦鲤券等你来领!
  • 算力套餐 HOT 让算力触手可及
  • 天翼云脑AOne NEW 连接、保护、办公,All-in-One!
  • 中小企业应用上云专场 产品组合下单即享折上9折起,助力企业快速上云
  • 息壤高校钜惠活动 NEW 天翼云息壤杯高校AI大赛,数款产品享受线上订购超值特惠
  • 天翼云电脑专场 HOT 移动办公新选择,爆款4核8G畅享1年3.5折起,快来抢购!
  • 天翼云奖励推广计划 加入成为云推官,推荐新用户注册下单得现金奖励
免费活动
  • 免费试用中心 HOT 多款云产品免费试用,快来开启云上之旅
  • 天翼云用户体验官 NEW 您的洞察,重塑科技边界

智算服务

打造统一的产品能力,实现算网调度、训练推理、技术架构、资源管理一体化智算服务
智算云(DeepSeek专区)
科研助手
  • 算力商城
  • 应用商城
  • 开发机
  • 并行计算
算力互联调度平台
  • 应用市场
  • 算力市场
  • 算力调度推荐
一站式智算服务平台
  • 模型广场
  • 体验中心
  • 服务接入
智算一体机
  • 智算一体机
大模型
  • DeepSeek-R1-昇腾版(671B)
  • DeepSeek-R1-英伟达版(671B)
  • DeepSeek-V3-昇腾版(671B)
  • DeepSeek-R1-Distill-Llama-70B
  • DeepSeek-R1-Distill-Qwen-32B
  • Qwen2-72B-Instruct
  • StableDiffusion-V2.1
  • TeleChat-12B

应用商城

天翼云精选行业优秀合作伙伴及千余款商品,提供一站式云上应用服务
进入甄选商城进入云市场创新解决方案
办公协同
  • WPS云文档
  • 安全邮箱
  • EMM手机管家
  • 智能商业平台
财务管理
  • 工资条
  • 税务风控云
企业应用
  • 翼信息化运维服务
  • 翼视频云归档解决方案
工业能源
  • 智慧工厂_生产流程管理解决方案
  • 智慧工地
建站工具
  • SSL证书
  • 新域名服务
网络工具
  • 翼云加速
灾备迁移
  • 云管家2.0
  • 翼备份
资源管理
  • 全栈混合云敏捷版(软件)
  • 全栈混合云敏捷版(一体机)
行业应用
  • 翼电子教室
  • 翼智慧显示一体化解决方案

合作伙伴

天翼云携手合作伙伴,共创云上生态,合作共赢
天翼云生态合作中心
  • 天翼云生态合作中心
天翼云渠道合作伙伴
  • 天翼云代理渠道合作伙伴
天翼云服务合作伙伴
  • 天翼云集成商交付能力认证
天翼云应用合作伙伴
  • 天翼云云市场合作伙伴
  • 天翼云甄选商城合作伙伴
天翼云技术合作伙伴
  • 天翼云OpenAPI中心
  • 天翼云EasyCoding平台
天翼云培训认证
  • 天翼云学堂
  • 天翼云市场商学院
天翼云合作计划
  • 云汇计划
天翼云东升计划
  • 适配中心
  • 东升计划
  • 适配互认证

开发者

开发者相关功能入口汇聚
技术社区
  • 专栏文章
  • 互动问答
  • 技术视频
资源与工具
  • OpenAPI中心
开放能力
  • EasyCoding敏捷开发平台
培训与认证
  • 天翼云学堂
  • 天翼云认证
魔乐社区
  • 魔乐社区

支持与服务

为您提供全方位支持与服务,全流程技术保障,助您轻松上云,安全无忧
文档与工具
  • 文档中心
  • 新手上云
  • 自助服务
  • OpenAPI中心
定价
  • 价格计算器
  • 定价策略
基础服务
  • 售前咨询
  • 在线支持
  • 在线支持
  • 工单服务
  • 建议与反馈
  • 用户体验官
  • 服务保障
  • 客户公告
  • 会员中心
增值服务
  • 红心服务
  • 首保服务
  • 客户支持计划
  • 专家技术服务
  • 备案管家

了解天翼云

天翼云秉承央企使命,致力于成为数字经济主力军,投身科技强国伟大事业,为用户提供安全、普惠云服务
品牌介绍
  • 关于天翼云
  • 智算云
  • 天翼云4.0
  • 新闻资讯
  • 天翼云APP
基础设施
  • 全球基础设施
  • 信任中心
最佳实践
  • 精选案例
  • 超级探访
  • 云杂志
  • 分析师和白皮书
  • 天翼云·创新直播间
市场活动
  • 2025智能云生态大会
  • 2024智算云生态大会
  • 2023云生态大会
  • 2022云生态大会
  • 天翼云中国行
天翼云
  • 活动
  • 智算服务
  • 产品
  • 解决方案
  • 应用商城
  • 合作伙伴
  • 开发者
  • 支持与服务
  • 了解天翼云
      • 文档
      • 控制中心
      • 备案
      • 管理中心

      【.NET 与树莓派】LED 数码管驱动模块——TM1638

      首页 知识中心 其他 文章详情页

      【.NET 与树莓派】LED 数码管驱动模块——TM1638

      2024-06-17 09:52:23 阅读次数:48

      NET

      LED 数码管,你可以将它看做是 N 个发光二级管的组合,一个灯负责显示一个段,七个段组合一位数字,再加一个小数点,这么一来,一位数码管就有八段。一般,按照顺时针的方向给每个段编号。

      【.NET 与树莓派】LED 数码管驱动模块——TM1638

      上图中的 h 就是显示小数点的段,许多电路图上都标为 dp。

      这么看来,要显示一位数字,你就需要九根连接线。由于连接的方向不同,又产生了“共阳”和“共阴”两个概念。

      共阳:即共享阳极,也就是电源正极。导线V接到电源正极上(需要串联电阻,网上很多说要 1k 欧,其实400-500欧就可以了),然后从V并联出八条走线,分别连接八段数码管,而每段数码管的负极都单独连接。这九根线就成了一正八负。

      共阴:就是使用共同的负极。用八条线(设为V1到V8),分别单独连接电源正极,然后串联电阻,依次接到八段数码管上,最后每段数码管的负相同,即八正一负。

      你要是觉得别人的图太复杂看不懂,老周替你找了一张简单的。

      【.NET 与树莓派】LED 数码管驱动模块——TM1638

      至于说怎么分辨出共阳和共阴,根据上面对二者的特点描述,方法也不难。首先,一条线连到电源正极,一条联到负极(当然不要忘了串电阻),然后在数码管上随便找两个引脚接入电路,并且要保证连接后其中某一段LED会亮的。这时候,你保持电源负极不变,用其他引脚轮流去接触电源正极,如果有多个LED发光,说明你手上的玩意儿是共阴的。同样,保持电源正极连接不变,依次尝试把其他引脚接到负极,如果有多段LED发光,说明是共阳的。

      那么,开发板如何控制哪段LED发光,哪段不发光?这里头的原理,还是那个不变的规律——电流从高电势流向低电势,即电压高的会流向电压低的。

      1、共阳数码管:共用电源正极,可以认为它输出的是高电平,然后八个段接到 GPIO 口,要想哪段LED发光就让对应的接口输出低电平,不发光就输出高电平。

      2、共阴数码管:共用电源负极,可以认为它输出的是低电平,要让某段LED发光,就让对应的 GPIO 口输出高电平。

      一位数码管就占用了九个 GPIO 接口了,要是两位数呢,再加九个,那就成了十八个了,要是有四位数呢,那估计你要买几块开发板了。就算你拼接了几块开发板,如何统一控制就很头痛了。为了节约 GPIO 引脚资源,于是又有新名词问世了——段扫描。

      这里咱们就别管它是静动扫描还是动态扫描,因为我们今天的主题是借助专门的驱动芯片的,所以有关扫描的事儿,简单了解就行。为了减少接线数量,可以把每位数的段合为一个并联电路,再单独一根线来控制数字位。例如

      【.NET 与树莓派】LED 数码管驱动模块——TM1638

       

       这么一折腾,四位数码管只需要 4 + 8 = 12 根线就能连接。不过,细心的你,此时肯定发现问题了,要是这样连接,岂不是在同一时刻只能允许一段LED发光?那我需要多段LED发光咋办?那就得扫描了,实际上就是不断地执行循环,轮番地切换控制,只要切换的速度够快,人眼是觉察不到闪烁的,于是就可以瞒天过海,骗过你的眼睛了。至于说能不能骗过猫的眼睛就不知道了,这有待生物学家们去验证了。

      比如,我要让这四位数码管显示1213,好的,“1”是 b、c 段发光,其他段不发光

      【.NET 与树莓派】LED 数码管驱动模块——TM1638

       

       “2”是 a、b、d、e、g 五段发光。

      【.NET 与树莓派】LED 数码管驱动模块——TM1638

       

       “3”是a、b、c、d、g 发光。

      【.NET 与树莓派】LED 数码管驱动模块——TM1638

       

       

      第一步,显示第一位“1”,把 1+ 接通,2+ 到 4+ 不通,再把 b c 段接通;

      第二步,显示第二位“2”,把 2+ 接通,1+、3+、4+ 不通,再接通 a b d e g 。

      第三步,显示第三位“1”,和第一位的段相同,但数位上是接通 3+,1+、2+、4+不通。

      第四步,显示第四位“3”,把 4+ 接通,其他位不通,再接通a b c d g。

      最后让上面四个步骤不断地循环。

      只要你的单片机够快,你几乎看不到闪烁。但树莓派是带操作系统的,不管怎样,通过系统层再到硬件的调用肯定会慢一拍,会出现闪烁或者部分LED段亮度不够的情况。这个循环可能用纯粹的微控制器开发板会快一点。

      然而,哪怕用上了扫描方案,还是不能解决问题。第一,占用开板的接口仍然很多,要是有八位数码管,那得16个以上的接口了;第二,开发板把“精力”都花在循环扫描上了,就没空去处理其他事情了,这样未免太浪费。于是,就出现了专门驱动LED数码管的芯片。常见的如  74HC595、TM1637、TM1638、TM1650 等。

      本文老周介绍的是 TM1638,这个“TM”不是“他妈”的意思,而是指“天微电子”。所以,你不能读作“他妈 1638”。1637 在微软开源的 Iot.Bindings 库里面已经封装了。现在某宝上能买到的 TM1637 模块基本上是封装为时钟模块,即没有小数点,而是中间加个“:”,显示时钟用的。

      而 TM1638 一般封装为一个复合模块,老周买的是这个,有八位数码管,下面有八个按钮(有的是十六个按钮),顶部有八个发光二极管。

      【.NET 与树莓派】LED 数码管驱动模块——TM1638

      这个模块有除了供电的两个引脚,用三根线来控制,怎么说也比用十几根线来得简便。

      STB:可以理解为命令控制线,在发送命令之前,STB要拉到低电平,发完命令或读取完按钮信息后,需要把STB拉回高电平。

      CLK:时钟线,其实用来控制硬件的数据处理节奏。

      DIO:数据线,高电平表示1,低电平表示0。

      注意:不管是发送还是接收数据,都是从字节的低位开始的。

       

      这个模块,其实如果玩熟练了,并不复杂,只是它用的不是标准的 SPI、IIC 协议,所以我们只能自行封装。依据数据手册,每个二进制位的读写操作都在时钟线的上升沿完成。上升沿就是 CLK 线从低电平转到高电平的瞬间,这个时间极短,就算侦听 PinEventTypes.Rising 事件(类似单片机中的中断),有可能也来不及,因为模块一旦收到此信号就会马上处理。所以,我们在写代码时,可以换个思路——在每个时钟上升沿到来之前把数据线DIO 的电平固定好,这样就不怕由于时间来不及而导致读写错位了。

      不妨看看数据手册中的时序图。

      【.NET 与树莓派】LED 数码管驱动模块——TM1638

       从时序图中可以看到。在CLK线发生上升沿时,DIO必须准备好数据(不管是拉高还是拉低),因为 TM1638 模块是以上升沿作为数据发送的信号的。也就是说,只要是在CLK的上升沿到来之前,都可以修改DIO的电平。

      故,下面的 WriteByte 方法,两个版本都是可以的。

              // 版本一
              void WriteByte(byte val)
              {
                  // 从低位传起
                  int i;
                  for (i = 0; i < 8; i++)
                  {
                      // 拉低clk线
                      _gpio.Write(CLKPin, 0);
                      // 修改dio线
                      if ((val & 0x01) == 0x01)
                      {
                          _gpio.Write(DIOPin, 1);
                      }
                      else
                      {
                          _gpio.Write(DIOPin, 0);
                      }
                      // 右移一位
                      val >>= 1;
                      // 拉高clk线,向模块发出一位
                      _gpio.Write(CLKPin, 1);
                  }
              }
      
               // 版本二
              void WriteByte(byte val)
              {
                  // 从低位传起
                  int i;
                  for (i = 0; i < 8; i++)
                  {
                      // 修改dio线
                      if ((val & 0x01) == 0x01)
                      {
                          _gpio.Write(DIOPin, 1);
                      }
                      else
                      {
                          _gpio.Write(DIOPin, 0);
                      }
                      // 右移一位
                      val >>= 1;
                      // 拉低clk线
                      _gpio.Write(CLKPin, 0);
                      // 拉高clk线,向模块发出一位
                      _gpio.Write(CLKPin, 1);
                  }
              }

      两个版本的区别在于:第一个版本中,每次发送二进制位时,先拉低CLK,再改变DIO,再拉高CLK;第二个版本则是先改变DIO的电平,再拉低CLK,然后又拉高CLK。

      其核心就是——每个二进制位都要制造一个CLK的上升沿,所以CLK在什么时候拉低不重要,重要的是只有拉低再拉高才能产生电平上升的跳变过程。

      而STB线的使用并不是看每个字节,而是看命令,发送命令前,STB要拉低电平,发送完命令后,STB线要拉高。命令可能是一个字节,也可能是两个、三个字节。总之,发送一条命令前要拉低STB,发完后要拉高STB。

       

      下面看看有哪些命令可用。

      【.NET 与树莓派】LED 数码管驱动模块——TM1638

       

       这个表把命令分为三类:设置命令、显示控制、要操作的寄存器的地址。模块通过一个字节的最高两位(B6、B7就是第7、8位)来区分。比如,你要调整数码管的显示亮度,属于显示控制命令,因此,你写入的命令字节的最高两位必须是 0b 10xx xxxx。

      1、设置命令

      格式:0b_01xx_xxxx

      【.NET 与树莓派】LED 数码管驱动模块——TM1638

       

       通过上表,会发现一件事——当把无关项全填上0后,原来有两条命令是一样的。配置模块为写显示寄存器模式时的命令是 0100 0000,并且将寄存器寻址方式设为自动增加模式时,命令也是 0100 0000。

      后面两条测试命令我们可以不管它,先看第一条,把数据写到显示寄存器,也就是说你要八位数码管显示会么,就把要显示的LED段数据写入对应的寄存器中。不知道大伙伴们还记不得前文中说的,数码管每个位有七段,加上小数点是八段,每段对应一个二进制位,哟西,正好是一个字节。排列顺序是从低位到高位。

      dp   g   f   e   d   c   b   a

      0     0  0   0   0   0   0   0

      如果要显示0,即a b c d e f 要点亮,那就是 0011 1111;

      要显示1,即 b c 段要点亮,也就是 0000 0110;

      要显示3,即 a b c d g 段要点亮,就是 0100 1111。

      最高位是小数点,若要让3后面的小数点点亮,就是 1100 1111。

      要点亮的位放 1,不点亮的位放 0。

       

      这款TM1638模块有八位数码管,因此,需要有八个寄存器来存放,每个寄存器对应一位。

      【.NET 与树莓派】LED 数码管驱动模块——TM1638

       

       可数据手册中我们看到了十六个寄存器,地址从 0x00 到 0x0F。原来每个数码位有两个字节,占了两个寄存器。第一个字节 SEG1 到 SEG8,就是一位数码管中的八段,那么第二个字节中还有两位(SEG9、SEG10)是啥?回过头再看看这模块,每一位数码管上面都对应有一盏小灯,所以这第二个字节的第一位(SEG9)就是用来控制这个小灯亮不亮的,因为模块只为单个数码管配了一个灯,所以只有 SEG9 位有效,SEG10 用不上。

      举个例子,假如我要在第二位数码管上显示“1”,从表中看到,GRID2 的 SEG1-SEG8,对应寄存器地址为 0x02,前面我们分析过,显示“1”,就是让 b c 段发光,字节是 0000 0110,所以,往 0x02 写入 0x06(0110)即可,如果还想点亮第二位数码管上面的灯,就向 0x03 写入 0x01(0000 0001)即可。

      咱们进一步总结发现,点亮数码管的寄存器地址都是偶数,即 2 * n,假设要控制第一位,地址就是 2 * 0 = 0,要控制第三位,则地址就是  2 * 2 = 4。排序从0开始,即第0位到第7位。

      点亮数码管上面的小灯,其寄存器地址是奇数,即 2 * n + 1,例如,要点亮第五位的小灯,寄存器地址为 2 * 4 + 1 = 9,写入 0x80。

       

      2、寻址与写数据

      下面说说两种寄存器寻址方式,即设置命令中的

      【.NET 与树莓派】LED 数码管驱动模块——TM1638

       

       如果是自动增加地址,要发送两条命令:

      1、(STB拉低)一个字节,0100 0000,表示自增地址(STB拉高);

      2、(STB拉低)N 个字节,其中第一个字节是首地址,之后是数据。模块会将第一个数据字节写入首地址,然后地址自动 +1,再写第二个,……

           例如,0x02 0x81 0x77 0x25,标定首地址是 0x02,把 0x81 写入 0x02;然后地址 +1 变成 0x03,再把 0x77 写入0x03;地址再++,变成0x04,把0x25写入0x04(STB拉高)。

      如果是固定地址呢

      1、(STB拉低)发送命令 0100 0100,即 0x44(STB拉高);

      2、(STB拉低)写入两个字节,第一个是地址 0x02,第二个是数据0x80(STB拉高);

      3、(STB拉低)写入两个字节,第一个是地址 0x03,第二个是数据 0x77(STB拉高);

      4、(STB拉低)写入两个字节,第一个是地址 0x04,第二个是数据 0x25(STB拉高)。

      时序如下

      【.NET 与树莓派】LED 数码管驱动模块——TM1638

       

       【.NET 与树莓派】LED 数码管驱动模块——TM1638

       

       

      3、显示控制命令

      【.NET 与树莓派】LED 数码管驱动模块——TM1638

       

       显示控制命令都是 10xx xxxx 格式,高四位字节都是 1000,参数设置用到的只有低四位。其中,低三位用来设置亮度,表中的“消光数量”说白了就是亮度调整,范围是 0 - 7,因为只有三个二进制位,所以最大值只能是 7。第四位用来设置是否开启数码管的显示,如果为 0 表示关闭数码管显示,就算你把亮度调到7也不会显示;如果为 1 表示开启数码管显示。说简单一点就是,第四位,1 时开显示器,0 是关显示器。

       

      =====================================================================================

      好了,前面所讲的都是理论介绍,这个模块还有一个扫描按键的功能,这个老周下一篇烂文再扯,本文的重点是说说怎么写显存(显示寄存器),即让数码管显示指定内容。

      前文中已经写好了 WriteByte 方法,下面咱们再加一层封装,写个 WriteCommand 方法,用于向 TM1638 发送命令。

              void WriteCommand(byte cmd, params byte[] data)
              {
                  // 拉低stb
                  _gpio.Write(STBPin, 0);
                  WriteByte(cmd);
                  if (data.Length > 0)
                  {
                      // 写附加数据
                      foreach (byte b in data)
                      {
                          WriteByte(b);
                      }
                  }
                  // 拉高stb
                  _gpio.Write(STBPin, 1);
              }

      如果命令只有一个字节,那么传参数时只考虑 cmd 参数,data 参数忽略;如果命令带附加数据,则传给 data 参数。比如上面说的自动增加地址,cmd 传寄存器地址,data 传要写入各个寄存器的数据。

      随后,我们再往上封装一层,实现 SetChar 方法,直接设置要显示的数据,以及显示在第几位数码管上。

              public void SetChar(byte c, byte pos)
              {
                  // 寄存器地址
                  byte reg = (byte)(pos * 2);
                  byte com = (byte)((byte)TM1638Command.SetDisplayAddress | reg);
                  WriteCommand(com, c);
              }

      参数 c 表示要写入的数据,也就是一位数码管中各个段的二进制位的值;pos 参数指的显示在第几位,老周买的这个模块有八位数码管,所以,pos 参数的取值范围是 0 到 7。寄存器的地址就是 pos * 2。

      为了在初始化时,或者需要时清空所有数码管的显示(所有二进制位置0),还要写一个 CleanChars 方法。

              public void CleanChars()
              {
                  int i = 0;
                  while(i < 8)
                  {
                      SetChar(0x00, (byte)i);
                      i++;
                  }
              }

      接下来是控制每位数码管对应的小灯。

              public void SetLED(byte n, bool on)
              {
                  byte addr = (byte)(n * 2 + 1); //寄存器地址
                  // 1100_xxxx
                  byte cmd = (byte)((byte)TM1638Command.SetDisplayAddress| addr );
                  byte data = (byte)(on? 1 : 0);
                  WriteCommand(cmd,data);
              }
      
              public void CleanLEDs()
              {
                  int i=0;
                  while(i<8)
                  {
                      SetLED((byte)i, false);
                      i++;
                  }
              }

      n 选择控制第几个灯,和数码管一样,从 0 到 7,on 表示是否点亮,true 点亮否则熄灭。

      上面代码用的命令,可以用枚举类型声明,使用时直接访问。

          internal enum TM1638Command : byte
          {
              // 读按钮扫描
              ReadKeyScanData = 0b_0100_0010,
              // 自动增加地址
              AutoIncreaseAddress = 0b_0100_0000,
              // 固定地址
              FixAddress = 0b_0100_0100,
              // 选择要读写的寄存器地址
              SetDisplayAddress = 0b_1100_0000,
              // 显示控制设置
              DisplayControl = 0b_1000_0000
          }

       

       

      为了方便操作,也可以将常用的数字(0-9)的数据用常量声明,使用时直接引用。

          public class Numbers
          {
              public const byte Num0 = 0b_0011_1111;  //0
              public const byte Num1 = 0b_0000_0110;  //1
              public const byte Num2 = 0b_0101_1011;  //2
              public const byte Num3 = 0b_0100_1111;  //3
              public const byte Num4 = 0b_0110_0110;  //4
              public const byte Num5 = 0b_0110_1101;  //5
              public const byte Num6 = 0b_0111_1101;  //6
              public const byte Num7 = 0b_0000_0111;  //7
              public const byte Num8 = 0b_0111_1111;  //8
              public const byte Num9 = 0b_0110_1111;  //9
      
              public const byte DP = 0b_1000_0000;    //小数点

                public static byte GetData(char c) =>
                      c switch
                      {
                          '0'     => Num0,
                          '1'     => Num1,
                          '2'     => Num2,
                          '3'     => Num3,
                          '4'     => Num4,
                          '5'     => Num5,
                          '6'     => Num6,
                          '7'     => Num7,
                          '8'     => Num8,
                          '9'     => Num9,
                          _       => Num0
                      };
          }

       

      下面是 TM1638 类的完整代码,这里老周选用的是固定地址的寄存器读写方式。

          public class TM1638 : IDisposable
          {
              GpioController _gpio;
      
              // 构造函数
              public TM1638(int stbPin, int clkPin, int dioPin)
              {
                  STBPin = stbPin;    // STB 线连接的GPIO号
                  CLKPin = clkPin;    // CLK 线连接的GPIO号
                  DIOPin = dioPin;    // DIO 线连接的GPIO号
                  _gpio = new();
                  // 将各GPIO引脚初始化为输出模式
                  InitPins();
                  // 设置为固定地址模式
                  InitDisplay(true);
              }
      
              // 打开接口,设定为输出
              private void InitPins()
              {
                  _gpio.OpenPin(STBPin, PinMode.Output);
                  _gpio.OpenPin(CLKPin, PinMode.Output);
                  _gpio.OpenPin(DIOPin, PinMode.Output);
              }
              private void InitDisplay(bool isFix = true)
              {
                  if (isFix)
                  {
                      WriteCommand((byte)TM1638Command.FixAddress);
                  }
                  else
                  {
                      WriteCommand((byte)TM1638Command.AutoIncreaseAddress);
                  }
                  // 清空显示
                  CleanChars();
                  CleanLEDs();
                  WriteCommand(0b1000_1111); //亮度最高 + 开启显示
              }
      
              #region 公共属性
              // 控制引脚号
              public int STBPin { get; set; }
              public int CLKPin { get; set; }
              public int DIOPin { get; set; }
              #endregion
      
              public void Dispose()
              {
                  _gpio?.Dispose();
              }
      
              #region 辅助方法
              void WriteByte(byte val)
              {
                  // 从低位传起
                  int i;
                  for (i = 0; i < 8; i++)
                  {
                      // 拉低clk线
                      _gpio.Write(CLKPin, 0);
                      // 修改dio线
                      if ((val & 0x01) == 0x01)
                      {
                          _gpio.Write(DIOPin, 1);
                      }
                      else
                      {
                          _gpio.Write(DIOPin, 0);
                      }
                      // 右移一位
                      val >>= 1;
                      //_gpio.Write(CLKPin, 0);
                      // 拉高clk线,向模块发出一位
                      _gpio.Write(CLKPin, 1);
                  }
              }
      
      
              void WriteCommand(byte cmd, params byte[] data)
              {
                  // 拉低stb
                  _gpio.Write(STBPin, 0);
                  WriteByte(cmd);
                  if (data.Length > 0)
                  {
                      // 写附加数据
                      foreach (byte b in data)
                      {
                          WriteByte(b);
                      }
                  }
                  // 拉高stb
                  _gpio.Write(STBPin, 1);
              }
              #endregion
      
              public void SetChar(byte c, byte pos)
              {
                  // 寄存器地址
                  byte reg = (byte)(pos * 2);
                  byte com = (byte)((byte)TM1638Command.SetDisplayAddress | reg);
                  WriteCommand(com, c);
              }
              public void SetLED(byte n, bool on)
              {
                  byte addr = (byte)(n * 2 + 1); //寄存器地址
                  // 1100_xxxx
                  byte cmd = (byte)((byte)TM1638Command.SetDisplayAddress| addr );
                  byte data = (byte)(on? 1 : 0);
                  WriteCommand(cmd,data);
              }
              public void CleanChars()
              {
                  int i = 0;
                  while(i < 8)
                  {
                      SetChar(0x00, (byte)i);
                      i++;
                  }
              }
              public void CleanLEDs()
              {
                  int i=0;
                  while(i<8)
                  {
                      SetLED((byte)i, false);
                      i++;
                  }
              }
          }

      下面简单试一下,在第一位数码管上显示4,第四位数码管上显示2,第七位数码管上显示5。并点亮第二、第八盏小灯。

              static void Main(string[] args)
              {
                  using TM1638 dev = new(13, 19, 26);
                  dev.SetChar(Numbers.Num4, 0);
                  dev.SetChar(Numbers.Num2, 3);
                  dev.SetChar(Numbers.Num5, 6);
                  dev.SetLED(1, true);
                  dev.SetLED(7, true);
              }

      上传到树莓派上面,运行效果如下图所示。

      【.NET 与树莓派】LED 数码管驱动模块——TM1638

       

      再给一个例子,咱们读取一下树莓派当前的 CPU 温度,并用数码管显示。

              static void Main(string[] args)
              {
                  using TM1638 dev = new(13, 19, 26);
                  while (true)
                  {
                      string result = File.ReadAllText("/sys/class/thermal/thermal_zone0/temp");
                      // 还要除以1000
                      result = (float.Parse(result) / 1000f).ToString("#.00");
                      Console.WriteLine("计算结果:\"{0}\"", result);
                      // 拆分字符串,显示各个数字
                      int len = result.Length;
                      List<byte> datas = new List<byte>();
                      for (byte i = 0; i < len; i++)
                      {
                          // 小数点不单独占一个位,要忽略
                          if (result[i] == '.')
                          {
                              continue;
                          }
                          char ch = result[i];
                          // 获取显示数据
                          byte b = Numbers.GetData(ch);
                          // 如果该位不是最后一位
                          // 且下一个字符是小数点,则应该点亮 DP
                          if (i < (len - 1) && result[i + 1] == '.')
                          {
                              b |= Numbers.DP;
                          }
                          datas.Add(b);
                      }
                      for (byte x = 0; x < datas.Count; x++)
                      {
                          dev.SetChar(datas[x], x);
                      }
                      Thread.Sleep(2000);
                  }
              }

      执行 dotnet 命令发布代码。

      dotnet publish

      执行 scp 命令上传到树莓派。

      scp -r bin\Debug\net5.0\publish\* pi@<树莓派地址>:/home/pi/<你自己挑个目录>

      然后运行示例程序:dotnet xxx.dll

      就能看到CPU的温度了。

      【.NET 与树莓派】LED 数码管驱动模块——TM1638

      版权声明:本文内容来自第三方投稿或授权转载,原文地址:https://www.cnblogs.com/tcjiaan/p/14929910.html,作者:东邪独孤,版权归原作者所有。本网站转在其作品的目的在于传递更多信息,不拥有版权,亦不承担相应法律责任。如因作品内容、版权等问题需要同本网站联系,请发邮件至ctyunbbs@chinatelecom.cn沟通。

      上一篇:Windows Server 2012 GUI与Core的切换

      下一篇:CentOS 查询指定用户组下的所有用户

      相关文章

      2024-06-26 06:18:07

      【.NET深呼吸】(WPF)跨窗口完成绑定

      在99.999975%的情形下,可视化元素之间的相互绑定都会在同一个容器中完成,如同一个窗口,同一个UserControl等。但在极少数的情况下,为了从最大限度减少代码赋值的前提下考虑,是可以使用跨窗口绑定。

      2024-06-26 06:18:07
      NET , WPF
      2024-06-26 06:17:16

      【.NET 与树莓派】TM1638 模块的按键扫描

      TM1638 的数码管驱动,这个模块除了驱动 LED 数码管,还有一个功能:按键扫描。

      2024-06-26 06:17:16
      NET
      2024-06-26 06:17:16

      【.NET 与树莓派】九种手势识别模块(PAJ7620)

      【.NET 与树莓派】九种手势识别模块(PAJ7620)

      2024-06-26 06:17:16
      NET , 寄存器
      2024-06-26 06:17:16

      【.NET 与树莓派】WS28XX 灯带的颜色渐变动画

      【.NET 与树莓派】WS28XX 灯带的颜色渐变动画

      2024-06-26 06:17:16
      NET
      2024-05-28 09:01:53

      【.net 深呼吸】监听剪贴板更新(针对Vista之后系统)

      针对 XP 及以前的监视剪贴板更改的方法就不讲了,因为 XP 已严重过时。

      2024-05-28 09:01:53
      NET , WPF
      2024-05-28 09:01:53

      【.net 深呼吸】在配置节中使用元素集合

      前一篇博文中,老周介绍了自定义配置节的方法,本文咱们再往深一层,再看看如何在自定义的配置节中使用配置元素集合。

      2024-05-28 09:01:53
      NET , 元素 , 集合
      2024-04-16 08:52:39

      .NET NPOI导出时间、公式等格式化

      .NET NPOI导出时间、公式等格式化

      2024-04-16 08:52:39
      NET
      2024-03-28 08:17:27

      【.NET深呼吸】Zip文件操作(2):动态生成Zip文档

      【.NET深呼吸】Zip文件操作(2):动态生成Zip文档

      2024-03-28 08:17:27
      IO , NET
      查看更多
      推荐标签

      作者介绍

      天翼云小翼
      天翼云用户

      文章

      33561

      阅读量

      5248580

      查看更多

      最新文章

      【.NET深呼吸】(WPF)跨窗口完成绑定

      2024-06-26 06:18:07

      【.NET 与树莓派】WS28XX 灯带的颜色渐变动画

      2024-06-26 06:17:16

      【.NET 与树莓派】九种手势识别模块(PAJ7620)

      2024-06-26 06:17:16

      【.NET 与树莓派】TM1638 模块的按键扫描

      2024-06-26 06:17:16

      .NET NPOI导出时间、公式等格式化

      2024-04-16 08:52:39

      【.NET深呼吸】Zip文件操作(2):动态生成Zip文档

      2024-03-28 08:17:27

      查看更多

      热门文章

      【.NET深呼吸】Zip文件操作(2):动态生成Zip文档

      2024-03-28 08:17:27

      .NET NPOI导出时间、公式等格式化

      2024-04-16 08:52:39

      【.NET 与树莓派】TM1638 模块的按键扫描

      2024-06-26 06:17:16

      【.NET 与树莓派】九种手势识别模块(PAJ7620)

      2024-06-26 06:17:16

      【.NET 与树莓派】WS28XX 灯带的颜色渐变动画

      2024-06-26 06:17:16

      【.NET深呼吸】(WPF)跨窗口完成绑定

      2024-06-26 06:18:07

      查看更多

      热门标签

      linux java python javascript 数组 前端 docker Linux vue 函数 shell git 节点 容器 示例
      查看更多

      相关产品

      弹性云主机

      随时自助获取、弹性伸缩的云服务器资源

      天翼云电脑(公众版)

      便捷、安全、高效的云电脑服务

      对象存储

      高品质、低成本的云上存储服务

      云硬盘

      为云上计算资源提供持久性块存储

      查看更多

      随机文章

      【.NET深呼吸】Zip文件操作(2):动态生成Zip文档

      【.NET 与树莓派】TM1638 模块的按键扫描

      【.NET 与树莓派】九种手势识别模块(PAJ7620)

      【.NET 与树莓派】WS28XX 灯带的颜色渐变动画

      【.NET深呼吸】(WPF)跨窗口完成绑定

      .NET NPOI导出时间、公式等格式化

      • 7*24小时售后
      • 无忧退款
      • 免费备案
      • 专家服务
      售前咨询热线
      400-810-9889转1
      关注天翼云
      • 旗舰店
      • 天翼云APP
      • 天翼云微信公众号
      服务与支持
      • 备案中心
      • 售前咨询
      • 智能客服
      • 自助服务
      • 工单管理
      • 客户公告
      • 涉诈举报
      账户管理
      • 管理中心
      • 订单管理
      • 余额管理
      • 发票管理
      • 充值汇款
      • 续费管理
      快速入口
      • 天翼云旗舰店
      • 文档中心
      • 最新活动
      • 免费试用
      • 信任中心
      • 天翼云学堂
      云网生态
      • 甄选商城
      • 渠道合作
      • 云市场合作
      了解天翼云
      • 关于天翼云
      • 天翼云APP
      • 服务案例
      • 新闻资讯
      • 联系我们
      热门产品
      • 云电脑
      • 弹性云主机
      • 云电脑政企版
      • 天翼云手机
      • 云数据库
      • 对象存储
      • 云硬盘
      • Web应用防火墙
      • 服务器安全卫士
      • CDN加速
      热门推荐
      • 云服务备份
      • 边缘安全加速平台
      • 全站加速
      • 安全加速
      • 云服务器
      • 云主机
      • 智能边缘云
      • 应用编排服务
      • 微服务引擎
      • 共享流量包
      更多推荐
      • web应用防火墙
      • 密钥管理
      • 等保咨询
      • 安全专区
      • 应用运维管理
      • 云日志服务
      • 文档数据库服务
      • 云搜索服务
      • 数据湖探索
      • 数据仓库服务
      友情链接
      • 中国电信集团
      • 189邮箱
      • 天翼企业云盘
      • 天翼云盘
      ©2025 天翼云科技有限公司版权所有 增值电信业务经营许可证A2.B1.B2-20090001
      公司地址:北京市东城区青龙胡同甲1号、3号2幢2层205-32室
      • 用户协议
      • 隐私政策
      • 个人信息保护
      • 法律声明
      备案 京公网安备11010802043424号 京ICP备 2021034386号