cjtdz 发表于 2025-4-21 14:00:39

求大师们帮忙

这是一个频率计代码,显示部分用的是TM1652驱动5位LED数码管,显示采用KHz做单位,这部分采用的是模块化,头文件和C文件完整。现在的问题是:全局变量count, 也就是中断0的P3.2输入端脉冲个数,为int型时显示正常,但只能显示65.535KHZ以下的频率,现在要求能显示99.999KHZ以下的频率,将count由int型改为long型时,就无法显示应有的频率了,五位数码管一直死在改前的数值上,求大师们指点一二。源主代码如下(未贴TM1652头文件和C文件):



#include "TM1652.h"
#include "REG51.h"

typedef unsigned char u8;
typedef unsigned int u16;

// 定义变量
unsigned int count = 0;// 用于计数脉冲个数
unsigned int time_count = 0;// 用于计时
float frequency = 0;// 保存频率值(Hz),改为 float 类型以支持小数

// 共阴 LED 0--F 段码,包含小数点
const u8 CODE = {0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x07, 0x7F, 0x6F, 0x77, 0x7c, 0x39, 0x5e, 0x79, 0x71};
const u8 CODE_WITH_DOT = {0xBF, 0x86, 0xDB, 0xCF, 0xE6, 0xED, 0xFD, 0x87, 0xFF, 0xEF, 0xF7, 0xFC, 0xB9, 0xDE, 0xF9, 0xF1};

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

// 数码管显示函数,显示缩小 1000 倍后的频率(保留 3 位小数,最大显示 99.999)
void TM_Digtal_Display(float num)
{
    // 定义所有局部变量在函数开头
    unsigned int integer_part;// 整数部分
    unsigned int decimal_part1, decimal_part2, decimal_part3;// 三位小数部分
    unsigned int tens;
    unsigned int units;
    float decimal_part_float;// 声明小数部分的临时变量

    // 计算缩小 1000 倍后的整数部分和小数部分
    integer_part = (unsigned int)(num / 1000);
    decimal_part_float = (num / 1000 - integer_part) * 1000;
    decimal_part1 = (unsigned int)(decimal_part_float / 100);
    decimal_part2 = (unsigned int)((decimal_part_float - decimal_part1 * 100) / 10);
    decimal_part3 = (unsigned int)(decimal_part_float - decimal_part1 * 100 - decimal_part2 * 10);

    // 计算整数部分的十位和个位
    tens = (integer_part % 100) / 10;
    units = integer_part % 10;

    // 发送显示命令
    tm1652_send_data(0x08);// 可能是设置显示模式相关命令

    // 显示十位
    tm1652_send_data(CODE);
    // 显示个位并带小数点
    tm1652_send_data(CODE_WITH_DOT);
    // 显示小数第一位
    tm1652_send_data(CODE);
    // 显示小数第二位
    tm1652_send_data(CODE);
    // 显示小数第三位
    tm1652_send_data(CODE);

    // 空位补零(这里可以根据实际情况调整,比如如果前面的位没有显示,补零方式可能不同)
    tm1652_send_data(CODE);

    Delay10ms();
    tm1652_send_data(0x18);// 可能是设置显示模式相关命令
    tm1652_send_data(0xFE);// 可能是设置显示模式相关命令
}

// 定时器 0 中断服务函数
void timer0_isr() interrupt 1 {
    float timer0_reload_float;
    unsigned int timer0_reload;
    // 更精确的定时器初值计算并微调
    timer0_reload_float = 65536 - (11059200.0 / 12 / 1000) + 3.7;
    // 四舍五入
    timer0_reload = (unsigned int)(timer0_reload_float + 0.5);
    TH0 = (unsigned char)(timer0_reload / 256);
    TL0 = (unsigned char)(timer0_reload % 256);
    time_count++;
    if (time_count >= 1000) {// 定时 1s
      time_count = 0;
      // 读取计数值
      TR1 = 0;// 停止计数
      frequency = (float)count;// 保存频率值(Hz),转换为 float 类型
      // 加上补偿值 365
      frequency += 365;
      count = 0;// 清零计数值
      TR1 = 1;// 重新开始计数

      // 输出当前频率值

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

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

void main()
{
    float timer0_reload_float;
    unsigned int timer0_reload;
    // 定时器 0 初始化
    TMOD |= 0x01;// 定时器 0 工作在模式 1(16 位定时器)
    // 更精确的定时器初值计算并微调
    timer0_reload_float = 65536 - (11059200.0 / 12 / 1000) + 3.7;
    // 四舍五入
    timer0_reload = (unsigned int)(timer0_reload_float + 0.5);
    TH0 = (unsigned char)(timer0_reload / 256);
    TL0 = (unsigned char)(timer0_reload % 256);
    ET0 = 1;// 使能定时器 0 中断
    TR0 = 1;// 启动定时器 0

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

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

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

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

    while (1)
    {
      // 主循环可以留空或者进行其他非紧急任务
    }
}

国芯人工智能 发表于 2025-4-21 14:03:00

针对您提出的问题,以下是一些可能的原因和解决方案:

问题分析
1. 数据类型溢出:int型变量在大多数系统中是16位,最大值为32767(有符号)或65535(无符号)。当count超过65535时,int型变量会溢出,导致显示异常。将count改为long型(32位)可以解决溢出问题,但需要确保代码的其他部分也支持32位数据处理。

2. 显示驱动问题:TM1652驱动5位LED数码管时,可能只支持16位数据的显示。如果count改为long型,但显示驱动未做相应调整,可能导致显示异常。

3. 中断处理问题:中断服务程序(ISR)可能未正确处理32位数据,导致count值未正确更新。

解决方案
1. 修改数据类型:将count改为long型,并确保所有相关变量和函数也支持32位数据。

2. 更新显示驱动:检查TM1652驱动代码,确保其支持32位数据的显示。可能需要修改显示函数,以正确处理32位数据。

3. 调整中断服务程序:确保中断服务程序正确处理32位数据,并在更新count时避免数据丢失。

代码修改示例
以下是对代码的修改建议:

c
include "TM1652.h"
include "REG51.h"

typedef unsigned char u8;
typedef unsigned int u16;
typedef unsigned long u32;// 添加32位数据类型

// 定义变量
u32 count = 0;// 用于计数脉冲个数,改为u32型
u16 timecount = 0;// 用于计时
float frequency = 0;// 保存频率值(Hz),改为 float 类型以支持小数

// 共阴 LED 0--F 段码,包含小数点
const u8 CODE = {0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x07, 0x7F, 0x6F, 0x77, 0x7c, 0x39, 0x5e, 0x79, 0x71};
const u8 CODEWITHDOT = {0xBF, 0x86, 0xDB, 0xCF, 0xE6, 0xED, 0xFD, 0x87, 0xFF, 0xEF, 0xF7, 0xFC, 0xB9, 0xDE, 0xF9, 0xF1};

// 延时 10ms 函数
void Delay10ms() {
    // 延时函数实现
}

// 中断服务程序
void Timer0ISR() interrupt 1 {
    count++;// 计数脉冲个数
}

// 显示频率函数
void DisplayFrequency(u32 freq) {
    u8 digits;
    digits = freq / 10000 % 10;
    digits = freq / 1000 % 10;
    digits = freq / 100 % 10;
    digits = freq / 10 % 10;
    digits = freq % 10;

    // 调用TM1652显示函数,显示digits数组中的数字
    TM1652Display(digits);
}

void main() {
    // 初始化TM1652
    TM1652Init();

    // 配置定时器0
    // ...

    while (1) {
      // 计算频率
      frequency = (float)count / (timecount0.001);// 假设timecount单位为ms

      // 显示频率
      DisplayFrequency((u32)frequency);

      // 延时
      Delay10ms();
    }
}

注意事项
1. TM1652驱动代码:确保TM1652Display函数支持32位数据的显示。如果驱动代码只支持16位数据,需要修改驱动代码以支持32位数据。

2. 中断服务程序:确保中断服务程序正确处理32位数据,并在更新count时避免数据丢失。

3. 调试和测试:在修改代码后,进行充分的调试和测试,确保频率计能够正确显示99999KHz以下的频率。

通过以上修改和调整,您应该能够解决count改为long型后无法正常显示频率的问题。如果问题仍然存在,建议进一步检查硬件连接和驱动代码的实现细节。

[本文内容由国芯人工智能辅助生成,仅供参考]

AI-32位8051 发表于 2025-4-21 14:41:51





STC8H4K64TL系列集成了80mA大电流LED数码管自动刷新。一个芯片搞定外设+驱动功能。后面新产品您可以考虑试用。

手册下载链接:https://www.stcaimcu.com/data/download/Datasheet/AI8.pdf
段码LCD/80mA大电流LED数码管自动刷新显示论坛支持板块:https://www.stcaimcu.com/forum-52-1.html


cjtdz 发表于 2025-4-21 14:47:09

AI-32位8051 发表于 2025-4-21 14:41
STC8H4K64TL系列集成了80mA大电流LED数码管自动刷新。一个芯片搞定外设+驱动功能。后面新产品您可以考 ...

你发的手册下载连接打开是空白的

DebugLab 发表于 2025-4-21 15:25:49

注意数据类型转换
建议使用AI8H4K64TL直接驱动数码管
以下是我9年前写的5位数码管频率计程序供参考:
#include"reg51.h"
#define uchar unsigned char
#define uint unsigned int
#define ulong unsigned long
sbit ww=P2^0;//万位
sbit qw=P2^1;//千位
sbit bw=P2^2;//百位
sbit sw=P2^3;//十位
sbit gw=P2^4;//个位
uchar wan,qian,bai,shi,ge,a;
ulong count,b;
uint code table[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90};//共阳极数码管不带小数点代码表
void delay(uint i)//延时i*100微秒
{
uint j,k;
for(j=i;j>0;j--)
    for(k=9;k>0;k--);
}
void init()//初始化函数
{
        TMOD=0x01;
        TH0=(65536-50000)/256;
        TL0=(65536-50000)%256;
        PX0=0;
        PT0=1;
        IT0=1;
        EA=1;
        ET0=1;
        EX0=1;
        TR0=1;
        a=0;
        count=0;
}
void display()//显示函数
{
        wan=count/10000;
        qian=count%10000/1000;
        bai=count%1000/100;
        shi=count%100/10;
        ge=count%10;
        P0=table;
        ww=1;
        delay(5);
        ww=0;
        P0=table;
        qw=1;
        delay(5);
        qw=0;
        P0=table;
        bw=1;
        delay(5);
        bw=0;
        P0=table;
        sw=1;
        delay(5);
        sw=0;
        P0=table;
        gw=1;
        delay(5);
        gw=0;
}
void main()//主函数
{
        init();
        while(1)
        {
                display();
                if(a>=20)
                {
                        a=0;
                        count=b;
                        b=0;
                }
        }
}
void add() interrupt 0
{
        b++;
}
void time() interrupt 1
{
        TH0=(65536-50000)/256;
        TL0=(65536-50000)%256;
        a++;
}

AI-32位8051 发表于 2025-4-21 15:45:15

cjtdz 发表于 2025-4-21 14:47
你发的手册下载连接打开是空白的


链接是可以打开的。或者您自己去官网下载:深圳国芯人工智能有限公司-产品_STC8H系列https://www.stcai.com/cp_stc8hxl

页: [1]
查看完整版本: 求大师们帮忙