找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 866|回复: 6
打印 上一主题 下一主题
收起左侧

51单片机+2片HC595四位LED数码管计数器C代码

[复制链接]
跳转到指定楼层
楼主
ID:33548 发表于 2025-3-13 22:00 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
用模块厂家资料+豆包+自己修改生成的51单片机+2片HC595四位LED数码管计数器C代码,可实现点动增加或减小1,长按连续加1或连续减1。实际调试OK,在此分享给大家。


/*51单片机+2片HC595四位LED数码管计数器C代码*/
//11.0592MHz
//可实现点动增加或减小1,长按连续加1或连续减1.

#include <REG51.H>
#include <intrins.h>  // 引入_nop_()函数头文件
#define uchar unsigned char
#define uint unsigned int

unsigned char code LED_0F[] =
{// 0     1     2     3    4     5     6     7    8     9     A     b    C    d     E    F    -
    0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90,0x8C,0xBF,0xC6,0xA1,0x86,0xFF,0xbf
};

uint count;
static unsigned char key_delay = 0;
sbit DIO = P1^0;              //串行数据输入
sbit RCLK  = P1^1;            //时钟脉冲信号——上升沿有效
sbit SCLK = P1^2;             //打入信号————上升沿有效
sbit UP_KEY=P2^0;             //增加按键
sbit DOWN_KEY=P2^1;           //减小按键
sbit CLE_KEY=P2^2;            //清零按键

uchar LED[8];     //用于LED的8位显示缓存
uchar display_index = 0;  // 当前显示的数位索引

// 调试用 LED 引脚定义
sbit DEBUG_LED = P3^7;
sbit KEY_DEBUG_LED = P3^6;

// 将计数值拆分成每一位并更新到LED数组中
void update_LED()
{
    LED[0] = count % 10;  // 个位
    LED[1] = (count % 100) / 10;  // 十位
    LED[2] = (count % 1000) / 100;  // 百位
    LED[3] = count / 1000;  // 千位
}

void LED_OUT(uchar X)   // LED单字节串行移位函数
{
    uchar i;
    for(i = 8; i >= 1; i--)
    {
        if (X & 0x80)
            DIO = 1;
        else
            DIO = 0;
        X <<= 1;
        SCLK = 0;
        SCLK = 1;
    }
}

// 延时函数,单位为毫秒
void delay_ms(uint ms)
{
    uint i, j;
    for (i = 0; i < ms; i++)
    {
        for (j = 0; j < 123; j++)
        {
            _nop_();
        }
    }
}

void key()
{
    static bit up_key_pressed = 0;  // 增加按键按下标志
    static bit down_key_pressed = 0;  // 减小按键按下标志
    static uint up_key_delay_count = 0;  // 增加按键延时计数
    static uint down_key_delay_count = 0;  // 减小按键延时计数

    /* 加键处理 */
    if(UP_KEY == 0)
    {
        delay_ms(20);  // 消抖延时
        if(UP_KEY == 0)
        {
            if(!up_key_pressed)  // 按键首次按下
            {
                count++;
                if(count > 9999)
                    count = 9999;
                up_key_pressed = 1;  // 设置按键按下标志
                up_key_delay_count = 0;  // 重置延时计数
            }
            else  // 按键已按下
            {
                up_key_delay_count++;
                if(up_key_delay_count >= 5)  // 延时5次,可根据需要调整
                {
                    count++;
                    if(count > 9999)
                        count = 9999;
                    up_key_delay_count = 0;  // 重置延时计数
                }
            }
        }
    }
    else
    {
        up_key_pressed = 0;  // 按键松开,清除标志
    }

    /* 减键处理 */
    if(DOWN_KEY == 0)
    {
        delay_ms(20);  // 消抖延时
        if(DOWN_KEY == 0)
        {
            if(!down_key_pressed)  // 按键首次按下
            {
                if (count > 0) {
                    count--;
                }
                down_key_pressed = 1;  // 设置按键按下标志
                down_key_delay_count = 0;  // 重置延时计数
            }
            else  // 按键已按下
            {
                down_key_delay_count++;
                if(down_key_delay_count >= 5)  // 延时5次,可根据需要调整
                {
                    if (count > 0) {
                        count--;
                    }
                    down_key_delay_count = 0;  // 重置延时计数
                }
            }
        }
    }
    else
    {
        down_key_pressed = 0;  // 按键松开,清除标志
    }

    /* 清除键处理 */
    if(CLE_KEY == 0)
    {
        delay_ms(20);  // 消抖延时
        if(CLE_KEY == 0)
        {
            count = 0;  // 清零计数
            update_LED(); // 及时更新显示缓存
        }
    }
}

// 定时器0初始化函数
void Timer0_Init() {
    TMOD |= 0x01;  // 设置定时器0为模式1(16位定时器)
    TH0 = (65536 - 2000) / 256;  // 定时2ms
    TL0 = (65536 - 2000) % 256;
    ET0 = 1;  // 使能定时器0中断
    EA = 1;   // 使能总中断
    TR0 = 1;  // 启动定时器0
}

// 定时器0中断服务函数
void Timer0_ISR() interrupt 1
{
    // 先声明变量
    unsigned char code *led_table;
    uchar i;

    // 重新加载初值
    TH0 = (65536 - 2000) / 256;
    TL0 = (65536 - 2000) % 256;

    // 显示当前数位
    led_table = LED_0F + LED[display_index];
    i = *led_table;

    LED_OUT(i);
    switch (display_index)
    {
        case 0: LED_OUT(0x01); break;
        case 1: LED_OUT(0x02); break;
        case 2: LED_OUT(0x04); break;
        case 3: LED_OUT(0x08); break;
    }

    RCLK = 0;
    RCLK = 1;

    // 更新显示索引
    display_index = (display_index + 1) % 4;
}

// 主函数
void main()
{
    count = 0;
    update_LED();
    Timer0_Init();

    while (1)
    {
        key();
        update_LED();
    }
}

评分

参与人数 1黑币 +50 收起 理由
admin + 50 共享资料的黑币奖励!

查看全部评分

分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏3 分享淘帖 顶 踩
回复

使用道具 举报

沙发
ID:126580 发表于 2025-3-19 19:00 | 只看该作者
可以讲讲怎么和豆包联系起来实现的过程吗?
回复

使用道具 举报

板凳
ID:105698 发表于 2025-3-20 08:24 | 只看该作者
同上,我也想知道。
回复

使用道具 举报

地板
ID:33548 发表于 2025-3-22 20:03 | 只看该作者
dtdzlujian 发表于 2025-3-19 19:00
可以讲讲怎么和豆包联系起来实现的过程吗?

把要求、硬件配置详细告诉豆包,豆包会自动生成C代码,哪些编译出错、改进、添加功能、改错、代码修改都可以完成
回复

使用道具 举报

5#
ID:759144 发表于 2025-3-22 21:10 | 只看该作者
单片机学习中,向无私分享的大神们致敬!
回复

使用道具 举报

6#
ID:383215 发表于 2025-3-24 17:24 | 只看该作者
感谢楼主的无私奉献!但是,个人认为,驱动四位数码管的最佳方案是TM1650,对比两片HC595驱动四位数码管有以下优点:
1、成本更低,买两片价格最低的HC595至少可以买TM1650两片以上。
2、电路简单,两片HC595驱动四位数码管,HC595的引脚和数码管管脚可以任意连接,让电路更简单,用软件确定四个公共端和小数点在内的八个段码的驱动,TM1650驱动公共端的四个管脚和驱动八个段码的管脚也是可以任意连接,只是驱动公共端和段码的管脚不能搞错,电路还是比两片HC595驱动四位数码管更简单。
3、占用单片机I/O口更少,楼主用两片HC595驱动四位数码管+三个按键,一共用了六个I/O口,用TM1650驱动四位数码管+多个按键,仅需两个I/O口,TM1650驱动四位数码管的同时还可以连接4×7=28个按键扫描。
4、占用单片机运行时间更少,TM1650IIC的速度没有HC595SPI快,但是,TM1650靠内部硬件扫描显示数码管,如果只在数字变动的时候发一次数据给TM1650,单片机的运行效率远远高于HC595。
5、TM1650用3.3V和5V驱动四位数码管,亮度几乎一致,并且有8极亮度可以通过软件设定。
对于用豆包生成的单片机代码有质疑,假若HC595的引脚和数码管的管脚任意连接,TM1650驱动公共端的四个管脚和驱动八个段码的管脚任意连接,豆包生成的单片机代码可以用吗?
回复

使用道具 举报

7#
ID:33548 发表于 2025-3-25 12:45 | 只看该作者
kmsj 发表于 2025-3-24 17:24
感谢楼主的无私奉献!但是,个人认为,驱动四位数码管的最佳方案是TM1650,对比两片HC595驱动四位数码管有 ...

现在论坛上有我贴上的TM1650驱动三位和四位LED的代码,都是调试成功的。
豆包生成的代码你只要说的详细,程序小时生成的代码基本没错,但大了就多少有问题,你可以修改,也可以让豆包改。
回复

使用道具 举报

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

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

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