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

树莓派开发相关知识七 -串口数码管

1、概述

一个普通的数码管实际上为7+1个LED灯。

上图可知,A-G加上DP点8个LED,通过不同的亮暗来显示出所需的数字。

如果同时要控制多个数码管,则需要的GPIO未免太多。

我们选择控制4个数码管,通过串行转并行的方式实现控制。

所谓串行转并行,即与串口类似,在一根线上加上时间的维度,通过时序来转换为不同的并行输出。即,我们可以通过两根线控制4个数码管32个灯。 这种串行转并行,总线协议的前兆,这里的实现方式与I2C总线非常类似。

一般串行总线的实现,是协议+地址+寄存器+数据+……这种形式。

tm1637驱动方式:

CLK、DIO两个引脚加上VCC与GND。

  • CLK:时钟线,与串口不同,不是通过波特率同步,而是通过CLK这根线的脉冲同步
  • DIO:数据线,与CLK配合,实现串行数据的传输。

2、接口说明

微处理器的数据通过两线总线接口和 TM1637 通信,在输入数据时当 CLK 是高电平时,DIO 上的信号必须保持不变;只有 CLK 上的时钟信号为低电平时,DIO 上的信号才能改变。数据输入的开始条件是 CLK为高电平时,DIO 由高变低;结束条件是 CLK 为高时,DIO 由低电平变为高电平。TM1637 的数据传输带有应答信号 ACK,当传输数据正确时,会在第八个时钟的下降沿,芯片内部会产生一个应答信号 ACK 将 DIO 管脚拉低,在第九个时钟结束之后释放 DIO 口线。

Command:读按键指令;

S0、S1、S2、K1、K2 组成按键信息编码,S0、S1、S2为SGn 的编码,K1、K2 为 K1 和 K2 键的编码,

读按键时,时钟频率应小于 250K,先读低位,后读高位。

协议中的start(S)与stop(P)状态。

  • start:CLK高电平时,DIO由高变低,则为start状态
  • stop:CLK高电平时,DIO由低变高,则为stop状态

如uart串口协议可知,有开始于结束的状态,这里的状态即为start与stop两种。

切记CLK时钟线处于高电平,DIO不能随便发生变化,否则为start/stop状态中的任意一个,此时模块会“重新开始”数据传输。

CLK低电平时,DIO可以随意改变状态。数据的传输是发生在CLK的上升沿,每次数据传输8位,LSB低位在前。

协议中的ack(A)状态。 ack:模块的应答信号,自动将DIO拉低表示获取8位数据完毕。

计算设备与外设模块之间的通信,由CLK、DIO这两根线根据协议,以时间为轴线进行数据传输。

此类协议的详细步骤详细的解释如下:

  • 平时不传输协议,CLK,DIO都拉高
  • DIO变低,则start状态开启
  • CLK拉低,DIO切换状态,CLK拉高,注意拉高之后DIO不能随意改状态,否则触发start或者stop。
  • 此时一位数据的传输,发生在CLK变低后DIO确定状态后,拉高的上升沿触发,即CLK从低变高的一瞬间,外设模块迅速锁定DIO此时的状态,并 当做一位数据。
  • 以此类推,重复8次,传输8位数据,低位在前。
  • 第8个数据传输完毕后的CLK下降沿,触发外设芯片内部的ACK,强制拉低DIO,表示外设芯片告诉主设备收到了8个数据。主设备通过ACK获知传 输过程有没有错误,即手动拉高DIO后再读取DIO的电平,如果切换为低电平表示外设强制拉低了。
  • 第9个时钟后,外设芯片释放DIO。
  • 这种8位数据的传输根据需求连续发生多次,后stop状态切换一轮数据结束。

3、TM1637控制代码实现

class TM1637:
    dio = 0
    clk = 0
    def __init__(self, dio, clk):
        self.dio = dio
        self.clk = clk
        GPIO.setup(clk, GPIO.OUT, initial = GPIO.HIGH)
        GPIO.setup(dio, GPIO.OUT, initial = GPIO.HIGH)
    def start(self):
        # 开始信号,clk为高时,dio由高变低
        GPIO.output(self.clk, GPIO.HIGH)
        GPIO.output(self.dio, GPIO.HIGH)
        GPIO.output(self.dio, GPIO.LOW)
        GPIO.output(self.clk, GPIO.LOW)
    def start(self):
        # 开始条件,默认clk高,dio高,clk高的时候,将dio从高拉低
        GPIO.output(self.clk, GPIO.HIGH)
        GPIO.output(self.dio, GPIO.HIGH)
        GPIO.output(self.dio, GPIO.LOW)
        GPIO.output(self.clk, GPIO.LOW)
    def end(self):
        # 结束条件,默认clk低,dio低,clk高的时候,将dio从低拉高
        GPIO.output(self.clk, GPIO.LOW)
        GPIO.output(self.dio, GPIO.LOW)
        GPIO.output(self.clk, GPIO.HIGH)
        GPIO.output(self.dio, GPIO.HIGH)
    def write(self, data):
        for i in range(0, 8):
            # 拉低clk
            GPIO.output(self.clk, GPIO.LOW)
            # 切换dio状态,低位在前 LSB
            if data & 0x01:
                GPIO.output(self.dio, GPIO.HIGH)
            else:
                GPIO.output(self.dio, GPIO.LOW)
            data >>= 1
            # 上升沿触发数据锁存
            GPIO.output(self.clk, GPIO.HIGH)
        # 下降沿触发ack,第八个下降沿
        GPIO.output(self.clk, GPIO.LOW)
        # 强制拉高dio,判断ack回应数据,必须在clk低电平时操作,否则可能触发stop
        GPIO.output(self.dio, GPIO.HIGH)
        # 第九个时钟
        GPIO.output(self.clk, GPIO.HIGH)
        GPIO.setup(self.dio, GPIO.IN)
        if GPIO.input(self.dio) == GPIO.HIGH:
            # 没有响应,出错
            GPIO.setup(self.dio, GPIO.OUT, initial = GPIO.HIGH)
            return None
        else:
            # 有响应,对了
            GPIO.setup(self.dio, GPIO.OUT, initial = GPIO.HIGH)
        return

4、两种控制方式

4.1 写 SRAM 数据地址自动加1模式

数据命令设置

4.2 写 SRAM 数据固定地址模式

地址命令设置

该指令用来设置显示寄存器的地址;如果地址设为0C6H 或更高,数据被忽略,直到有效地址被设定;上电时,地址默认设为00H。

显示控制

5、控制实现代码

# 地址自动加一模式,data使用列表
def send_auto_data(self, data):
    # command1:设置数据
    # 01000000
    self.start()
    self.write(0B01000000)
    self.end()
    # command2:设置地址
    # 11000000
    self.start()
    self.write(0B11000000)
    # data1-n
    self.write(num[data[0]])
    self.write(num[data[1]] | 0x80) # 中间的冒号
    self.write(num[data[2]])
    self.write(num[data[3]])
    self.end()
    # command3:控制显示
    # 10001111
    self.start()
    self.write(0B10001111)
    self.end()
    
 # 固定地址模式,0x0为第一个数码管,以此类推
def send_addr_data(self, addr, data):
    if addr < 0 or addr > 3:
        return None
    # 设置数据
    self.start()
    self.write(0B01000100)
    self.end()
    # 设置地址
    self.start()
    addr |= (0B11000000)
    self.write(addr)
    # 设置数据
    self.write(data)
    self.end()
     # 显示控制
    self.start()
     self.write(0B10001111)
     self.end()

6、调用代码

#!/usr/bin/env python
#coding:utf-8

import TM167
import RPi.GPIO as GPIO
import time
nums=[0B00111111,0B00000110,0B01011011,0B01001111,0B01100110,0B01101101,0B1111101,0B00000111,0B01111111,0B01101111]
GPIO.setwarnings(False)
GPIO.setmode(GPIO.BCM)
obj=TM167.TM1637(12,16)

#初始化
for i in range(4):
	obj.send_addr_data(i,nums[0])
time.sleep(1)
for i in range(4):
	obj.send_addr_data(i,0)
time.sleep(0.5)
flag=False
#封装函数 小时 分钟
def showinfo(h,m):
	global flag
	ts=[h/10,h%10,m/10,m%10]
	for i in range(4):
		if i==1:
			if flag==False:
				obj.send_addr_data(i,nums[ts[i]]|0B10000000)
				flag=True
			else:
				obj.send_addr_data(i,nums[ts[i]])
				flag=False
		else:
			obj.send_addr_data(i,nums[ts[i]])

while(1):
	t=time.localtime(time.time())
	#showinfo(t.tm_hour,t.tm_min)
	h=t.tm_hour
	m=t.tm_min
	obj.send_auto_data((h/10,h%10,m/10,m%10),flag)
	if flag ==False:
		flag=True
	else:
		flag=False
	#ts=t.tm_sec
	time.sleep(0.5)
obj.send_addr_data(0,nums[0])


http://www.kler.cn/a/377112.html

相关文章:

  • 经验证:将数据从索尼传输到Android的 4 种方法
  • Springboot使用RabbitMQ实现关闭超时订单的一个简单示例
  • vim里搜索关键字
  • MIT S081 Lab 2 System Calls
  • 1、ELK的架构和安装
  • mybatis 和 mybatisPlus 兼容性问题
  • 从0开始学统计-什么是中心极限定理
  • [perl] 数组与哈希
  • 【Linux】IPC进程间通信:并发编程实战指南(一)
  • 纯前端生成PDF(jsPDF)并下载保存或上传到OSS
  • 提升当当网数据爬取效率:代理IP并发抓取技术
  • [Redis] Redis事务
  • Linux内核与用户空间
  • 问:Redis如何做到原子性?
  • (自用)机器学习python代码相关笔记
  • ES入门:查询和聚合
  • Java之继承
  • Rust 跨平台应用的最佳实践
  • MiniWord
  • RHCE: DNS服务器
  • Redis为什么用跳表实现有序集合
  • 如何引用一个已经定义过的全局变量?
  • 一些硬件知识【2024/11/2】
  • 鸿蒙生态下开发挑战-鸿蒙低代码开发工具展望及优势
  • 如何在Python爬虫等程序中设置和调用http代理
  • Systemd:现代 Linux 系统服务管理的核心