建材秒知道
登录
建材号 > 设计 > 正文

51单片机课程设计

快乐的滑板
超级的月光
2023-01-25 16:10:32

51单片机课程设计

最佳答案
刻苦的羊
无聊的长颈鹿
2026-05-07 20:27:15

这样的课题设计,我个人建议,还是自己编程练习练习的好,这对以后出来工作是很有帮助的!!如果实在真的想不出办法来解决,来找找我也是可以的.不过我是用C语言来编写程序的,而不是汇编语言写的

最新回答
坚定的眼神
霸气的糖豆
2026-05-07 20:27:15

单片机的外部结构:

1. DIP40双列直插; 5

2. P0,P1,P2,P3四个8位准双向I/O引脚;(作为I/O输入时,要先输出高电平)

3. 电源VCC(PIN40)和地线GND(PIN20);

4. 高电平复位RESET(PIN9);(10uF电容接VCC与RESET,即可实现上电复位)

5. 内置振荡电路,外部只要接晶体至X1(PIN18)和X0(PIN19);(频率为主频的12倍)

6. 程序配置EA(PIN31)接高电平VCC;(运行单片机内部ROM中的程序)

7. P3支持第二功能:RXD、TXD、INT0、INT1、T0、T1

单片机内部I/O部件:(所为学习单片机,实际上就是编程控制以下I/O部件,完成指定任务)

1. 四个8位通用I/O端口,对应引脚P0、P1、P2和P3;

2. 两个16位定时计数器;(TMOD,TCON,TL0,TH0,TL1,TH1)

3. 一个串行通信接口;(SCON,SBUF)

4. 一个中断控制器;(IE,IP)

针对AT89C52单片机,头文件AT89x52.h给出了SFR特殊功能寄存器所有端口的定义。

C语言编程基础:

1. 十六进制表示字节0x5a:二进制为01011010B;0x6E为01101110。

2. 如果将一个16位二进数赋给一个8位的字节变量,则自动截断为低8位,而丢掉高8位。

3. ++var表示对变量var先增一;var—表示对变量后减一。

4. x |= 0x0f表示为 x = x | 0x0f

5. TMOD = ( TMOD &0xf0 ) | 0x05表示给变量TMOD的低四位赋值0x5,而不改变TMOD的高四位。

6. While( 1 )表示无限执行该语句,即死循环。语句后的分号表示空循环体,也就是{}

在某引脚输出高电平的编程方法:(比如P1.3(PIN4)引脚)

代码

1. #include <AT89x52.h>//该头文档中有单片机内部资源的符号化定义,其中包含P1.3

2. void main( void ) //void 表示没有输入参数,也没有函数返值,这入单片机运行的复位入口

3. {

4. P1_3 = 1 //给P1_3赋值1,引脚P1.3就能输出高电平VCC

5. While( 1 ) //死循环,相当 LOOP: goto LOOP

6. }

注意:P0的每个引脚要输出高电平时,必须外接上拉电阻(如4K7)至VCC电源。

在某引脚输出低电平的编程方法:(比如P2.7引脚)

代码

1. #include <AT89x52.h>//该头文档中有单片机内部资源的符号化定义,其中包含P2.7

2. void main( void ) //void 表示没有输入参数,也没有函数返值,这入单片机运行的复位入口

3. {

4. P2_7 = 0 //给P2_7赋值0,引脚P2.7就能输出低电平GND

5. While( 1 ) //死循环,相当 LOOP: goto LOOP

6. }

在某引脚输出方波编程方法:(比如P3.1引脚)

代码

1. #include <AT89x52.h>//该头文档中有单片机内部资源的符号化定义,其中包含P3.1

2. void main( void ) //void 表示没有输入参数,也没有函数返值,这入单片机运行的复位入口

3. {

4. While( 1 ) //非零表示真,如果为真则执行下面循环体的语句

5. {

6. P3_1 = 1 //给P3_1赋值1,引脚P3.1就能输出高电平VCC

7. P3_1 = 0 //给P3_1赋值0,引脚P3.1就能输出低电平GND

8. }//由于一直为真,所以不断输出高、低、高、低……,从而形成方波

9. }

将某引脚的输入电平取反后,从另一个引脚输出:( 比如 P0.4 = NOT( P1.1) )

代码

1. #include <AT89x52.h>//该头文档中有单片机内部资源的符号化定义,其中包含P0.4和P1.1

2. void main( void ) //void 表示没有输入参数,也没有函数返值,这入单片机运行的复位入口

3. {

4. P1_1 = 1 //初始化。P1.1作为输入,必须输出高电平

5. While( 1 ) //非零表示真,如果为真则执行下面循环体的语句

6. {

7. if( P1_1 == 1 ) //读取P1.1,就是认为P1.1为输入,如果P1.1输入高电平VCC

8. { P0_4 = 0 } //给P0_4赋值0,引脚P0.4就能输出低电平GND

2008-11-21 10:57 回复

chen33chen

10位粉丝

2楼

9. else //否则P1.1输入为低电平GND

10. //{ P0_4 = 0 } //给P0_4赋值0,引脚P0.4就能输出低电平GND

11. { P0_4 = 1 } //给P0_4赋值1,引脚P0.4就能输出高电平VCC

12. }//由于一直为真,所以不断根据P1.1的输入情况,改变P0.4的输出电平

13. }

将某端口8个引脚输入电平,低四位取反后,从另一个端口8个引脚输出:( 比如 P2 = NOT( P3 ) )

代码

1. #include <AT89x52.h>//该头文档中有单片机内部资源的符号化定义,其中包含P2和P3

2. void main( void ) //void 表示没有输入参数,也没有函数返值,这入单片机运行的复位入口

3. {

4. P3 = 0xff //初始化。P3作为输入,必须输出高电平,同时给P3口的8个引脚输出高电平

5. While( 1 ) //非零表示真,如果为真则执行下面循环体的语句

6. {//取反的方法是异或1,而不取反的方法则是异或0

7. P2 = P3^0x0f //读取P3,就是认为P3为输入,低四位异或者1,即取反,然后输出

8. }//由于一直为真,所以不断将P3取反输出到P2

9. }

注意:一个字节的8位D7、D6至D0,分别输出到P3.7、P3.6至P3.0,比如P3=0x0f,则P3.7、P3.6、P3.5、P3.4四个引脚都输出低电平,而P3.3、P3.2、P3.1、P3.0四个引脚都输出高电平。同样,输入一个端口P2,即是将P2.7、P2.6至P2.0,读入到一个字节的8位D7、D6至D0。

第一节:单数码管按键显示

单片机最小系统的硬件原理接线图:

1. 接电源:VCC(PIN40)、GND(PIN20)。加接退耦电容0.1uF

2. 接晶体:X1(PIN18)、X2(PIN19)。注意标出晶体频率(选用12MHz),还有辅助电容30pF

3. 接复位:RES(PIN9)。接上电复位电路,以及手动复位电路,分析复位工作原理

4. 接配置:EA(PIN31)。说明原因。

发光二极的控制:单片机I/O输出

将一发光二极管LED的正极(阳极)接P1.1,LED的负极(阴极)接地GND。只要P1.1输出高电平VCC,LED就正向导通(导通时LED上的压降大于1V),有电流流过LED,至发LED发亮。实际上由于P1.1高电平输出电阻为10K,起到输出限流的作用,所以流过LED的电流小于(5V-1V)/10K = 0.4mA。只要P1.1输出低电平GND,实际小于0.3V,LED就不能导通,结果LED不亮。

开关双键的输入:输入先输出高

一个按键KEY_ON接在P1.6与GND之间,另一个按键KEY_OFF接P1.7与GND之间,按KEY_ON后LED亮,按KEY_OFF后LED灭。同时按下LED半亮,LED保持后松开键的状态,即ON亮OFF灭。

代码

1. #include <at89x52.h>

2. #define LED P1^1 //用符号LED代替P1_1

3. #define KEY_ON P1^6 //用符号KEY_ON代替P1_6

4. #define KEY_OFF P1^7 //用符号KEY_OFF代替P1_7

5. void main( void )//单片机复位后的执行入口,void表示空,无输入参数,无返回值

6. {

7. KEY_ON = 1 //作为输入,首先输出高,接下KEY_ON,P1.6则接地为0,否则输入为1

8. KEY_OFF = 1 //作为输入,首先输出高,接下KEY_OFF,P1.7则接地为0,否则输入为1

9. While( 1 ) //永远为真,所以永远循环执行如下括号内所有语句

10. {

11. if( KEY_ON==0 ) LED=1//是KEY_ON接下,所示P1.1输出高,LED亮

12. if( KEY_OFF==0 ) LED=0//是KEY_OFF接下,所示P1.1输出低,LED灭

13. } //松开键后,都不给LED赋值,所以LED保持最后按键状态。

14. //同时按下时,LED不断亮灭,各占一半时间,交替频率很快,由于人眼惯性,看上去为半亮态

15. }

数码管的接法和驱动原理

一支七段数码管实际由8个发光二极管构成,其中7个组形构成数字8的七段笔画,所以称为七段数码管,而余下的1个发光二极管作为小数点。作为习惯,分别给8个发光二极管标上记号:a,b,c,d,e,f,g,h。对应8的顶上一画,按顺时针方向排,中间一画为g,小数点为h。

我们通常又将各二极与一个字节的8位对应,a(D0),b(D1),c(D2),d(D3),e(D4),f(D5),g(D6),h(D7),相应8个发光二极管正好与单片机一个端口Pn的8个引脚连接,这样单片机就可以通过引脚输出高低电平控制8个发光二极的亮与灭,从而显示各种数字和符号;对应字节,引脚接法为:a(Pn.0),b(Pn.1),c(Pn.2),d(Pn.3),e(Pn.4),f(Pn.5),g(Pn.6),h(Pn.7)。

如果将8个发光二极管的负极(阴极)内接在一起,作为数码管的一个引脚,这种数码管则被称为共阴数码管,共同的引脚则称为共阴极,8个正极则为段极。否则,如果是将正极(阳极)内接在一起引出的,则称为共阳数码管,共同的引脚则称为共阳极,8个负极则为段极。

以单支共阴数码管为例,可将段极接到某端口Pn,共阴极接GND,则可编写出对应十六进制码的七段码表字节数据

幽默的帆布鞋
愤怒的秋天
2026-05-07 20:27:15

刚给一个兄弟做的

KEYVAL EQU 30H

KEYTM EQU 31H

KEYSCAN EQU 32H

DAT EQU 33H

SCANLED EQU 39H

CLK EQU 77H

SEC EQU 78H

MIN EQU 79H

HOUR EQU 7AH

PAUSE BIT 00H

DOT BIT 01H

ORG 0000H

LJMP MAIN

ORG 000BH

LJMP T0ISR 50ms定时

ORG 001BH

LJMP T1ISR 扫描显示

ORG 0030H

MAIN:

MOV SP,#5FH

MOV TMOD,#11H

MOV TH0,#03CH

MOV TL0,#0B0H

MOV TH1,#0ECH

MOV TL1,#078H

MOV KEYVAL,#0

MOV SCANLED,#0

MOV 33H,#10H

MOV 34H,#10H

MOV 35H,#10H

MOV 36H,#10H

MOV 37H,#10H

MOV 38H,#10H

MOV SEC,#0

MOV MIN,#0

MOV HOUR,#0

MOV CLK,#0

CLR PAUSE

SETB EA

SETB ET1

SETB TR1

LOOP:

LCALL KEYSEL

MOV A,KEYVAL

CJNE A,#0FFH,LOOP1

SJMP LOOP

LOOP1:

CJNE A,#10,LOOP2 “ON”启动

SETB TR0

SETB ET0

SETB PAUSE

SJMP LOOP

LOOP2:

CJNE A,#11,LOOP3 “=”清零

MOV SEC,#0

MOV MIN,#0

MOV HOUR,#0

LCALL DISCHG

SJMP LOOP

LOOP3:

CJNE A,#15,LOOP4 “+”暂停

CLR TR0

CLR ET0

CLR PAUSE

SJMP LOOP

LOOP4:

CJNE A,#14,LOOP5 “-”清显示暂停

MOV 33H,#10H

MOV 34H,#10H

MOV 35H,#10H

MOV 36H,#10H

MOV 37H,#10H

MOV 38H,#10H

CLR TR0

CLR ET0

CLR PAUSE

SJMP LOOP

LOOP5:

CJNE A,#10,LOOP6 数字键

LOOP6:

JC LOOP7

LJMP LOOP

LOOP7:

JNB PAUSE,LOOP8 暂停状态可以输入数字键

LJMP LOOP

LOOP8:

MOV 33H,34H

MOV 34H,35H

MOV 35H,36H

MOV 36H,37H

MOV 37H,38H

MOV 38H,KEYVAL

MOV A,34H

SWAP A

ORL A,33H

LCALL BCDH

MOV HOUR,A

MOV A,36H

SWAP A

ORL A,35H

LCALL BCDH

MOV MIN,A

MOV A,38H

SWAP A

ORL A,37H

LCALL BCDH

MOV SEC,A

LJMP LOOP

------------------

BCD转换为十六进制

BCDH:

MOV B,#10H

DIV AB

MOV R7,B

MOV B,#10

MUL AB

ADD A,R7

RET

------------------

十六进制转换为BCD

HBCD:

MOV B,#10

DIV AB

SWAP A

ORL A,B

RET

------------------

KEYSEL:

MOV KEYVAL,#0

MOV KEYSCAN,#0EFH

LCALL GETKEY

MOV A,KEYTM

JZ KEYS1

MOV KEYVAL,A

SJMP KEYRTN

KEYS1:

MOV KEYSCAN,#0DFH

LCALL GETKEY

MOV A,KEYTM

JZ KEYS2

CLR C

ADD A,#4

MOV KEYVAL,A

SJMP KEYRTN

KEYS2:

MOV KEYSCAN,#0BFH

LCALL GETKEY

MOV A,KEYTM

JZ KEYS3

CLR C

ADD A,#8

MOV KEYVAL,A

SJMP KEYRTN

KEYS3:

MOV KEYSCAN,#7FH

LCALL GETKEY

MOV A,KEYTM

JZ KEYRTN

CLR C

ADD A,#12

MOV KEYVAL,A

KEYRTN:

LCALL CHGKEY

RET

--------------------

GETKEY:

MOV KEYTM,#0

MOV A,KEYSCAN

MOV P3,A

NOP

MOV A,P3

ANL A,#0FH

XRL A,#0FH

JZ NOKEY

MOV R2,#10

LCALL DELAY

MOV A,P3

ANL A,#0FH

XRL A,#0FH

JZ NOKEY

MOV A,P3

ANL A,#0FH

MOV R7,A

SF:

MOV A,P3

ANL A,#0FH

XRL A,#0FH

JNZ SF

MOV A,R7

CJNE A,#0EH,NK1

MOV KEYTM,#1

SJMP NOKEY

NK1:

CJNE A,#0DH,NK2

MOV KEYTM,#2

SJMP NOKEY

NK2:

CJNE A,#0BH,NK3

MOV KEYTM,#3

SJMP NOKEY

NK3:

CJNE A,#07H,NOKEY

MOV KEYTM,#4

NOKEY: RET

--------------------

DELAY:

MOV R3,#50

DELAY1:

MOV R4,#100

DJNZ R4,$

DJNZ R3,DELAY1

DJNZ R2,DELAY

RET

--------------------

T0ISR:

PUSH ACC

CLR TR0

MOV TH0,#3CH

MOV TL0,#0B0H

SETB TR0

INC CLK

MOV A,CLK

CJNE A,#20,T0ISRE

MOV CLK,#0

INC SEC

MOV A,SEC

CJNE A,#60,T0ISRE

MOV SEC,#0

INC MIN

MOV A,MIN

CJNE A,#60,T0ISRE

MOV MIN,#0

INC HOUR

MOV A,HOUR

CJNE A,#24,T0ISRE

MOV SEC,#0

MOV MIN,#0

MOV HOUR,#0

T0ISRE:

LCALL DISCHG

POP ACC

RETI

--------------------

DISCHG:

MOV A,HOUR

LCALL HBCD

PUSH ACC

ANL A,#0FH

MOV 34H,A

POP ACC

ANL A,#0F0H

SWAP A

MOV 33H,A

MOV A,MIN

LCALL HBCD

PUSH ACC

ANL A,#0FH

MOV 36H,A

POP ACC

ANL A,#0F0H

SWAP A

MOV 35H,A

MOV A,SEC

LCALL HBCD

PUSH ACC

ANL A,#0FH

MOV 38H,A

POP ACC

ANL A,#0F0H

SWAP A

MOV 37H,A

RET

--------------------

T1ISR:

PUSH ACC

CLR TR1

MOV TH1,#0ECH

MOV TL1,#78H

SETB TR1

MOV DPTR,#LEDTAB

T100:

MOV R0,#DAT

MOV A,SCANLED

ADD A,R0

MOV R0,A

MOV A,SCANLED

JNZ T101

MOV P2,#01H

CLR DOT

SJMP T1DIS

T101:

DEC A

JNZ T102

MOV P2,#02H

SETB DOT

SJMP T1DIS

T102:

DEC A

JNZ T103

MOV P2,#04H

CLR DOT

SJMP T1DIS

T103:

DEC A

JNZ T104

MOV P2,#08H

SETB DOT

SJMP T1DIS

T104:

DEC A

JNZ T105

MOV P2,#10H

CLR DOT

SJMP T1DIS

T105:

MOV P2,#20H

CLR DOT

T1DIS:

MOV A,@R0

MOVC A,@A+DPTR

JNB DOT,T1DIS1

ORL A,#01H

T1DIS1:

CPL A

MOV P0,A

INC SCANLED

MOV A,SCANLED

CJNE A,#6,T1END

MOV SCANLED,#0

T1END:

POP ACC

RETI

--------------------

CHGKEY:

MOV A,KEYVAL

JZ KV16

DEC A

JNZ KV01

MOV KEYVAL,#7

RET

KV01:

DEC A

JNZ KV02

MOV KEYVAL,#4

RET

KV02:

DEC A

JNZ KV03

MOV KEYVAL,#1

RET

KV03:

DEC A

JNZ KV04

MOV KEYVAL,#10

RET

KV04:

DEC A

JNZ KV05

MOV KEYVAL,#8

RET

KV05:

DEC A

JNZ KV06

MOV KEYVAL,#5

RET

KV06:

DEC A

JNZ KV07

MOV KEYVAL,#2

RET

KV07:

DEC A

JNZ KV08

MOV KEYVAL,#0

RET

KV08:

DEC A

JNZ KV09

MOV KEYVAL,#9

RET

KV09:

DEC A

JNZ KV10

MOV KEYVAL,#6

RET

KV10:

DEC A

JNZ KV11

MOV KEYVAL,#3

RET

KV11:

DEC A

JNZ KV12

MOV KEYVAL,#11

RET

KV12:

DEC A

JNZ KV13

MOV KEYVAL,#12

RET

KV13:

DEC A

JNZ KV14

MOV KEYVAL,#13

RET

KV14:

DEC A

JNZ KV15

MOV KEYVAL,#14

RET

KV15:

DEC A

JNZ KV16

MOV KEYVAL,#15

RET

KV16:

MOV KEYVAL,#0FFH

RET

--------------------

LEDTAB: DB 0FCH "0" 00H

DB 60H "1" 01H

DB 0DAH "2" 02H

DB 0F2H "3" 03H

DB 66H "4" 04H

DB 0B6H "5" 05H

DB 0BEH "6" 06H

DB 0E0H "7" 07H

DB 0FEH "8" 08H

DB 0F6H "9" 09H

DB 0EEH "A" 0AH

DB 3EH "B" 0BH

DB 9CH "C" 0CH

DB 7AH "D" 0DH

DB 9EH "E" 0EH

DB 8EH "F" 0FH

DB 00H " " 10H

--------------------

END

怕孤独的宝贝
饱满的乌龟
2026-05-07 20:27:15

哈哈 有个1602显示的 不过程序太长 贴不上 给你个数码管的吧 不行再联系

1302.c

#include<DS1302.h>

#include<key.h>

uchar bit_ser[]={0xfe,0xfd,0xfb,0xf7,0xef,0xdf}

uchar seven_seg[] = {0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90}

void timer0_init(void)  //T0初始化函数,用于时间的动态显示

{

TMOD = 0x21

TL0 = (65536-5000) % 256

TH0 = (65536-5000) / 256

EA = 1

ET0 = 1

TR0 = 1

}

void timer0_isr(void) interrupt 1  //T0中断处理函数

{

char flag   //flag用于表示调整时闪烁的亮或灭

TR0 = 0

TL0 = (65536-5000) % 256

TH0 = (65536-5000) / 256

TR0 = 1

flag = x / 100 * 0xff //设置闪烁标志,如果x大于100则flag为0xff,小于100则为0x00

x++

if(x > 200)

x = 0

switch(i)

{

case 0:

P2 = bit_ser[0]

if(setflag == 3)  //根据setflag的值判断当前位是否需要闪烁

P0 = flag | seven_seg[dis_buffer[0]]

else

P0 = seven_seg[dis_buffer[0]]

break

case 1:

P2 = bit_ser[1]

if(setflag == 3)

P0 =flag | seven_seg[dis_buffer[1]]

else

P0 =seven_seg[dis_buffer[1]]

break

case 2:

P2 = bit_ser[2]

if(setflag == 2)

P0 =flag | seven_seg[dis_buffer[2]]

else

P0 =seven_seg[dis_buffer[2]]

break

case 3:

P2 = bit_ser[3]

if(setflag == 2)

P0 =flag | seven_seg[dis_buffer[3]]

else

P0 =seven_seg[dis_buffer[3]]

break

case 4:

P2 = bit_ser[4]

if(setflag == 1)

P0 =flag | seven_seg[dis_buffer[4]]

else

P0 =seven_seg[dis_buffer[4]]

break

case 5:

P2 = bit_ser[5]

if(setflag == 1)

P0 =flag | seven_seg[dis_buffer[5]]

else

P0 =seven_seg[dis_buffer[5]]

break

}

i++

if(i >= 6)

{

i = 0

if(j == 10)

{

j = 0

if(setflag == 0)

DS1302_GetTime(&Time) //如果setflag是0,就从1302中读出时间,因为setflag不是0时,说明处于调整状态,不需要读时间

dis_buffer[5] = Time.Second % 10 //把当前时间放入显示缓冲区

dis_buffer[4] = Time.Second / 10

dis_buffer[3] = Time.Minute % 10

dis_buffer[2] = Time.Minute / 10

dis_buffer[1] = Time.Hour % 10

dis_buffer[0] = Time.Hour / 10

}

j++

}

}

void main()

{

Initial_DS1302(Time)

timer0_init()

while(1)

{

set_down()

timer_down()

up_down()

down_down()

beepflag_down()

if(setflag == 0 && Time.Hour == romhour && Time.Minute == romminute && Beepflag == 1) //判断蜂鸣器是否要响

Beep = !Beep

}

}

//key.c

#include<reg51.h>

#define uchar unsigned char

#define uint unsigned int

uchar i = 0,j = 0,x = 0,setflag,flag_set,flag_timer   //setflag用来表示调整的位置,flag_set和flag_timer分别表示当前处于调整状态还是定时状态

SYSTEMTIME Time={0,20,15,3,30,6,10}    //系统时间的初始值2010年6月30日星期三,15时20分0秒

char dis_buffer[6]    //存放显示数据的缓冲区

sbit Beep_flag = P3^2    //蜂鸣器的接口

sbit key_timer = P3^4    //定时按钮

sbit key_set = P3^5    //调整按钮

sbit key_up = P3^6    //增加按钮

sbit key_down = P3^7    //减小按钮

char romhour,romminute,romsec    //分别存放定时的时,分,秒

bit Beepflag    //标记闹钟是否开启

//延时函数

void delays(uchar x)

{

while(x) x--

}

//设置键的处理函数

void set()

{

setflag ++

flag_set = 1

if(setflag >= 4)

{

setflag = 0

flag_set = 0

Initial_DS1302(Time)

}

}

//定时间的处理函数

void timer()

{

setflag ++

flag_timer = 1

if(setflag == 1)

{

Time.Hour = romhour

Time.Minute = romminute

Time.Second = romsec

}

else if(setflag >= 4)

{

setflag = 0

flag_timer = 0

romhour = Time.Hour

romminute = Time.Minute

romsec = Time.Second

}

}

//增加键的处理函数

void up()

{

switch(setflag)

{

case 0:

break

case 1:

Time.Second ++

if(Time.Second >= 60)

Time.Second = 0

break

case 2:

Time.Minute ++

if(Time.Minute >= 60)

Time.Minute = 0

break

case 3:

Time.Hour ++

if(Time.Hour >= 24)

Time.Hour = 0

break

}

}

//减小键的处理函数

void down()

{

switch(setflag)

{

case 0:

break

case 1:

Time.Second --

if(Time.Second < 0)

Time.Second = 59

break

case 2:

Time.Minute --

if(Time.Minute < 0)

Time.Minute = 59

break

case 3:

Time.Hour --

if(Time.Hour < 0)

Time.Hour = 23

break

}

}

//设置键的扫描函数

void set_down()

{

if(key_set == 0 && flag_timer == 0)

{

delays(100)

if(key_set == 0)

{

set()

}

while(!key_set)

}

}

//定时键的扫描函数

void timer_down()

{

if(key_timer == 0 && flag_set == 0)

{

delays(100)

if(key_timer == 0)

{

timer()

}

while(!key_timer)

}

}

//增加键的扫描函数

void up_down()

{

if(key_up == 0 && setflag != 0)

{

delays(100)

if(key_up == 0)

{

up()

while(!key_up)

}

}

}

//减少键的处理函数

void down_down()

{

if(key_down == 0 && setflag != 0)

{

delays(100)

if(key_down == 0)

{

down()

while(!key_down)

}

}

}

//定时开关的扫描处理函数

void beepflag_down()

{

if(Beep_flag == 0)

{

delays(100)

{

Beepflag = !Beepflag

while(!Beep_flag)

}

}

}

//ds1302.h

#ifndef _REAL_TIMER_DS1302

#define _REAL_TIMER_DS1302

#include <REG51.h>

sbit  DS1302_CLK = P1^1              //实时时钟时钟线引脚

sbit  DS1302_IO  = P1^2              //实时时钟数据线引脚

sbit  DS1302_RST = P1^3              //实时时钟复位线引脚

sbit  ACC0 = ACC^0

sbit  ACC7 = ACC^7

sbit  Beep = P2^7

typedef struct __SYSTEMTIME__

{   char Second

char Minute

char Hour

char Week

char Day

char Month

char Year

}SYSTEMTIME //定义的时间类型

#define AM(X) X

#define PM(X) (X+12)               // 转成24小时制

#define DS1302_SECOND 0x80          //秒寄存器

#define DS1302_MINUTE 0x82          //分寄存器

#define DS1302_HOUR 0x84

#define DS1302_WEEK 0x8A

#define DS1302_DAY 0x86

#define DS1302_MONTH 0x88

#define DS1302_YEAR 0x8C

#define DS1302_RAM(X) (0xC0+(X)*2)    //用于计算 DS1302_RAM 地址的宏

void DS1302InputByte(unsigned char d)  //实时时钟写入一字节(内部函数)

{   unsigned char i

ACC = d

for(i=8 i>0 i--)

{ DS1302_IO  = ACC0            //相当于汇编中的 RRC

DS1302_CLK = 1

DS1302_CLK = 0                 //发一个高跳变到低的脉冲

ACC = ACC >> 1

}

}

unsigned char DS1302OutputByte(void)  //实时时钟读取一字节(内部函数)

{  unsigned char i

for(i=8 i>0 i--)

{ ACC = ACC >>1          //相当于汇编中的 RRC

ACC7 = DS1302_IO

DS1302_CLK = 1

DS1302_CLK = 0                 //发一个高跳变到低的脉冲

}

return(ACC)

}

void Write1302(unsigned char ucAddr, unsigned char ucDa)//ucAddr: DS1302地址, ucData: 要写的数据

{ DS1302_RST = 0

DS1302_CLK = 0

DS1302_RST = 1

DS1302InputByte(ucAddr)        // 地址,命令

DS1302InputByte(ucDa)        // 写1Byte数据

DS1302_CLK = 1

DS1302_RST = 0                  //RST 0->1->0,CLK 0->1

}

unsigned char Read1302(unsigned char ucAddr) //读取DS1302某地址的数据

{ unsigned char ucData

DS1302_RST = 0

DS1302_CLK = 0

DS1302_RST = 1                      //enable

DS1302InputByte(ucAddr|0x01)        // 地址,命令

ucData = DS1302OutputByte()         // 读1Byte数据

DS1302_CLK = 1                      //RST 0->1->0,CLK 0->1

DS1302_RST = 0

return(ucData)

}

void DS1302_SetProtect(bit flag)        //是否写保护

{ if(flag)

Write1302(0x8E,0x80) //WP=1,不能写入

else

Write1302(0x8E,0x00)//WP=0,可以写入

}

void DS1302_SetTime(unsigned char Address, unsigned char Value)        // 设置时间函数

{ DS1302_SetProtect(0)

Write1302(Address, ((Value/10)<<4 | (Value%10))) //高4位为十位,低4位为个位

DS1302_SetProtect(1)

}

//获取时间函数,从DS1302内读取时间然后存入Time内

void DS1302_GetTime(SYSTEMTIME *Time)

{ unsigned char ReadValue

ReadValue = Read1302(DS1302_SECOND)

Time->Second = ((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F)//转换成10进制的秒

ReadValue = Read1302(DS1302_MINUTE)

Time->Minute = ((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F)

ReadValue = Read1302(DS1302_HOUR)

Time->Hour = ((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F)

ReadValue = Read1302(DS1302_DAY)

Time->Day = ((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F)

ReadValue = Read1302(DS1302_WEEK)

Time->Week = ((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F)

ReadValue = Read1302(DS1302_MONTH)

Time->Month = ((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F)

ReadValue = Read1302(DS1302_YEAR)

Time->Year = ((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F)

}

//利用STime初始化DS1302

void Initial_DS1302(SYSTEMTIME STime)

{ unsigned char Second=Read1302(DS1302_SECOND)

if(Second&0x80)   DS1302_SetTime(DS1302_SECOND,0)  //如果第七为1(表明没有启动), 则启动时钟

DS1302_SetTime(DS1302_SECOND,STime.Second)  //设定起始时间

DS1302_SetTime(DS1302_MINUTE,STime.Minute)

DS1302_SetTime(DS1302_HOUR,STime.Hour)

DS1302_SetTime(DS1302_DAY,STime.Day)

DS1302_SetTime(DS1302_MONTH,STime.Month)

DS1302_SetTime(DS1302_YEAR,STime.Year)

DS1302_SetTime(DS1302_WEEK,STime.Week)

}

#endif

朴素的台灯
聪慧的白猫
2026-05-07 20:27:15
:利用单片机的定时器功能,令十字路口的红绿灯交替点亮和熄灭(用实验箱上的8只发光二极管分成南北、东西两组各4只表示),并且用LED数码管显示时间(实验箱上的8只数码管中,用两端的各2只表示南北、东西两组的计时)

我可以帮你做,提供电路图和源程序

闪闪的墨镜
碧蓝的季节
2026-05-07 20:27:15
想以后从事于单片机,大学中完成这个课程应该是最基本的考验一课程,

我并不推荐用51系列,因为arm m3使用JTAG调试起来更方便一些,其它有带语音存储器带液晶驱动的功能单片机,性价比很高,开发起来也是非常容易,型号很偏资料少,新手只是做课程来学习的就不考虑这些单片机呢,

首先说一下你的硬件上怎么做,这个电路图,参考,郭天祥的(新概念单片机ISD4004语音芯片去画),1602那本书上面都有,键盘,喇叭,书都有了,郭天祥的《十天学会单片机》视频除了ISD系列语音芯片代码没有一句一句讲解外,其它每句都进行了讲解,ISD4004是在他的教程书里面讲的,跟你上面的ISD是一个公司的,都有源代码,做好之后,把驱动调好之后,源码自己复制上去就行了,没有人比天祥一句一句解释的更详细,

考虑系统实现,做8个按键分别对应8个站台,按下1~8中的一个按键播放1~8站台的声音,声音文件让淘宝的店家帮你想录得文件烧录到语言芯片中,声音文件不要想的太复杂,对于程序员来说,录好的声音,只需要调用就好,就相当于调用8个函数那样简单,按键的设计很多种,这个只是最容易理解的一种,

你们所做的这个公交报站系统,在实际项目中只是很小一步很,想贴近于真正开发,就需要增加GPS模块,淘宝上买,也有源代码,公交系统还有一个后台监控程序,用VC++开发一个图形化界面,(ARM9)WinCE系统中图形画,显示公交的站台信息,