基于6引脚8.8.8.数码管的99.9秒显示器
1.电路板电路原理“擎天柱Ai8051U转89C52-DIP40核心板”,用AI8051U-34k64单片机的timer0产生100us中断,作查理复用方式的LED的底层驱动,timer1中断产生1s计时,累加计时产生1s时间,制作0~99.9计时器,P33外接按键控制定时器启动、暂停、清零,单排6脚3位8.8.8.数码管显示。
2. 6引脚8.8.8.数码管的电路结构
3.源代码
//主程序文件 main.c
//AI8051U驱动三位8.8.8数码管显示的999s计时器下载成功 32bit模式
/**********************************************************
三位8.8.8数码管,共6个引脚,引脚组合
--- PIN1PIN2PIN3PIN4PIN5PIN6 列/阳极
PIN1 -- DP1 DP2 -- -- --
PIN2 -- -- F1 G1 C1 --
PIN3 -- A1 -- F2 G2 E2
PIN4 -- B1 D2 -- A2 D3
PIN5 G3 E1 B2 C2 -- F3
PIN6 A3 D1 B3 E3 C3 --
行/阴极
********************************************************/
#include "AI8051U.h" //调用头文件 手册 AI8051U.PDF
#include "stc32_stc8_usb.h" //调用头文件
#include "intrins.h" //调用头文件
#include "led.h" //调用led扫描头文件
#include "timer.h" //调用timer初始化头文件
#include "key.h" //调用按键扫描头文件
//#include "def.h" //调用定义数据类型头文件main.c里包含该头文件
#define MAIN_Fosc 24000000UL //时钟24MHZ
//全局变量声明
volatile u8 T1_1Sflag=0; //timer1溢出标志
volatile bit key_stime_ok; //10ms按键时间标志
volatile u8 T1_100ms,T1_1S = 0; //100ms,1s计时单元
volatile u8 buff; //显存
void main(void)
{
u16 T1_1S=0,T1_cnt=0; //T1秒计时,及10ms计时
u8 times = 0,Key_value = 0; //按键次数,键值
WTST = 0; //设置程序指令延时参数,赋值为0可将CPU执行指令的速度设置为最快
P_SW2 |= EAXFR;//扩展寄存器(XFR)访问使能
CKCON = 0; //提高访问XRAM速度
P1M1 = 0x00; P1M0 = 0x00; //设置为准双向口
P2M1 = 0x00; P2M0 = 0x00; //设置为准双向口
//P3M1 = 0x00; P3M0 = 0x00; //设置为准双向口
P4M1 = 0x00; P4M0 = 0x00; //设置为准双向口
P5M1 = 0x00; P5M0 = 0x00; //设置为准双向口
P6M1 = 0x00; P6M0 = 0x00; //设置为准双向口
P7M1 = 0x00; P7M0 = 0x00; //设置为准双向口
Timer0_init( ); //timer0初始化函数
Timer1_init( ); //timer1初始化函数
EA= 1; // 开总中断
ET0 = 1; // 定时/计数器0允许中断
ET1 = 1; // 定时/计数器1允许中断
while (1)
{
if(key_stime_ok) //10s按键扫描时间到
{
key_stime_ok = 0; //10ms按键时间标志清0
if(read_key()) //读取键值
{
times++; //按键次数加1
if(3 == times) //按键次数达3次
times = 0; //按键次数清0
switch (times) //根据按键次数执行不同的动作
{
case 1:
TR1 = 1; //T0开始运行
break;
case 2:
TR1 = 0; //T0暂停运行
break;
case 0:
TR1 = 0; //T0停止运行
T1_100ms = 0;//100ms计时单元清0
T1_1S = 0; //1s计时器清0
break;
}
}
}
if(1==T1_1Sflag) //如果timer1定时1s溢出标志为1
{
T1_1Sflag = 0; // 必须声明为volatile,防止编译器优化,后面可以省略延时
//DG_Display(buff,0,buff,0,buff); //显示xx.x
if(++T1_cnt == 100) //10ms*100=1s
{
T1_cnt = 0;
//P2^=0xff; //调试用
T1_1S++;
if(T1_1S > 99)
T1_1S = 0;
}
}
//DG_Display(buff,0,buff,1,buff); //显示xx.x 放此处无法显示100ms
buff = T1_1S / 10; buff = T1_1S % 10; buff = T1_100ms;
}
}
//========================================================================
// 函数: void timer0_int (void) interrupt TIMER0_VECTOR
// 描述:timer0中断函数.
// 参数: none.
// 返回: none.
// 版本: V1.0, 2015-1-12
//========================================================================
void timer0_int (void) interrupt 1 //100us中断一次
{
static u8 T0_cnt = 0;
Led_under_deal( ); //数码管灯阵扫描函数
if(++T0_cnt == 100) //满100us*100=10ms
{
T0_cnt = 0;
key_stime_ok = 1; //按键扫描标志置1
DG_Display(buff,0,buff,1,buff); //显示xx.x
}
}
//========================================================================
// 函数: void timer1_int (void) interrupt TIMER1_VECTOR
// 描述:timer1中断函数.
// 参数: none.
// 返回: none.
// 版本: V1.0, 2015-1-12
//========================================================================
void timer1_int (void) interrupt 3
{
static u8 T1_cnt = 0;
if(++T1_cnt == 50) //满2ms*50=100ms
{
T1_cnt = 0;
T1_100ms++; //T1定时100ms单元加1
if(10 == T1_100ms)
{
T1_100ms = 0;
T1_1Sflag = 1; //timer1定时1s溢出标志置1
}
}
}
//按键扫描C文件 key.c
#include "key.h" //调用按键扫描头文件
#include "AI8051U.h" //调用头文件 手册 AI8051U.PDF
//======基于状态机的按键处理程序=============================
sbit KWIN = P3^3; //单按键位置INT1
#define key_state_00 //状态0,初态,无按键按下
#define key_state_11 //状态1,按键确认态
#define key_state_22 //状态2,计时1
unsigned char read_key(void)
{
static unsigned char key_state = 0;
unsigned char key_press, key_return = 0;
P3M1 &= ~(1 << 3); P3M0 &= ~(1 << 3); //P33设置为准双向口
P3 |= 1 << 3; //P33写1
key_press = KWIN; // 读按键I/O电平
switch (key_state)
{
case key_state_0:// 按键初始态
if (!key_press) key_state = key_state_1;// 键被按下,状态转换到键确认态
break;
case key_state_1:// 按键确认态
if (!key_press)
{
key_return = 1;// 输出"1"
key_state = key_state_2;// 按键仍按下,状态转换到计时1
}
else
key_state = key_state_0;// 按键已抬起,转换到按键初始态
break;
case key_state_2:
if (key_press)
key_state = key_state_0;// 按键已释放,转换到按键初始态
break;
}
return key_return;
}
//LED驱动函数C文件 led.c
#include "led.h"
/**********************************************************
三位8.8.8数码管,共6个引脚,引脚组合
--- PIN1PIN2PIN3PIN4PIN5PIN6 列/阳极
PIN1 -- DP1 DP2 -- -- --
PIN2 -- -- F1 G1 C1 --
PIN3 -- A1 -- F2 G2 E2
PIN4 -- B1 D2 -- A2 D3
PIN5 G3 E1 B2 C2 -- F3
PIN6 A3 D1 B3 E3 C3 --
行/阴极
********************************************************/
ByteBit_Union DG1_Flag = {0}; //变量不可以放led.h文件里定义
ByteBit_Union DG2_Flag = {0}; //此处定义可以加初值
ByteBit_Union DG3_Flag = {0};
/*********************************************************
函数:Led_under_deal
描述: LED底层处理(正反扫)(100us 中断)
输入值: 无
输出值: 无
返回值: 无
**********************************************************/
void Led_under_deal(void)
{
static unsigned char led_disp_step = 0; //static
//全部端口为输入口
led_io_1_in;
led_io_2_in;
led_io_3_in;
led_io_4_in;
led_io_5_in;
led_io_6_in;
clr_led_io_1;//
clr_led_io_2;
clr_led_io_3;
clr_led_io_4;
clr_led_io_5;
clr_led_io_6;
//根据引脚组合按行扫描
if(led_disp_step==0) //第一行
{
if(DG1_DP)
{
led_io_2_out;
set_led_io_2;
}
if(DG2_DP)
{
led_io_3_out;
set_led_io_3;
}
led_io_1_out;
clr_led_io_1;
}
else if(led_disp_step==1)//第二行
{
if(DG1_F)
{
led_io_3_out;
set_led_io_3;
}
if(DG1_G)
{
led_io_4_out;
set_led_io_4;
}
if(DG1_C)
{
led_io_5_out;
set_led_io_5;
}
led_io_2_out;
clr_led_io_2;
}
else if(led_disp_step==2) //第三行
{
if(DG1_A)
{
led_io_2_out;
set_led_io_2;
}
if(DG2_F)
{
led_io_4_out;
set_led_io_4;
}
if(DG2_G)
{
led_io_5_out;
set_led_io_5;
}
if(DG2_E)
{
led_io_6_out;
set_led_io_6;
}
led_io_3_out;
clr_led_io_3;
}
else if(led_disp_step==3)//第四行
{
if(DG1_B)
{
led_io_2_out;
set_led_io_2;
}
if(DG2_D)
{
led_io_3_out;
set_led_io_3;
}
if(DG2_A)
{
led_io_5_out;
set_led_io_5;
}
if(DG3_D)
{
led_io_6_out;
set_led_io_6;
}
led_io_4_out;
clr_led_io_4;
}
else if(led_disp_step==4)//第5行
{
if(DG3_G)
{
led_io_1_out;
set_led_io_1;
}
if(DG1_E)
{
led_io_2_out;
set_led_io_2;
}
if(DG2_B)
{
led_io_3_out;
set_led_io_3;
}
if(DG2_C)
{
led_io_4_out;
set_led_io_4;
}
if(DG3_F)
{
led_io_6_out;
set_led_io_6;
}
led_io_5_out;
clr_led_io_5;
}
else if(led_disp_step==5)//第6行
{
if(DG3_A)
{
led_io_1_out;
set_led_io_1;
}
if(DG1_D)
{
led_io_2_out;
set_led_io_2;
}
if(DG3_B)
{
led_io_3_out;
set_led_io_3;
}
if(DG3_E)
{
led_io_4_out;
set_led_io_4;
}
if(DG3_C)
{
led_io_5_out;
set_led_io_5;
}
led_io_6_out;
clr_led_io_6;
}
led_disp_step++;
if(led_disp_step>=6)led_disp_step=0;
}
/*数码全显或全关*/
void DG_ALL(unsigned char EN_DIS)
{
if(EN_DIS) //全开
{
DG1_Flag.byte = 0xff;
DG2_Flag.byte = 0xff;
DG3_Flag.byte = 0xff;
}
else //全关
{
DG1_Flag.byte = 0;
DG2_Flag.byte = 0;
DG3_Flag.byte = 0;
}
}
//3位数码管,显示00.9,dp1为百位小数点,dp2为十位小数点
void DG_Display(u8 num1,u8 dp1,u8 num2,u8 dp2,u8 num3)
{
DG_ALL(0);//全写0,灭
if(1 == dp1) DG1_DP = 1; //显示第一位.
if(1 == dp2) DG2_DP = 1; //显示第二位.
switch(num1)
{
case 0: //A.B.C.D.E.F
//if(1 == dp1) DG1_DP = 1; //.
DG1_A = 1;DG1_B = 1;DG1_C = 1;
DG1_D = 1;DG1_E = 1;DG1_F = 1;
break;
case 1: //B.C
DG1_B = 1;DG1_C = 1;
break;
case 2: //A.B.D.E.G
DG1_A = 1;DG1_B = 1;DG1_D = 1;
DG1_E = 1;DG1_G = 1;
break;
case 3: //A.B.C.D.G
DG1_A = 1;DG1_B = 1;DG1_C = 1;
DG1_D = 1;DG1_G = 1;
break;
case 4: //B.C.F.G
DG1_B = 1;DG1_C = 1;DG1_F = 1;
DG1_G = 1;
break;
case 5: //A.C.D.F.G
DG1_A = 1;
DG1_C = 1;DG1_D = 1;
DG1_F = 1;DG1_G = 1;
break;
case 6: //A.C.D.E.F.G
DG1_A = 1;DG1_C = 1;DG1_D = 1;
DG1_E = 1;DG1_F = 1;DG1_G = 1;
break;
case 7: //A.B.C
DG1_A = 1;DG1_B = 1;DG1_C = 1;
break;
case 8: //A.B.C.D.E.F.G
DG1_A = 1;DG1_B = 1;DG1_C = 1;DG1_D = 1;
DG1_E = 1;DG1_F = 1;DG1_G = 1;
break;
case 9: //A.B.C.D.F.G
DG1_A = 1;DG1_B = 1;DG1_C = 1;
DG1_D = 1;DG1_F = 1;DG1_G = 1;
break;
default:break;
}
switch(num2)
{
case 0: //A.B.C.D.E.F
//if(1 == dp2) DG2_DP = 1; //.
DG2_A = 1;DG2_B = 1;DG2_C = 1;
DG2_D = 1;DG2_E = 1;DG2_F = 1;
break;
case 1: //B.C
DG2_B = 1;DG2_C = 1;
break;
case 2: //A.B.D.E.G
DG2_A = 1;DG2_B = 1;DG2_D = 1;
DG2_E = 1;DG2_G = 1;
break;
case 3: //A.B.C.D.G
DG2_A = 1;DG2_B = 1;DG2_C = 1;
DG2_D = 1;DG2_G = 1;
break;
case 4: //B.C.F.G
DG2_B = 1;DG2_C = 1;DG2_F = 1;DG2_G = 1;
break;
case 5: //A.C.D.F.G
DG2_A = 1;DG2_C = 1;DG2_D = 1;
DG2_F = 1;DG2_G = 1;
break;
case 6: //A.C.D.E.F.G
DG2_A = 1;DG2_C = 1;DG2_D = 1;
DG2_E = 1;DG2_F = 1;DG2_G = 1;
break;
case 7: //A.B.C
DG2_A = 1;DG2_B = 1;DG2_C = 1;
break;
case 8: //A.B.C.D.E.F.G
DG2_A = 1;DG2_B = 1;DG2_C = 1;DG2_D = 1;
DG2_E = 1;DG2_F = 1;DG2_G = 1;
break;
case 9: //A.B.C.D.F.G
DG2_A = 1;DG2_B = 1;DG2_C = 1;
DG2_D = 1;DG2_F = 1;DG2_G = 1;
break;
default:break;
}
switch(num3)
{
case 0: //A.B.C.D.E.F
DG3_A = 1;DG3_B = 1;DG3_C = 1;
DG3_D = 1;DG3_E = 1;DG3_F = 1;
break;
case 1: //B.C
DG3_B = 1;DG3_C = 1;
break;
case 2: //A.B.D.E.G
DG3_A = 1;DG3_B = 1;DG3_D = 1;
DG3_E = 1;DG3_G = 1;
break;
case 3: //A.B.C.D.G
DG3_A = 1;DG3_B = 1;DG3_C = 1;
DG3_D = 1;DG3_G = 1;
break;
case 4: //B.C.F.G
DG3_B = 1;DG3_C = 1;
DG3_F = 1;DG3_G = 1;
break;
case 5: //A.C.D.F.G
DG3_A = 1;DG3_C = 1;DG3_D = 1;
DG3_F = 1;DG3_G = 1;
break;
case 6: //A.C.D.E.F.G
DG3_A = 1;DG3_C = 1;DG3_D = 1;
DG3_E = 1;DG3_F = 1;DG3_G = 1;
break;
case 7: //A.B.C
DG3_A = 1;DG3_B = 1;DG3_C = 1;
break;
case 8: //A.B.C.D.E.F.G
DG3_A = 1;DG3_B = 1;DG3_C = 1;DG3_D = 1;
DG3_E = 1;DG3_F = 1;DG3_G = 1;
break;
case 9: //A.B.C.D.F.G
DG3_A = 1;DG3_B = 1;DG3_C = 1;
DG3_D = 1;DG3_F = 1;DG3_G = 1;
break;
default:break;
}
}//led扫描头文件led.h
#ifndef __LED_H__
#define __LED_H__
#include "AI8051U.h" //调用头文件 手册 AI8051U.PDF
#include "def.h" //调用定义数据类型头文件
//typedef unsigned char u8;
//typedef unsigned int u16;
//typedef unsigned long u32;
//#define u8unsigned char
//#define u16unsigned int
typedef union
{
unsigned char byte;
struct{
unsigned char bit0:1;
unsigned char bit1:1;
unsigned char bit2:1;
unsigned char bit3:1;
unsigned char bit4:1;
unsigned char bit5:1;
unsigned char bit6:1;
unsigned char bit7:1;
}Bits;
}ByteBit_Union;
//#defineled_io_6P05 //led io口
//#defineled_io_5P04 //led io口
//#defineled_io_4P03 //led io口
//#defineled_io_3P02 //led io口
//#defineled_io_2P01 //led io口
//#defineled_io_1P00 //led io口
//某位清0
//#defineclr_led_io_6 P0 &=~(1<<5) //led_io_6=0
#defineclr_led_io_6 P05 = 0
#defineclr_led_io_5 P04 = 0 //led io口清0
#defineclr_led_io_4 P03 = 0 //led io口清0
#defineclr_led_io_3 P02 = 0 //led io口清0
#defineclr_led_io_2 P01 = 0 //led io口清0
#defineclr_led_io_1 P00 = 0 //led io口清0
//某位置1
//#defineset_led_io_6 P0 |=(1<<5) //led io口写1
#defineset_led_io_6 P05 = 1
#defineset_led_io_5 P04 = 1 //led io口写1
#defineset_led_io_4 P03 = 1 //led io口写1
#defineset_led_io_3 P02 = 1 //led io口写1
#defineset_led_io_2 P01 = 1 //led io口写1
#defineset_led_io_1 P00 = 1 //led io口写1
#defineled_io_6_in{P0M1 |=1<<5;P0M0 &= ~(1<<5);} //io6置为高阻输入
#defineled_io_5_in{P0M1 |=1<<4;P0M0 &= ~(1<<4);} //io5置为输入
#defineled_io_4_in{P0M1 |=1<<3;P0M0 &= ~(1<<3);} //io4置为输入
#defineled_io_3_in{P0M1 |=1<<2;P0M0 &= ~(1<<2);} //io3置为输入
#defineled_io_2_in{P0M1 |=1<<1;P0M0 &= ~(1<<1);} //io2置为输入
#defineled_io_1_in{P0M1 |=1<<0;P0M0 &= ~(1<<0);} //io1置为输入
#defineled_io_6_out{P0M1 &= ~(1<<5);P0M0|=1<<5;}
#defineled_io_5_out{P0M1 &= ~(1<<4);P0M0|=1<<4;} //io5置为推挽输出
#defineled_io_4_out{P0M1 &= ~(1<<3);P0M0|=1<<3;} //io4置为输出
#defineled_io_3_out{P0M1 &= ~(1<<2);P0M0|=1<<2;} //io3置为输出
#defineled_io_2_out{P0M1 &= ~(1<<1);P0M0|=1<<1;} //io2置为输出
#defineled_io_1_out{P0M1 &= ~(1<<0);P0M0|=1<<0;} //io1置为输出
/*数码管段显*/
extern ByteBit_Union DG1_Flag;
#define DG1_A DG1_Flag.Bits.bit0
#define DG1_B DG1_Flag.Bits.bit1
#define DG1_C DG1_Flag.Bits.bit2
#define DG1_D DG1_Flag.Bits.bit3
#define DG1_E DG1_Flag.Bits.bit4
#define DG1_F DG1_Flag.Bits.bit5
#define DG1_G DG1_Flag.Bits.bit6
#define DG1_DP DG1_Flag.Bits.bit7
extern ByteBit_Union DG2_Flag;
#define DG2_A DG2_Flag.Bits.bit0
#define DG2_B DG2_Flag.Bits.bit1
#define DG2_C DG2_Flag.Bits.bit2
#define DG2_D DG2_Flag.Bits.bit3
#define DG2_E DG2_Flag.Bits.bit4
#define DG2_F DG2_Flag.Bits.bit5
#define DG2_G DG2_Flag.Bits.bit6
#define DG2_DP DG2_Flag.Bits.bit7
extern ByteBit_Union DG3_Flag;
#define DG3_A DG3_Flag.Bits.bit0
#define DG3_B DG3_Flag.Bits.bit1
#define DG3_C DG3_Flag.Bits.bit2
#define DG3_D DG3_Flag.Bits.bit3
#define DG3_E DG3_Flag.Bits.bit4
#define DG3_F DG3_Flag.Bits.bit5
#define DG3_G DG3_Flag.Bits.bit6
//#define DG3_DP DG3_Flag.Bits.bit7
void Led_under_deal(void); //数码管灯阵扫描函数,100us调用一次
void DG_ALL(unsigned char EN_DIS); //数码全显或全关
//3位数码管,显示00.9,dp1为百位小数点,dp2为十位小数点
void DG_Display(u8 num1,u8 dp1,u8 num2,u8 dp2,u8 num3);
//extern ByteBit_Union DG1_Flag; //变量放led.h文件里声明需加extern修饰
//extern ByteBit_Union DG2_Flag; //但不可定义,加上初值
//extern ByteBit_Union DG3_Flag;
#endif
//timer初始化C文件
#include "timer.h" //调用timer初始化头文件
#include "AI8051U.h" //调用头文件 手册 AI8051U.PDF
#define MAIN_Fosc 24000000UL //时钟24MHZ
//24MHZ,1T,一条指令耗时1/24us,定时100us,初值2400
//Timer 0 中断频率, 10000次/秒,定时100us,1/100us=10000HZ
#define Timer0_Reload (MAIN_Fosc / 10000) //定时100us
#define Timer1_Reload (MAIN_Fosc / 48000) //定时2ms
//官方文件
void Timer0_init(void)
{
TR0 = 0; //停止计数
#if (Timer0_Reload < 64) // 如果用户设置值不合适, 则不启动定时器
#error "Timer0设置的中断过快!"
#elif ((Timer0_Reload/12) < 65536UL) // 如果用户设置值不合适, 则不启动定时器
ET0 = 1; //允许中断
//PT0 = 1; //高优先级中断
TMOD &= ~0x03;
TMOD |= 0;//工作模式, 0: 16位自动重装, 1: 16位定时/计数, 2: 8位自动重装, 3: 16位自动重装, 不可屏蔽中断
//T0_CT = 1;//计数
T0_CT = 0;//定时
//T0CLKO = 1; //输出时钟
T0CLKO = 0; //不输出时钟
#if (Timer0_Reload < 65536UL)
T0x12 = 1;//1T mode
TH0 = (u8)((65536UL - Timer0_Reload) / 256);
TL0 = (u8)((65536UL - Timer0_Reload) % 256);
#else
T0x12 = 0;//12T mode
TH0 = (u8)((65536UL - Timer0_Reload/12) / 256);
TL0 = (u8)((65536UL - Timer0_Reload/12) % 256);
#endif
TR0 = 1; //开始运行
#else
#error "Timer0设置的中断过慢!"
#endif
}
//========================================================================
// 函数: void Timer1_init(void)
// 描述: timer1初始化函数.
// 参数: none.
// 返回: none.
// 版本: V1.0, 2015-1-12
//========================================================================
void Timer1_init(void)
{
TR1 = 0; //停止计数
#if (Timer1_Reload < 64) // 如果用户设置值不合适, 则不启动定时器
#error "Timer1设置的中断过快!"
#elif ((Timer1_Reload/12) < 65536UL) // 如果用户设置值不合适, 则不启动定时器
ET1 = 1; //允许中断
//PT1 = 1; //高优先级中断
TMOD &= ~0x30;
TMOD |= (0 << 4); //工作模式, 0: 16位自动重装, 1: 16位定时/计数, 2: 8位自动重装
//T1_CT = 1;//计数
T1_CT = 0;//定时
//T1CLKO = 1; //输出时钟
T1CLKO = 0; //不输出时钟
#if (Timer1_Reload < 65536UL)
T1x12 = 1;//1T mode
TH1 = (u8)((65536UL - Timer1_Reload) / 256);
TL1 = (u8)((65536UL - Timer1_Reload) % 256);
#else
T1x12 = 0;//12T mode
TH1 = (u8)((65536UL - Timer1_Reload/12) / 256);
TL1 = (u8)((65536UL - Timer1_Reload/12) % 256);
#endif
//TR1 = 1; //开始运行
#else
#error "Timer1设置的中断过慢!"
#endif
}
//timer.h4.视频效果
这种方式用少量io引脚
而io需支持高阻
显示驱动部分要是有详细注释就更好了{:qiang:} 经典的89系列没有高阻模式 1. LED底层处理(正反扫)(100us 中断)
void Led_under_deal(void)
要结合表格三位8.8.8数码管,共6个引脚,引脚组合
--- PIN1PIN2PIN3PIN4PIN5PIN6 列/阳极
PIN1 -- DP1 DP2 -- -- -- 第一行
PIN2 -- -- F1 G1 C1 -- 第2行
PIN3 -- A1 -- F2 G2 E2
PIN4 -- B1 D2 -- A2 D3
PIN5 G3 E1 B2 C2 -- F3
PIN6 A3 D1 B3 E3 C3 --
行/阴极
例如 if(led_disp_step==0) //第一行
45. {
46. if(DG1_DP) //点亮DG1_DP
47. {
48. led_io_2_out; //正极输出口
49. set_led_io_2; //正极输出1
50. }
51. if(DG2_DP) //点亮DG2_DP
52. {
53. led_io_3_out; //正极输出口
54. set_led_io_3; //输出1
55. }
56. led_io_1_out; //负极输出口
57. clr_led_io_1; //负极输出0
58. }
为了可以使用每一段,定义了联合位域结构体。
2. //3位数码管,显示00.9,dp1为百位小数点,dp2为十位小数点
void DG_Display(u8 num1,u8 dp1,u8 num2,u8 dp2,u8 num3)
{
case 0: //A.B.C.D.E.F这里实际采用了共阴数码管的字段码,显示0,码是0x3f,其他类似
为了限流,每一个LED引脚串联了47欧+47欧电阻 yyq_007 发表于 2026-6-29 17:21
为了限流,每一个LED引脚串联了47欧+47欧电阻
https://www.stcaimcu.com/forum.php?mod=redirect&goto=findpost&ptid=24176&pid=219748
楼主程序整得比较复杂,其实这种数码管有规律的,按照其规律驱动,程序会比较简单。
这种数码管常见于移动电源(充电宝)、无线话筒、小家电上。
大量使用的充电宝的驱动方式,N个IO最多可以驱动N(N-1)个LED,称之为“查理复用”,驱动原则是:
分N个时隙驱动,每次驱动时一个IO做COM驱动,另外(N-1)个IO做SEG驱动。
先把所有IO设置为高阻。
对于共阴,不显示的SEG为高阻,显示的SEG推挽输出1, COM推挽输出0。
对于共阳,不显示的SEG为高阻,显示的SEG推挽输出0, COM推挽输出1。
梁工 发表于 2026-6-30 10:59
楼主程序整得比较复杂,其实这种数码管有规律的,按照其规律驱动,程序会比较简单。
这种数码管常见于移动 ...
学习初期自个思考的常见写法
后期可尝试整理使用循环和数组
逻辑整合简化可能程序到百行左右 yyq_007 发表于 2026-6-29 17:21
为了限流,每一个LED引脚串联了47欧+47欧电阻
从我的实践经验来看,相比高阻模式+推挽模式+外部限流电阻的组合,使用开漏模式+内部上拉实现的效果更好一些,而且更省物料
查理复用结构的数码管每个IO都串限流电阻的话,容易出现部分笔划亮度不均匀的情况
页:
[1]
2