一、 概述
二、 51单片机 ,TM1638芯片+DS1302驱动共阴数码管时钟,最后包括
按键检测程序(是分开的。)
TM1638是带键盘扫描接口的LED(发光二极管显示器)驱动控制专用电路,内部集 成有MCU 数字接口、数据锁存器、LED 高压驱动、键盘扫描等电路。主要应用于冰箱、
空调 、家庭影院等产品的高段位显示屏驱动。
二、 特性说明
• 采用功率CMOS 工艺 • 显示模式 10 段×8 位 • 键扫描(8×3bit)
• 辉度调节电路(占空比8 级可调) • 串行接口(CLK,STB,DIO)
• 振荡方式:RC 振荡(450KHz+5%) • 内置上电复位电路 • 采用SOP28封装
三、、 管脚定
义:
电路图数码管:
程序代码:
/*************** TM1638.H头文件 *******************/ #ifndef _TM1638_H #define _TM1638_H
//引脚定义
sbit DIO=P1^0; sbit CLK=P1^1; sbit STB=P1^2;
//写一个8Bit数据
void TM1638_Write(unsigned char DATA) //写数据函数 { unsigned char i; for(i=0;i<8;i++) { CLK=0; if(DATA&0X01) DIO=1; else DIO=0; DATA>>=1; CLK=1; } }
/*unsigned char TM1638_Read(void) //读数据函数 { unsigned char i; unsigned char temp=0; DIO=1; //设置为输入 for(i=0;i<8;i++) { temp>>=1; CLK=0; if(DIO) temp|=0x80; CLK=1; } return temp; } */
void Write_COM(unsigned char cmd) //发送命令字 { STB=0;
TM1638_Write(cmd); //写命令 STB=1; }
void Write_DATA(unsigned char add,unsigned char DATA) //指定地址写入数据 { Write_COM(0x44); STB=0; TM1638_Write(0xc0|add); //地址高位为1:11** ****,写地址 TM1638_Write(DATA); STB=1; }
void init_TM1638(void) { unsigned char i; Write_COM(0x8a);//亮度 Write_COM(0x40); //写 数据命令,写数据到显示寄存器 STB=0; TM1638_Write(0xc0); //写地址命令 for(i=0;i<16;i++) TM1638_Write(0x00); STB=1; }
#endif
/***************************DS1302.H头文件***************************/
#ifndef DS1302_H #define DS1302_H
#define uchar unsigned char #define uint unsigned int #include\"DELAY.h\"
sbit acc0=ACC^0; //移位时的第0位 sbit acc7=ACC^7; //移位时用的第7位
uchar second,minute,hour,day,month,year,week,count=0; uchar ReadValue,num,time; sbit SCLK=P2^0; sbit DATA=P2^1; sbit RST=P2^2;
void Write1302(uchar dat)
{
uchar i;
SCLK=0; //拉低SCLK,为脉冲上升沿写入数据做好准备 delay1(2); //稍微等待,使硬件做好准备 for(i=0;i<8;i++) //连续写8个二进制位数据 {
DATA=dat&0x01; //取出dat的第0位数据写入1302 delay(2); //稍微等待,使硬件做好准备 SCLK=1; //上升沿写入数据
delay1(2); //稍微等待,使硬件做好准备
SCLK=0; //重新拉低SCLK,形成脉冲
dat>>=1; //将dat的各数据位右移1位,准备写入下一个数据位 } }
void WriteSet1302(uchar Cmd,uchar dat) {
RST=0; //禁止数据传递
SCLK=0; //确保写数居前SCLK被拉低 RST=1; //启动数据传输
delay1(2); //稍微等待,使硬件做好准备 Write1302(Cmd); //写入命令字 Write1302(dat); //写数据
SCLK=1; //将时钟电平置于已知状态 RST=0; //禁止数据传递 }
uchar Read1302(void) {
uchar i,dat;
delay(2); //稍微等待,使硬件做好准备 for(i=0;i<8;i++) //连续读8个二进制位数据 {
dat>>=1; //将dat的各数据位右移1位,因为先读出的是字节的最低位 if(DATA==1) //如果读出的数据是1
dat|=0x80; //将1取出,写在dat的最高位
SCLK=1; //将SCLK置于高电平,为下降沿读出 delay1(2); //稍微等待
SCLK=0; //拉低SCLK,形成脉冲下降沿 delay1(2); //稍微等待 }
return dat; //将读出的数据返回 }
uchar ReadSet1302(uchar Cmd) {
uchar dat;
RST=0; //拉低RST
SCLK=0; //确保写数居前SCLK被拉低 RST=1; //启动数据传输 Write1302(Cmd); //写入命令字 dat=Read1302(); //读出数据
SCLK=1; //将时钟电平置于已知状态 RST=0; //禁止数据传递 return dat; //将读出的数据返回 }
void Init_DS1302(void) {
WriteSet1302(0x8E,0x00); //根据写状态寄存器命令字,写入不保护指令
WriteSet1302(0x80,((0/10)<<4|(0%10))); //根据写秒寄存器命令字,写入秒的初始值 WriteSet1302(0x82,((41/10)<<4|(41%10))); //根据写分寄存器命令字,写入分的初始值 WriteSet1302(0x84,((15/10)<<4|(15%10))); //根据写小时寄存器命令字,写入小时的初始值 WriteSet1302(0x86,((29/10)<<4|(24%10))); //根据写日寄存器命令字,写入日的初始值 WriteSet1302(0x88,((2/10)<<4|(2%10))); //根据写月寄存器命令字,写入月的初始值 WriteSet1302(0x8c,((10/10)<<4|(11%10))); //nian WriteSet1302(0x8a,((0/10)<<4|(0%10)));
WriteSet1302(0x8E,0x80); //根据写状态寄存器命令字,写入保护指令 }
#endif
/***************显示头文件*******************************/ #include\"TM1638.h\"
uchar data DisBuffer[8]={0,0,0,0,0,0,0,0}; /*显示缓存区*/ //各个数码管显示的值 uchar code tab[]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F,0x77,0x7C,0x39,0x5E,0x79,0x71,0x40,0xef};
void display1638(uchar hour,uchar minute,uchar second) { uchar i; DisBuffer[0]=hour/10; DisBuffer[1]=hour%10; DisBuffer[3]=minute/10; DisBuffer[4]=minute%10; DisBuffer[6]=second/10; DisBuffer[7]=second%10;
DisBuffer[2]=16; DisBuffer[5]=16; for(i=0;i<8;i++) { Write_DATA(i*2,tab[DisBuffer[i]]); } }
void DisplayHour(newval) { DisBuffer[0]=newval/10; DisBuffer[1]=newval%10; for(i=0;i<2;i++) { Write_DATA(i*2,tab[DisBuffer[i]]); } }
#endif
/**********************************************************/ //下面是处理程序头文件,调试功能的实现,但是本人接调时的来源是
//是鼠标芯片,所以这里都写上,各位可以根据自己是按键还是其他的,做修改 /***********************************************/ #ifndef CHULI_H #define CHULI_H
#define uchar unsigned char #define uint unsigned int #include\"DISPLAY.h\" #include\"DS1302.h\"
void read_date(void) {
ReadValue = ReadSet1302(0x81);
second=((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F); ReadValue = ReadSet1302(0x83);
minute=((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F); ReadValue = ReadSet1302(0x85);
hour=((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F); ReadValue = ReadSet1302(0x87);
day=((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F); ReadValue = ReadSet1302(0x89);
month=((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F); ReadValue = ReadSet1302(0x8d);
year=((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F);
ReadValue=ReadSet1302(0x8b); //读星期 week=ReadValue&0x07; display1638(hour,minute,second) ; }
void turn_val(char newval,uchar flag,uchar newaddr,uchar s1num) {
newval=ReadSet1302(newaddr); //读取当前时间
newval=((newval&0x70)>>4)*10+(newval&0x0f); 十进制
if(flag) //判断是加一还是减一 { newval++; switch(s1num)
{ case 1: if(newval>99) newval=0; DisplayYear(newval); break; case 2: if(newval>12) newval=1; DisplayMonth(newval); break; case 3: if(newval>31) newval=1; DisplayDay(newval); break; case 4: if(newval>6) newval=0; DisplayWeek(newval); break;
case 5: if(newval>23) newval=0; DisplayHour(newval); break;
case 6: if(newval>59) newval=0; DisplayMinute(newval); break;
case 7: if(newval>59) newval=0; DisplaySecond(newval); break; default:break; } } else { newval--; switch(s1num)
{ case 1: if(newval==0) newval=99;
//将bcd码转换成
DisplayYear(newval); break; case 2: if(newval==0) newval=12; DisplayMonth(newval); break; case 3: if(newval==0) newval=31; DisplayDay(newval); break; case 4: if(newval<0) newval=6; DisplayWeek(newval); break;
case 5: if(newval<0) newval=23; DisplayHour(newval); break;
case 6: if(newval<0) newval=59; DisplayMinute(newval); break;
case 7: if(newval<0) newval=59; DisplaySecond(newval); break; default:break; } }
WriteSet1302((newaddr-1),((newval/10)<<4)|(newval%10)); 入寄存器 }
void write_flsh(uchar com,uchar dat) { Write_DATA(com,tab[16]); delay(100); Write_DATA(com,tab[dat]); }
void sp2_mouse(void) { uchar miao,z,flag=0; rd=0; miao=ReadSet1302(0x81); second=miao; WriteSet1302(0x80,miao|0x80); while(1) { led=0; /////////////////////////////////////// /* if((move_x<4)&&(flag==0))
//将新数据写
{ write_flash(0x02,1) ; if((mouse_data[0]&0x01)&&(flag==1)) { while(mouse_data[0]&0x01); while(1) { write_flash(0x02,1) ; z=move_x; if(move_x>z) { delayms(10); turn_val(year,1,0x8d,1); } if(z>move_x) {delayms(10); turn_val(year,0,0x8d,1); } if(mouse_data[0]&0x01) { while(mouse_data[0]&0x01); flag=1; move_x=3; z=move_x; break; } } } }
/////////////////////////////////////////////////////// if((move_x>=4)&&(move_x<6)&&(flag==0)) { write_com(0x87); if(mouse_data[0]&0x01) { while(mouse_data[0]&0x01); while(1) { z=move_x; write_com(0x87); if(move_x>z) { delayms(10); turn_val(month,1,0x89,2); } if(z>move_x) {delayms(10); turn_val(month,0,0x89,2);
} if(mouse_data[0]&0x01) { while(mouse_data[0]&0x01); flag=1; move_x=5; z=move_x; break; } } } }
///////////////////////////////////////////////////////// if((move_x>=6)&&(move_x<8)&&(flag==0)) { write_com(0x8a); if(mouse_data[0]&0x01) { while(mouse_data[0]&0x01); while(1) { z=move_x; write_com(0x8a); if(move_x>z) { delayms(10); turn_val(day,1,0x87,3); } if(z>move_x) { delayms(10); turn_val(day,0,0x87,3); } if(mouse_data[0]&0x01) { while(mouse_data[0]&0x01); flag=1; move_x=7; z=move_x; break; } } } } /////////////////////////////////////////////////////////// if((move_x>=8)&&(move_x<10)&&(flag==0))
{ write_com(0x8e); if(mouse_data[0]&0x01) { while(mouse_data[0]&0x01); while(1) { z=move_x; write_com(0x8e); if(move_x>z) { delayms(10); turn_val(week,1,0x8b,4); } if(z>move_x) {delayms(10); turn_val(week,0,0x8b,4); } if(mouse_data[0]&0x01) { while(mouse_data[0]&0x01); flag=1; move_x=9; z=move_x; break; } } } } */ //////////////////////////////////////////////////////////// if((move_x>=10)&&(move_x<12)&&(flag==0)) { write_flash(0x02,1) ; if(mouse_data[0]&0x01) { while(mouse_data[0]&0x01); while(1) { z=move_x; write_flash(0x02,1) ; if(move_x>z) { delayms(10); turn_val(hour,1,0x85,5); } if(z>move_x)
{ delayms(10); turn_val(hour,0,0x85,5); } if(mouse_data[0]&0x01) { while(mouse_data[0]&0x01); flag=1; move_x=11; z=move_x; break; } } } }
////////////////////////////////////////////////////////////// if((move_x>=12)&&(move_x<14)&&(flag==0)) { write_com(0xc4) ; if(mouse_data[0]&0x01) { while(mouse_data[0]&0x01); while(1) { z=move_x; write_com(0xc4) ; if(move_x>z) { delayms(10); turn_val(minute,1,0x83,6); } if(z>move_x) {delayms(10); turn_val(minute,0,0x83,6); } if(mouse_data[0]&0x01) { while(mouse_data[0]&0x01); flag=1; move_x=13; z=move_x; break; } } } }
//写入分寄存器//写入分寄存器
//////////////////////////////////////////////////////////////// if((move_x>=14)&&(flag==0)) { write_com(0xc7); if(mouse_data[0]&0x01) { while(mouse_data[0]&0x01); while(1) { z=move_x; write_com(0xc7); if(move_x>z) { delayms(10); turn_val(second,1,0x81,7); } if(z>move_x) {delayms(10); turn_val(second,0,0x81,7); } if(mouse_data[0]&0x01) { while(mouse_data[0]&0x01); flag=1; move_x=15; z=move_x; break; } } } }
/////////////////////////////////////////////////////////////// if((mouse_data[0]&0x01)&&(z!=move_x)) {flag=0; while(mouse_data[0]&0x01); }
////////////////////////////////////////////////////////////// if((mouse_data[0]&0x01)&&(flag==1)&&(z==move_x)) {flag=0; delayms(300); miao=ReadSet1302(0x81); second=miao; WriteSet1302(0x80,second&0x7f); write_com(0x0c) ;
WriteSet1302(0x8E,0x80); //根据写状态寄存器命令字,写入不保护指令 break; } } } #endif
/*********鼠标芯片*****/ #ifndef PS2_H #define PS2_H
#include\"DELAY.h\"
sbit mouse_SDA=P3^4;//数据线P3_5 计数器0输入端口 sbit mouse_CLK=P3^3;//时钟线P3_3 外部中断1输入端口 sbit led=P3^6; bit pp=0; bit ACK=0;
uchar bdata mouse_byte; //接收字节 bdata-->可寻址的片内RAM sbit mouse_byte_bit0=mouse_byte^0;//mouse_byte第0位 sbit mouse_byte_bit1=mouse_byte^1;//mouse_byte第1位 sbit mouse_byte_bit2=mouse_byte^2;//mouse_byte第2位 sbit mouse_byte_bit3=mouse_byte^3;//mouse_byte第3位 sbit mouse_byte_bit4=mouse_byte^4;//mouse_byte第4位 sbit mouse_byte_bit5=mouse_byte^5;//mouse_byte第5位 sbit mouse_byte_bit6=mouse_byte^6;//mouse_byte第6位 sbit mouse_byte_bit7=mouse_byte^7;//mouse_byte第7位
uchar mouse_buffer[11];//接收位数据缓冲区
uchar mouse_buffer_bit=0;//mouse_buffer[mouse_buffer_bit]
uchar mouse_data[4];//接收鼠标数据缓冲区,分别存放:功能信息字节,x位移量,y位移量 uchar mouse_data_bit=0;//mouse_data[mouse_data_bit]
uchar move_x;//存放横坐标 uint move_y;//存放纵坐标 uchar move_z;
extern uchar move_x;
/*********************************************************************** 发送数据
************************************************************************/ void Init_ter(void) {
EA=1; //开放中断 EX1=1;//允许外部中断1
PX1=1;//设置中断优先级 设外部中断1为最高优先级别 }
void host_to_mouse(uchar cmd) {
uchar i; EX1=0;
mouse_CLK=0; delay100; delay100; ACC=cmd;
pp=~P; //获得奇偶校验位 mouse_SDA=0; mouse_CLK=1; for(i=0;i<8;i++) {
while(mouse_CLK==1); mouse_SDA=cmd&0x01; cmd>>=1;
while(mouse_CLK==0); }
while(mouse_CLK==1);
mouse_SDA=pp; //发送奇偶校验位 while(mouse_CLK==0); while(mouse_CLK==1); mouse_SDA=1;
while(mouse_CLK==0); while(mouse_CLK==1);
ACK=mouse_SDA; //接收应答位 while(mouse_CLK==0); EX1=1; }
void Init_mouse(void) {
host_to_mouse(0xf4); delayms(50); Init_ter(); delayms(50);
host_to_mouse(0xf3); delayms(50);
host_to_mouse(0xc8); delayms(50);
host_to_mouse(0xf3);
delayms(50);
host_to_mouse(0x64); delayms(50);
host_to_mouse(0xf3); delayms(50);
host_to_mouse(0x50); delayms(50);
host_to_mouse(0xf2); delayms(200); mouse_data[0]=0; mouse_data[1]=0; mouse_data[2]=0; mouse_data[3]=0; move_x=10; move_y=0; move_z=0; }
/********************************************* 奇校检
**********************************************/ uchar Checkout(void) { ACC=mouse_byte; if(~P==mouse_buffer[9]) return 1; else return 0; }
/********************************************************* 数据分析及处理
**********************************************************/ void data_analyse(void) { //将收到的11位信号中截取8位数据放进mouse_byte mouse_byte_bit0=mouse_buffer[1]; mouse_byte_bit1=mouse_buffer[2]; mouse_byte_bit2=mouse_buffer[3]; mouse_byte_bit3=mouse_buffer[4]; mouse_byte_bit4=mouse_buffer[5];
mouse_byte_bit5=mouse_buffer[6]; mouse_byte_bit6=mouse_buffer[7]; mouse_byte_bit7=mouse_buffer[8]; if(Checkout())//如果校验正确 { if(mouse_data_bit<4) mouse_data[mouse_data_bit++]=mouse_byte; if(mouse_data_bit==4) { mouse_data_bit=0; if(mouse_data[0]&0x10)//如果\"X sign bit\"为1,表示鼠标向右左移 { move_x-=(256-mouse_data[1]);//x坐标减 if(move_x<=1)move_x=17; } else { move_x+=mouse_data[1];//x坐标加 if(move_x>=17)move_x=2; } if(mouse_data[0]&0x20) { move_y-=(256-mouse_data[2]);//y坐标减 } else { move_y+=mouse_data[2];//y坐标加 } if(mouse_data[3]&0x08) { move_z-=(16-(mouse_data[3]&0x0f)); } else { mouse_data[3]=mouse_data[3]&0x0f; move_z+=mouse_data[3]; //Z坐标加 } } } }
/************************************************** 外部中断1
***************************************************/ void ReceiveData(void) interrupt 2 { led=0; if(mouse_buffer_bit<=10) { while(mouse_CLK==0);//等待设备拉高时钟线 mouse_buffer[mouse_buffer_bit++]=mouse_SDA;//接收数据 } if(mouse_buffer_bit==10) { data_analyse();//数据分析及处理 mouse_buffer_bit=0; } }
#endif
////////////////////////////////主函数部分//////////////////////////////////////////////////// #include #include\"TM1638.h\" #include\"DS1302.h\" #include\"DELAY.h\" #include\"CHULI.h\" #include\"DISPLAY.h\" void main() { delayms(500); init_TM1638(); delayms(50); Init_DS1302(); //将1302初始化 delay(500); while(1) { read_date(); delayms(50); } } /**********************************************/ 再来一个按键测试的程序:这个是另外的,与上面的无关; #ifndef _TM1638_H #define _TM1638_H #include #define DATA_COMMAND 0X40 #define DISP_COMMAND 0x80 #define ADDR_COMMAND 0XC0 //引脚定义 sbit DIO=P1^0; sbit CLK=P1^1; sbit STB=P1^2; unsigned char code tab[]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F,0x77,0x7C,0x39,0x5E,0x79,0x71,0x40}; void TM1638_Write(unsigned char DATA) //写数据函数 { unsigned char i; for(i=0;i<8;i++) { CLK=0; if(DATA&0X01) DIO=1; else DIO=0; DATA>>=1; CLK=1; } } unsigned char TM1638_Read(void) //读数据函数 { unsigned char i; unsigned char temp=0; DIO=1; //设置为输入 for(i=0;i<8;i++) { temp>>=1; CLK=0; if(DIO) temp|=0x80; CLK=1; } return temp; } void Write_COM(unsigned char cmd) { STB=0; TM1638_Write(cmd); STB=1; } //发送命令字 unsigned char Read_key(void) { unsigned char c[4],i,key_value=0; STB=0; TM1638_Write(0x42); //读取键盘值 for(i=0;i<4;i++) c[i]=TM1638_Read(); STB=1; //4个字节数据合成一个字节 for(i=0;i<4;i++) key_value|=c[i]; for(i=0;i<4;i++) if(c[i]==key_value) break; return (i*8+key_value); } void Write_DATA(unsigned char add,unsigned char DATA) //指定地址写入数据 { Write_COM(0x44); STB=0; TM1638_Write(0xc0|add); TM1638_Write(DATA); STB=1; } /*void Write_oneLED(unsigned char num,unsigned char flag) //单独控制一个LED函数,num为需要控制的led序号,flag为0时熄灭,不为0时点亮 { if(flag) Write_DATA(2*num+1,1); else Write_DATA(2*num+1,0); } void Write_allLED(unsigned char LED_flag) //控制全部LED函数,LED_flag表示各个LED状态 { unsigned char i; for(i=0;i<8;i++) { if(LED_flag&(1<void init_TM1638(void) { unsigned char i; Write_COM(0x8a);//亮度 Write_COM(0x40); STB=0; TM1638_Write(0xc0); for(i=0;i<16;i++) TM1638_Write(0x00); STB=1; } #endif #include unsigned char num[8]; //各个数码管显示的值 unsigned char x=0xff; sbit key=P3^4; int main(void) { init_TM1638(); system_init(); display(x); delay_ms(200); display1638(); while(1) { display1638(); // detectkey(); x=Read_key(); display(~x); } } void display1638() { uchar i; if(sec_flag|i) { num[0]=hour/10; num[1]=hour%10; num[3]=minute/10; num[4]=minute%10; num[6]=second/10; num[7]=second%10; num[2]=16; num[5]=16; for(i=0;i<8;i++) { Write_DATA(i*2,tab[num[i]]); } } } #ifndef _555_H #define _555_H #include #define uchar unsigned char void delay_ms(uchar); void display(); void detectkey(); void display1638(); uchar code tap[10]={ 0xC0,/*0*/ 0xF9,/*1*/ 0xA4,/*2*/ 0xB0,/*3*/ 0x99,/*4*/ 0x92,/*5*/ 0x82,/*6*/ 0xF8,/*7*/ 0x80,/*8*/ 0x90,/*9*/ }; sbit key_hour=P3^5; sbit key_min=P3^6; uchar hour=12; uchar minute=0; uchar second=0; uchar flag=0; uchar sec_flag=0; /************************* 初始化程序 **************************/ void system_init() { TMOD=0x01; EA=1; ET0=1; EX0=1; IT0=1; TR0=1; TH0=(65536-50000)/256; TL0=(65536-50000)%256; } /************************* 定时器中断0中断处理程序 **************************/ void int1_ISR() interrupt 1 { TH0=(65536-50000)/256; TL0=(65536-50000)%256; flag++; if(flag==20) { sec_flag=1; second++; flag=0; } if(second==60) { second=0; minute++; } if(minute==60) { minute=0; hour++; hour%=24; } } /************************* 按键程序 **************************/ void detectkey() { delay_ms(10); if(key_hour==0) { hour++; hour=hour%24; while(!key_hour) display(); } if(key_min==0) { minute++; minute=minute%60; while(!key_min) display(); } if(P3_7==0) { hour=12; minute=0; second=0; while(!P3_5) display(); } } /************************* 显示程序 **************************/ void display(uchar i) { P0=i; } /************************* 延时处理程序 **************************/ void delay_ms(uchar no) { uchar i,j; for(i=0;i 说明:按键值送P0接的LED显示。其过程不影响数码管显示时间。 希望对各位有帮助! 因篇幅问题不能全部显示,请点此查看更多更全内容