本帖最后由 WangChong 于 2024-4-16 20:34 编辑
一: TM1637 规格参数及其硬件原理
TM1637 是一种带键盘扫描接口的LED(发光二极管显示器)驱动控制专用电路,内部集成有MCU 数
字接口、数据锁存器、LED 高压驱动、键盘扫描等电路。本产品性能优良,质量可靠。主要应用于电磁炉、
微波炉及小家电产品的显示屏驱动。
管脚定义信息如下:
其中和单片机的通讯使用类I2C的自定义通讯协议。可以通过串行Data和Clock时钟线将数据写到对应的寄存器(低位在前),从而往对应的六个寄存器内写数据来驱动最多六个数码管,但是由于模组设计的原因,在TM1637数码管驱动上最多可以驱动4个,也就是正好4位28段。
通信时序:
起始信号:IO初始化之后,保持高电平, 在CLK为高电平期间 ,DIO 从高拉低。
结束信号:在ACK结束之后,SCK低电平期和SDA低电平期间,SCK先拉高,然后DIO 再拉高。
接受从机ACK:TM1637 的数据传输带有应答信号 ACK,当传输数据正确时,会在第八个时钟的下降沿,芯片内部会
产生一个应答信号 ACK 将 DIO 管脚拉低,在第九个时钟结束之后释放DIO口线
指令数据:在输入数据时当 CLK 是高电平时,DIO 上的信号必须保持不变;只有 CLK 上的时钟信号为低电平时,DIO 上的信号才能改变。数据输入的开始条件是 CLK为高电平时,DIO 由高变低;结束条件是 CLK 为高时,DIO由低电平变为高电平。
2- 写 SRAM 数据地址自动加 1 模式
上述所说,通过往地址寄存器里写入数据可以控制数码管的显示,这里的写SARM数据地址自动加1模式的意思是,比如说我现在要往四个数码管写如数字1234, 通过使用这个模式,只需要往第一个数码管寄存器内写入1的数据后,数码管的地址会逐渐偏移 从原本的0x01 逐渐+1。 0x01,写入1, 0x02,写入2, 0x03,写入3,0x04,写入4。 而不需要每次去指定写入的地址。
3- 写 SRAM 数据固定地址模式
写SRAM固定地址的模式的意思是说,通过往固定的地址内写入数据来操控对应的数码管显示。
官方程序Sequence diagram
官方推荐的Sequence diagram中包括了我们程序所要写的处理逻辑,但是实际上我们并不需要来处理是否用用户按下按键的操作逻辑,所以我们再发送显示控制命令后,可以直接结束。
数据命令相关(Command)
我们用于写数据驱动数码管,所以可以仅仅关注数据指令0100 0000 (0x40H)
地址命令相关
这里地址命令我们仅仅需要关注的只有前四个,因为这个数码管设计虽然能驱动6个但是硬件实现貌似只有四个,地址分别为(0xC0H),(0xC1H) (0xC2H) (0xC3H)
来控制第一、第二、第三、第四个数码管显示。
显示控制
通过往显示控制寄存器中写入不同的数据来控制数码管的显示。经过我的实际测试和上述寄存器定义,点亮数码管的HEX为从0x88, 到0x8F. LSB第四位为1的原因是因为1是用来控制开关,所以是8. 也就是0x80. 所以亮度可以从0x80到0x8f。
二: 程序以及测试
我这里一共提供了两个文件,分别是头文件TM1637.h 和源文件TM1637.C. 具体的使用方法是,复制这两个文件到项目中,并且在Cmakelist.txt target_sources中引入即可。
在搞明白原理之后,我们来看一下代码和硬件连接部分,可以使用任意的板载GPIO口和TM1637进行连接。只需要在代码宏中更改IO定义。
我这里使用的是PIN16 (TM1637_CLOCK) 和 PIN17(TM1637_DATA) 分别连接模块的 CLK和DIO。 VCC-VCC, GND-GND
头文件:
- #ifndef __TM1637__
- #define __TM1637__
- #include "bflb_mtimer.h"
- #include "bflb_gpio.h"
- // 亮度等级
- enum LIGHT_DEGREE
- {
- LEVEL1 = 0x88, // 设置脉冲宽度为 1/16
- LEVEL2 = 0x89, // 设置脉冲宽度为 2/16
- LEVEL3 = 0x8A, // 设置脉冲宽度为 4/16
- LEVEL4 = 0x8B, // 设置脉冲宽度为 10/16
- LEVEL5 = 0x8C, // 设置脉冲宽度为 11/16
- LEVEL6 = 0x8D, // 设置脉冲宽度为 12/16
- LEVEL7 = 0x8E, // 设置脉冲宽度为 13/16
- LEVEL8 = 0x8F, // 设置脉冲宽度为 14/16
- };
- /*定义时钟PIN*/
- #define TM1637_CLOCK GPIO_PIN_16
- /*定义dataPIN*/
- #define TM1637_DATA GPIO_PIN_17
- /**
- * @brief 初始化GPIO
- *
- */
- void TM1637_init();
- /**
- * @brief 使数码管显示数字
- *
- * @param numer1 第一个数字
- * @param numer2 第二个数字
- * @param numer3 第三个数字
- * @param numer4 第四个数字
- * @param colon 是否显示冒号(:) 接受参数 0 or 1
- * 0 不显示
- * 1 显示
- * @param level 亮度等级,
- */
- void TM1637_display(unsigned char numer1, unsigned char numer2, unsigned char numer3, unsigned char numer4, unsigned char colon, enum LIGHT_DEGREE level);
- #endif
复制代码
源文件
- #include "TM1637.h"
- struct bflb_device_s *gpio;
- /* 数码管支持的数字 */
- unsigned char tab[] = {
- 0x3F, /*0*/
- 0x06, /*1*/
- 0x5B, /*2*/
- 0x4F, /*3*/
- 0x66, /*4*/
- 0x6D, /*5*/
- 0x7D, /*6*/
- 0x07, /*7*/
- 0x7F, /*8*/
- 0x6F, /*9*/
- 0x77, /*10 A*/
- 0x7C, /*11 b*/
- 0x58, /*12 c*/
- 0x5E, /*13 d*/
- 0x79, /*14 E*/
- 0x71, /*15 F*/
- 0x76, /*16 H*/
- 0x38, /*17 L*/
- 0x54, /*18 n*/
- 0x73, /*19 P*/
- 0x3E, /*20 U*/
- 0x00, /*21 黑屏*/
- };
- void TM1637_init()
- {
- gpio = bflb_device_get_by_name("gpio");
- bflb_gpio_init(gpio, TM1637_CLOCK, GPIO_OUTPUT); // 修改为 TM1637_CLOCK
- bflb_gpio_init(gpio, TM1637_DATA, GPIO_OUTPUT); // 修改为 TM1637_DATA
- }
- void clock_set()
- {
- bflb_gpio_set(gpio, TM1637_CLOCK); // 修改为 TM1637_CLOCK
- }
- void clock_reset()
- {
- bflb_gpio_reset(gpio, TM1637_CLOCK); // 修改为 TM1637_CLOCK
- }
- void data_set()
- {
- bflb_gpio_set(gpio, TM1637_DATA); // 修改为 TM1637_DATA
- }
- void data_reset()
- {
- bflb_gpio_reset(gpio, TM1637_DATA); // 修改为 TM1637_DATA
- }
- void Delay_us(unsigned int us)
- {
- bflb_mtimer_delay_us(us);
- }
- void TM1637_start(void)
- {
- clock_set();
- data_set();
- Delay_us(2);
- data_reset();
- }
- void TM1637_ack(void)
- {
- unsigned char i = 0;
- clock_reset();
- Delay_us(5);
- while (bflb_gpio_read(gpio, TM1637_DATA) && (i < 250))
- {
- i++;
- }
- clock_set();
- Delay_us(2);
- clock_reset();
- }
- void TM1637_stop(void)
- {
- clock_reset();
- Delay_us(2);
- data_reset();
- Delay_us(2);
- clock_set();
- Delay_us(2);
- data_set();
- Delay_us(2);
- }
- void TM1637_Write(unsigned char DATA)
- {
- unsigned char i;
- for (i = 0; i < 8; i++)
- {
- clock_reset();
- if (DATA & 0x01)
- {
- data_set();
- }
- else
- {
- data_reset();
- }
- Delay_us(3);
- DATA = DATA >> 1;
- clock_set();
- Delay_us(3);
- }
- }
- void TM1637_display(unsigned char numer1, unsigned char numer2, unsigned char numer3, unsigned char numer4, unsigned char colon, enum LIGHT_DEGREE level)
- {
- // 写 SRAM 数据地址自动加 1 模式
- TM1637_start();
- // 发送起始地址
- TM1637_Write(0x40);
- TM1637_ack();
- TM1637_stop();
- TM1637_start();
- TM1637_Write(0xc0);
- TM1637_ack();
- TM1637_Write(tab[numer1]);
- TM1637_ack();
- TM1637_Write(tab[numer2] | colon << 7); // h为1时显示时钟中间的两点
- TM1637_ack();
- TM1637_Write(tab[numer3]);
- TM1637_ack();
- TM1637_Write(tab[numer4]);
- TM1637_ack();
- TM1637_stop();
- TM1637_start();
- TM1637_Write(level); // 开启显示
- TM1637_ack();
- TM1637_stop();
- }
复制代码
用户不需要关注那么多细节,只需要引入TM1637.h 然后调用初始化,和显示方法即可,如下所示。
- #include "bflb_mtimer.h"
- #include "board.h"
- #include "bflb_gpio.h"
- #include "TM1637.h"
- int main(void)
- {
- int index = 0;
- board_init();
- TM1637_init();
- unsigned char flag = 0x01;
- while (1)
- {
- int digit1 = index % 10; // 个位
- int digit2 = (index / 10) % 10; // 十位
- int digit3 = (index / 100) % 10; // 百位
- int digit4 = (index / 1000) % 10; // 千位
- TM1637_display(digit4, digit3, digit2, digit1, flag, LEVEL1);
- arch_delay_ms(100);
- flag = !flag;
- index++;
- }
- }
复制代码
上述代码提供了一个测试方法,使其数码管数字进行累加。
效果演示:
【M61点亮TM1637】
VERSION2: 新增了调整亮度等级的功能。
VERSION2: 代码:
TM1637 (2).zip
(4.76 KB, 下载次数: 3)
|