找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 1978|回复: 1
打印 上一主题 下一主题
收起左侧

发个AT89C2051制作的时钟程序+仿真,功能还是很强大的,大家玩得开心就好!

[复制链接]
跳转到指定楼层
楼主

// so said EVELYN the modified DOG
//#pragma less_pedantic
#define uint8_t unsigned char
#define uint16_t unsigned short int
// Clock related defines
#define CLOCK_TIMER_HIGH                0x3C
#define CLOCK_TIMER_LOW                        0xD5        // original ASM source was 0xB5, but experimentation shows this should be a more accurate value
#define CLOCK_TIMER_COUNT                20
#define CLOCK_COLON_COUNT                10                // 1/2 of CLOCK_TIMER_COUNT
#define CLOCK_BLINK_COUNT                5
#define CLOCK_INCREMENT_COUNT        4

// Button related defines
#define BUTTON_PRESS                        2
#define BUTTON_PRESS_LONG                40

// Display related defines
#define LED_BLANK                        10
#define LED_h                                11
#define LED_A                                12
#define LED_L                                13
#define LED_y                                14
#define LED_n                                15

// digit to led digit lookup table
// 1 = on, 0 = off
// a, f, b, e, d, c, g, dp
const uint8_t ledtable[] = {
        0xFC,        // 0
        0x24,        // 1
        0xBA,        // 2
        0xAE,        // 3
        0x66,        // 4
        0xCE,        // 5
        0xDE,        // 6
        0xA4,        // 7
        0xFE,        // 8
        0xEE,        // 9
        0x00,   // <blank>
        0x56,        // 'h'
        0xF6,   // 'A'
        0x58,        // 'L'
        0x6E,        // 'y'
        0x16,   // 'n'
};

// display buffer
uint8_t dbuf[4];

// clock variables
volatile uint8_t clock_hour = 12;
volatile uint8_t clock_minute = 0;
volatile uint8_t clock_second = 55;
volatile uint8_t next_second = CLOCK_TIMER_COUNT;
volatile uint8_t next_blink = CLOCK_BLINK_COUNT;
volatile uint8_t next_increment = CLOCK_INCREMENT_COUNT;

volatile bit CLOCK_RUNNING = 1;
volatile bit TWELVE_TIME = 0;                        // 0 = 24 hour, 1 = 12 hour

// alarm variables
volatile uint8_t alarm_hour = 12;
volatile uint8_t alarm_minute = 1;
volatile bit ALARM_ENABLE = 1;

// flag to determine whether or not to display the colon (every half second)
// can also be repurposed for blinking numbers during time set
volatile bit show_colon = 0;

// flag when to display a digit (for blinking purposes during set time mode)
volatile bit show_blink = 0;

// flag when to make the next digit increment
// used while holding down the digit increment button during set time mode
volatile bit clock_increment = 0;

// timer variables
volatile uint8_t timer_minute = 0;
volatile uint8_t timer_second = 0;
volatile bit TIMER_RUNNING = 0;

// number of ms between display refresh
//uint8_t display_dimmer = 10;

// button variables
volatile uint8_t debounce[] = {0, 0};
volatile bit B1_PRESSED = 0;
volatile bit B1_RELEASED = 0;
volatile bit B1_PRESSED_LONG = 0;
volatile bit B1_RELEASED_LONG = 0;
volatile bit B2_PRESSED = 0;
volatile bit B2_RELEASED = 0;
volatile bit B2_PRESSED_LONG = 0;
volatile bit B2_RELEASED_LONG = 0;

// clock state
typedef enum {
        NORMAL,
        MIN_SEC,
        EDIT_HOUR,
        EDIT_MIN,
        SET_24H,
        SHOW_ALARM,
        EDIT_ALARM_HOUR,
        EDIT_ALARM_MIN,
        ENABLE_ALARM,
        ALARMING,
        TIMER
} clock_state_t;
clock_state_t clock_state = NORMAL;

// check button status and set appropriate flags
// Bn_PRESSED* flags will be set ONCE PER PRESS. This means software can UNSET these flags if desired.
void button_status(void) {

        // button 1
        if (P3_4 == 0) {
                if (debounce[0] < BUTTON_PRESS_LONG) {
                        debounce[0]++;
                        if (debounce[0] == BUTTON_PRESS) {
                                B1_RELEASED = 0;
                                B1_PRESSED = 1;       
                        }
                        if (debounce[0] == BUTTON_PRESS_LONG) {
                                B1_RELEASED_LONG = 0;
                                B1_PRESSED_LONG = 1;
                        }       
                }
        } else {
                debounce[0] = 0;
                if (B1_PRESSED) {
                        B1_RELEASED = 1;
                }
                B1_PRESSED = 0;
                if (B1_PRESSED_LONG) {
                        B1_RELEASED_LONG = 1;
                }
                B1_PRESSED_LONG = 0;
        }

        // button 2
        if (P3_5 == 0) {
                if (debounce[1] < BUTTON_PRESS_LONG) {
                        debounce[1]++;
                        if (debounce[1] == BUTTON_PRESS) {
                                B2_RELEASED = 0;
                                B2_PRESSED = 1;
                        }
                        if (debounce[1] == BUTTON_PRESS_LONG) {
                                B2_RELEASED_LONG = 0;
                                B2_PRESSED_LONG = 1;
                        }
                }
        } else {
                debounce[1] = 0;
                if (B2_PRESSED) {
                        B2_RELEASED = 1;
                }
                B2_PRESSED = 0;
                if (B2_PRESSED_LONG) {
                        B2_RELEASED_LONG = 1;
                }
                B2_PRESSED_LONG = 0;
        }
}

// timer reset
void timer_reset() {
        timer_minute = 0;
        timer_second = 0;
}

void increment_timer_minute() {
        if (++timer_minute == 60) {
                timer_minute = 0;
                // increment_timer_hour();
        }
}

void increment_timer_second() {
        if (++timer_second == 60) {
                timer_second = 0;
                increment_timer_minute();
        }
}

// increment hour by 1
void increment_hour() {
        if (++clock_hour == 24) {
                clock_hour = 0;
        }
}

// increment minute by 1
void increment_minute() {
        if (++clock_minute == 60) {
                clock_minute = 0;
                if (CLOCK_RUNNING) {
                        increment_hour();
                }
        }
}

// increment second by 1
void increment_second() {
        if (++clock_second == 60) {
                clock_second = 0;
                if (CLOCK_RUNNING) {
                        increment_minute();
                }
        }
        if (TIMER_RUNNING) {
                increment_timer_second();
        }
}

void increment_alarm_hour() {
        if (++alarm_hour == 24) {
                alarm_hour = 0;
        }
}

// increment minute by 1
void increment_alarm_minute() {
        if (++alarm_minute == 60) {
                alarm_minute = 0;
                if (CLOCK_RUNNING) {
                        increment_alarm_hour();
                }
        }
}


/* i feel like i need a time object that i pass to the increment_* functions and current time, alarm, and timer would all be objects of this type.
* but what about RUNNING flag?
* that would have to be part of the object type as well
* ...
* why do the increment_* functions test for clock_running? the thing.... for setting the time/alarm. don't increment if we're in a SET CLOCK mode
* perhaps another flag to add to the clock object, a SET MODE boolean
*
* maybe call the 'running' flag ENABLE; this would be more applicable a word to the alarm state
*/


// Timer0 ISR, used to maintain the time, executes every 50ms
void timer0_isr(void) interrupt 1 using 1 {

        // reset timer
    TL0 = CLOCK_TIMER_LOW;
    TH0 = CLOCK_TIMER_HIGH;

        // is the clock running?
        if (CLOCK_RUNNING) {

                // then keep track of when to increment the seconds
                if (--next_second == 0) {
                        next_second = CLOCK_TIMER_COUNT;
                        show_colon = 1;
                        increment_second();
                } else if (next_second == CLOCK_COLON_COUNT) {
                        show_colon = 0;
                }
        }

        // toggle digit blinking
        if (--next_blink == 0) {
                next_blink = CLOCK_BLINK_COUNT;
                show_blink = !show_blink;
        }

        // control digit increment
        if (--next_increment == 0) {
                next_increment = CLOCK_INCREMENT_COUNT;
                clock_increment = 1;                // flag will be unset by software
        }

        button_status();
}

// execute 500 DJNZ instructions which should equate to 1 millisecond
void delay1ms(void) {
#pragma asm
                MOV R0,#250
                MOV R1,#250
        L_00001:
                DJNZ R0, L_00001
        L_00002:
                DJNZ R1, L_00002
#pragma endasm
}

void delay(uint16_t ms) {
        do {
                delay1ms();
        } while (--ms > 0);
}

// display refresh
void display_update(void) {
        uint8_t digit = 4;
//        static uint8_t display_dimmer_counter = 0;

//        if (display_dimmer_counter == 0) {
//                display_dimmer_counter = display_dimmer;

                // disable all digits
                P3 |= 0x0F;

                for (digit = 0; digit<4; digit++) {
               
                        // enable appropriate segments
                        P1 = dbuf[digit];

                        // enable appropriate digit (set it to 0; leave others 1)
                        P3 &= (~(1 << digit));

                        // delay
                        delay1ms();

                        // disable all digits
                        P3 |= 0x0F;
                }
//        } else {
//                display_dimmer_counter--;
//                delay1ms();
//        }
}

// set the display buffer first and second digits to the current hour
void set_hour_dbuf(uint8_t display_hour) {
        uint8_t hour;

        if (TWELVE_TIME) {
                hour = display_hour % 12;
                if (hour==0) {
                        hour = 12;
                }
        } else {
                hour = display_hour;
        }

        dbuf[0] = ledtable[(hour/10)];
        dbuf[1] = ledtable[(hour%10)];
}

void init(void) {

        // Display initialization
        P1 = 0x00;                        // disable all segments
        P3 |= 0x04;                        // disable all digits

        // Timer0 initialization
        TMOD = 0x01;                        // Set Timer0 to mode 1, 16-bit
        TH0 = CLOCK_TIMER_HIGH;
        TL0 = CLOCK_TIMER_LOW;                // Set counter to 15541, overlfow at 65536, a difference of 49995; about 50 milliseconds per trigger
        PT0 = 1;                        // Giver Timer0 high priority
        ET0 = 1;                        // Enable Timer0 interrupt
        TR0 = 1;                            // Enable Timer0
        EA = 1;                                // Enable global interrupts

        // Other
        P3_7 = 1;                        // disable buzzer
}

void main(void) {

        // initialization routine
        init();

        // main program loop
    while(1) {

                // alarm mode
                if (ALARM_ENABLE && CLOCK_RUNNING && alarm_hour == clock_hour && alarm_minute == clock_minute) {
                        if (clock_second == 0 && clock_state != ALARMING) {
                                clock_state = ALARMING;
                        }
                        if (clock_state == ALARMING) {
                                if (show_colon == 1) {
                                        P3_7 = !P3_7;        // P3_7 = show_colon; (this toggling creates an interesting effect)
                                } else {
                                        P3_7 = 1;        // if doing the toggling effect, need to make sure buzzer is off during blink
                                }
                        }
                } else if (clock_state == ALARMING) {        // turn off the alarm after 1 minute
                        clock_state = NORMAL;
                        P3_7 = 1;                        // turn off the alarm
                }

                // handle button events based on current clock state
                switch (clock_state) {

                        case ALARMING:
                                if (B1_RELEASED || B2_RELEASED) {
                                        clock_state = NORMAL;
                                        P3_7 = 1;                                // turn off alarm
                                        B1_RELEASED = 0;
                                        B2_RELEASED = 0;
                                }
                                break;

                        case EDIT_ALARM_MIN:
                                if (B1_PRESSED) {
                                        clock_state = ENABLE_ALARM;
                                        B1_PRESSED = 0;
                                } else if (B2_PRESSED) {
                                        increment_alarm_minute();
                                        B2_PRESSED = 0;
                                } else if (B2_PRESSED_LONG && clock_increment == 1) {
                                        increment_alarm_minute();
                                        clock_increment = 0;
                                }
                                break;

                        case EDIT_ALARM_HOUR:
                                if (B1_PRESSED) {
                                        clock_state = EDIT_ALARM_MIN;
                                        B1_PRESSED = 0;
                                } else if (B2_PRESSED) {
                                        increment_alarm_hour();
                                        B2_PRESSED = 0;                                       
                                } else if (B2_PRESSED_LONG && clock_increment == 1) {
                                        increment_alarm_hour();
                                        clock_increment = 0;
                                }
                                break;

                        case ENABLE_ALARM:
                                if (B1_PRESSED) {
                                        clock_state = NORMAL;
                                        B1_PRESSED = 0;
                                } else if (B2_PRESSED) {
                                        ALARM_ENABLE = !ALARM_ENABLE;
                                        B2_PRESSED = 0;
                                }
                                break;

                        case SHOW_ALARM:
                                if (B1_PRESSED_LONG) {
                                        clock_state = EDIT_ALARM_HOUR;
                                        B1_PRESSED = 0;
                                        B1_PRESSED_LONG = 0;
                                } else if (B1_RELEASED) {
                                        clock_state = ENABLE_ALARM;
                                        B1_RELEASED = 0;
                                }
                                break;

                        case TIMER:
                                if (B2_RELEASED) {
                                        clock_state = NORMAL;
                                        B2_RELEASED = 0;
                                } else if (B1_PRESSED_LONG) {
                                        timer_reset();
                                        // really need to create some sort of change/state or button clear routine
                                        // otherwise possible to enter TIMER state with B1_PRESSED_LONG set if you push both buttons at the same time.
                                } else if (B1_RELEASED_LONG) {
                                        // a LONG press is a reset, do not toggle the timmer on a LONG press
                                        B1_RELEASED = 0;
                                        B1_RELEASED_LONG = 0;
                                } else if (B1_RELEASED) {
                                        TIMER_RUNNING = !TIMER_RUNNING;        // toggle timer
                                        B1_RELEASED = 0;
                                }
                                break;
       
                        case SET_24H:
                                if (B2_RELEASED) {
                                        clock_state = TIMER;
                                        B2_RELEASED = 0;
                                } else if (B1_RELEASED) {
                                        TWELVE_TIME = !TWELVE_TIME;
                                        B1_RELEASED = 0;
                                }
                                break;

                        case EDIT_MIN:
                                if (B1_PRESSED) {                        // exit edit mode
                                        clock_state = NORMAL;
                                        B1_PRESSED = 0;
                                        CLOCK_RUNNING = 1;
                                } else if (B2_PRESSED) {                // increment minute
                                        increment_minute();
                                        clock_second = 0;                // reset seconds to 0 when time is changed
                                        B2_PRESSED = 0;
                                } else if (B2_PRESSED_LONG && clock_increment == 1) {
                                        increment_minute();                // hold down the button to rapidly increase minute
                                        clock_increment = 0;
                                }
                                break;

                        case EDIT_HOUR:
                                CLOCK_RUNNING = 0;
                                if (B1_PRESSED) {                        // switch to edit minute mode
                                        clock_state = EDIT_MIN;
                                        B1_PRESSED = 0;
                                } else if (B2_PRESSED) {                // increment hour
                                        increment_hour();
                                        clock_second = 0;                // reset seconds to 0 when time is changed
                                        B2_PRESSED = 0;                                       
                                } else if (B2_PRESSED_LONG && clock_increment == 1) {
                                        increment_hour();                // hold down the button to rapidly increase hour
                                        clock_increment = 0;
                                }
                                break;

                        case MIN_SEC:
                                if (B2_RELEASED) {
                                        clock_state = SET_24H;
                                        B2_RELEASED = 0;
                                }
                                break;
                       
                        case NORMAL:
                        default:
                                if (B2_RELEASED) {
                                        clock_state = MIN_SEC;
                                        B2_RELEASED = 0;
                                } else if (B1_PRESSED_LONG) {
                                        clock_state = EDIT_HOUR;
                                        B1_PRESSED = 0;
                                        B1_PRESSED_LONG = 0;
                                } else if (B1_RELEASED) {
                                        clock_state = SHOW_ALARM;
                                        B1_RELEASED = 0;
                                }
                                break;
                }

                // generate display based on current clock state
                // button events and display are separated as state may change during button events
                switch (clock_state) {
                        case ALARMING:
                                if (show_colon == 1) {
                                        set_hour_dbuf(clock_hour);
                                        dbuf[2] = ledtable[(clock_minute/10)];
                                        dbuf[3] = ledtable[(clock_minute%10)];
                                        dbuf[1] |= 1;
                                } else {
                                        dbuf[0] = ledtable[LED_BLANK];
                                        dbuf[1] = ledtable[LED_BLANK];
                                        dbuf[2] = ledtable[LED_BLANK];
                                        dbuf[3] = ledtable[LED_BLANK];
                                }
                                break;

                        case ENABLE_ALARM:
                                dbuf[0] = ledtable[LED_A];
                                dbuf[1] = ledtable[LED_L];
                                dbuf[2] = ledtable[LED_BLANK];
                                if (ALARM_ENABLE) {
                                        dbuf[3] = ledtable[LED_y];
                                } else {
                                        dbuf[3] = ledtable[LED_n];
                                }
                                break;

                        case EDIT_ALARM_MIN:

                                set_hour_dbuf(alarm_hour);
                                if (show_blink == 1) {
                                        dbuf[2] = ledtable[(alarm_minute/10)];
                                        dbuf[3] = ledtable[(alarm_minute%10)];
                                } else {
                                        dbuf[2] = ledtable[LED_BLANK];
                                        dbuf[3] = ledtable[LED_BLANK];
                                }
                                if (!TWELVE_TIME || alarm_hour > 11) {
                                        dbuf[1] |= 1;
                                }
                                break;

                        case EDIT_ALARM_HOUR:

                                if (show_blink == 1) {
                                        set_hour_dbuf(alarm_hour);
                                } else {
                                        dbuf[0] = ledtable[LED_BLANK];
                                        dbuf[1] = ledtable[LED_BLANK];
                                }
                                dbuf[2] = ledtable[(alarm_minute/10)];
                                dbuf[3] = ledtable[(alarm_minute%10)];
                                if (!TWELVE_TIME || alarm_hour > 11) {
                                        dbuf[1] |= 1;
                                }
                                break;

                        case SHOW_ALARM :

                                if (show_colon == 1) {
                                        set_hour_dbuf(alarm_hour);
                                        dbuf[2] = ledtable[(alarm_minute/10)];
                                        dbuf[3] = ledtable[(alarm_minute%10)];
                                        dbuf[1] |= 1;
                                } else {
                                        dbuf[0] = ledtable[LED_BLANK];
                                        dbuf[1] = ledtable[LED_BLANK];
                                        dbuf[2] = ledtable[LED_BLANK];
                                        dbuf[3] = ledtable[LED_BLANK];
                                }
                                break;

                        case TIMER:
                                dbuf[0] = ledtable[(timer_minute/10)];
                                dbuf[1] = ledtable[(timer_minute%10)];
                                dbuf[2] = ledtable[(timer_second/10)];
                                dbuf[3] = ledtable[(timer_second%10)];
                                if (!TIMER_RUNNING || show_colon) {
                                        dbuf[1] |= 1;
                                }
                                break;

                        case SET_24H:

                                if (TWELVE_TIME) {
                                        dbuf[0] = ledtable[1];
                                        dbuf[1] = ledtable[2];
                                } else {
                                        dbuf[0] = ledtable[2];
                                        dbuf[1] = ledtable[4];
                                }
                                dbuf[2] = ledtable[LED_h];
                                dbuf[3] = ledtable[LED_BLANK];
                                break;

                        case EDIT_MIN:

                                set_hour_dbuf(clock_hour);
                                if (show_blink == 1) {
                                        dbuf[2] = ledtable[(clock_minute/10)];
                                        dbuf[3] = ledtable[(clock_minute%10)];
                                } else {
                                        dbuf[2] = ledtable[LED_BLANK];
                                        dbuf[3] = ledtable[LED_BLANK];
                                }

                                // colon does not blink when setting time
                                // in 12 hour format, colon is only on when hour represents PM
                                if (!TWELVE_TIME || clock_hour > 11) {
                                        dbuf[1] |= 1;
                                }

                                break;

                        case EDIT_HOUR:

                                if (show_blink == 1) {
                                        set_hour_dbuf(clock_hour);
                                } else {
                                        dbuf[0] = ledtable[LED_BLANK];
                                        dbuf[1] = ledtable[LED_BLANK];
                                }
                                dbuf[2] = ledtable[(clock_minute/10)];
                                dbuf[3] = ledtable[(clock_minute%10)];

                                // colon does not blink when setting time
                                // in 12 hour format, colon is only on when hour represents PM
                                if (!TWELVE_TIME || clock_hour > 11) {
                                        dbuf[1] |= 1;
                                }

                                break;

                        case MIN_SEC:

                                // update display buffer to show current time
                                dbuf[0] = ledtable[(clock_minute/10)];
                                dbuf[1] = ledtable[(clock_minute%10)];
                                dbuf[2] = ledtable[(clock_second/10)];
                                dbuf[3] = ledtable[(clock_second%10)];

                                // blinking colon
                                if (show_colon == 1) {
                                        dbuf[1] |= 1;
                                }
                                break;

                        case NORMAL:
                        default:

                                // update display buffer to show current time
                                set_hour_dbuf(clock_hour);
                                dbuf[2] = ledtable[(clock_minute/10)];
                                dbuf[3] = ledtable[(clock_minute%10)];

                                // blinking colon
                                if (show_colon == 1) {
                                        dbuf[1] |= 1;
                                }
                                break;
                }

                // update the display
                display_update();
    }
}

新建位图图像.jpg (319.56 KB, 下载次数: 71)

新建位图图像.jpg

Clock.zip

108.25 KB, 下载次数: 17, 下载积分: 黑币 -5

评分

参与人数 1黑币 +50 收起 理由
admin + 50 共享资料的黑币奖励!

查看全部评分

分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏1 分享淘帖 顶 踩
回复

使用道具 举报

沙发
ID:16255 发表于 2021-1-19 09:54 | 只看该作者
连时钟芯片都不用,估计走时不太准确。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表