十天学会单片机Day1点亮数码管(数码管、外部中断、定时器中断)
2016-03-30 20:59
645 查看
1.引脚定义
P3口各引脚第二功能定义
XTAL1(19脚) XTAL2(18脚):外接时钟引脚。XTAL1为片内震荡电路的输入端,XTAL2为片内震荡电路的输出端。
8051时钟两种方式:①片内时钟震荡,两引脚外接晶振和震荡电容。
②外部时钟方式,XTAL1接地,外部时钟信号从XTAL2脚输入。
RST(9脚):单片机复位引脚。当输入连续两个机器周期以上高电平时为有效。复位后程序计数器PC=0000H,读取第一条指令码。即从头开始执行程序。
ALE(30脚):在没有外部存储器期间,ALE以1/6振荡周期频率输出(6分频),当访问外部存储器时,以1/12振荡周期输出(12分频)。
EA(上划线)(31脚):接高电平时,单片机读取内部程序存储器。接低电平,单片机直接读取外部(ROM)。(板子上直接接高)
P0口(39~32脚):双向8位三态I/O口,早期51芯片内部无上拉电阻,为高阻态,需外部接上拉电阻。
P1口(1~8脚):准双向8位I/O口,之所以称它为"准双向",是因为改口作为输入使用前,要先向该口进行写1操作,有个"准"备过程,称为准双向口。
P2口(21~28脚):准双向8位I/O口。
P3口(10~17脚):准双向8位I/O口。
2.复位电路
![](https://oscdn.geek-share.com/Uploads/Images/Content/202001/25/11b83dd3ee0e0d7505444df8eb862f1f.png)
按键按下,RST=5V,按键时长大于两个时钟周期,则复位。
上电自动复位:上电瞬间,电容充电,之后电容放电,τ = √(RC) >两个时钟周期 ,自动复位。
3.晶振
![](https://oscdn.geek-share.com/Uploads/Images/Content/202001/25/175dc146d76b85b089a6573ce4b74098.png)
非极性电容,上电帮助晶振起振。12M左右 30pf,6M左右20pf。具体参考厂家提供的晶振要求负载电容选值。(Day0有详细介绍)
4.数码管
![](https://oscdn.geek-share.com/Uploads/Images/Content/202001/25/d8bf9d5afac146ab73c83b22d416bde3.png)
![](https://oscdn.geek-share.com/Uploads/Images/Content/202001/25/e9ee92fc095d31bc25633acfdf8b5f84.png)
开发板中用的为共阴极。即WE选信号给低,则导通(WE提供一个GND作用)。
利用74HC573锁存器的锁存功能。(详细见Day0 ⑤锁存器),先控制位选信号P2.7口高,选定哪个数码管,后P2.7低锁存。再控制段选信号P2.6高,亮什么数字后,P2.6低锁存。
![](https://oscdn.geek-share.com/Uploads/Images/Content/202001/25/eb7a48645eb1268dd3e5f6e7743756f9.png)
超级亮,但是别的数码管有淡淡的光,以下进行改进
![](https://oscdn.geek-share.com/Uploads/Images/Content/202001/25/84d36603a5b3f9c7bd1704efc13c82a3.jpg)
接下来是数码管的动态扫描,其实是一个个显示,由于频率太快,人眼无法识别,达到目的。
![](https://oscdn.geek-share.com/Uploads/Images/Content/202001/25/2fcfb15999be8d14ac4f7cd33d2ac7a2.jpg)
5.中断
52单片机共有6个中断源
INT0:外部中断0.由P3.2端口线引入,低电平或下降沿引起。
INT1:外部中断1.由P3.3端口线引入,低电平或下降沿引起。
T0:定时器/计数器0中断,由T0计数器计满回零引起。
T1:定时器/计数器1中断,由T1计数器计满回零引起。
T2:定时器/计数器2中断,由T2计数器计满回零引起。
TI/RI:串行口中断,串行端口完成一帧字符发送/接收后引起。
52单片机中断级别
中断允许寄存器IE (1为开 0为关)
单片机复位时全部清零。可进行位寻址,即可对该寄存器每一位进行单独操作。
只有打开全局开关,其它各位的开关才可以开启。
每个位开关赋值为1则开,赋值为0则关。
使用方法
①整体赋值:IE=0x81;(开启全局中断,打开外部中断0)
②单独赋值:EA=1;EX0=1;(开启全局中断,打开外部中断0)
中断优先级寄存器IP
单片机复位时全部清零。可进行位寻址。
每个位赋值为1,将对应中断定义为高优先级中断;赋值0,则定义为低优先级中断。
在没有设置中断优先级情况下,按照默认中断级别响应中断,设置后,则按设置顺序确定相应的先后顺序。
定时器/计数器工作方式寄存器TMOD
单片机复位时全部清零。不可进行位寻址。
GATE:
GATE = 0 定时器/计数器启动与停止仅受TCON寄存器中TRX(X=0,1)来控制。
当TR0=1,启动定时器T0。
当TR1=1,启动定时器T1。
GATE = 1 定时器/计数器启动与停止由TCON寄存器中TRX(X=0,1)和外部中断引脚(INT0 或 INT1)上的电平状态共同控制。
当INT0引脚为高电平时且TR0置位,TR0=1;启动定时器T0。
当INT1引脚为高电平时且TR1置位,TR1=1;启动定时器T1。
C/T(上划线):定时器模式和计数器模式选择位
C/T=0时为定时模式: 加1计数器对脉冲f进行计数,每来一个脉冲,计数器加1,直到计时器TFx满溢出。
C/T=1时为计数模式: 加1计数器对来自输入引脚T0(P3.4)和T1(P3.5)的外信号脉冲进行计数,每来一个脉冲,计数器加1,直到计时器TFx满溢出。
M1M0:方式选择功能
定时器/计数器的4种工作方式
控制寄存器TCON
单片机复位时全部清零。可进行位寻址。
TF1:定时器1溢出标志位。当定时器1计满溢出时,由硬件使TF1置“1”,并且申请中断。进入中断服务程序后,由硬件自动清“0”,在查询方式下用软件清“0”。
TR1:定时器1运行控制位。由软件清“0”关闭定时器1。当GATE=1,且/INT1为高电平时,TR1置“1”启动定时器1;当GATE=0,TR1置“1”启动定时器1。
TF0:定时器0溢出标志。其功能及操作情况同TF1。
TR0:定时器0运行控制位。其功能及操作情况同TR1。
IE1:外部中断1请求标志位。
IT1:外部中断1触发方式选择位。当IT1=0,为低电平触发方式;当IT1=1,为下降沿触发方式。
IE0:外部中断0请求标志位。
IT0:外部中断0触发方式选择位。 当IT0=0,为低电平触发方式;当IT0=1,为下降沿触发方式。
中断响应条件
①CPU开中断(EA=1)
②此中断允许位为1
③中断源有中断请求
中断服务程序格式
void 函数名() interrupt 中断号 using 工作组
{
}
//using 工作组 指这个中断函数使用单片机内存中4组工作寄存器中哪一组,C51编译器在编译程序时会自动分配工作组,因此最后这句话可以省略不写。
//中断号见前 52单片机中断级别 表格
外部中断
涉及寄存器IE TCON (IP)
![](https://oscdn.geek-share.com/Uploads/Images/Content/202001/25/c4ae54694e9f0dd4c8469e94c158c182.jpg)
中断ing
定时器中断
[b]涉及寄存器IE TMOF TCON (IP) THX TLX (x=0,1)[/b]
定时器中断程序初始化
1.对TMOD赋值,以确定T0和T1的工作方式
2.计算初值,并将初值写入TH0、TL0 或 TH1、TL1
3.中断方式时,则对IE赋值,开发中断
4.使TR0或TR1置位,启动定时器/计数器定时或计数(TCON)
定时器初值问题:
假设时钟频率为12MHZ,12个时钟周期为一个机器周期,那么此时机器周期为1us。计满TH0、TL0需要2^16-1个数,再来一个脉冲计数器溢出,向CPU请求中断。例如要定时50ms
要给TH0和TL0装初值,在初值基础上计数50000后溢出,中断。若要定时1s,则产生20次50ms中断即可。
结论:用定时器方式1是,机器周期为Tcy,定时器产生一次中断时间为t,那么需要计数的个数N= t/Tcy.
THX = (65535 -N) / 256
TLX = (65535 - N) % 256
practice:
59s循环计时。
标号 | 引脚 | 第二功能 | 说明 |
P3.0 | 10 | RXD | 串行输入口 |
P3.1 | 11 | TXD | 串行输出口 |
P3.2 | 12 | INT0(上划线) | 外部中断0 |
P3.3 | 13 | INT1(上划线) | 外部中断1 |
P3.4 | 14 | T0 | 定时器/计数器0 外部输入端 |
P3.5 | 15 | T1 | 定时器/计数器1 外部输入端 |
P3.6 | 16 | WR(上划线) | 外部数据存储器写脉冲 |
P3.7 | 17 | RD(上划线) | 外部数据存储器读脉冲 |
8051时钟两种方式:①片内时钟震荡,两引脚外接晶振和震荡电容。
②外部时钟方式,XTAL1接地,外部时钟信号从XTAL2脚输入。
RST(9脚):单片机复位引脚。当输入连续两个机器周期以上高电平时为有效。复位后程序计数器PC=0000H,读取第一条指令码。即从头开始执行程序。
ALE(30脚):在没有外部存储器期间,ALE以1/6振荡周期频率输出(6分频),当访问外部存储器时,以1/12振荡周期输出(12分频)。
EA(上划线)(31脚):接高电平时,单片机读取内部程序存储器。接低电平,单片机直接读取外部(ROM)。(板子上直接接高)
P0口(39~32脚):双向8位三态I/O口,早期51芯片内部无上拉电阻,为高阻态,需外部接上拉电阻。
P1口(1~8脚):准双向8位I/O口,之所以称它为"准双向",是因为改口作为输入使用前,要先向该口进行写1操作,有个"准"备过程,称为准双向口。
P2口(21~28脚):准双向8位I/O口。
P3口(10~17脚):准双向8位I/O口。
2.复位电路
![](https://oscdn.geek-share.com/Uploads/Images/Content/202001/25/11b83dd3ee0e0d7505444df8eb862f1f.png)
按键按下,RST=5V,按键时长大于两个时钟周期,则复位。
上电自动复位:上电瞬间,电容充电,之后电容放电,τ = √(RC) >两个时钟周期 ,自动复位。
3.晶振
![](https://oscdn.geek-share.com/Uploads/Images/Content/202001/25/175dc146d76b85b089a6573ce4b74098.png)
非极性电容,上电帮助晶振起振。12M左右 30pf,6M左右20pf。具体参考厂家提供的晶振要求负载电容选值。(Day0有详细介绍)
4.数码管
![](https://oscdn.geek-share.com/Uploads/Images/Content/202001/25/d8bf9d5afac146ab73c83b22d416bde3.png)
![](https://oscdn.geek-share.com/Uploads/Images/Content/202001/25/e9ee92fc095d31bc25633acfdf8b5f84.png)
开发板中用的为共阴极。即WE选信号给低,则导通(WE提供一个GND作用)。
利用74HC573锁存器的锁存功能。(详细见Day0 ⑤锁存器),先控制位选信号P2.7口高,选定哪个数码管,后P2.7低锁存。再控制段选信号P2.6高,亮什么数字后,P2.6低锁存。
//共阴极数码管静态显示1 #include <reg52.h> sbit DUAN = P2^6; sbit WE = P2^7; int main() { WE = 1; //打开WE选信号 P0 = 0xDF; //选WE6的数码管,给低,其余给高 WE = 0; //关闭WE选信号 DUAN = 1; //打开段选信号 P0 = 0x06; //亮1,即bc接高,其余低 DUAN = 0; //关闭段选信号 return 0; }
![](https://oscdn.geek-share.com/Uploads/Images/Content/202001/25/eb7a48645eb1268dd3e5f6e7743756f9.png)
超级亮,但是别的数码管有淡淡的光,以下进行改进
//共阴极数码管静态显示1 防干扰 #include <reg52.h> sbit DUAN = P2^6; sbit WE = P2^7; int main() { WE = 1; P0 = 0xDF; WE = 0; P0 = 0xFF; //关闭所有显示,防止打开段选后发生混乱 DUAN = 1; P0 = 0x06; DUAN = 0; P0 = 0xFF; //关闭所有显示,防止打开位选后发生混乱 return 0; }
![](https://oscdn.geek-share.com/Uploads/Images/Content/202001/25/84d36603a5b3f9c7bd1704efc13c82a3.jpg)
接下来是数码管的动态扫描,其实是一个个显示,由于频率太快,人眼无法识别,达到目的。
//共阴极数码管动态显示 #include <reg52.h> sbit DUAN = P2^6; sbit WE = P2^7; unsigned char DuanTable[] = {0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07, 0x7F,0x6F,0x77,0x7C,0x39,0x5E,0x79,0x71}; unsigned char WeTable[] = {0xFE,0xFD,0xFB,0xF7,0xEF,0xDF}; void delayms(unsigned int n); int main() { unsigned int i = 0; while(1) { for(i = 0; i < 6; i++) { DUAN = 1; P0 = DuanTable[i+1]; DUAN = 0; P0 = 0xFF; WE = 1; P0 = WeTable[i]; WE = 0; P0 = 0xFF; delayms(1); } } return 0; } void delayms(unsigned int n) //误差 -0.651041666667us { unsigned char a,b; unsigned int i; for(i = 0; i < n; i++) { for(b=4;b>0;b--) for(a=113;a>0;a--); } }
![](https://oscdn.geek-share.com/Uploads/Images/Content/202001/25/2fcfb15999be8d14ac4f7cd33d2ac7a2.jpg)
5.中断
52单片机共有6个中断源
INT0:外部中断0.由P3.2端口线引入,低电平或下降沿引起。
INT1:外部中断1.由P3.3端口线引入,低电平或下降沿引起。
T0:定时器/计数器0中断,由T0计数器计满回零引起。
T1:定时器/计数器1中断,由T1计数器计满回零引起。
T2:定时器/计数器2中断,由T2计数器计满回零引起。
TI/RI:串行口中断,串行端口完成一帧字符发送/接收后引起。
中断源 | 默认中断级别 | 序号(C语言用) | 入口地址(汇编语言用) |
INT0 外部中断0 | 最高 | 0 | 0003H |
T0 定时器/计数器0中断 | 第2 | 1 | 000BH |
INT1 外部中断1 | 第3 | 2 | 0013H |
T1 定时器/计数器1中断 | 第4 | 3 | 001BH |
TI/RI 串行口中断 | 第5 | 4 | 0023H |
T2 定时器/计数器2中断 | 最低 | 5 | 002BH |
位序号 | D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 |
说明 | 全局中断位 | 无效位 | 定时/计数2 (52单片机) | 串行口中断 | 定时/计数1 | 外部中断1 | 定时/计数0 | 外部中断0 |
位符号(写程序时可直接引用) | EA | -- | ET2 | ES | ET1 | EX1 | ET0 | EX0 |
位地址 | AFH | -- | ADH | ACH | ABH | AAH | A9H | A8H |
只有打开全局开关,其它各位的开关才可以开启。
每个位开关赋值为1则开,赋值为0则关。
使用方法
①整体赋值:IE=0x81;(开启全局中断,打开外部中断0)
②单独赋值:EA=1;EX0=1;(开启全局中断,打开外部中断0)
位序号 | D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 |
说明 | 无效位 | 无效位 | 无效位 | 串行口中断优先级控制位 | 定时器/计数器1中断优先级控制位 | 外部中断1中断优先级控制位 | 定时器/计数器0中断优先级控制位 | 外部中断0中断优先级控制位 |
位符号 | -- | -- | -- | PS | PT1 | PX1 | PT0 | PX0 |
位地址 | -- | -- | -- | BCH | BBH | BAH | B9H | B8H |
每个位赋值为1,将对应中断定义为高优先级中断;赋值0,则定义为低优先级中断。
在没有设置中断优先级情况下,按照默认中断级别响应中断,设置后,则按设置顺序确定相应的先后顺序。
位序号 | D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 |
位符号 | GATE | C/T(上划线) | M1 | M0 | GATE | C/T(上划线) | M1 | M0 |
定时器1 | 定时器0 |
GATE:
GATE = 0 定时器/计数器启动与停止仅受TCON寄存器中TRX(X=0,1)来控制。
当TR0=1,启动定时器T0。
当TR1=1,启动定时器T1。
GATE = 1 定时器/计数器启动与停止由TCON寄存器中TRX(X=0,1)和外部中断引脚(INT0 或 INT1)上的电平状态共同控制。
当INT0引脚为高电平时且TR0置位,TR0=1;启动定时器T0。
当INT1引脚为高电平时且TR1置位,TR1=1;启动定时器T1。
C/T(上划线):定时器模式和计数器模式选择位
C/T=0时为定时模式: 加1计数器对脉冲f进行计数,每来一个脉冲,计数器加1,直到计时器TFx满溢出。
C/T=1时为计数模式: 加1计数器对来自输入引脚T0(P3.4)和T1(P3.5)的外信号脉冲进行计数,每来一个脉冲,计数器加1,直到计时器TFx满溢出。
M1M0:方式选择功能
M1 | M0 | 工作方式 | 功能说明 |
0 | 0 | 方式0 | 13位定时器/计数器 |
0 | 1 | 方式1 | 16位定时器/计数器 |
1 | 0 | 方式2 | 自动重载8位定时器/计数器 |
1 | 1 | 方式3 | T0分为2个8位独立计数器,T1无方式3 |
位序号 | D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 |
位符号 | TF1 | TR1 | TF0 | TR0 | IE1 | IT1 | IE0 | IT0 |
位地址 | 8FH | 8EH | 8DH | 8CH | 8BH | 8AH | 89H | 88H |
定时器/计数器控制 | 外部中断控制 |
TF1:定时器1溢出标志位。当定时器1计满溢出时,由硬件使TF1置“1”,并且申请中断。进入中断服务程序后,由硬件自动清“0”,在查询方式下用软件清“0”。
TR1:定时器1运行控制位。由软件清“0”关闭定时器1。当GATE=1,且/INT1为高电平时,TR1置“1”启动定时器1;当GATE=0,TR1置“1”启动定时器1。
TF0:定时器0溢出标志。其功能及操作情况同TF1。
TR0:定时器0运行控制位。其功能及操作情况同TR1。
IE1:外部中断1请求标志位。
IT1:外部中断1触发方式选择位。当IT1=0,为低电平触发方式;当IT1=1,为下降沿触发方式。
IE0:外部中断0请求标志位。
IT0:外部中断0触发方式选择位。 当IT0=0,为低电平触发方式;当IT0=1,为下降沿触发方式。
中断响应条件
①CPU开中断(EA=1)
②此中断允许位为1
③中断源有中断请求
中断服务程序格式
void 函数名() interrupt 中断号 using 工作组
{
}
//using 工作组 指这个中断函数使用单片机内存中4组工作寄存器中哪一组,C51编译器在编译程序时会自动分配工作组,因此最后这句话可以省略不写。
//中断号见前 52单片机中断级别 表格
外部中断
涉及寄存器IE TCON (IP)
//外部中断0 低电平触发 #include <reg52.h> sbit DUAN = P2^6; sbit WE = P2^7; unsigned char DuanTable[] = {0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07, 0x7F,0x6F,0x77,0x7C,0x39,0x5E,0x79,0x71}; unsigned char WeTable[] = {0xFE,0xFD,0xFB,0xF7,0xEF,0xDF}; void delayms(unsigned int n); int main() { unsigned int i = 0; EA = 1;//打开总中断 EX0 = 1;//打开外部中断0中断 //IT0 = 0; 电平触发 由于TCON在复位时自动清零,所以可以省略 while(1) { for(i = 0; i < 6; i++) { DUAN = 1; P0 = DuanTable[i+1]; DUAN = 0; P0 = 0xFF; WE = 1; P0 = WeTable[i]; WE = 0; P0 = 0xFF; delayms(1); } } return 0; } void delayms(unsigned int n) //误差 -0.651041666667us { unsigned char a,b; unsigned int i; for(i = 0; i < n; i++) { for(b=4;b>0;b--) for(a=113;a>0;a--); } } void exter0() interrupt 0 //中断函数无需在main前声明 中断全部显示0 P3,2口INT0 { int i = 0; for(i = 0; i < 6; i++) { DUAN = 1; P0 = DuanTable[0]; DUAN = 0; P0 = 0xFF; WE = 1; P0 = WeTable[i]; WE = 0; P0 = 0xFF; delayms(1); } }
![](https://oscdn.geek-share.com/Uploads/Images/Content/202001/25/c4ae54694e9f0dd4c8469e94c158c182.jpg)
中断ing
定时器中断
[b]涉及寄存器IE TMOF TCON (IP) THX TLX (x=0,1)[/b]
定时器中断程序初始化
1.对TMOD赋值,以确定T0和T1的工作方式
2.计算初值,并将初值写入TH0、TL0 或 TH1、TL1
3.中断方式时,则对IE赋值,开发中断
4.使TR0或TR1置位,启动定时器/计数器定时或计数(TCON)
定时器初值问题:
假设时钟频率为12MHZ,12个时钟周期为一个机器周期,那么此时机器周期为1us。计满TH0、TL0需要2^16-1个数,再来一个脉冲计数器溢出,向CPU请求中断。例如要定时50ms
要给TH0和TL0装初值,在初值基础上计数50000后溢出,中断。若要定时1s,则产生20次50ms中断即可。
结论:用定时器方式1是,机器周期为Tcy,定时器产生一次中断时间为t,那么需要计数的个数N= t/Tcy.
THX = (65535 -N) / 256
TLX = (65535 - N) % 256
//定时器0中断 方式1 中断显示0 #include <reg52.h> sbit DUAN = P2^6; sbit WE = P2^7; unsigned char DuanTable[] = {0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07, 0x7F,0x6F,0x77,0x7C,0x39,0x5E,0x79,0x71}; unsigned char WeTable[] = {0xFE,0xFD,0xFB,0xF7,0xEF,0xDF}; unsigned int t = 0; void delayms(unsigned int n); int main() { unsigned int i = 0; TMOD = 0x01; //TMOD不能位寻址 定时器0工作方式1 TH0 = (65535 - 50000) / 256; TL0 = (65535 - 50000) % 256; EA = 1;//打开总中断 ET0 = 1;//打开定时器0中断 TR0 = 1; while(1) { for(i = 0; i < 6; i++) { DUAN = 1; P0 = DuanTable[i+1]; DUAN = 0; P0 = 0xFF; WE = 1; P0 = WeTable[i]; WE = 0; P0 = 0xFF; delayms(1); } if(t >= 100) { for(i = 0; i < 6; i++) { DUAN = 1; P0 = DuanTable[0]; DUAN = 0; P0 = 0xFF; WE = 1; P0 = WeTable[i]; WE = 0; P0 = 0xFF; delayms(1); } if(t >= 250) t = 0; } } return 0; } void delayms(unsigned int n) //误差 -0.651041666667us { unsigned char a,b; unsigned int i; for(i = 0; i < n; i++) { for(b=4;b>0;b--) for(a=113;a>0;a--); } } void T0_Time() interrupt 1 //中断函数无需在main前声明 中断全部显示0 P3,2口INT0 { TH0 = (65535 - 50000) / 256; TL0 = (65535 - 50000) % 256; t++; }
practice:
59s循环计时。
//60s倒计时 定时器0中断+数码管显示 #include <reg52.h> sbit DUAN = P2^6; sbit WE = P2^7; unsigned char DuanTable[] = {0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07, 0x7F,0x6F,0x77,0x7C,0x39,0x5E,0x79,0x71}; unsigned char WeTable[] = {0xFE,0xFD,0xFB,0xF7,0xEF,0xDF}; unsigned int t = 0, num = 59; void delayms(unsigned int n); int main() { unsigned int i = 0; TMOD = 0x01; //TMOD不能位寻址 定时器0工作方式1 TH0 = (65535 - 50000) / 256; TL0 = (65535 - 50000) % 256; EA = 1;//打开总中断 ET0 = 1;//打开定时器0中断 TR0 = 1; while(1) { //十位数 DUAN = 1; P0 = DuanTable[num/10]; DUAN = 0; P0 = 0xFF; WE = 1; P0 = WeTable[4]; WE = 0; P0 = 0xFF; delayms(5); //个位数 DUAN = 1; P0 = DuanTable[num%10]; DUAN = 0; P0 = 0xFF; WE = 1; P0 = WeTable[5]; WE = 0; P0 = 0xFF; delayms(1); } return 0; } void delayms(unsigned int n) //误差 -0.651041666667us { unsigned char a,b; unsigned int i; for(i = 0; i < n; i++) { for(b=4;b>0;b--) for(a=113;a>0;a--); } } void T0_Time() interrupt 1 //中断函数无需在main前声明 中断全部显示0 P3,2口INT0 { TH0 = (65535 - 50000) / 256; TL0 = (65535 - 50000) % 256; t++; if(t >= 20) { num--; t = 0; } if(num == 0) num = 59; }
相关文章推荐
- 我的java学习之小游戏_ 打字母01
- 一个技术人员35岁之前要做的10件事
- SecureCRT远程连接到虚拟机Ubuntu Linux上
- 第3周项目4-用穷举法解决组合问题(4)三色球问题
- [iOS]MRC和ARC
- angularjs学习5--过滤器(二)
- ActiveMQ的基本使用
- Go语言学习七:结构体
- Pyserial能够在Shell中运行良好,但是在脚本中运行失败
- T4模板异常:System.ArgumentException: Empty path name is not legal.
- html5 圆角ie8
- Excel导入导出,通过datatable转存(篇一)
- HDU 1827 Summer Holiday 强连通分量缩点
- Dynamics CRM2016 Web API之Expand related entities & $ref & $count
- 进程与线程区别
- Dynamics CRM2016 Web API之Expand related entities & $ref & $count
- Dynamics CRM2016 Web API之Expand related entities & $ref & $count
- Dynamics CRM2016 Web API之Expand related entities & $ref & $count
- 最大堆与最小堆的实现
- 【LeetCode】9. Palindrome Number回文数判断