当前位置: 首页 > news >正文

嵌入式人工智能(44-基于树莓派4B的扩展板-LED按键数码管TM1638)

树莓派性能非常强悍,但是对于某些复杂的项目来说,会出现心有余而口不足的情况,为了解决这类问题,可以在树莓派上使用扩展板,我们介绍几款常见的扩展板,不仅可以扩展到树莓派,其他单片机或嵌入式处理器均可以扩展。这几种扩展板分别是IIC Bus Expansion Board 、TM1638、PCA9685、PCF8574。

1、IIC Bus Expansion Board 

这个也叫IIC集线器,Hub,我们之前介绍过,凡是IIC总线设备均可以接,一共可扩展8个IIC设备,如OLED、PCF8591、气压传感器,光照强度传感器等,使用IIC总线通信的芯片还是很多的,这个设备不仅可以扩展,还可以级联,用起来非常方便。

2、TM1638

下图是扩展板的正面图,方方正正,规规整整,看着真舒服,比接一堆杜邦线好看多了。而且淘宝售价仅5元。它是按键数码管LED显示模块,只需要连接树莓派3根GPIO线,就可以实现基本功能的输入输出。玩过单片机的同学都知道,按键LED数码管各8个是非常消耗IO口的,至少也需要十几个端口把,通过这个芯片全部解决,我后面的实验都用这个来做输入输出了,但是要想玩好,还需要理解Python语言的多线程与异步编程,后面有机会我也会详细介绍。

(1)简介

TM1638是深圳市天微电子有限公司设计的一款带键盘扫描接口的LED(发光二极管显示器)驱动控制专用芯片,内部集成有MCU数字接口、数据锁存器、LED高压驱动、键盘扫描等电路。主要应用于冰箱、空调 、家庭影院等产品的高段位显示屏驱动。

(2)器件特性

  • 采用功率CMOS 工艺
  • 显示模式 10 段×8 位
  • 键扫描(8×3bit)
  • 8级辉度可调
  • 串行接口(CLK,STB,DIO)
  • 振荡方式:RC 振荡(450KHz+5%)
  • 内置上电复位电路
  • 采用SOP28封装

(3)TM1638引脚图

(4)TM1638的寄存器

TM1638芯片寄存器还是很多的,这个还是要看数据手册,网上的资料也有很多,我本来不想再复制过来了,但是我觉得这个资料还是经常需要参考学习,毕竟如果不了解这些,驱动程序就没有办法写。

a、显示寄存器(LED与数码管)

b、按键地址

 (5)指令表

 

 

(7)数据格式

  • TM1638的数据读取和发送都在CLK的上升沿进行,因为DIO在时钟的下降沿控制N管动作,此时读数不稳定。
  • TM1638采取低位在前的数据格式,每次发送和读取都是1byte长度,即8位二进制数据
  • 每次STB拉低之后的第一个字节作为指令,处理指令时当前其它处理被终止。

3、Python下的驱动程序

这个驱动需要根据时序写,我找了mircoPython的驱动,引入了GPIO库,对此进行了修改,整个代码太长,我把用到的放一下。

from micropython import const
import time
import RPi.GPIO as GPIO# 指定编号规则为BOARD
GPIO.setmode(GPIO.BOARD)
# 关闭警告
GPIO.setwarnings(False)TM1638_CMD1 = const(64)  # 0x40 data command
TM1638_CMD2 = const(192) # 0xC0 address command
TM1638_CMD3 = const(128) # 0x80 display control command
TM1638_DSP_ON = const(8) # 0x08 display on
TM1638_READ = const(2)   # 0x02 read key scan data
TM1638_FIXED = const(4)  # 0x04 fixed address mode# 0-9, a-z, blank, dash, star
_SEGMENTS = bytearray(b'\x3F\x06\x5B\x4F\x66\x6D\x7D\x07\x7F\x6F\x77\x7C\x39\x5E\x79\x71\x3D\x76\x06\x1E\x76\x38\x55\x54\x3F\x73\x67\x50\x6D\x78\x3E\x1C\x2A\x76\x6E\x5B\x00\x40\x63')class TM1638(object):"""Library for the TM1638 LED display driver."""def __init__(self, stb, clk, dio, brightness=7):self.stb = stbself.clk = clkself.dio = dioif not 0 <= brightness <= 7:raise ValueError("Brightness out of range")self._brightness = brightnessself._on = TM1638_DSP_ONGPIO.setup(self.clk, GPIO.OUT,initial=1)GPIO.setup(self.dio, GPIO.OUT,initial=0)GPIO.setup(self.stb, GPIO.OUT,initial=1)self.clear()self._write_dsp_ctrl()def _write_data_cmd(self):# data command: automatic address increment, normal modeself._command(TM1638_CMD1)def _set_address(self, addr=0):# address command: move to addressself._byte(TM1638_CMD2 | addr)def _write_dsp_ctrl(self):# display command: display on, set brightnessself._command(TM1638_CMD3 | self._on | self._brightness)def _command(self, cmd):GPIO.output(self.stb,0)self._byte(cmd)GPIO.output(self.stb,1)def _byte(self, b):GPIO.setup(self.dio, GPIO.OUT)for i in range(8):GPIO.output(self.clk,0)GPIO.output(self.dio,(b >> i) & 1)#self.dio((b >> i) & 1)GPIO.output(self.clk,1)def _scan_keys(self):"""Reads one of the four bytes representing which keys are pressed."""pressed = 0GPIO.setup(self.dio, GPIO.IN, pull_up_down=GPIO.PUD_UP)for i in range(8):GPIO.output(self.clk,0)#if self.dio.value():if GPIO.input(self.dio):pressed |= 1 << iGPIO.output(self.clk,1)#GPIO.output(self.clk,0)GPIO.setup(self.dio, GPIO.OUT)return presseddef power(self, val=None):"""Power up, power down or check status"""if val is None:return self._on == TM1638_DSP_ONself._on = TM1638_DSP_ON if val else 0self._write_dsp_ctrl()def brightness(self, val=None):"""Set the display brightness 0-7."""# brightness 0 = 1/16th pulse width# brightness 7 = 14/16th pulse widthif val is None:return self._brightnessif not 0 <= val <= 7:raise ValueError("Brightness out of range")self._brightness = valself._write_dsp_ctrl()def clear(self):"""Write zeros to each address"""self._write_data_cmd()GPIO.output(self.stb,0)self._set_address(0)for i in range(16):self._byte(0x00)GPIO.output(self.stb,1)def write(self, data, pos=0):"""Write to all 16 addresses from a given position.Order is left to right, 1st segment, 1st LED, 2nd segment, 2nd LED etc."""if not 0 <= pos <= 15:raise ValueError("Position out of range")self._write_data_cmd()GPIO.output(self.stb,0)self._set_address(pos)for b in data:self._byte(b)GPIO.output(self.stb,1)def led(self, pos, val):"""Set the value of a single LED"""self.write([val], (pos << 1) + 1)def leds(self, val):"""Set all LEDs at once. LSB is left most LED.Only writes to the LED positions (every 2nd starting from 1)"""self._write_data_cmd()pos = 1for i in range(8):GPIO.output(self.stb,0)self._set_address(pos)self._byte((val >> i) & 1)pos += 2GPIO.output(self.stb,1)def segments(self, segments, pos=0):"""Set one or more segments at a relative position.Only writes to the segment positions (every 2nd starting from 0)"""if not 0 <= pos <= 7:raise ValueError("Position out of range")self._write_data_cmd()for seg in segments:GPIO.output(self.stb,0)self._set_address(pos << 1)self._byte(seg)pos += 1GPIO.output(self.stb,1)def keys(self):"""Return a byte representing which keys are pressed. LSB is SW1"""keys = 0GPIO.output(self.stb,0)self._byte(TM1638_CMD1 | TM1638_READ)for i in range(4):keys |= self._scan_keys() << iGPIO.output(self.stb,1)return keysdef encode_digit(self, digit):"""Convert a character 0-9, a-f to a segment."""return _SEGMENTS[digit & 0x0f]def encode_string(self, string):"""Convert an up to 8 character length string containing 0-9, a-z,space, dash, star to an array of segments, matching the length of thesource string excluding dots, which are merged with previous char."""segments = bytearray(len(string.replace('.','')))j = 0for i in range(len(string)):if string[i] == '.' and j > 0:segments[j-1] |= (1 << 7)continuesegments[j] = self.encode_char(string[i])j += 1return segmentsdef encode_char(self, char):"""Convert a character 0-9, a-z, space, dash or star to a segment."""o = ord(char)if o == 32:return _SEGMENTS[36] # spaceif o == 42:return _SEGMENTS[38] # star/degreesif o == 45:return _SEGMENTS[37] # dashif o >= 65 and o <= 90:return _SEGMENTS[o-55] # uppercase A-Zif o >= 97 and o <= 122:return _SEGMENTS[o-87] # lowercase a-zif o >= 48 and o <= 57:return _SEGMENTS[o-48] # 0-9raise ValueError("Character out of range: {:d} '{:s}'".format(o, chr(o)))def show(self, string, pos=0):"""Displays a string"""segments = self.encode_string(string)self.segments(segments[:8], pos)

(1)这里的数码管定义SEGMENTS = bytearray(b'\x3F\x06\x5B\x4F\x66\x6D\x7D\x07\x7F\x6F\x77\x7C\x39\x5E\x79\x71\x3D\x76\x06\x1E\x76\x38\x55\x54\x3F\x73\x67\x50\x6D\x78\x3E\x1C\x2A\x76\x6E\x5B\x00\x40\x63')

可以看出0为3F,是共阴极数码管的段码。bytearray() 是 Python 的一个内置函数,用于创建一个可变字节序列。与 bytes 类型不同,bytearray 对象的内容是可以修改的。它主要用于在需要字节级别的数据操作时,提供一种更灵活、可变的存储方式。这个和C51的字符型变量用一个字节存储契合。

这样我们可以在文件中自己定义个列表。0-9的段码放进去

dispaly_list=[b'\x3F',b'\x06',b'\x5B',b'\x4F',b'\x66',b'\x6D',b'\x7D',b'\x07',b'\x7F',b'\x6F']

我们就可以让单个数码管显示了。调用类的segments方法,这个地方和C语言不同,因为Python是面向对象,而C是面向过程,后面实验也会提到。如果让第0个数码管显示0那么则:

tm.segments(dispaly_list[0],0),如果让第7个数码管显示3那么则:tm.segments(dispaly_list[3],7)。

想显示哪个数码管就显示哪个数码管,想关哪个就关哪个。有了这个方法,然后我们就可以利用数码管一次显示8个字符、数字,当然我们主要还是显示数字。其他的方法可以自行编写。

(2)LED灯可以点亮一个,也可以点亮多个。注意看led和leds函数

tm.leds(0b01010101)同时给8个灯二进制数0-1,1为亮,0为灭

tm.led(0,1)这是对单个LED控制,第0个灯点亮

(3)tm.keys()获取键值,按键1按下得到的键值为1,第二个是2,第三个是4,第四个是8,第5个是16,2**(n-1),因此要转成1、2、3、4需要数学的取对数函数才行。

4.实验代码与现象

实验就是按键按第几个,数码管第一个显示按键的键值,对应的LED灯亮

import TM1638
import time
import mathtm=TM1638.TM1638(stb=36,clk=38,dio=40) ##标号一致 板子有标记
tm.brightness(2)#循环读取按键值并更新数码管显示
while True:keys = tm.keys()if keys:print(keys)key_num = int(math.log(keys,2))print(key_num)# 读取到按键,这里简单地显示第一个按下的键值tm.show(str(key_num))#tm.number(int(keys))tm.leds(2**key_num)time.sleep(0.15)

就这几行代码完全可以实现,当然程序的问题关键仍然是time.sleep函数的休眠时间,不能给的太长,太长则按键不灵,这里将sleep设置为0.15,显示和按键都没有问题。

相关文章:

嵌入式人工智能(44-基于树莓派4B的扩展板-LED按键数码管TM1638)

树莓派性能非常强悍&#xff0c;但是对于某些复杂的项目来说&#xff0c;会出现心有余而口不足的情况&#xff0c;为了解决这类问题&#xff0c;可以在树莓派上使用扩展板&#xff0c;我们介绍几款常见的扩展板&#xff0c;不仅可以扩展到树莓派&#xff0c;其他单片机或嵌入式…...

linux通过抓包工具tcpdump查看80端口访问量情况

方法&#xff1a; tcpdump -i ens32 -tn dst port 80 -c 10 | awk -F"." {print $1"."$2"."$3"."$4} | sort | uniq -c | sort -nr |head -n 10 #-i&#xff1a;指定端口 #-t&#xff1a;在输出的每一行不打印时间戳 #-n&#xff…...

Mac 上安装和卸载 SDKMAN 及管理多个 JDK

前言 当电脑上有多个 JDK 环境的时候&#xff0c;切换管理比较麻烦&#xff0c;这时候可以使用 SDKMAN 来安装、管理 JDK。 一、安装 SDKMAN! 1. 安装前置条件 首先&#xff0c;确保已经安装了 curl 。如果没有&#xff0c;可以通过 Homebrew 来安装&#xff1a; brew inst…...

字节测开一面面经

1 . 自我介绍 2 . 讲一下常见的数据结构 : 讲了数组,set,list,map,树&#xff0c;图&#xff0c;队列 &#xff0c; 栈等 ; 3 . 讲一下java反射场景和作用 ; 4 . 讲一下你了解的机器学习算法 ; 5 . 我讲完ML之后 &#xff0c; 问了knn和贝叶斯的使用的场景区别(没答上来) ; 6 .…...

HTML 段落

HTML 段落 概述 HTML&#xff08;超文本标记语言&#xff09;是构建网页的标准语言&#xff0c;而段落是构成网页内容的基本单元。在HTML中&#xff0c;段落是通过<p>标签来定义的。本文将详细介绍HTML段落的相关知识&#xff0c;包括段落的基本结构、样式设置、以及在…...

【Mind+】掌控板入门教程04 迷你动画片

还记得小时候每天放学必看的动画片吗&#xff1f;还记得那些年陪伴我一起长大的卡通人物吗&#xff1f;勇救爷爷的葫芦娃&#xff0c;我们的朋友小哪吒&#xff0c;相信这些经典的动画形象已经成为了一代人童年的美好回忆。今天就让我们用掌控板来制作一部迷你动画片吧。 项目示…...

文件上传漏洞-HackBar使用

介绍 HackBar 是一个用于浏览器的扩展插件&#xff0c;主要用于进行网络渗透测试和安全评估。它提供了一系列方便的工具和功能&#xff0c;可以帮助用户执行各种网络攻击和测试&#xff0c;包括 XSS、SQL 注入、CSRF、路径穿越等 下载地址 可以到github上面去下载&#xff0…...

鸿蒙媒体开发【相机数据采集保存】音频和视频

相机数据采集保存 介绍 本示例主要展示了相机的相关功能&#xff0c;使用libohcamera.so 接口实现相机的预览、拍照、录像、前后置摄像头切换进行拍照、录像&#xff0c;以及对焦、曝光等控制类功能。 效果预览 使用说明 弹出是否允许“CameraSample”使用相机&#xff1f;…...

【java基础】徒手写Hello, World!程序

文章目录 前提&#xff1a;java环境变量配置使用vscode编写helloworld解析 前提&#xff1a;java环境变量配置 https://blog.csdn.net/xzzteach/article/details/140869188 使用vscode编写helloworld code .为什么用code看下图 报错了&#xff01;&#xff01;&#xff01;&…...

对 vllm 与 ollama 的一些研究

今天咱们来聊聊 vllm 和 ollama 这两个听起来就挺酷的玩意儿。这俩都是现在 AI 圈子里的大明星&#xff0c;专门用来让那些超大型的 AI 模型跑得更顺溜。 先说说 vllm 吧&#xff0c;这家伙的绝活儿是剪枝。啥叫剪枝呢&#xff1f;想象一下&#xff0c;你有个花园&#xff0c;…...

浅谈基础的图算法——强联通分量算法(c++)

文章目录 强联通分量SCC概念例子有向图的DFS树代码例题讲解[POI2008] BLO-Blockade题面翻译题目描述输入格式输出格式样例 #1样例输入 #1样例输出 #1 思路AC代码 【模板】割点&#xff08;割顶&#xff09;题目背景题目描述输入格式输出格式样例 #1样例输入 #1样例输出 #1 提示…...

C#:通用方法总结—第13集

大家好&#xff0c;今天继续讲解我们的通用方法系列。 下面是今天要介绍的通用方法&#xff1a; &#xff08;1&#xff09;这个通用方法为ug获取选择圆边的圆心 /// <summary> /// ug获取选择圆边的圆心 /// </summary> /// <param name"a">&l…...

AI答题应用平台相关面试题

目录 1、请介绍整个系统后端的架构设计&#xff0c;有哪些模块以及各模块之间的关系&#xff1f; 2、你在项目中是如何设计库表的&#xff1f;可以从字段、索引、关联等方面回答。 3、为什么使用策略模式来封装不同的应用评分算法&#xff1f;它有哪些好处&#xff1f;具体如…...

树莓派NAS系统搭建教程:使用Flask和SQLite实现HTTP/HTTPS文件管理(代码示例)

一、项目概述 随着物联网&#xff08;IoT&#xff09;技术的发展&#xff0c;数据存储和共享需求日益增长。本文将介绍如何利用树莓派&#xff08;Raspberry Pi&#xff09;搭建一个网络附加存储&#xff08;NAS&#xff09;系统&#xff0c;以实现数据的集中管理、共享和访问…...

mysql如何储存大量数据,分库存分表的建议和看法

MySQL 在处理大量数据时&#xff0c;分库分表是常见的策略&#xff0c;可以有效提升数据库的性能和扩展性。下面是关于 MySQL 分库分表的建议和看法&#xff1a; 1. 何时考虑分库分表 数据量大&#xff1a;当单一数据库实例无法处理大规模数据或达到性能瓶颈时&#xff0c;可以…...

Golang | Leetcode Golang题解之第310题最小高度树

题目&#xff1a; 题解&#xff1a; func findMinHeightTrees(n int, edges [][]int) []int {if n 1 {return []int{0}}g : make([][]int, n)deg : make([]int, n)for _, e : range edges {x, y : e[0], e[1]g[x] append(g[x], y)g[y] append(g[y], x)deg[x]deg[y]}q : []i…...

【面试系列】软件架构师 高频面试题及详细解答

欢迎来到我的博客,很高兴能够在这里和您见面!欢迎订阅相关专栏: 工💗重💗hao💗:野老杂谈 ⭐️ 全网最全IT互联网公司面试宝典:收集整理全网各大IT互联网公司技术、项目、HR面试真题. ⭐️ AIGC时代的创新与未来:详细讲解AIGC的概念、核心技术、应用领域等内容。 ⭐…...

二百五十四、OceanBase——Linux上安装OceanBase数据库(四):登录ocp-express,配置租户管理等信息

一、目的 在部署OceanBase成功后&#xff0c;接下来就是登录ocp-express&#xff0c;配置租户管理等信息&#xff01; 二、ocp-express网址以及账密信息 三、实施步骤 1 登录ocp-express 2 集群总览 3 租户管理 3.1 新建租户 3.2 配置新租户信息 剩下的几个模块了解即可&am…...

HCIP学习作业一 | HCIA复习

要求&#xff1a; R1-R2-R3-R4-R5 RIP 100 运行版本2 R6-R7 RIP 200 运行版本1 1.使用合理IP地址规划网络&#xff0c;各自创建环回接口 2.R1创建环回 172.16.1.1/24 172.16.2.1/24 172.16.3.1/24 3.要求R3使用R2访问R1环回 4.减少路由条目数量&#xff0c;R1-R2之间…...

OCR图片矫正、表格检测及裁剪综合实践

问题描述 实际工程中&#xff0c;我们经常需要对图片进行预处理&#xff0c;比如&#xff1a; 1、图片是倾斜的 2、图片背景需要处理掉 3、图片的公章需要剔除 4、图片过暗&#xff0c;过亮 5、图片表格检测 6、图片表格版面分析 。。。。。。等等各种情况。 结果展示…...

uniapp 对接腾讯云IM群组成员管理(增删改查)

UniApp 实战&#xff1a;腾讯云IM群组成员管理&#xff08;增删改查&#xff09; 一、前言 在社交类App开发中&#xff0c;群组成员管理是核心功能之一。本文将基于UniApp框架&#xff0c;结合腾讯云IM SDK&#xff0c;详细讲解如何实现群组成员的增删改查全流程。 权限校验…...

conda相比python好处

Conda 作为 Python 的环境和包管理工具&#xff0c;相比原生 Python 生态&#xff08;如 pip 虚拟环境&#xff09;有许多独特优势&#xff0c;尤其在多项目管理、依赖处理和跨平台兼容性等方面表现更优。以下是 Conda 的核心好处&#xff1a; 一、一站式环境管理&#xff1a…...

SkyWalking 10.2.0 SWCK 配置过程

SkyWalking 10.2.0 & SWCK 配置过程 skywalking oap-server & ui 使用Docker安装在K8S集群以外&#xff0c;K8S集群中的微服务使用initContainer按命名空间将skywalking-java-agent注入到业务容器中。 SWCK有整套的解决方案&#xff0c;全安装在K8S群集中。 具体可参…...

3.3.1_1 检错编码(奇偶校验码)

从这节课开始&#xff0c;我们会探讨数据链路层的差错控制功能&#xff0c;差错控制功能的主要目标是要发现并且解决一个帧内部的位错误&#xff0c;我们需要使用特殊的编码技术去发现帧内部的位错误&#xff0c;当我们发现位错误之后&#xff0c;通常来说有两种解决方案。第一…...

【python异步多线程】异步多线程爬虫代码示例

claude生成的python多线程、异步代码示例&#xff0c;模拟20个网页的爬取&#xff0c;每个网页假设要0.5-2秒完成。 代码 Python多线程爬虫教程 核心概念 多线程&#xff1a;允许程序同时执行多个任务&#xff0c;提高IO密集型任务&#xff08;如网络请求&#xff09;的效率…...

今日科技热点速览

&#x1f525; 今日科技热点速览 &#x1f3ae; 任天堂Switch 2 正式发售 任天堂新一代游戏主机 Switch 2 今日正式上线发售&#xff0c;主打更强图形性能与沉浸式体验&#xff0c;支持多模态交互&#xff0c;受到全球玩家热捧 。 &#x1f916; 人工智能持续突破 DeepSeek-R1&…...

在WSL2的Ubuntu镜像中安装Docker

Docker官网链接: https://docs.docker.com/engine/install/ubuntu/ 1、运行以下命令卸载所有冲突的软件包&#xff1a; for pkg in docker.io docker-doc docker-compose docker-compose-v2 podman-docker containerd runc; do sudo apt-get remove $pkg; done2、设置Docker…...

vue3+vite项目中使用.env文件环境变量方法

vue3vite项目中使用.env文件环境变量方法 .env文件作用命名规则常用的配置项示例使用方法注意事项在vite.config.js文件中读取环境变量方法 .env文件作用 .env 文件用于定义环境变量&#xff0c;这些变量可以在项目中通过 import.meta.env 进行访问。Vite 会自动加载这些环境变…...

【开发技术】.Net使用FFmpeg视频特定帧上绘制内容

目录 一、目的 二、解决方案 2.1 什么是FFmpeg 2.2 FFmpeg主要功能 2.3 使用Xabe.FFmpeg调用FFmpeg功能 2.4 使用 FFmpeg 的 drawbox 滤镜来绘制 ROI 三、总结 一、目的 当前市场上有很多目标检测智能识别的相关算法&#xff0c;当前调用一个医疗行业的AI识别算法后返回…...

Typeerror: cannot read properties of undefined (reading ‘XXX‘)

最近需要在离线机器上运行软件&#xff0c;所以得把软件用docker打包起来&#xff0c;大部分功能都没问题&#xff0c;出了一个奇怪的事情。同样的代码&#xff0c;在本机上用vscode可以运行起来&#xff0c;但是打包之后在docker里出现了问题。使用的是dialog组件&#xff0c;…...