切换到宽版
爱科技/爱创意/爱折腾;电子/数码爱好者的家!欢迎访问新版数码之家网站
  • 3480阅读
  • 11回复

[C51]做了个数码管时钟, 大神帮忙看下 [复制链接]

上一主题 下一主题
 

发帖
117
M币
2
专家
0
粉丝
7
只看楼主 倒序阅读 我要置顶 楼主  发表于: 2017-04-29


主控 89C52加pr8501B数码管驱动芯片,12M晶振,
seg1-7对应a-g,grid1-4对应左到右7段共阴数码管;
看了发一个两年前的作品【15元打造超级环保电子钟】或对初学者有所帮助
这文章,说8501跟tm1629程序通用,到处找资料,找到这篇:tm1629 驱动
成功点亮不过是倒着亮的,成了|秒2|秒1|分2|分1了|,改过显示小时和分了,只有4位就不要秒了,
管子是7段的,用两个LED并连接到G段SEG8,LED负极接到小时个位grid上,本人不大懂编程,现在问题
是秒点两秒闪一下,这个怎么改成一秒一闪呢?程序如下本人做了更改;
#include<reg52.h>
#include<intrins.h>
#define nop _nop_();
#define uchar unsigned char
#define uint unsigned int sbit stb =P1^0;//定义片选通讯口
sbit clk =P1^1;//定义时钟通讯口
sbit dio =P1^2;//定义数据输入/输出通讯口
bdata uchar y=0;//定义可以位寻址全局变量y
sbit y7 =y^7;
uchar show[16] = {0x76,0x7b,0x38,0x38,0x3f,0x40,0x40,0x40,0x40,0x40};//初始化显示“HELLO”字符代码 不好用少几位
uchar CODE[10] ={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f}; //0~9显示代码
uchar TIME_seconds,seconds_2,sub_1,sub_2,shi_1,shi_2; //时间寄存器,依次从秒个位至小时十位
uchar TIME_count; //定时中断控制制位
uchar T_count;   //时钟小数点闪
uchar count4;   //保存按键控制对应的数码管闪
uchar key_FLAG1;//按键标志位
uchar key_COUNT1;//按键移动数动显示数据
uchar key_LED=0;  //按键单独显示赋值寄存器
uchar count7;
/*********************************   功能: TM1629写数据**********************************/
void write(uchar wr_data){
     uchari;
  stb=0;   //给有效的片选信号(片选信号是低电平有效)
nop;  
nop;  
for(i=0;i<8;i++)//开始传送8位数据,每循环一次传送一位数据
{
     clk=0;  
     nop;  
     nop;
     wr_data>>= 1;//移位数据,低位在前!
     nop;
     dio =CY;
     nop;
     nop;
     clk =1;
     nop;
   }
}
/*********************************  功能:读按键子程序 由y 返回1BIT按键数据**********************************/
unsigned char read(){
  uchar d;
   stb =0;  //给有效的片选信号(片选信号是低电平有效)
   dio =1;  //将DIO置高,因为没有按键按下时,键值默认为00H,此时为了与键值有区别
  for(d=0;d<8;d++)   {
     clk =0;
nop;  if(dio==1)     {
     y7 = 1;
}  else    {

y7 = 0;
}
clk = 1;
if(d!=7){y=(y>>1);}  
nop;
nop;
}
return(y);  
}  
/*********************************   TM1629控制指令功能: 驱动LED屏做相应的显示**********************************/
void xianshi(uchar show_led[16]){
  ucharh;  stb = 1;  clk = 1; dio = 1;
write(0x40);//写数据到显示寄存器,采用地址自动加一
stb = 1;
write(0xc0);//显示寄存器的00H单元开始
for(h=0;h<16;h++)  {  
  write(show_led[h]);//给显示寄存器送数据,  }
   stb=1;
  write(0x8b);//显示控制参数,点亮数码屏幕,亮度可以通过改变低三位调节
  stb = 1;
}
//-------读按键以及相应的显示处理-------
void panjian(){
   uchar count3,key[4];   stb = 1;
  write(0x42);//送读按键命令(42H),
  for(count3=0;count3<5;count3++)  {
     key[count3]=read();//读4BIT按键数据,  }
  if((key_FLAG1 != 0x02))   {
  if((key[0]==0x01)){key_LED= 0;key_FLAG1 =
0x01;show[key_COUNT1] = CODE[key_LED];} //K3与SEG1按键按下,数码管显示数字0
  if((key[0]==0x02)){key_LED= 1;key_FLAG1 =
0x01;show[key_COUNT1] = CODE[key_LED];} //K2与SEG1按键按下,数码管显示数字1
  if((key[0]==0x04)){key_LED= 2;key_FLAG1 =
0x01;show[key_COUNT1] = CODE[key_LED];} //K1与SEG2按键按下,数码管显示数字2。
  if((key[0]==0x08)){key_LED= 3;key_FLAG1 =
0x01;show[key_COUNT1] = CODE[key_LED];} //K0与SEG2按键按下,数码管显示数字3。
  if((key[0]==0x80)){key_LED= 4;key_FLAG1 =
0x01;show[key_COUNT1] = CODE[key_LED];} //K0与SEG3按键按下,数码管显示数字4。
  if((key[0]==0x40)){key_LED= 5;key_FLAG1 =
0x01;show[key_COUNT1] = CODE[key_LED];} //K1与SEG3按键按下,数码管显示数字5。
  if((key[0]==0x20)){key_LED= 6;key_FLAG1 =
0x01;show[key_COUNT1] = CODE[key_LED];} //K2与SEG4按键按下,数码管显示数字6。
   if((key[0]==0x10)){key_LED=7;key_FLAG1 =
0x01;show[key_COUNT1] = CODE[key_LED];} //K3与SEG4按键按下,数码管显示数字7。
  if((key[1]==0x01)){key_LED= 8;key_FLAG1 =
0x01;show[key_COUNT1] = CODE[key_LED];} //K3与SEG5按键按下,数码管显示数字8。
  if((key[1]==0x02)){key_LED= 9;key_FLAG1 =
0x01;show[key_COUNT1] = CODE[key_LED];} //K2与SEG5按键按下,数码管显示数字9
}  if((key[1]==0x04)){key_FLAG1= 0x00; count7 = 0;}             //K1与SEG6按键按下,key_FLAG1 = 0x00启动定时器,时间开始。
  if((key[1]==0x08)){count7 = 0x01;TR0 = 0;key_FLAG1 = 0x02;} //当K0与SEG6按键按下,key_FLAG1= 0x02单独显示数字按键无效!  暂停。
  if((key[1]==0x80))                                         // K0与SEG7按键按下,key_FLAG1= 0x00启动定时器,时间开始。
   {  key_FLAG1 = 0x00;
   count7 = 0;
    shi_2 = 0;
    shi_1 = 0;
    sub_2 = 0;
    sub_1 = 0;
    seconds_2 =0;
    TIME_seconds = 0;
}     if((key[1] == 0x40))   // K1与SEG7按键按下,控制数码管右移一位
   {

    show[key_COUNT1] = count4;
    key_FLAG1 = 0x01;//key_FLAG1 = 0x00关闭定时器,时间暂停。
         key_COUNT1 ++;
  if((key_COUNT1 == 10)){ key_COUNT1 = 0;}   }  
   if((key[1] == 0x20))   // K2与SEG7按键按下,控制数码管左移一位  
{show[key_COUNT1] = count4;
    key_FLAG1 = 0x01;//key_FLAG1 = 0x00关闭定时器,时间暂停。
  if((key_COUNT1==0)){ key_COUNT1 = 10;}          key_COUNT1 -= 1;
}    if((key_FLAG1 == 0x01)){ count4 =show[key_COUNT1];}//保存当前按键位显示数据
  if((count7 != 0x01)){ key_FLAG1 = 0;}   }
/**********************************     定时中断函数入口功能: 每50MS中断一次**********************************/
void time0(void) interrupt 1 using 2{
TH0=0x3c;  TL0=0xb0;
  TIME_count++;  if(TIME_count==21)  {                               此处的21是什么意思??我的时间跑的慢我改成20了
   TIME_count = 0;
    TIME_seconds++;// 秒寄存器加1
T_count ^= 0x80;  }}                                                            这个秒点这么算什么意思?????????
/*********************************     时钟函数功能: 处理时钟显示**********************************/
voidTIME_show(){
  //sub_1 =sub_1|0x80;  //shi_1 = shi_1|0x80;
  show[15] =CODE[TIME_seconds];// 数码屏上最后一个“8”字,依次下去       我改成10
  show[14] =CODE[seconds_2];   //数码屏倒数第二个“8”字,                        我改成11
  show[13] = CODE[sub_1]|T_count;                                                              我改成12
show[12] = CODE[sub_2];                                                                              我改成13
  show[11] =CODE[shi_1]|T_count;                                                                  我改成14
show[10] =CODE[shi_2];                                                                                 我改成15
  if(TIME_seconds ==10)  //对时间数据进行处理,以免溢出。
{ TIME_seconds = 0;
    seconds_2+=1;
} if(seconds_2 == 6)   {
    seconds_2 = 0;

    sub_1 +=1;
}  if(sub_1== 10)   {
     sub_1 =0;
     sub_2 +=1;
}   if(sub_2 == 6)        {
     sub_2 =0;
   shi_1+=1;    }
  if(shi_1== 10)   {
     shi_1 =0;

shi_2 +=1;
}   if(shi_2== 6)  //时钟每60小时自动清0   {             改成12小时制     if(shi_2== 1&shi_1==3)  { shi_2 =0;shi_1 = 1;   }
     shi_2 =0;
    shi_1 = 0;
    sub_2 = 0;
    sub_1 = 0;
    seconds_2 = 0;
   TIME_seconds = 0;
}}      
/*********************************    延时函数功能: 1ms延时**********************************/
void delay_ms(uchar cyc){//当将=1的时候,延时1ms

uchar ii,jj;
for(jj=1;jj<=cyc;jj++){
      for(ii=0;ii<200;ii++)  {  
                      nop;  }
} }
/*********************************    主函数**********************************/
void main(){
uchar count6;//按键按下时,所控制的位闪!
P0=0xff; P1=0xff; P2=0xff;P3=0xff;//初始化单片机I/O口
TMOD=0x01;  //定时器设置
TH0=0x3c; TL0=0xb0;IE=0x82; TF0=1;
xianshi(show);//初始化显示“HELLO”字符
_delay_ms(230);
_delay_ms(230);
_delay_ms(230);  
_delay_ms(230);  

_delay_ms(230);    //共延时1s
count4 =show[key_COUNT1];

while(1)//循环

{
count6+=1;

if((count6%2))
{

   show[key_COUNT1] = count4;//基数时,显示当位数
   }
else
   { show[key_COUNT1] =0; //偶数时,灭当位数!程序循环2次,闪一次。}

if(key_FLAG1 == 0x02){ TR0 = 0;}
if(key_FLAG1 == 0x00){ TR0 = 1;}
stb = 1;
dio = 1;
clk = 1;
TIME_show();  //控制做时钟显示
panjian();    //判断按键值
xianshi(show); //根据按键值,给显示寄存器送相应的显示数据
_delay_ms(230);//延时240ms!

if(count6== 201){ count6 = 0;}
}
}


[ 此帖被黑色0幽默在2017-04-29 18:58重新编辑 ]
本文内容包含图片或附件,获取更多资讯,请 登录 后查看;或者 注册 成为会员获得更多权限
本帖最近打赏记录:共2条打赏M币+11
离线bg4rff

发帖
1518
M币
1237
专家
8
粉丝
32
只看该作者 1楼 发表于: 2017-04-29
T_count ^= 0x80;  }}               这个秒点这么算什么意思?????????
位异或运算,位和1异或即相当于位取反
显示时钟函数不需要一直调用,数据变化时调用一次就行
就是在定时中断中 if(TIME_count==21) 时,给个标志位
主循环中判断标志位是否更新显示时钟
调用显示时钟先清除标志

发帖
117
M币
2
专家
0
粉丝
7
只看该作者 2楼 发表于: 2017-04-29
回 bg4rff 的帖子
bg4rff:T_count ^= 0x80;紀紀 这个秒点这么算什么意思?????????
位异或运算,位和1异或即相当于位取反
显示时钟函数不需要一直调用,数据变化时调用一次就行
就是在定时中断中  ..(2017-04-29 18:07)嬀/color]回 bg4rff 的帖子

不大懂,能点亮就不错了搞好多天的,只是我这个秒点怎么两秒一闪啊,怎么改啊大神,
离线bg4rff

发帖
1518
M币
1237
专家
8
粉丝
32
只看该作者 3楼 发表于: 2017-04-29

T_count ^= 0x80;  
TIME_show();  //控制做时钟显示,放在这里,主程序里面的不要
}}               这个秒点这么算什么意思?????????


发帖
117
M币
2
专家
0
粉丝
7
只看该作者 4楼 发表于: 2017-04-29
自己来已经搞定更改如下
TIME_count++;
     if(TIME_count==9|TIME_count==19){T_count ^= 0x80;}//半秒或1秒时
        if(TIME_count==20){TIME_count = 0;TIME_seconds++;}

之前这样改了 if(TIME_count==10){T_count ^= 0x80;}错了不行,谢谢楼上几个,
现在两秒点是一秒一亮,之前亮一秒灭一秒,

发帖
117
M币
2
专家
0
粉丝
7
只看该作者 5楼 发表于: 2017-04-29
回 bg4rff 的帖子
bg4rff:T_count ^= 0x80;
TIME_show();//控制做时钟显示,放在这里,主程序里面的不要
}} 这个秒点这么算什么意思?????????
.......(2017-04-29 21:03)嬀/color]回 bg4rff 的帖子

直接放到那里编译不过,不会用标志位谢谢了
离线bg4rff

发帖
1518
M币
1237
专家
8
粉丝
32
只看该作者 6楼 发表于: 2017-04-29
回 黑色0幽默 的帖子
黑色0幽默:自己来已经搞定更改如下
TIME_count++;
     if(TIME_count==9|TIME_count==19){T_count ^= 0x80;}//半秒或1秒时
        if(TIME_count==20){TIME_count = 0;TIME_seconds++;}
....... (2017-04-29 21:22) 回 黑色0幽默 的帖子

1秒亮灭各一次,所以在0-20之间,改变两次,间隔其实不是很重要的
在开头添加
void TIME_show(void);
或者把中断函数和TIME_show()函数位置对调一下
也就是说C文件里面要调用的函数必须在前面有定义
离线独行者

发帖
1062
M币
6929
专家
2
粉丝
26
只看该作者 7楼 发表于: 2017-04-30
楼主辛苦,谢谢分享。

发帖
117
M币
2
专家
0
粉丝
7
只看该作者 8楼 发表于: 2017-04-30
谢谢已改成功跟着秒点刷新,只是按键还没接,也不只道8501b支持按键功能不
离线bg4rff

发帖
1518
M币
1237
专家
8
粉丝
32
只看该作者 9楼 发表于: 2017-05-02
改红外,首先您要有红外的遥控器,然后还要知道或者大概知道遥控器的编码,然后对应的按键处理就差不多了
快速回复
限80 字节
“新手上路”发帖需审核后才能显示(请认真发帖),达到数码9级后取消此限制
 
上一个 下一个