optical/NxFuncs/keyled/tm1637.c
2025-09-04 09:45:08 +08:00

255 lines
4.8 KiB
C
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "tm1637.h"
#if (LEDKEY_TM1637 != 0)
#include "delay.h"
#include "inout.h"
//------------------------------------------------------------------------------
// 软件模拟I2C
#define SetTM1637CLKLow SetI2cSCLOn
#define SetTM1637CLKHigh SetI2cSCLOff
#define SetTM1637DIOLow SetI2cSDAOn
#define SetTM1637DIOHigh SetI2cSDAOff
#define SetTM1637DIOIn SetI2cSDAIn
#define SetTM1637DIOOut SetI2cSDAOut
#define GetTM1637DIOStatus GetI2cSDAInputStatus
#ifndef TM1637Delay
#define TM1637Delay(dl) DelayUs(dl)
#endif
//---------------------------------------
// 发送起始位
// CLK 为高电平时DIO由高变低
void SetI2CStart(void)
{
SetTM1637DIOOut();
SetTM1637CLKHigh();
SetTM1637DIOHigh();
TM1637Delay(2);
SetTM1637DIOLow();
TM1637Delay(2);
}
// 发送停止位
// CLK 为高电平时DIO由低变高
void SetI2CStop(void)
{
SetTM1637DIOOut();
SetTM1637CLKLow();
TM1637Delay(2);
SetTM1637DIOLow();
TM1637Delay(2);
SetTM1637CLKHigh();
TM1637Delay(2);
SetTM1637DIOHigh();
TM1637Delay(2);
}
// 等待应答位
// 传输数据正确时, 在第八个时钟下降沿, 芯片内部会产生一个ACK信号, 将DIO管脚拉低, 在第九个时钟结束之后释放DIO总线。
// 返回值0接收应答成功
// -1接收应答失败
int WaitI2CAck(void)
{
int timout;
SetTM1637CLKLow(); // 第九个下降沿
SetTM1637DIOIn(); // 设置为输入
TM1637Delay(5); // 在第八个时钟下降沿之后延时 5us, 开始判断 ACK 信号
// 等待 ACK
timout = 100;
do
{
if (GetTM1637DIOStatus() == 0) // ACK 低电平
{
break;
}
timout--;
TM1637Delay(1);
}while (timout > 0);
#if (1) // 超时处理
if (timout <= 0)
{
SetI2CStop();
printf("I2C No reply\r\n");
return -1;
}
#endif
SetTM1637CLKHigh(); // 设置第9个CLK为高电平, 结束ACK状态
TM1637Delay(2);
SetTM1637CLKLow(); // 设置为低电平,
return 0;
}
// 写一个字节
// 数据在CLK的低电平时才能在CLK的高电平被传输不能变化
// 每传输一个字节, 芯片内部在第八个时钟下降沿产生一个ACK
void WriteI2CByte(u8 dat)
{
int i;
SetTM1637DIOOut();
for (i = 0; i < 8; i++)
{
SetTM1637CLKLow(); // 设置为低电平, 准备数据
if ((dat & 0x01) != 0) // TM1637 低位在前, 和标准I2C不相同
{
SetTM1637DIOHigh();
}
else
{
SetTM1637DIOLow();
}
TM1637Delay(3);
dat >>= 1;
SetTM1637CLKHigh(); // 设置为高电平, 传输数据
TM1637Delay(3);
}
}
// 从总线上读一个字节
u8 ReadI2CByte(void)
{
int i;
u8 dat = 0;
SetTM1637DIOIn(); // 设置为输入状态
for (i = 0; i < 8; i++)
{
SetTM1637CLKLow(); // 设置为低电平, 准备数据
dat >>= 1;
TM1637Delay(3); // 4
SetTM1637CLKHigh(); // 设置为高电平, 读取数据
if ((GetTM1637DIOStatus()) != 0) // TM1637 低位在前, 和标准I2C不相同
{
dat |= 0x80;
}
TM1637Delay(3); // 4
}
return dat;
}
//---------------------------------------------------------
// 读取按键信息
// 读按键时,时钟频率应小于 250K先读低位后读高位。
// S0、S1、S2、K1、K2 为按键信息编码
u8 TM1637ReadKey(void)
{
u8 keyval;
// command
SetI2CStart(); // 起始位
WriteI2CByte(DATA_CMD_BITS|READ_KEY_VAL); // 读按键命令
WaitI2CAck(); // 等待回应
// 按键数据读取
keyval = ReadI2CByte(); // 读取数据
WaitI2CAck(); // 等待回应
SetI2CStop(); // 结束
switch (keyval)
{
case KEY_K1SG1:
case KEY_K1SG2:
case KEY_K1SG3:
case KEY_K1SG4:
case KEY_K1SG5:
case KEY_K1SG6:
case KEY_K1SG7:
case KEY_K1SG8:
case KEY_K2SG1:
case KEY_K2SG2:
case KEY_K2SG3:
case KEY_K2SG4:
case KEY_K2SG5:
case KEY_K2SG6:
case KEY_K2SG7:
case KEY_K2SG8:
break;
default:
keyval = KEY_NONE;
}
return keyval;
}
// 写显示寄存器(地址自增)
void TM1637WriteLedData(u8 baddr, u8 * pBuff, u8 disp)
{
if (baddr < LED_REG1_ADDR || baddr > LED_REG6_ADDR || pBuff == NULL)
{
return;
}
// printf("TM1637WriteLedData begin\r\n");
// command1 设置数据
// printf("command1\r\n");
SetI2CStart(); // 起始位
WriteI2CByte(DATA_CMD_BITS|WRITE_LED_REG|ADDR_AUTO_INC); // 写数据到显示寄存器, 地址自动增加
WaitI2CAck(); // 等待回应
SetI2CStop(); // 结束
// command2 设置地址
// printf("command2\r\n");
SetI2CStart(); // 起始位
WriteI2CByte(ADDR_CMD_BITS|LED_REG_BEG_ADDR); // 写为起始地址
WaitI2CAck(); // 等待回应
// Data1~N传输显示数据
//printf("send data\r\n");
while (baddr <= LED_REG6_ADDR)
{
//printf("data=0x%x\r\n", *pBuff);
WriteI2CByte(*pBuff); // 写入LED数据
WaitI2CAck(); // 等待回应
pBuff++;
baddr++;
}
SetI2CStop(); // 结束
// printf("command3\r\n");
// command3 控制显示
SetI2CStart(); // 起始位
WriteI2CByte(DISP_CTRL_BITS|(disp & 0x0f)); // 写显示控制数据
WaitI2CAck(); // 等待回应
SetI2CStop(); // 结束
// printf("TM1637WriteLedData end\r\n");
}
// 设置显示模式
// 开关和亮度
void TM1637SetLedDisp(u8 disp)
{
SetI2CStart(); // 起始位
WriteI2CByte(DISP_CTRL_BITS|(disp & 0x0f)); // 写显示控制数据
WaitI2CAck(); // 等待回应
SetI2CStop(); // 结束
}
#endif