255 lines
4.8 KiB
C
255 lines
4.8 KiB
C
|
||
|
||
|
||
#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
|