TM1637、AIP1637代码驱动
可移植性高,适用于Arduino、STM32、51等
这两款芯片通用
TM1637、AIP137简介
TM1637 是一种带键盘扫描接口的LED(发光二极管显示器)驱动控制专用电路,内部集成有MCU 数 字接口、数据锁存器、LED 高压驱动、键盘扫描等电路。本产品性能优良,质量可靠。主要应用于电磁炉、 微波炉及小家电产品的显示屏驱动。采用DIP/SOP20的封装形式
此类芯片的通讯协议是类似I2C但他不是标准的I2C协议,传输协议低位先行LSB
微处理器的数据通过两线总线接口和 TM1637 通信,在输入数据时当 CLK 是高电平时,DIO 上的信号 必须保持不变;只有 CLK 上的时钟信号为低电平时,DIO 上的信号才能改变。数据输入的开始条件是 CLK 为高电平时,DIO 由高变低;结束条件是 CLK 为高时,DIO 由低电平变为高电平。 TM1637 的数据传输带有应答信号 ACK,当传输数据正确时,会在第八个时钟的下降沿,芯片内部会 产生一个应答信号 ACK 将 DIO 管脚拉低,在第九个时钟结束之后释放 DIO 口线
SRAM写入操作
这款芯片有两种写入数据的方式一种为连续写入地址会自增,另外一种是固定地址写入也就是一次只写入一次。
我们想要实现的效果是这样的:
tm_display(0, (counter / 1000) % 10);
tm_display(1, (counter / 100) % 10);
tm_display(2, (counter / 10) % 10);
tm_display(3, counter % 10);
这个方法的作用是指定显示Index索引和要显示的内容
所以这个方式固定地址模式更加会适合我们的程序编写。
好了接下里我们来软件手写实现下通讯驱动。
代码实现
首先我们先定义几个通用方法
tm1637.h文件
#define CLK_PIN 2
#define DIO_PIN 3
#define CLK_0 digitalWrite(CLK_PIN, LOW)
#define CLK_1 digitalWrite(CLK_PIN, HIGH)
#define DIO_0 digitalWrite(DIO_PIN, LOW)
#define DIO_1 digitalWrite(DIO_PIN, HIGH)
#define DIO_R digitalRead(DIO_PIN)
#define CLK_OUT pinMode(CLK_PIN, OUTPUT)
#define DIO_OUT pinMode(DIO_PIN, OUTPUT)
#define DIO_IN pinMode(DIO_PIN, INPUT)
// 微秒延迟
#define tm_delay_us(us_num) delayMicroseconds(us_num)
void tm_init(void);
void tm_display(uint8_t index, uint8_t numer);
void tm_clear(void);
void tm_set_point(uint8_t PointFlag);
不同的平台直接取修改宏定义下的函数即可。
.c文件的实现
和I2c一样都需要有start和stop起始和结束
/**
* 数据传输开始
* 数据输入的开始条件是 CLK
为高电平时,DIO 由高变低;
*/
void dat_start() {
DIO_OUT;
tm_delay_us(2);
CLK_1;
DIO_1;
tm_delay_us(2);
DIO_0;
CLK_0;
}
/**
* 传输结束
* 结束条件是 CLK 为高时,DIO 由低电平变为高电平
*/
void dat_stop() {
CLK_0;
DIO_0;
tm_delay_us(2);
CLK_1;
DIO_1;
}
然后就是数据的发送。这里和标准的I2c不同的是它是LSB低位先行
int dat_send8(uint8_t data) {
// 这个发送时序是LSB 从低位到高位
for (int i = 0; i < 8; i++) {
CLK_0;
if (data & 0x01) {
DIO_1;
} else {
DIO_0;
}
tm_delay_us(3);
CLK_1;
tm_delay_us(3);
data >>= 1;
}
return dat_ack_check();
}
每次数据的发送需要IC芯片的ACK,所以我们去检查ACK信号
TM1637 的数据传输带有应答信号 ACK,当传输数据正确时,会在第八个时钟的下降沿,芯片内部会 产生一个应答信号 ACK 将 DIO 管脚拉低,在第九个时钟结束之后释放 DIO 口线
int dat_ack_check() {
uint8_t ack = 0, errorRetry = 5;
DIO_1;
tm_delay_us(5);
DIO_IN;
tm_delay_us(5);
CLK_0;
tm_delay_us(5);
while (DIO_R) {
if (errorRetry <= 0) {
break;
}
tm_delay_us(1);
errorRetry--;
}
if (errorRetry) {
ack = 1;
CLK_1;
tm_delay_us(5);
}
CLK_0;
DIO_OUT;
return ack;
}
这里稍微有点绕我们来解释下这段代码的意思:
首先因为文档说了:会在第八个时钟的下降沿,芯片内部会 产生一个应答信号 ACK 将 DIO 管脚拉低。
所以我们先将DIO引脚拉高之后再将CLK引脚拉低,到这里我们就可以去监听下DIO引脚的高低变化去读取它的值,代码中使用了while循环去读取并且加入了超时重试机制。
在外循环内如果没有超时全部那么errorRetry的剩余次数一定大于1那么条件就为真,我们就可以认为是读取到了低电平while退出了循环。 之后呢看文档:在第九个时钟结束之后释放 DIO 口线。 所以我们在这个if内在将CLK拉高,方法的结束最后在将CLK拉低为了后面传输数据做准备,也为了防止出错。
接下里我们设置下SRAM写入的模式为固定地址模式
/**
* 固定地址模式
*/
void tm_sram_lock() {
dat_start();
dat_send8(0x44); // 固定地址模式
dat_stop();
}
然后设置亮度为最高
void tm_lock_light(uint8_t commant) {
dat_start();
dat_send8(commant);
dat_stop();
}
参数内传入:0x8f就好。
整体看下显示代码
void tm_lock_show(uint8_t index, uint8_t number) {
uint8_t zero = 0xc0;
dat_start();
dat_send8(zero + index); // 发送地址
dat_send8(coding(number));
dat_stop();
}
void tm_lock_light(uint8_t commant) {
dat_start();
dat_send8(commant);
dat_stop();
}
void tm_init(void) {
DIO_OUT;
CLK_OUT;
tm_sram_lock();
}
void tm_display(uint8_t index, uint8_t number) {
tm_lock_show(index, number);
tm_lock_light(0x8f);
}
在线运行:https://wokwi.com/projects/367022808928992257
Github源码分享: https://github.com/ccy-studio/CCY-Arduino-SensorDemo/tree/master/ESP32C3-TM1637
评论区