第九集 数码管 数码管外形

数码管类型

实验箱上的8位数码管是用三根数据线通过两个74HC595移位寄存器芯片控制8位LED数码管的

移位寄存器传输数据原理


添加74HC595传输数据语句,同时修改周期任务调度语句,将其它LED灯控制语句注释掉

数码管动态显示的原理的要求

将程序集中在main.c中
//运行频率24Mhz,使用ai8051u实验箱,通过两个74hc595向8位数码管显示简易时钟
#include "AI8051U.h"
#include "usb.h" //USB调试及复位所需头文件
#include "intrins.h"
#define MAIN_Fosc 24000000L //定义主时钟
#define u8 unsigned char //8位无符号数
#define u16 unsigned int //16位无符号整数
#define Dat P34 //向595传输数据的引脚编号
#define RCK P35 //595锁存数据引脚编号
#define SCK P32 //向595数据移位时钟信号引脚编号
//USB调试及复位所需定义
char *USER_DEVICEDESC = NULL;
char *USER_PRODUCTDESC = NULL;
char *USER_STCISPCMD = "@STCISP#"; //设置自动复位到ISP区的用户接口命令
bit state0,state1,state2,state3; //状态0~3
u8 Second,Minute,Hour,Bit_Count=0; //秒,分,时,数码管位码控制
u8 Seg_Table[]= //数码管段码表
{
0x3F, /*'0', 0*/
0x06, /*'1', 1*/
0x5B, /*'2', 2*/
0x4F, /*'3', 3*/
0x66, /*'4', 4*/
0x6D, /*'5', 5*/
0x7D, /*'6', 6*/
0x07, /*'7', 7*/
0x7F, /*'8', 8*/
0x6F, /*'9', 9*/
0x77, /*'A', 10*/
0x7C, /*'B', 11*/
0x39, /*'C', 12*/
0x5E, /*'D', 13*/
0x79, /*'E', 14*/
0x71, /*'F', 15*/
0x40, /*'-', 16*/
0x00, /*' ', 17*/
0x80, /*'.', 18*/
};
u8 Bit_Table[]= //数码管位码表(需取反)
{
0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80
};
//-----------数码管显示程序--------------------
void Init_595(void) //595初始化,引脚全0
{
Dat=0;SCK=0;RCK=0;
}
void SendByte(u8 Date) //发送1字节数据到595并移位
{
u8 i;
for(i=0;i<8;i++)
{
Date<<=1; //数值左移1位
Dat=CY; //将左移1位的数据(在CY中)放入595数据引脚
SCK=1; //移位时钟线拉高
SCK=0;
}
}
void Seg(u8 Segmented,u8 Bit_Code)
{
SendByte(Segmented); //发送段码数据
SendByte(Bit_Code); //发送位码数据
RCK=1; //锁存器锁存
RCK=0;
}
void Dis_Seg(void)
{
switch(Bit_Count)
{
case 0:
Seg(Seg_Table[Hour/10],~Bit_Table[0]);break; //输出0位数码管数字
case 1:
Seg(Seg_Table[Hour%10],~Bit_Table[1]);break; //输出1位数码管数字
case 2:
Seg(Seg_Table[16],~Bit_Table[2]);break;
case 3:
Seg(Seg_Table[Minute/10],~Bit_Table[3]);break;
case 4:
Seg(Seg_Table[Minute%10],~Bit_Table[4]);break;
case 5:
Seg(Seg_Table[16],~Bit_Table[5]);break;
case 6:
Seg(Seg_Table[Second/10],~Bit_Table[6]);break;
case 7:
Seg(Seg_Table[Second%10],~Bit_Table[7]);break;
}
Bit_Count++;Bit_Count%=8; //位码自加1,且小于8
}
//---------各个定时执行程序--------------------
void Led0(void) //4个led闪烁控制
{
state0=!state0;
P00=state0;
}
void Led1(void)
{
state1=!state1;
P01=state1;
}
void Led2(void)
{
state2=!state2;
P02=state2;
}
void Led3(void)
{
state3=!state3;
P03=state3;
}
void Time(void) //计时程序
{
Second++; //秒
if(Second>59)
{
Second=0;Minute++;
}
if(Minute>59) //分
{
Minute=0;Hour++;
}
if(Hour>23) //时
{
Hour=0;
}
}
//-----------------------周期任务调度-------------------------------
typedef struct //定义周期任务控制结构体
{
u8 Run; //运行程序标志
u16 Count; //计数值
u16 Reload; //重载计数值
void(*Task_Fuction)(void); //需要运行的程序
}Task_Control;
Task_Control Task_Com[]= //周期任务结构体实例化
{ //运行标志/计数值/重载值/运行程序名
{0, 1000, 1000,Led0}, //4个Led定时亮灭
{0, 2000, 2000,Led1},
{0, 4000, 4000,Led2},
{0, 8000, 8000,Led3},
{0, 10000,10000,Time}, //时钟计时
{0, 10, 10,Dis_Seg}, //数码管显示
};
u8 Task_Num=sizeof(Task_Com)/sizeof(Task_Com[0]); //计算要循环几次任务
void Task_Mark_Handler_Callback(void) //任务标记处理回调函数(在中断中)
{
u8 i;
for(i=0;i<Task_Num;i++) //循环各个实例任务
{
if(Task_Com[i].Count) //如计数值非0
{
Task_Com[i].Count--; //计数值自减1
if(Task_Com[i].Count==0) //如计数值为0
{
Task_Com[i].Count=Task_Com[i].Reload; //将重载值赋值给计数值
Task_Com[i].Run=1; //运行程序标志置1
}
}
}
}
void Task_Pro_Handler_Callback(void) //任务处理回调函数
{
u8 i;
for(i=0;i<Task_Num;i++) //逐个循环结构体内各个任务
{
if(Task_Com[i].Run) //如果运行标志为1
{
Task_Com[i].Run=0; //运行标志置0
Task_Com[i].Task_Fuction(); //运行相应位置的程序
}
}
}
//--------------------定时器--------------------------------------
void Timer0_Isr(void) interrupt 1 //定时器0中断
{
Task_Mark_Handler_Callback(); //中断计数标记要执行的结构体程序
}
void Timer0_Init(void) //100微秒@24.000MHz
{
AUXR |= 0x80; //定时器时钟1T模式
TMOD &= 0xF0; //设置定时器模式
TL0 = 0xA0; //设置定时初始值
TH0 = 0xF6; //设置定时初始值
TF0 = 0; //清除TF0标志
TR0 = 1; //定时器0开始计时
ET0 = 1; //使能定时器0中断
}
/******************** 主函数 **************************/
void main(void)
{
WTST = 0; //设置程序指令延时参数,赋值为0可将CPU执行指令的速度设置为最快
EAXFR = 1; //扩展寄存器(XFR)访问使能
CKCON = 0; //提高访问XRAM速度
RSTFLAG |= 0x04; //软复位标志写1清零,设置硬件复位后需要检测P3.2的状态选择运行区域,硬件复位后进入系统ISP检测到P3.2为低电平,才会进入USB下载模式
P0M1 = 0x00; P0M0 = 0xff; //设置为推挽输出
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; //设置为准双向口
usb_init(); //usb初始化
EUSB = 1; //IE2相关的中断位操作使能后,需要重新设置EUSB
Timer0_Init(); //定时器0初始化
Init_595(); //74HC595初始化
EA = 1; //总中断开关打开
P40 = 0; //P0 LED Power On
while(1)
{
Task_Pro_Handler_Callback(); //当有标识时运行相应的程序
}
}
程序运行效果