电子钟实验报告
71117317 胡昱
一、 实验名称
模拟电子钟
二、 实验内容
用动态显示方式,利用单片机控制 6 位一体数码管,使其两位一组,分别代
表时、分、秒。设置六个按键,实现调整设置时间的功能,分别是:
1.设置按键,点击之后进入设置状态,可以设定最左边的数码管开始闪烁,
其余五位不亮;
2.左移按键,点击后闪烁的数码管向左移动一个;
3.右移按键,点击后闪烁的数码管向右移动一个;
4.加 1 键,点击之后当前闪烁的数码管数值加一;
5.减 1 键,点击后当前闪烁的数码管内数值减一;
6.运行按键,点击后设置完成,时间开始运行。
每次调整时间的时候只有一个数码管闪烁,可以增加或者减少其中数值,其
他的数码管不亮,通过左移右移减一加一,依次设置每一个数码管内部的数值。
三、 设计思路
硬件部分:所用到的硬件有 7SEG-MPX6-CC-BLUE、9C08052A1000FKHFT、BUTTON、
MSP430F249、RX8 以及 POWER 等。其中,6 位一体数码管的 ABCDEFG 和 DP 引脚接
MSP430F249 的 P4 口,12345 和 G 引脚接 MSP430F249 的 P5 口。6 个 BUTTON 分别
接在 P1.0 至 P1.5,未按下时为高电平,按下后为低电平。
软件部分:(1)计时部分:为了实现计时,我采用了定时器中断的方法。初
始化时设置定时器 TA0 的 CCR0 为 819,采用的时钟源为 SMCLK,每当执行 18 次
中断后秒数加一,同时判断是否要进位。(2)动态显示部分:由于硬件的特性,
在任意时刻,P5.0 至 P5.7 中只有一个口能够输出低电平,即只能有 1 位数码管
被点亮。因此需要用到人眼的视觉暂存效应,即在 1 秒内循环扫描 6 位数码管的
次数必须大于 25 次,就可以模拟出持续点亮的效果。所以在 main()函数里,
dislpay()函数会一直被执行。同时,为了保证数码管的显示亮度,每位数码管
点亮的持续时间应相同且在 1ms 左右,所以 display()函数最后进行了 1ms 的延
时。另外,为了实现设置状态下设置位的闪烁,我在 displayWhenSet()函数里
面让设置位对应的数码管在 25 次扫描循环中只显示 1 次。(3)设置按键部分:
这部分我是使用中断+查询的方式实现的。SET 按键连接的是 P1.0 口,所以我开
启了 P1.0 口的中断。SET 按键按下后会进入到 P1 口中断服务程序,即 Port1_ISR()
函数。在 Port1_ISR()中,持续监听 P1.1 口至 P1.5 口。若 START 键按下,则会
跳出持续监听,结束中断服务程序。若其他按键按下,则会做出相应的处理。并
且,利用 MSP430 系列默认不能进行中断嵌套的特性,进入设置模式后定时器 TA0
的中断会被屏蔽掉。
四、 电路图及源代码
电路图:
源代码:
1. #include "msp430f249.h"
2.
3. /*****************************************软件延时,主频
1M*******************/
4. #define CPU_F1 ((double)1000000)
5. #define delay_us1M(x) __delay_cycles((long)(CPU_F1*(double)x/1000000.0))
6. #define delay_ms1M(x) __delay_cycles((long)(CPU_F1*(double)x/1000.0))
7. /****************************************************************************
/
8.
9. //全局变量
10. //共阴极数码管段码表
11. unsigned char const Led_Tab1[]={0x3f,0x06,0x5b,0x4f,
0x66,0x6d,0x7d,0x07,
12.
13.
0x7f,0x6f,0x77,0x7c,
14.
0x39,0x5e,0x79,0x71};
15. unsigned int time_counter = 0;
16. unsigned int time[3];//时、分、秒
17. unsigned char dis_buff[6];//显示缓冲区,存放要显示的 6 个字符的段码值
18.
19. //函数
20. //扫描显示函数
21. void display(void)
22. {
23.
24.
25.
26.
27.
28.
29.
30.
31. }
32.
33. //设置模式显示函数
34. void displayWhenSet(int flag)
35. {
36.
37.
38.
39.
40.
41.
static unsigned int i = 0;
P5OUT = 0xff;
P4OUT = 80;
P4OUT = Led_Tab1[dis_buff[i]];// 时间值送显示缓冲区函数
P5OUT = ~(1<
flash = 0;
delay_ms1M(1);// 增加点亮时间,让设置位更亮一点
}
else
{
i = 0;
//每 25 次显示中只显示 1 次设置位
if(i == flag)
{
}
}
delay_ms1M(1);
++flash;
if(++i == 6)
i = 0;
if(flash == 25)
{
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59. }
60.
61. //时间值送显示缓冲区函数
62. void time_to_disbuffer(void)
63. {
64.
65.
66.
67.
68.
69.
70. }
71.
72. main()
73. {
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
//初始化时间
time[2] = 13;
time[1] = 14;
dis_buff[0] = time[2]/10;// 小时
dis_buff[1] = time[2]%10;
dis_buff[2] = time[1]/10;// 分钟
dis_buff[3] = time[1]%10;
dis_buff[4] = time[0]/10;// 秒
dis_buff[5] = time[0]%10;
WDTCTL = WDTPW + WDTHOLD;// 关看门狗
P4DIR = 0xff;// 段码端口初始化
P5DIR = 0xff;// 位选端口初始化
//初始化定时器 A
TA0CCTL0 = CCIE;// CCRO 中断允许
TA0CCR0 = 819; ;// 定时时间间隔 10ms
TA0CTL = TASSEL_2 + MC_2 + TACLR;// 时钟源选 SMCLK,增计数模式,清零计数器
// 清除 P1.0 口中断标志位
// P1.0 口中断使能
_EINT();// 打开中断,响应按键
display();//显示扫描
time_counter++;
time[0] = 0;
time_to_disbuffer();
//显示时间
while(1)
{
}
//初始化中断
P1IFG &= ~BIT0;
P1IE |= BIT0;
86.
87.
88.
89.
90.
91.
92.
93.
94.
95.
96.
97.
98.
99.
100.}
101.
102.// TA0 中断服务程序
103.#pragma vector=TIMER0_A0_VECTOR
104.__interrupt void TIMER0_A0_ISR(void)
105.{
106.
107.
108.
109.
110.
111.
112.
113.
114.
115.
116.
117.
118.
119.
120.
121.
122.
123.
124.
125.
126.
127.
128.}
129.
time[0] = 0;
if(++time[1] >= 60)
{
//时间流逝
if(++time[0] >= 60)
{
time[1] = 0;
if(++time[2] >= 24)
time[2] = 0;
if(time_counter == 18)
{
//归零
time_counter = 0;
}
}
}
//修改显示缓冲区
time_to_disbuffer();
130.// P1 口中断服务程序
131.#pragma vector=PORT1_VECTOR
132.__interrupt void Port1_ISR(void)
133.{
134.
135.
136.
int record = P1IFG;
//0 表示时的十位,1 表示时的个位,2 表示分的十位,3 表示分的个位,4 表示秒的十位,5
表示秒的个位
137.
138.
139.
140.
141.
142.
143.
144.
145.
146.
147.
148.
149.
150.
151.
152.
153.
154.
155.
156.
157.
158.
159.
160.
161.
162.
163.
164.
165.
166.
167.
168.
169.
170.
171.
172.
int flag = 0;
while(1)
{
if(P1IFG & BIT5)
{
//重新开始运行
break;
}
else if(P1IFG & BIT1)
{
//加 1
switch(flag)
{
case 0:
time[2] += 10;
break;
case 1:
time[2] += 1;
break;
case 2:
time[1] += 10;
break;
case 3:
time[1] += 1;
break;
case 4:
time[0] += 10;
break;
case 5:
time[0] += 1;
173.
174.
175.
176.
177.
178.
179.
180.
181.
182.
183.
184.
185.
186.
187.
188.
189.
190.
191.
192.
193.
194.
195.
196.
197.
198.
199.
200.
201.
202.
203.
204.
205.
206.
207.
208.
209.
210.
211.
212.
213.
214.
215.
216.
break;
default:
//重新置 0
flag = 0;
break;
}
//测试是否合法时间,非法的话进行进位操作
//检测秒
if(time[0] >= 60)
{
time[0] -= 60;
if(++time[1] >= 60)
{
time[1] = 0;
if(++time[2] >= 24)
time[2] = 0;
}
}
//检测分钟
if(time[1] >= 60)
{
time[1] -= 60;
if(++time[2] >= 24)
time[2] = 0;
}
//检测小时
if(time[2] >= 24)
{
if(time[2] == 24)
time[2] = 0;
else
time[2] -= 30;
}
}
else if(P1IFG & BIT2)
{
//减 1
switch(flag)
{
case 0:
if(time[2] >= 10)
time[2] -= 10;
217.
218.
219.
220.
221.
222.
223.
224.
225.
226.
227.
228.
229.
230.
231.
232.
233.
234.
235.
236.
237.
238.
239.
240.
241.
242.
243.
244.
245.
246.
247.
248.
249.
250.
251.
252.
253.
254.
255.
256.
257.
258.
259.
260.
else
time[2] += 14;
break;
case 1:
if(time[2] == 0)
time[2] = 23;
else
time[2] -= 1;
break;
case 2:
if(time[1] >= 10)
time[1] -= 10;
else
{
time[1] += 50;
//借位
if(time[2] == 0)
time[2] = 23;
else
--time[2];
}
break;
case 3:
if(time[1] == 0)
{
time[1] = 59;
//借位
if(time[2] == 0)
time[2] = 23;
else
--time[2];
}
else
time[1] -= 1;
break;
case 4:
if(time[0] >= 10)
time[0] -= 10;
else
{