可以单独现实的2x4数码管
#include "digital_display_tube.h"
//74hc595 先发高位再发低位,第一个字节是断码,第二个字节是位选
//sck上升沿移位data,sck低电平时准备data,8个data后rck输出
typedef struct
{
u8 num;
u8 point;
} digital_display_tube;
u8 code smgduan[18] = {0x3f, 0x06, 0x5b, 0x4f, 0x66, 0x6d, 0x7d, 0x07,
0x7f, 0x6f, 0x77, 0x7c, 0x39, 0x5e, 0x79, 0x71, 0x40}; // 0-f, 负号
u8 code wei[8]={127,191,223,239,247,251,253,254};
digital_display_tube digital_tube[8];
u8 display1_len = 0;
u8 display2_len = 0;
bit digital_tube_on = 0; // data管显示开关
bit display_mode = 0; // 显示模式:0单参数,1双参数
void digital_display_tube_init(void)
{
u8 i;
for (i = 0; i < 8; i++)
{
digital_tube[i].num = i;
digital_tube[i].point = 0; // 无小shu点
}
display1_len=8;
digital_display_on();
}
void digital_display_on(void)
{
digital_tube_on = 1;
}
void digital_display_off(void)
{
digital_tube_on = 0;
}
void hc595_send_char(u8 duan){
u8 i;
RCK=0;
for(i=0;i<8;i++)
{
SCK=0;
DAT= (duan&0x80 ) ?1:0 ;
//printf("num: d% send: %d dat: %d \r\n",(int)i,(int)duan,(int)DAT);
duan<<=1;
SCK=0;
SCK=1;
}
RCK=1;
RCK=0;
}
void digital_display_tube_refresh(){
u8 i,w;
if (digital_tube_on == 0)
return;
if (display_mode == 0) // 单参shu模式
{
for (i = 0; i < display1_len; i++)
{
w=smgduan[digital_tube[i].num] + (digital_tube[i].point ? 0x80 : 0x00);
hc595_send_char(w);
hc595_send_char(wei[7-i-display1_len]);
delay_ms(refresh_speed);
}
}
else // 双参数模式
{
//printf("双参数模式刷新 \n");
for (i = 0; i < display1_len; i++)
{
w=smgduan[digital_tube[7-i].num] + (digital_tube[7-i].point ? 0x80 : 0x00);
hc595_send_char(w);
hc595_send_char(wei[i]);
delay_ms(refresh_speed);
}
for (i = 0; i < display2_len; i++)
{
w=smgduan[digital_tube[3-i].num] + (digital_tube[3-i].point ? 0x80 : 0x00);
hc595_send_char(w);
hc595_send_char(wei[i+4]);
delay_ms(refresh_speed);
}
}
}
void digital_display_tube_display(u32 num1, u32 num2)
{
u8 str[8] = {0xff}, i;
if (num1 != 0)
{
display_mode = 0; // 单参数模式
sprintf(str, "%lu", num1);
display1_len = strlen(str);
if (display1_len > 8)
{
display1_len = 8; // 超过8位只显示前8位
}
for (i = 0; i < 8; i++)
{
str[i] = str[i] == ' ' ? 0xff : str[i] - '0'; // 将空格转换为0xff,数字字符转换为对应的数字
digital_tube[i].num = str[i] & 0x0f; // 取数字部分
}
display2_len = 0; // 单参数模式时,第二个数长度为0
}
if (num2 != 0)
{
display_mode = 1; // 双参数模式
sprintf(str, "%lu", num2);
display2_len = strlen(str);
if (display2_len > 4)
{
display2_len = 4; // 超过4位只显示前4位
}
for (i = 0; i < 4; i++)
{
str[i] = str[i] == ' ' ? 0xff : str[i] - '0'; // 将空格转换为0xff,数字字符转换为对应的数字
digital_tube[4 + i].num = str[i] & 0x0f; // 取数字部分
}
}
// for (i = 0; i < 8; i++)
// {
// printf("num1:%d ; num2:%d -- digital_tube[%d].num = %02x \n", (int)num1, (int)num2, (int)i, (int)digital_tube[i].num);
// }
}
// 显示时钟函数:hour 小时(0~23),min 分钟(0~59)
// 显示格式:8位数码管 → 时 时 . 分 分 (中间小数点作为冒号)
void show_time(u8 hour, u8 min)
{
u8 h1, h2; // 小时十位、个位
u8 m1, m2; // 分钟十位、个位
u8 i;
// 关闭显示,防止刷新冲突
digital_display_off();
// 拆分小时
h1 = hour / 10; // 小时十位
h2 = hour % 10; // 小时个位
// 拆分分钟
m1 = min / 10; // 分钟十位
m2 = min % 10; // 分钟个位
// 清空所有数码管
for(i=0; i<8; i++)
{
digital_tube[i].num = 0xff; // 不亮
digital_tube[i].point = 0;
}
// ====================== 8位数码管显示时钟 ======================
// 第0位:小时十位
digital_tube[0].num = h1;
digital_tube[0].point = 0;
// 第1位:小时个位
digital_tube[1].num = h2;
digital_tube[1].point = 1; // 打开小数点 → 模拟冒号:
// 第2位:分钟十位
digital_tube[2].num = m1;
digital_tube[2].point = 0;
// 第3位:分钟个位
digital_tube[3].num = m2;
digital_tube[3].point = 0;
// ==============================================================
// 设置显示长度(只显示前4位)
display1_len = 4;
display2_len = 0;
display_mode = 0; // 单参数模式
// 打开显示
digital_display_on();
}
#ifndef DIGITAL_DISPLAY_TUBE_H
#define DIGITAL_DISPLAY_TUBE_H
#include "config.h"
#define SCK P32
#define DAT P34
#define RCK P35
//#define digital_tube_segment_selection P0 // data线
//#define digital_tube_position_selection P2 // data管位选 (digital_tube_position_selection & 0xe3) | (i << 2);
#define refresh_speed 3 // 刷新速度
void digital_display_tube_init(void);
void digital_display_on(void);
void digital_display_off(void);
void show_time(u8 hour, u8 min);
void digital_display_tube_display(u32 num1, u32 num2);
void digital_display_tube_refresh(); // 刷新data管显示
#endif