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

TM1652显示问题

[复制链接]
  • 打卡等级:常住居民III
  • 打卡总天数:120
  • 最近打卡:2025-05-01 07:02:40

71

主题

84

回帖

212

积分

中级会员

积分
212
发表于 5 天前 | 显示全部楼层 |阅读模式
用TM1652驱动5位8段数码管做了一个频率计,在显示65535以下的频率时都正常,在显示70000左右的频率时只能显示2500多,有关的频率计数、变量都是定义成32位的,怎么调试都不对,难道TM1652不能显示65535以上的数字?
回复

使用道具 举报 送花

3

主题

1160

回帖

1031

积分

等待验证会员

积分
1031
发表于 5 天前 | 显示全部楼层
在您使用TM1652驱动5位8段数码管进行频率计设计时,遇到在显示70000左右频率时只能显示2500多的问题,这确实是一个值得深入探讨的技术问题。以下是对此问题的专业分析及可能的解决方案。

问题分析

1. TM1652的显示能力:
   TM1652是一款常用的LED驱动芯片,支持多位数码管显示。其显示能力主要受限于其内部寄存器的位数和驱动逻辑。TM1652通常用于驱动4位或5位数码管,其显示范围在0到9999或0到99999之间。然而,TM1652本身并不直接限制显示的数字大小,而是通过其驱动逻辑和寄存器配置来实现显示。

2. 频率计数与显示:
   您提到频率计数和变量都是定义成32位的,这意味着在软件层面,您能够处理高达2^32-1(约42亿)的频率值。然而,TM1652的显示能力可能限制了实际显示的数字范围。如果TM1652的显示逻辑或寄存器配置不支持显示超过65535的数字,那么在显示70000时可能会出现异常。

3. 显示异常的可能原因:
寄存器溢出:TM1652的显示寄存器可能只有16位,导致在显示超过65535的数字时发生溢出,从而显示错误的值。
驱动逻辑限制:TM1652的驱动逻辑可能不支持显示超过65535的数字,导致在显示70000时只能显示2500多。
软件处理错误:在将32位频率值转换为TM1652可接受的显示格式时,可能存在处理错误,导致显示异常。

解决方案

1. 检查TM1652的寄存器配置:
   确保TM1652的寄存器配置支持显示超过65535的数字。查阅TM1652的数据手册,确认其显示寄存器的位数和驱动逻辑是否支持大数字显示。

2. 软件处理优化:
   在将32位频率值转换为TM1652可接受的显示格式时,确保正确处理高位和低位。可以尝试将32位频率值分解为多个部分,分别显示在数码管的不同位上。

3. 使用多片TM1652:
   如果TM1652的显示能力确实有限,可以考虑使用多片TM1652来驱动更多的数码管,以扩展显示范围。例如,使用两片TM1652分别驱动5位数码管的高位和低位,从而实现更大范围的数字显示。

4. 更换驱动芯片:
   如果TM1652的显示能力无法满足需求,可以考虑更换其他支持更大显示范围的LED驱动芯片。例如,选择支持32位显示的驱动芯片,以确保能够正确显示高频率值。

调试建议

1. 逐步调试:
   从显示65535以下的频率开始,逐步增加频率值,观察显示变化。记录每次显示异常时的频率值,以便更好地定位问题。

2. 使用调试工具:
   使用示波器或逻辑分析仪等调试工具,监测TM1652的输入信号和输出信号,确保信号传输正确无误。

3. 代码审查:
   仔细审查频率计数和显示相关的代码,确保没有逻辑错误或数据处理错误。特别是检查32位频率值到TM1652显示格式的转换部分。

结论

在您使用TM1652驱动5位8段数码管进行频率计设计时,遇到在显示70000左右频率时只能显示2500多的问题,可能是由于TM1652的显示能力限制或软件处理错误所致。通过检查TM1652的寄存器配置、优化软件处理、使用多片TM1652或更换驱动芯片等方法,可以有效解决这一问题。同时,通过逐步调试、使用调试工具和代码审查,可以更好地定位和解决问题。希望以上分析和建议对您有所帮助。

[本文内容由国芯人工智能辅助生成,仅供参考]
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:常住居民III
  • 打卡总天数:193
  • 最近打卡:2025-05-01 00:30:50
已绑定手机

5

主题

39

回帖

784

积分

高级会员

积分
784
发表于 5 天前 | 显示全部楼层
发程序吧,应该是程序的问题。
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:常住居民III
  • 打卡总天数:162
  • 最近打卡:2025-05-01 06:56:44
已绑定手机

56

主题

1319

回帖

2938

积分

荣誉版主

无情的代码机器

积分
2938
发表于 4 天前 | 显示全部楼层
此处应该贴工程
三天不学习,赶不上刘少奇~
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:以坛为家II
  • 打卡总天数:423
  • 最近打卡:2025-05-01 07:10:25
已绑定手机

76

主题

4833

回帖

8343

积分

超级版主

DebugLab

积分
8343
发表于 4 天前 | 显示全部楼层
65535是unsigned int的最大值,更大的值需要声明为unsigned long,注意数据类型和范围
DebugLab
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:常住居民III
  • 打卡总天数:120
  • 最近打卡:2025-05-01 07:02:40

71

主题

84

回帖

212

积分

中级会员

积分
212
发表于 4 天前 | 显示全部楼层
C_w*** 发表于 2025-4-26 22:31
发程序吧,应该是程序的问题。

主文件;
#include "TM1652.h"
#include "AI8051U.h"
#define MAIN_Fosc       11059200L   // 定义主时钟
#define Timer0_Reload   (65536UL -(MAIN_Fosc / 1000))       // Timer 0 中断频率, 1000次/秒
typedef unsigned char u8;
typedef unsigned int u16;
typedef unsigned long u32;

// 定义变量
unsigned long count = 0;  // 用于计数脉冲个数
unsigned int time_count = 0;  // 用于计时
unsigned long frequency = 0;  // 保存频率值(Hz)
unsigned int timer0_reload;  // 定时器 0 重载值

// 共阴 LED 0--F 段码,包含小数点
const u8 CODE[16] = {0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x07, 0x7F, 0x6F, 0x77, 0x7c, 0x39, 0x5e, 0x79, 0x71};

// 延时 10ms 函数
void Delay10ms()         //@11.0592MHz
{
    unsigned char i, j;
    i = 18;
    j = 235;
    do
    {
        while (--j);
    } while (--i);
}

// 数码管显示函数,显示 Hz 频率
void TM_Digtal_Display(long frequency)
{
    unsigned char wan, qian, bai, shi, ge;
    // 计算变量值
    wan = frequency / 10000;
    qian = (frequency % 10000) / 1000;
    bai = (frequency % 1000) / 100;
    shi = (frequency % 100) / 10;
    ge = frequency % 10;

    // 发送显示命令
    tm1652_send_data(0x08);  // 可能是设置显示模式相关命令
    // 显示万位
    tm1652_send_data(CODE[wan]);
    // 显示千位
    tm1652_send_data(CODE[qian]);
    // 显示百位
    tm1652_send_data(CODE[bai]);
    // 显示十位
    tm1652_send_data(CODE[shi]);
    // 显示个位
    tm1652_send_data(CODE[ge]);

    // 空位补零
    tm1652_send_data(CODE[0]);

    Delay10ms();
    tm1652_send_data(0x18);  // 显示控制命令
    tm1652_send_data(0xFE);  // 设置占空比15/16,段驱动电流8/8,最大亮度。
}

// 定时器 0 中断服务函数
void timer0_isr() interrupt 1
{
    TH0 = (unsigned char)(timer0_reload / 256);
    TL0 = (unsigned char)(timer0_reload % 256);
    time_count++;
    if (time_count >= 1000) {  // 定时 1s
        time_count = 0;
        // 读取计数值
        frequency = count;  // 保存频率值(Hz)
        count = 0;  // 清零计数值

        // 在中断服务程序中调用显示函数
        TM_Digtal_Display(frequency);
    }
}

// 外部中断 0 服务函数,用于计数脉冲
void int0_isr() interrupt 0
{
    count++;
}

void main()
{
        
        P_SW2 |= EAXFR;
    // 提高访问XRAM速度
    CKCON = 0;

    // 配置端口模式为标准 I/O 模式(具体根据实际需求调整)
    P3M0 = 0x00;
    P3M1 = 0x00;
    P4M0 = 0x00;
    P4M1 = 0x00;

    // 定时器 0 初始化
    timer0_reload = Timer0_Reload;
    TH0 = (unsigned char)(timer0_reload / 256);
    TL0 = (unsigned char)(timer0_reload % 256);
    // 设置定时器 0 为模式 1(16 位定时器)
    TMOD &= 0x0F;
    TMOD |= 0x01;
    // 使能定时器 0 中断
    ET0 = 1;  
    // 启动定时器 0
    TR0 = 1;  

    // 外部中断 0 初始化
    // 设置为下降沿触发
    IT0 = 1;  
    // 使能外部中断 0
    EX0 = 1;  

    // 定时器 1 初始化,用于计数脉冲
    // 设置定时器 1 为模式 1(16 位计数器)
    TMOD &= 0xF0;
    TMOD |= 0x50;
    TH1 = 0;
    TL1 = 0;
    // 启动定时器 1
    TR1 = 1;  

    // 全局中断使能
    EA = 1;  

    // 开机显示 00000
    TM_Digtal_Display(0);   

    while(1)
    {
        // 主循环中不需要重复调用显示函数,显示在定时器中断中完成
    }
}

TM1652头文件:

#ifndef __TM1652_H__
#define __TM1652_H__

#include "AI8051U.h"
sbit D_out = P4^3;    //模拟UART输出,至TM1652数据输入脚D_in
void Delay52us();
//void Delay5ms();
void Delay104us();
void tm1652_send_data(unsigned char sdat)        ;

#endif


TM1652 C文件:

#include "TM1652.h"
#include "AI8051U.h"

void Delay52us()                //@11.0592MHz
{
    unsigned char i;
    i = 21;
    while (--i);
}



void Delay104us()                //@11.0592MHz
{
    unsigned char i;
    i = 45;
    while (--i);
}

void tm1652_send_data(unsigned char sdat)                                //向TM1652发送数据
{
    unsigned char i = 0, sfalg = 0;
    //
    D_out = 0;
    Delay52us();    //延迟52us

    //??8???
    for (i = 0; i < 8; i++)
    {
        if (sdat & 0x01)
        {
            D_out = 1;
            sfalg++;
        }
        else
        {
            D_out = 0;
        }
        Delay52us();
        sdat >>= 1;
    }

    //校验
    if (sfalg % 2 == 0)
    {
        D_out = 1;
    }
    else
    {
        D_out = 0;
    }
    Delay52us();
    //
    D_out = 1;
    Delay104us();
        }



现在头都大了,移植到AI8051U,连开机00000都不显示了
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:常住居民III
  • 打卡总天数:193
  • 最近打卡:2025-05-01 00:30:50
已绑定手机

5

主题

39

回帖

784

积分

高级会员

积分
784
发表于 4 天前 | 显示全部楼层
cjt*** 发表于 2025-4-27 16:51
主文件;
#include "TM1652.h"
#include "AI8051U.h"

void Delay52us(void)        //@11.0592MHz
{
        unsigned long edata i;

        _nop_();
        _nop_();
        i = 142UL;
        while (i) i--;
}

void Delay104us(void)        //@11.0592MHz
{
        unsigned long edata i;

        _nop_();
        i = 286UL;
        while (i) i--;
}

延时程序有问题吧,你用软件算一下。

这种模拟的时序我一般用定时器做。


再说了都用了这么高级的单片机了,就别模拟了,用串口吧。
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:常住居民III
  • 打卡总天数:121
  • 最近打卡:2025-05-01 19:17:52
已绑定手机

19

主题

208

回帖

492

积分

中级会员

积分
492
发表于 4 天前 | 显示全部楼层
几点建议:
1. void TM_Digtal_Display(long frequency) 中的输入参数类型最好更改为 unsigned long frequency, 和 函数调用的实际参数类型保持一致;
2. Timer0 中断函数里面:
    TR0 =0;//增加
    TH0 = (unsigned char)(timer0_reload / 256);
    TL0 = (unsigned char)(timer0_reload % 256);
    TR0 =1;//增加
3. // 在中断服务程序中调用显示函数
        TM_Digtal_Display(frequency);
这个在中断函数里面进行显示操作,就不合理。
因为你的定时器本来定义1ms中断一次,但是你的显示函数显示5位字符,加上控制命令,以及显示函数内部延时了10ms,.导致显示函数至少费时13ms以上了!
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:常住居民III
  • 打卡总天数:121
  • 最近打卡:2025-05-01 19:17:52
已绑定手机

19

主题

208

回帖

492

积分

中级会员

积分
492
发表于 4 天前 | 显示全部楼层
这样导致你测量外部中断的时间周期也不是1s了。
回复 支持 反对

使用道具 举报 送花

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

本版积分规则

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

GMT+8, 2025-5-1 22:21 , Processed in 0.147316 second(s), 105 queries .

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

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