#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