找回密码
 立即注册
查看: 43|回复: 8

大佬们,我的51和tm1637通信老是失败,这是为什么呢

[复制链接]
  • 打卡等级:初来乍到
  • 打卡总天数:1
  • 最近打卡:2025-09-16 10:55:51
已绑定手机

1

主题

4

回帖

17

积分

新手上路

积分
17
发表于 昨天 10:55 | 显示全部楼层 |阅读模式
这是代码,用逻辑分析仪看了只有 发送数据命令帧芯片有反馈低电平,其他都是没有反馈的,查看逻辑发送是正确的,就是没有反馈信号


#include "stc8h.h"                        //包含STC8H的头文件

// TM1637引脚定义 - 复用在P3口
sbit clk = P3^2;  // TM1637时钟线,复用P3.2引脚
sbit dio = P3^3;  // TM1637数据线,复用P3.3引脚
sbit resp_ind = P3^4;
// 共阴极数码管段码表 (0-9,熄灭)
unsigned char code digitTable[] = {
    0xc0, // 0
    0xf9, // 1
    0xa4, // 2
    0xb0, // 3
    0x99, // 4
    0x92, // 5
    0x82, // 6
    0xf8, // 7
    0x80, // 8  <-- 这是我们需要显示的数字
    0x90, // 9
    0xff  // 熄灭
};

// 延时函数
void Delay_us(unsigned int i)    // 微秒级延时
{
    for(;i>0;i--)
        _nop_();
       
}

void Delay_ms(unsigned int ms)   // 毫秒级延时
{
   unsigned int i;
    // 1毫秒 = 1000微秒,循环调用微秒延时
    for(i = 0; i < ms; i++)
    {
        Delay_us(1000);  // 每次循环延时1000微秒(1毫秒)
    }
}

// TM1637通信函数
void I2CStart(void)             // 起始信号
{
    clk = 1;
    dio = 1;
    Delay_us(2);
    dio = 0;
          Delay_us(2);
}

void I2CStop(void)               // 停止信号
{
    clk = 0;
    Delay_us(2);
    dio = 0;
    Delay_us(2);
    clk = 1;
    Delay_us(2);
    dio = 1;
          Delay_us(2);
}

// 带超时的应答信号检测(修复死循环问题)
void I2Cask(void)               
{   
    unsigned int timeout = 0;    // 超时计数器
    clk = 0;  
    Delay_us(5);                 // 等待应答的初始延时(符合手册时序)
   
    // 等待从机应答,最多等待1ms(避免长时间卡死)
    while(dio) {
        Delay_us(1);            // 每1us检测一次
        timeout++;
        if(timeout > 5000) {    // 超时1ms
            resp_ind = 1;       // 1:标记无应答
            break;              // 跳出等待循环
        }
    }
   
    // 如果未超时(正常应答)
    if(timeout < 1000) {
        resp_ind = 0;           // 0:标记有应答
    }
   
    // 恢复时钟线状态(无论是否应答,均按手册时序处理)
    clk = 1;
    Delay_us(2);
    clk = 0;
}

// 优化的写字节函数(对齐TM1637时序,低位在前)
void I2CWrByte(unsigned char oneByte)  
{  
    unsigned char i;
    for(i=0;i<8;i++)
    {
        clk = 0;
        Delay_us(2);  // 数据建立时间
        // 输出当前最低位
        if(oneByte & 0x01)   
        {                                       
            dio = 1;
        }
        else
        {
            dio = 0;
        }
        Delay_us(2);  // 数据稳定
        oneByte >>= 1;  
        clk = 1;      // 芯片采样当前位
        Delay_us(2);  // 确保采样完成
    }  
}

unsigned char ScanKey(void)                //读按键
{  
    unsigned char rekey,i;
    I2CStart();
    I2CWrByte(0x42);                     //读按键命令
    I2Cask();   
    dio=1;                               // 在读按键前拉高数据线
    for(i=0;i<8;i++)                    //从低位开始读
    {  clk=0;
        rekey=rekey>>1;
        Delay_us(30);
        clk=1;
        if(dio)
        {
            rekey=rekey|0x80;
        }
        else
        {
            rekey=rekey|0x00;
        }
        Delay_us(30);
    }   
    I2Cask();
    I2CStop();
    return (rekey);
}

// 修复的显示函数(完整通信流程)
void SmgDisplay(void)
{
    // 1. 发送数据命令帧(地址自动增加+写显示)
    I2CStart();
    I2CWrByte(0x40);  
    I2Cask();
    I2CStop();
    Delay_ms(1);  // 等待芯片就绪

    // 2. 发送地址帧+数据帧
    I2CStart();
    I2CWrByte(0xc0);                 //设置首地址
    I2Cask();
  
    I2CWrByte(digitTable[4]);
    I2Cask();
    I2CStop();

    // 3. 发送显示控制帧(开显示+最大亮度)
    I2CStart();
    I2CWrByte(0x8f);               
    I2Cask();   
    I2CStop();
}

// TM1637初始化函数
void TM1637Init(void) {
    clk = 1;
    dio = 1;
    resp_ind = 1;
}

// 主函数
void main(void)
{
    P_SW2 |= 0x80;                  //允许访问扩展的特殊寄存器,XFR

    // 设置所有I/O口为准双向口模式
    P0M0 = 0x00; P0M1 = 0x00;      
    P1M0 = 0x00; P1M1 = 0x00;      
    P2M0 = 0x00; P2M1 = 0x00;      
    P3M0 = 0x00; P3M1 = 0x00;       //P3口准双向模式,用于TM1637通信
    P4M0 = 0x00; P4M1 = 0x00;      
    P5M0 = 0x00; P5M1 = 0x00;      
    P6M0 = 0x00; P6M1 = 0x00;      
    P7M0 = 0x00; P7M1 = 0x00;      

    P40 = 0;                        //打开LED部分的供电
   
    TM1637Init();       // 初始化TM1637   
    Delay_ms(50);       // 等待芯片上电稳定

    while (1)
    {
        SmgDisplay();       
        Delay_ms(1000); // 每秒刷新一次显示
    }
}

回复

使用道具 举报 送花

  • 打卡等级:初来乍到
  • 打卡总天数:1
  • 最近打卡:2025-09-16 10:55:51
已绑定手机

1

主题

4

回帖

17

积分

新手上路

积分
17
发表于 昨天 10:56 | 显示全部楼层
初始化写成死循环里边是为了逻辑分析仪查看
回复

使用道具 举报 送花

  • 打卡等级:偶尔看看III
  • 打卡总天数:36
  • 最近打卡:2025-09-16 14:12:44

14

主题

154

回帖

1789

积分

版主

积分
1789
发表于 昨天 14:13 | 显示全部楼层
已帮您转发给技术,耐心等待哦
回复

使用道具 举报 送花

  • 打卡等级:以坛为家II
  • 打卡总天数:560
  • 最近打卡:2025-09-16 05:09:25
已绑定手机

86

主题

6122

回帖

1万

积分

超级版主

积分
11330
发表于 昨天 14:19 | 显示全部楼层
驱动数码管建议用8H4K64TL,80mA大电流IO,自动扫描,不需要外接其他芯片
以下是1637数码管显示程序
  1. void I2C_Start(void)
  2. {
  3.         SCL=1;
  4.         SDA=1;
  5.         _nop_();
  6.         SDA=0;
  7.         _nop_();
  8. }
  9. void I2C_Stop(void)
  10. {
  11.         SCL=1;
  12.         SDA=0;
  13.         _nop_();
  14.         SDA=1;
  15.         _nop_();
  16. }
  17. void I2C_Send(unsigned char temp)
  18. {
  19.         unsigned char i;
  20.         SCL=0;
  21.         _nop_();
  22.         for(i=0;i<8;i++)
  23.         {
  24.                 if((temp>>i)&0x01)
  25.                         SDA=1;
  26.                 else
  27.                         SDA=0;
  28.                 _nop_();
  29.                 SCL=1;
  30.                 _nop_();
  31.                 SCL=0;
  32.                 _nop_();
  33.         }
  34.         SCL=1;
  35.         _nop_();
  36.         SCL=0;
  37.         _nop_();
  38. }
  39. void Display(unsigned char temp)
  40. {
  41.         unsigned char i;
  42.         I2C_Start();
  43.         I2C_Send(0x40);
  44.         I2C_Stop();
  45.         I2C_Start();
  46.         I2C_Send(0xc0);
  47.         for(i=0;i<4;i++)
  48.         {
  49.                 I2C_Send(~Buff[i]);
  50.         }
  51.         I2C_Stop();
  52.         I2C_Start();
  53.         if(temp<8)
  54.                 I2C_Send(0x88|temp);
  55.         else
  56.                 I2C_Send(0x8f);
  57.         I2C_Stop();
  58. }
复制代码


回复

使用道具 举报 送花

  • 打卡等级:初来乍到
  • 打卡总天数:1
  • 最近打卡:2025-09-16 10:55:51
已绑定手机

1

主题

4

回帖

17

积分

新手上路

积分
17
发表于 昨天 14:48 | 显示全部楼层
Debu*** 发表于 2025-9-16 14:19
驱动数码管建议用8H4K64TL,80mA大电流IO,自动扫描,不需要外接其他芯片
以下是1637数码管显示程序

我找到个很神奇的原因,tm1637数据手册是低位在前发送,但是低位发送是不会理我的,没有反馈消息,但是我修改为高位发送,就有反馈信息了,我目前正在纳闷中
void I2CWrByte(unsigned char oneByte)
{
    unsigned char i;
   
    for(i = 0; i < 8; i++)
    {
        clk = 0;
        Delay_us(2);
        
      
        if(oneByte & 0x01)
            dio = 1;
        else
            dio = 0;
            
        Delay_us(2);
        clk = 1;
        Delay_us(2);
        
        oneByte <<= 1;  
    }
}下边按位移动,之前右移低位就没有反馈信息,我换成左移高位发送就有反馈信息
回复

使用道具 举报 送花

  • 打卡等级:初来乍到
  • 打卡总天数:1
  • 最近打卡:2025-09-16 10:55:51
已绑定手机

1

主题

4

回帖

17

积分

新手上路

积分
17
发表于 昨天 14:53 | 显示全部楼层
Debu*** 发表于 2025-9-16 14:19
驱动数码管建议用8H4K64TL,80mA大电流IO,自动扫描,不需要外接其他芯片
以下是1637数码管显示程序

而且这个和芯片手册时序不一样,感觉芯片手册好像不对劲
回复

使用道具 举报 送花

  • 打卡等级:以坛为家II
  • 打卡总天数:495
  • 最近打卡:2025-09-16 15:37:51

9

主题

423

回帖

3025

积分

论坛元老

积分
3025
发表于 昨天 20:33 | 显示全部楼层
使用天微的显示驱动芯片,一定要注意芯片型号和版本,有些后缀不同版本不同功能很大差异,要对照相应版本的数据手册去用
单片机DIO脚需要配置成准双向,以防止应答信号引起逻辑冲突.

代码中,等待1637应答之前需要把DIO脚设为准双向或高阻,然后DIO写1,然后在延时等待1637的应答信号把DIO拉低,
如果上次传的字节最后一位是0,忘记修改DIO脚模式同时置1的话,可能会错误识别应答信号.还不如直接用延时忽略应答

回复

使用道具 举报 送花

  • 打卡等级:初来乍到
  • 打卡总天数:1
  • 最近打卡:2025-09-16 10:55:51
已绑定手机

1

主题

4

回帖

17

积分

新手上路

积分
17
发表于 昨天 21:24 | 显示全部楼层
网*** 发表于 2025-9-16 20:33
使用天微的显示驱动芯片,一定要注意芯片型号和版本,有些后缀不同版本不同功能很大差异,要对照相应版本的数 ...

void SmgDisplay(void)                   //写显示寄存器
{     
       
unsigned char i;  
    I2CStart();
    I2CWrByte(0x40);                    // 40H地址自动加1模式,44H固定地址模式,本程序采用自加1模式
                I2Cask();
    I2CStop();
                I2CStart();
    I2CWrByte(0xC0);      
    Delay_us(5);          //设置首地址,
         dio = 1;
                I2Cask();
  
        for(i=0;i<6;i++)                 //地址自加,不必每次都写地址
         {
                 I2CWrByte(0x3f);             //送数据
                 I2Cask();
         }
         I2CStop();

         I2CStart();
         I2CWrByte(0x8f);                //开显示 ,最大亮度
             Delay_us(5);  
        //I2Cask();   
         找到没有应答卡主的地方了,这个开启显示和设置地址的应答没有反馈信号,而且这个数据如果是0xff也没有信号但是换成0x3f就有,而且看了一下和d0当前关系可能不是很大,开启显示和地址无论设置那个模式都没有应答
回复

使用道具 举报 送花

  • 打卡等级:以坛为家II
  • 打卡总天数:495
  • 最近打卡:2025-09-16 15:37:51

9

主题

423

回帖

3025

积分

论坛元老

积分
3025
发表于 昨天 21:45 | 显示全部楼层
fengh*** 发表于 2025-9-16 21:24
void SmgDisplay(void)                   //写显示寄存器
{     
       

1637芯片跟1651芯片接口一样,
我以前写的1651驱动都是直接忽略掉ASK应答信号,只发一个时钟脉冲跳过.
总归要保证应答期间不能把DIO配置为推挽,
回复

使用道具 举报 送花

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|手机版|深圳国芯人工智能有限公司 ( 粤ICP备2022108929号-2 )

GMT+8, 2025-9-17 09:31 , Processed in 0.135908 second(s), 100 queries .

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

快速回复 返回顶部 返回列表