前言
整理代码的时候发现之前写的一个单片机(STC89C51)代码,主要是利用3个中断源(计时中断,外部中断),蜂鸣器,8个LED灯,独立按键(矩阵按键)以及8片阴极数码管完成一个数字电子时钟,并且具有调分钟数(+,-),调小时数(+,-),报警的功能。贴上来(代码很乱,emm不想改了,不过跑是没问题的2333
设计
-
给两个中断
一,时间处理中断时间每秒刷新一下数码管
二,中断按键1 设置时间 中断按键2 退出设置时间 -
按键控制
按键1 时针+1
按键2 时针-1
按键3 分针+1
按键4 分针-1 -
当时间的table运行到某个状态的时候报警(led闪烁5秒 可以配合着时间中断进行变化)
C51程序代码:
#include<reg52.h>
#include<intrins.h>
#define uint unsigned int
/* 32 -- 25 33 -- 24 s23:hour+1 s17:hour-1 s10:minute+1 s5:minute-1 s6:set timer s11:exit set */
sbit led_en = P1^2;
sbit lcd_en = P1^7;
sbit line_en = P1^3;
sbit wei = P1^1;
sbit duan = P1^0;
sbit wengmingqi = P3^7;
sbit KEY1 = P2^4;
sbit KEY2 = P2^5;
uint table1[] = {0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x40}; //0~9,- 段码
uint table2[] = {0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f}; //位码
uint time_table[] = {1,2,10,0,0,10,0,0}; //12-00-00 当前时间
uint time_tag_table[] = {1,2,10,0,0,10,0,4}; //12-10-00 目标事件时间
uint led_table[2]={0xff,0xfe}; //led亮灭
int second=0,minute=0,hour=12; //当前时钟的时间
int res_second=4,res_minute=0,res_hour=12; //目标事件时间
uint key_table1[4] = {0xfe,0xfd,0xfb,0xf7};
uint key_table2[4] = {0x7e,0x7d,0x7b,0x77};
uint i = 1,j = 1,temp,flag,s,t;
uint count = 0, res_count = 0;
void delay(uint k)
{
for(s=0;s<k;s++) {
for(t=0;t<110;t++)
;
}
}
void display()
{
for(j=0;j<8;j++) {
duan = 1;
P0=table1[time_table[j]];
duan = 0;
wei = 1;
P0 = table2[j];
wei = 0;
delay(2);
}
}
void timeself_change()
{
if(second==60) {
second = 0;
minute++;
}
if(minute==60) {
minute = 0;
hour++;
}
if(hour==24) {
hour = 0;
}
if(minute <0) {
minute = (minute+60)%60;
hour--;
}
if(hour <0) {
hour = (hour+24)%24;
}
time_table[0]=hour/10;
time_table[1]=hour%10;
time_table[3]=minute/10;
time_table[4]=minute%10;
time_table[6]=second/10;
time_table[7]=second%10;
}
void interrupt_Init()
{
EX0 = 1;
IT0 = 1;
PX0 = 1;
EX1 = 1;
IT1 = 1;
PX1 = 0; //低优先级
TMOD=0x10; //T1做定时器,方式1
TL1=(65536 - 50000) % 256;
TH1=(65536 - 50000) / 256; //设置定时器的初值
ET1=1; //允许T1中断
TR1=1; //启动定时器
EA = 1;
}
void timer0_interrupt() interrupt 3
{
TL1=(65536 - 50000) % 256;
TH1=(65536 - 50000) / 256; //设置定时器的初值
count++;
}
void key()
{
int i;
for(i=03;i>=0;i--) {
P2 = key_table1[i];
temp = P2;
temp = temp&0xf0;
while(temp!=0xf0) {
delay(5);
temp = P2;
temp = temp & 0xf0;
while(temp!=0xf0) {
temp = P2;
if(temp == key_table2[i]) {
switch(i) {
case 0:
minute--;
break;
case 1:
minute++;
break;
case 2:
hour--;
break;
case 3:
hour++;
break;
}
}
while(temp!=0xf0) {
temp=P2;
temp = temp & 0xf0;
}
}
}
}
timeself_change();
delay(28);
}
void digital_interrupt_1() interrupt 2
{
delay(28);
flag = 1;
if(KEY1 == 0)
{
while(1) {
key();
display();
if(flag == 0)
break;
}
}
}
void digital_interrupt_2() interrupt 0
{
delay(28);
if(KEY2 == 0) {
flag = 0;
}
}
int pan()
{
if(hour != res_hour || minute != res_minute || second != res_second)
return 0;
return 1;
}
void main()
{
lcd_en = 0;
P0 = 0x00;
line_en = 0;
P0 = 0xff;
wei = 0;
led_en = 0;
interrupt_Init();
wengmingqi = 1;
while(1)
{
display();
if(count == 20) { //updatedisplay
count=0;
second++;
timeself_change();
if(pan() || res_count) {
if(res_count == 0) {
res_count=5;
}
else {
res_count--;
if(res_count == 0) {
led_en = 1;
P0=0xff;
led_en = 0;
wengmingqi=1;
}
}
}
}
if(res_count != 0) { //处理时间到的事件
led_en = 1;
P0=led_table[res_count&1];
led_en = 0;
wengmingqi = !(res_count&1);
}
}
}
总结
写这种片上的代码主要还是要把电路基础弄清楚,以及会看引脚功能图,对于IIC那些模块通信的话注重把原理弄清除,必要的时候还要利用示波器观察调试,让代码符合运行标准。(Ps:例程运用十分重要!因为不是写驱动啥的,要学会高效地完成一个任务。