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

news2025/1/13 2:32:47

树莓派性能非常强悍,但是对于某些复杂的项目来说,会出现心有余而口不足的情况,为了解决这类问题,可以在树莓派上使用扩展板,我们介绍几款常见的扩展板,不仅可以扩展到树莓派,其他单片机或嵌入式处理器均可以扩展。这几种扩展板分别是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 = stb
        self.clk = clk
        self.dio = dio

        if not 0 <= brightness <= 7:
            raise ValueError("Brightness out of range")
        self._brightness = brightness
        self._on = TM1638_DSP_ON

        GPIO.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 mode
        self._command(TM1638_CMD1)

    def _set_address(self, addr=0):
        # address command: move to address
        self._byte(TM1638_CMD2 | addr)

    def _write_dsp_ctrl(self):
        # display command: display on, set brightness
        self._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 = 0
        GPIO.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 << i
            GPIO.output(self.clk,1)
            #GPIO.output(self.clk,0)
        GPIO.setup(self.dio, GPIO.OUT)
        return pressed

    def power(self, val=None):
        """Power up, power down or check status"""
        if val is None:
            return self._on == TM1638_DSP_ON
        self._on = TM1638_DSP_ON if val else 0
        self._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 width
        if val is None:
            return self._brightness
        if not 0 <= val <= 7:
            raise ValueError("Brightness out of range")
        self._brightness = val
        self._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 = 1
        for i in range(8):
            GPIO.output(self.stb,0)
            self._set_address(pos)
            self._byte((val >> i) & 1)
            pos += 2
            GPIO.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 += 1
            GPIO.output(self.stb,1)

    def keys(self):
        """Return a byte representing which keys are pressed. LSB is SW1"""
        keys = 0
        GPIO.output(self.stb,0)
        self._byte(TM1638_CMD1 | TM1638_READ)
        for i in range(4):
            keys |= self._scan_keys() << i
        GPIO.output(self.stb,1)
        return keys

    def 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 the
        source string excluding dots, which are merged with previous char."""
        segments = bytearray(len(string.replace('.','')))
        j = 0
        for i in range(len(string)):
            if string[i] == '.' and j > 0:
                segments[j-1] |= (1 << 7)
                continue
            segments[j] = self.encode_char(string[i])
            j += 1
        return segments

    def 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] # space
        if o == 42:
            return _SEGMENTS[38] # star/degrees
        if o == 45:
            return _SEGMENTS[37] # dash
        if o >= 65 and o <= 90:
            return _SEGMENTS[o-55] # uppercase A-Z
        if o >= 97 and o <= 122:
            return _SEGMENTS[o-87] # lowercase a-z
        if o >= 48 and o <= 57:
            return _SEGMENTS[o-48] # 0-9
        raise 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 math

tm=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,显示和按键都没有问题。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1980213.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Vue3 列表自动滚动播放(表头固定、列表内容自动滚动播放)+ vue3-seamless-scroll - 附完整示例

vue3-seamless-scroll&#xff1a;Vue3.0 无缝滚动组件&#xff0c;支持Vite2.0&#xff0c;支持服务端打包 目前组件支持上下左右无缝滚动&#xff0c;单步滚动&#xff0c;并且支持复杂图标的无缝滚动&#xff0c;目前组件支持平台与Vue3.0支持平台一致。 目录 效果 一、介绍…

安装vscode -- linux

前言 相信很多人在刚开始使用linux时&#xff0c;不知道怎么安装vscode来辅助我们编程&#xff0c;那么我将在此记录我所用的安装vscode的方法。 安装方法 方法一&#xff1a;snap 第一步&#xff1a;检查软件更新状况 sudo apt update在终端输入上述命令&#xff0c;会提…

大模型学习笔记 - LLM 之RLHF人类对齐的简单总结

LLM - RLHF人类对齐的简单总结 LLM-人类对齐 1. RLHF(Reinforcement Learning from Human Feedback, RLHF),基于人类反馈的强化学习2 奖励模型训练3 强化学习训练 3.1 PPO介绍3.2 进阶的RLHF的介绍 3.2.1. 过程监督奖励模型3.2.2. 基于AI反馈的强化学习3.2.3. 非强化学习的对齐…

卷积神经网络 - 基本卷积函数的变体篇

序言 在深度学习和卷积神经网络&#xff08; CNN \text{CNN} CNN&#xff09;的广阔领域中&#xff0c;基本卷积函数是构建网络结构的基础&#xff0c;它们通过滑动窗口的方式对输入数据进行特征提取。然而&#xff0c;随着应用场景和数据复杂性的增加&#xff0c;单一的卷积方…

苹果Vision Pro生态发展:现状、挑战与未来展望

苹果公司以其创新技术和强大的生态系统闻名于世。在最近的财报会议上,CEO蒂姆库克分享了Vision Pro平台的最新进展,引发了业界的广泛关注。本文将深入探讨Vision Pro生态的现状、面临的挑战以及与其他XR平台的对比分析。 一、Vision Pro生态现状 据库克介绍,Vision Pro平台…

爬1688商品---(测试版)

半成品. from DrissionPage import ChromiumPage import time from selenium import webdriver urlhttps://p4psearch.1688.com/hamlet.html?scene6&cositebaidujj_pz&locationre&trackid885662561117990122602pageChromiumPage()page.get(url)def key_wof():inde…

C++ QT开发 学习笔记(3)

C QT开发 学习笔记(3) - WPS项目 标准对话框 对话框类说明静态函数函数说明QFileDialog文件对话框getOpenFileName()选择打开一个文件getOpenFileNames()选择打开多个文件getSaveFileName()选择保存一个文件getExistingDirectory()选择一个己有的目录getOpenFileUrl()选择打幵…

荒原之梦考研:考研二战会很难吗?

考研二战是不是很难&#xff0c;其实很大程度上取决于我们自己&#xff0c;我们能否认清自己的优势&#xff0c;能否指定和执行合理的计划&#xff0c;有没有强大的心理支撑等&#xff0c;都是决定考研二战能否成功&#xff0c;或者能否比较轻松的成功的关键。 在本文中&#…

HCIP重修总笔记(中)

第八节 BGP基础 一、BGP产生背景 BGPBorder Gateway Protocol&#xff0c;边界网关协议)是一种用于自治系统间的动态路出协议&#xff0c;是一种外部网关协议。 自治系统AS:一组同一个管理机构进行管理&#xff0c;对外呈现统一选路策略的路由器的集合。 自治系统编号: …

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

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

数据结构实验报告-顺序表

桂 林 理 工 大 学 实 验 报 告 一、实验名称 实验1 顺序表 二、实验内容&#xff1a; 1.将书中介绍的顺序表的基本算法(如初始化、求长度、插人、删除、输出等)汇总在一起&#xff0c;用一个完整的程序实现顺序表的基本运算&#xff0c;并且编写顺序表的判空、判满等基…

最常见的AI大模型总结

前言&#xff1a;大模型可以根据其主要的应领域和功能&#xff0c;可以分类为“文生文”&#xff08;Text-to-Text&#xff09;、“文生图”&#xff08;Text-to-Image&#xff09;和“文生视频”&#xff08;Text-to-Video&#xff09;&#xff0c;都是基于自然语言处理&#…

JVM从入门到放弃

前言&#xff1a;关于JVM&#xff0c;其实有很多大厂开发了不同版本的JVM&#xff0c;比较知名的有&#xff1a;Sun HotSpot VM、BEA JRockit VM、IBM J9 VM、 Azul VM、 Apache Harmony、 Google Dalvik VM、 Microsoft JVM等等。现在使用的比较多的JDK8版本就是Sun HotSpot V…

「C++系列」指针

文章目录 一、指针的定义二、指针的基本概念1. 基本概念2. 案例代码示例 1&#xff1a;基本指针使用示例 2&#xff1a;指针与数组 3. 注意事项 三、指针的用途1. 指针的用途2. 案例代码案例1. 动态内存分配案例2. 函数参数&#xff08;通过指针修改值&#xff09;案例3. 数组和…

poky yocto(04):编译在vmware上运行的镜像

编译镜像 bitbake build-appliance-image 得到文件&#xff1a;build-appliance-image-qemux86-64.wic.vmdk 问题的关键来了&#xff0c;如何启动这个东西呢&#xff1f;由名字可知&#xff0c;这是一个vmware的硬盘文件&#xff0c;需要创建一个新的虚拟机加载它。 创建虚拟…

黑神话悟空游戏电脑配置要求 黑神话悟空Steam销量全球两连冠 黑神话悟空苹果笔记本电脑能玩吗 黑神话悟空是什么类型的游戏

相信不少游戏爱好者&#xff0c;近期被《黑神话&#xff1a;悟空》这款游戏刷屏了&#xff0c;备受期待的国产单机大作《黑神话:悟空》将于8月20日全球同步上线&#xff0c;登陆 PC (Steam / Epic / WeGame) 和 PS5 平台。凭借空前的关注度&#xff0c;该游戏有望成为国产游戏行…

sql注入漏洞复现

and 11 正常 and 12 报错 从这就已经说明是sql数字型注入了 上sqlmap验证一下 存在布尔盲注&#xff0c;时间盲注...... 我是在漏洞盒子上提交的&#xff0c;能不能通过看运气吧 下面这个漏洞已经是很久之前的了&#xff0c;现在已经是修复了&#xff0c;当时还是太年轻了...…

文献阅读:扩散波模型的物理信息神经网络

目录 摘要 Abstract 扩散波模型的物理信息神经网络 文献摘要 讨论|结论 理论知识 扩散波动方程&#xff08;曼宁方程&#xff09; 梯度停止&#xff08;Stop-gradient&#xff09;技术 时分PINN(TPINN) 新结构(fPINN) 实验设置 稳定流问题 等速和扩散问题 非线性速…

基于STM32的简易音频播放系统

目录 引言环境准备工作 硬件准备软件安装与配置系统设计 系统架构硬件连接代码实现 初始化代码音频播放代码应用场景 简易音频播放语音提示系统常见问题及解决方案 常见问题解决方案结论 1. 引言 音频播放系统在日常生活中有着广泛的应用&#xff0c;从简单的语音提示到复杂…

基于Transformer的语音识别与音频分类

重磅推荐专栏: 《大模型AIGC》 《课程大纲》 《知识星球》 本专栏致力于探索和讨论当今最前沿的技术趋势和应用领域,包括但不限于ChatGPT和Stable Diffusion等。我们将深入研究大型模型的开发和应用,以及与之相关的人工智能生成内容(AIGC)技术。通过深入的技术解析和实践经…