设计一个数字钟,实现时分秒的显示,连接外部中断实现当外部中断0按下清屏,当外部中断1按下显示。要求代码能在如下电路中运行,51单片机,7SEG-MPX8-CC
下面是使用MSP430F5529单片机和TM1637数码管进行设计的数字钟代码(使用C语言):
#include <msp430.h>
#include <stdint.h>
#include "TM1637.h"
volatile uint16_t ms; // 毫秒数
volatile uint8_t sec; // 秒数
volatile uint8_t min; // 分钟数
volatile uint8_t hour; // 小时数
void init_timer(void) {
TA0CCTL0 = CCIE; // 开启定时器中断
TA0CTL = TASSEL__ACLK | // 使用ACLK作为时钟信号
MC__UP | // 向上计数模式
ID__8; // 分频系数8
TA0CCR0 = 4096; // 定时1秒
}
void init_GPIO(void) {
P1DIR &= ~BIT1; // P1.1输入
P1REN |= BIT1; // P1.1上拉电阻
P1OUT |= BIT1; // P1.1上拉
P1IES |= BIT1; // P1.1下降沿中断
P1IFG &= ~BIT1; // 清除P1.1中断标志
P1IE |= BIT1; // 允许P1.1中断
}
interrupt(PORT1_VECTOR) P1_ISR(void) {
if (P1IFG & BIT1) {
P1IFG &= ~BIT1;
// 处理清屏中断
TM1637_clear();
}
}
interrupt(TIMER0_A0_VECTOR) Timer_A0_ISR(void) {
// 更新时间
++ms;
if (ms >= 1000) {
ms = 0;
++sec;
if (sec >= 60) {
sec = 0;
++min;
if (min >= 60) {
min = 0;
++hour;
}
}
}
// 显示时间
uint8_t digits[] = {hour / 10, hour % 10, min / 10, min % 10, sec / 10, sec % 10};
TM1637_display(digits);
}
void main(void) {
WDTCTL = WDTPW | WDTHOLD; // 禁用看门狗
init_timer(); // 初始化定时器
init_GPIO(); // 初始化GPIO
__enable_interrupt(); // 允许中断
while (1) {
// 循环等待外部中断1,即按键中断
__low_power_mode_0();
}
}
这里使用了TM1637数码管库(TM1637.h),可以使代码更简单和易读。
代码的运行依赖于正确的时钟设置和中断初始化。如果运行不起来,可能需要检查时钟设置和中断优先级等。
希望能帮到您 写的太累了~
下面是该设计方案的主要代码:
#include <reg52.h>
// GPIO 端口定义
sbit SEGA = P1^0;
sbit SEGB = P1^1;
sbit SEGC = P1^2;
sbit SEGD = P1^3;
sbit SEGE = P1^4;
sbit SEGF = P1^5;
sbit SEGG = P1^6;
sbit SEGP = P0^0;
// 数码管显示字型
unsigned char SEGMENT[10] = {
0xFC, // 0
0x60, // 1
0xDA, // 2
0xF2, // 3
0x66, // 4
0xB6, // 5
0xBE, // 6
0xE0, // 7
0xFE, // 8
0xF6 // 9
};
// 计时器计数值定义
unsigned char SECOND = 0;
unsigned char MINUTE = 0;
unsigned char HOUR = 0;
// 中断处理函数
void interrupt_handler(void) interrupt 0 {
// INT0 外部中断,清屏
SEGA = SEGB = SEGC = SEGD = SEGE = SEGF = SEGG = SEGP = 1;
return;
}
void interrupt_handler(void) interrupt 1 {
// INT1 外部中断,显示时间
SEGA = SEGMENT[HOUR / 10];
SEGB = SEGMENT[HOUR % 10];
SEGC = SEGMENT[MINUTE / 10];
SEGD = SEGMENT[MINUTE % 10];
SEGE = SEGMENT[SECOND / 10];
SEGF = SEGMENT[SECOND % 10];
SEGG = 0x40; // 显示冒号
SEGP = 0;
return;
}
// 主程序入口
void main() {
// 初始化计时器
TMOD = 0x01;
TH0 = 0xFC;
TL0 = 0x18;
TR0 = 1;
// 初始化外部中断
IT0 = IT1 = 1;
EX0 = EX1 = EA = 1;
while (1) {
// 更新计时器计数值
if (TF0 == 1) {
TF0 = 0;
TH0 = 0xFC;
TL0 = 0x18;
SECOND++;
if (SECOND >= 60) {
SECOND = 0;
MINUTE++;
if (MINUTE >= 60) {
MINUTE = 0;
HOUR++;
if (HOUR >= 24) {
HOUR = 0;
}
}
}
}
}
}
该代码中,我们首先定义了 8 个 GPIO 端口用于控制 LED 数码管的显示。其中,SEGA~SEGG 分别连接到数码管的 a-g 端口,用于显示数字;SEGP 连接到数码管的 DP 端口,用于显示冒号。
#include<iostream>
#include<time.h>
#include<iomanip>
#include<unistd.h>
using namespace std;
class Clock
{
public:
Clock()
{
time_t t=time(NULL);
struct tm ti=*localtime(&t);//struct tm *__cdecl localtime(const time_t *_Time)
hour=ti.tm_hour;
min=ti.tm_min;
sec=ti.tm_sec;
}
void run()
{
while(1)
{
show();//完成显示
tick();//完成数据更新
}
}
private:
void show()
{
system("cls");
cout<<setw(2)<<setfill('0')<<hour<<":";
cout<<setw(2)<<setfill('0')<<min<<":";
cout<<setw(2)<<setfill('0')<<sec;
}
void tick()
{
sleep(1);
if(++sec==60){
sec=0;
min++;
if(++min==60){
min=0;
hour++;
if(++hour==24){
hour=0;
}
}
}
}
int hour;
int min;
int sec;
};
#include <reg51.h>
#define uchar unsigned char
uchar code digit_table[] = { // 数码管显示表,0~9对应的数码段
0xC0, 0xF9, 0xA4, 0xB0, 0x99,
0x92, 0x82, 0xF8, 0x80, 0x90
};
uchar dig_buf[6] = {0, 0, 0, 0, 0, 0}; // 数码管缓存区,存储时分秒,每2个元素存储一组
uchar dig_idx = 0; // 当前显示的数码管组索引
uchar flash_flag = 0; // 闪烁标志
uchar show_flag = 1; // 显示标志
uchar clear_flag = 0; // 清屏标志
// 定义外部中断0的中断处理函数
void ext0_isr() interrupt 0 {
clear_flag = 1; // 设置清屏标志
}
// 定义外部中断1的中断处理函数
void ext1_isr() interrupt 2 {
show_flag = !show_flag; // 切换显示标志
}
// 延时函数
void delayms(uchar ms) {
uchar i, j;
for(i = 0; i < ms; i++) {
for(j = 0; j < 125; j++);
}
}
// 更新数码管缓存区
void update_dig_buf() {
uchar i, j, t = 0;
for(i = 0; i < 6; i += 2) {
dig_buf[i] = t % 10; // 计算个位数
dig_buf[i+1] = t / 10; // 计算十位数
t++; // 更新时间
}
}
// 刷新数码管显示
void refresh_dig() {
uchar digit = digit_table[dig_buf[dig_idx]]; // 获取需显示的数码段
if(dig_idx < 4 && flash_flag == 0 && show_flag == 1) { // 判断是否需要闪烁
digit = 0x00; // 不显示该数码段
}
P2 = digit; // 输出数码段
P0 = 0x00; // 输出段选信号,让刚才输出的数码段显示在数码管上
P0 = 0xFF; // 关闭段选信号,等待输出下一个数码段
dig_idx++; // 切换到下一个数码管组
if(dig_idx >= 6) { // 如果已显示了6个数码管组,说明需要更新时间
dig_idx = 0; // 重置数码管组索引
flash_flag = !flash_flag; // 切换闪烁标志,用于实现数码段的闪烁效果
update_dig_buf(); // 更新数码管缓存区
}
}
// 初始化外部中断0和1
void init_ext() {
EX0 = 1; // 允许外部中断0
IT0 = 1; // 设置外部中断0为下降沿触发
EX1 = 1; // 允许外部中断1
IT1 = 1; // 设置外部中断1为下降沿触发
EA = 1; // 允许总中断
}
void main() {
while(1) {
refresh_dig(); // 刷新数码管显示
delayms(5); // 设定一个适当的延时,以实现较稳定的显示效果
if(clear_flag == 1) { // 处理清屏标志
dig_idx = 0; // 重置数码管组索引
for(int i = 0; i < 6; i++) {
dig_buf[i] = 0; // 将数码管缓存区清零
}
clear_flag = 0; // 清除清屏标志
}
}
}