目录
1.点亮LED灯
1.1LED灯闪烁
1.2控制LED灯按时闪烁:
1.3 LED灯流水灯
1.4二进制点灯
2.独立按键控制LED灯
2.1按键控制LED亮灭
2.2.按键控制灯左右移动
3.数码管
3.1静态数码管显示
3.2.动态数码管显示
4.模块化编程
5.LCD1602调试工具
6.矩阵键盘
6.1.介绍矩阵键盘
6.2.矩阵键盘在LCD上按键显示
6.3.矩阵键盘制作密码锁
7.定时器
7.1关于定时器的基本概念
7.2.中断系统介绍
7.3.寄存器:
7.4.如何实现用定时器记1秒
7.5.模块化定时器
7.6.定时器使用的示例
LED点亮原理(示意图如下):
电阻:作用限流,大小为102(其中2为倍率),即1000欧姆。
由CPU通过控制配置的寄存器控制硬件电路,寄存器后面连接导线,通过一个驱动器(增大电流),连接到io口端口,使引脚输出高低电平:(TTL电平)高电平5V,低电平0V。
左端VCC接电源正极,故端口输出高电平时(表示为1),负极接正,LED不点亮;
端口输出低电平时(表示为0),负极接负,LED点亮;
注意:写代码不支持直接写二进制,二进制应该换为16进制(0x为前缀)
注意:LED灯对应的二进制数字是从右往左一一对应,如0111 1111,是第8个灯亮,不是第一个灯亮
示例1:led灯的亮灭
#include
void main()
{
P2=0xFE; //亮 1111 1110
P2=0xFE; //灭 1111 1111
}
调用stc-isp软件的软件延时计算器,调节系统频率为12.000,指令集为STC-Y1,自定义长度为800毫秒,生成C代码即可复制使用。
注意 _nop_的使用需要加头文件#include
#include
#include
void Delay800ms() //@12.000MHz
{
unsigned char i, j, k;
_nop_();
i = 7;
j = 21;
k = 96;
do
{
do
{
while (--k);
} while (--j);
} while (--i);
}
void main(){
P2=0xFE;
Delay800ms();
P2=0xFF;
Delay800ms();
}
生成1毫秒延时的函数,通过while循环实现时长的自定义调节函数。
#include
#include
void Delay1ms(unsigned int xms) //@12.000MHz
{
unsigned char i, j;
while(xms){
i = 2;
j = 239;
do
{
while (--j);
} while (--i);
xms--;
}
}
void main(){
while(1){
P2=0xFE; //1111 1110
Delay1ms(800);
P2=0xFD; //1111 1101
Delay1ms(700);
P2=0xFB; //1111 1011
Delay1ms(600);
P2=0xF7; //1111 0111
Delay1ms(500);
P2=0xEF; //1110 1111
Delay1ms(400);
P2=0xDF; //1101 1111
Delay1ms(300);
P2=0xBF; //1011 1111
Delay1ms(200);
P2=0x7F; //0111 1111
Delay1ms(100);
}
}
#include
#include
void Delay(unsigned int xms) //@12.000MHz
{
unsigned char i, j;
while(xms){
i = 2;
j = 239;
do
{
while (--j);
} while (--i);
xms--;
}
}
void main(){
unsigned char LEDnum=0; //引入变量
while(1){
if(P3_1==0){
Delay(20); //通过delay去抖
while(P3_1==0); //while作用:
//按键启动if循环,松手走出while循环,运行下一步代码
Delay(20);
LEDnum++; //16进制0,1,2,3,4
P2=~LEDnum; //取反
}
}
1.按键抖动:对于机械开关,当机械触点断开、闭合时,由于机械触点的弹性作用,一个开关在闭合时不会马上稳定地接通,在断开时也不会一下子断开,所以在开关闭合及断开的瞬间会伴随一连串的抖动
2.认识独立按键:一端共同接正极,当另一端(P3)连接低电平时,即表示按键接通
注意K1,K2,K3,K4分别对应代码的P3_1 P3_0 P3_2 P3_3
#include
#include
void Delayms(unsigned int xms) //@12.000MHz
{
unsigned char i, j;
while(xms){
i = 2;
j = 239;
do
{
while (--j);
} while (--i);
xms--;
}
}
void main(){
if(P3_1==0){ //按键执行
Delayms(20); //除去抖动
while(P3_1==0); //按键,进入空白循环,不执行下面
Delayms(20);
P2_1=~P2_1; //松键状态改变
}
}
相关运算符
按位左移:0011 1100<<1 即0111 1000
按位右移:0011 1100>>2 即0000 1111
按位与:0001 1000& 0010 1010 每一位单独操作 结果0000 1000 即0&一切 为0 1&X为X本身
按位或:0001 1000 | 0010 1010 结果0011 1010 1|一切为1 0|X为X本身
按位异或:0001 1000^0010 1010 结果0011 0010 即一样为0,不一样为1
取反:~00001111 11110000
#include
#include
void Delay(unsigned int xms) //@12.000MHz
{
unsigned char i, j;
while(xms){
i = 2;
j = 239;
do
{
while (--j);
} while (--i);
xms--;
}
}
void main(){
unsigned char LEDnum=0;
while(1){
if(P3_1==0){
Delay(20);
while(P3_1==0);
Delay(20);
if(LEDnum>=8){
LEDnum=0;
}
//LEDnum=1 0000 0001---0000 0010 取反1111 1101
P2=~(0x01<
3.1.1.一位数码管
示意图如下:
共阴极连接(右上图):8个LED的阴极都连接到一个端口上
共阳极连接(右下图):8个LED的阳极都连接到一个端口上
51单片机的开发板为共阴极连接,即公共端阴极接低电平,未选端给相应数据,输入1即为亮;反之,共阳极连接则将公共端接正极电源,未选端输入0为亮
3.1.2.多位数码管
示意图如下:
即多分出几个小单元,公共端独立,未选端连在一起,作用是节省了io口,但同一个时刻下只能显示同样的数字,若要显示不同数字可通过动态数码管显示(利用人眼视觉暂留和数码管显示余晖的原理)
3.1.3. 138译码器
作用:和数码管相连接,8个io口简化为3个,其示意图如下:
使用原理:
左边P2端123依次输入二进制数字,右边对应的十进制接口显示0,其他均为1
示例:输入二进制(101),对应十进制(5),即Y5口为0,对应LED口数据为1111 1011,(0即为接通,即第6个数码管显示,其他数码管不显示)(注意Y是从0开始计,Y5为0即LED6为0)
3.1.4. 74HC245
(示意图如上)
作用:单片机高电平驱动能力有限,输出的最大电流不能太大,低电平驱动能力强一些。加入缓冲器74HC245,提高驱动能力,吸收P0端口的微弱信号,再从VCC电源汲取能量,驱动数码管灯光更亮
3.1.5 操作示例一:使第三个数码管显示6
P2口控制数码管显示的位置,0为接通,P0口控制数码管显示的数字,1为接通;
其中:由计算可得
0对应0x3F、1对应0x06、2对应0x5B、3对应0x4F、4对应0x66、
5对应0x6D、6对应0x7D、7对应0x07、8对应0x7F、9对应0x6F
A对应0x77、B对应0x7C、C对应0x39、D对应0x5E、
E对应0x79、F对应0x71、空对应0x00,
#include
void main(){
P2_4=1; //ABC ——234——011 —— 3 —— Y2 —— 第二个数码管
P2_3=1;
P2_2=0;
while(1){
P0=0x7D; //注意从下往上读数0111 1101 —— 显示6
}
}
操作示例二:写一个函数,方便改变数码管显示位置和数字
#include
unsigned char NUM[]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F};
void Nixie(unsigned char location,number){
switch(location)
{
case 1:
P2_4=1;P2_3=1;P2_2=1;
break;
case 2:
P2_4=1;P2_3=1;P2_2=0;
break;
case 3:
P2_4=1;P2_3=0;P2_2=1;
break;
case 4:
P2_4=1;P2_3=0;P2_2=0;
break;
case 5:
P2_4=0;P2_3=1;P2_2=1;
break;
case 6:
P2_4=0;P2_3=1;P2_2=0;
break;
case 7:
P2_4=0;P2_3=0;P2_2=1;
break;
case 8:
P2_4=0;P2_3=0;P2_2=0;
break;
}
P0=NUM[number];
}
void main(){
Nixie(1,1);
while(1){}; //不可省去
}
#include
void Delayms(unsigned int xms) //@12.000MHz
{
unsigned char i, j;
while(xms){
i = 2;
j = 239;
do
{
while (--j);
} while (--i);
xms--;
}
}
unsigned char NUM[]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F};
void Nixie(unsigned char location,unsigned char number){
switch(location)
{
case 1:
P2_4=1;P2_3=1;P2_2=1;
break;
case 2:
P2_4=1;P2_3=1;P2_2=0;
break;
case 3:
P2_4=1;P2_3=0;P2_2=1;
break;
case 4:
P2_4=1;P2_3=0;P2_2=0;
break;
case 5:
P2_4=0;P2_3=1;P2_2=1;
break;
case 6:
P2_4=0;P2_3=1;P2_2=0;
break;
case 7:
P2_4=0;P2_3=0;P2_2=1;
break;
case 8:
P2_4=0;P2_3=0;P2_2=0;
break;
}
P0=NUM[number];
Delayms(2);
P0=0x00; //把前一个数据清零,防止对下一个显示有影响
}
void main(){
while(1){
Nixie(1,1);
Nixie(2,3);
Nixie(3,1);
Nixie(4,4);
};
}
1.基本概念
传统方式编程:所有的函数均放在main.c里,若使用的模块比较多,则一个文件内会有很多的代码,不利于代码的组织和管理,而且很影响编程者的思路
模块化编程:把各个模块的代码放在不同的.c文件里,在.h文件里提供外部可调用函数的声明,其它.c文件想使用其中的代码时,只需要#include "XXX.h"文件即可。使用模块化编程可极大的提高代码的可阅读性、可维护性、可移植性等
.c文件:函数、变量的定义
.h文件:可被外部调用的函数、变量的声明
注意:任何自定义的变量、函数在调用前必须有定义或声明(同一个.c) 使用到的自定义函数的.c文件必须添加到工程参与编译 使用到的.h文件必须要放在编译器可寻找到的地方(工程文件夹根目录、安装目录、自定义)
C语言的预编译:以#开头,作用是在真正的编译开始之前,对代码做一些处理(预编译)
示例:
1.文件必须添加到目录列表中
2.Delay.h 函数声明
#ifndef _DELAY_H_
#define _DELAY_H_
void Delay(unsigned int xms);
#endif
3.Delay.c 函数定义
#include
#include
void Delay(unsigned int xms) //@12.000MHz
{
unsigned char i, j;
while(xms){
i = 2;
j = 239;
do
{
while (--j);
} while (--i);
xms--;
}
}
4.Nixie.h 函数声明
#ifndef _Nixie_H_
#define _Nixie_H_
void Nixie(unsigned char location,unsigned char number);
#endif
5.Nixie.c 函数定义
#include
#include "Delay.h"
unsigned char NUM[]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F};
void Nixie(unsigned char location,unsigned char number){
switch(location)
{
case 1:
P2_4=1;P2_3=1;P2_2=1;
break;
case 2:
P2_4=1;P2_3=1;P2_2=0;
break;
case 3:
P2_4=1;P2_3=0;P2_2=1;
break;
case 4:
P2_4=1;P2_3=0;P2_2=0;
break;
case 5:
P2_4=0;P2_3=1;P2_2=1;
break;
case 6:
P2_4=0;P2_3=1;P2_2=0;
break;
case 7:
P2_4=0;P2_3=0;P2_2=1;
break;
case 8:
P2_4=0;P2_3=0;P2_2=0;
break;
}
P0=NUM[number];
Delay(2);
P0=0x00;
}
6.main.c 主函数
#include
#include "Delay.h" 是在程序目录寻找文件
#include
#include "Delay.h"
#include "Nixie.h"
void main(){
while(1){
Nixie(1,1);
Nixie(2,3);
Nixie(3,1);
Nixie(4,4);
}
}
1.基本概念:使用LCD1602液晶屏作为调试窗口,提供类似printf函数的功能,可实时观察单片机内部数据的变换情况,便于调试和演示。 LCD1602代码属于模块化的代码,即只需要知道所提供函数的作用和使用方法就可以使用LCD1602,不用自己编码程序。
模块化代码如下:
2.注意:由于外设互相干扰,使用LCD1602后,数码管显示乱码
原理(示意图如下):LCD1602连接P0口(数码管接口)和P2口(3个LED接口),引脚冲突,故使用LCD1602时无法正常使用数码管和LED灯
3.使用注意:模块函数LCD1602.c和LCD1602.h应该和project放在同一个文件里
4.示例1:使用LCD1602输出
注意:主函数使用LCD前要初始化,加入LCD_Init();
#include
#include "LCD1602.h"
void main(){
LCD_Init();
while(1){
LCD_ShowChar(1,1,'A');
LCD_ShowString(1,3,"hello world");
LCD_ShowNum(2,1,18,4); //无符号数字,长度4位,多余补0,显示0018
LCD_ShowSignedNum(2,6,-65,3); //有符号数字
LCD_ShowHexNum(2,10,0xFF,2); //输出FF
LCD_ShowBinNum(2,13,0xF,4); //二进制数在keil里用16进制表示,输出1111
}
}
示例2:使用LCD显示递增数字,主函数如下
#include
#include "LCD1602.h"
#include "Delay.h"
unsigned int number=0;
void main(){
LCD_Init();
while(1){
Delay(300);
LCD_ShowNum(1,1,number,4);
number++;
}
}
1.概念:在键盘中按键数量较多时,为了减少IO口的占用,通常将按键排列成矩阵形式 采用逐行或逐列的“扫描”,就可以读出任何位置按键的状态,其特点是:两端都接io口,可以按行扫描或按列扫描。
2.扫描:
数码管扫描(输出扫描)原理:显示第1位→显示第2位→显示第3位→……,然后快速循环这个过程,最终实现所有数码管同时显示的效果
矩阵键盘扫描(输入扫描)原理:读取第1行(列)→读取第2行(列) →读取第3行(列) → ……,然后快速循环这个过程,最终实现所有按键同时检测的效果
以上两种扫描方式的共性:节省I/O口
3.注意事项:为了避免外设互相干扰,矩阵键盘使用按列扫描。
矩阵键盘的P10~13口和五线四相步进电机相连,进而与蜂鸣器的BZ口相连,驱使蜂鸣器一直响。采用逐列扫描,即给P10~13口赋值,读取P14~17。
示例:P13~10从左到右依次赋值0111 即第一列接通,1011即第二列接通……逐列依次读取P14~17的数据。
按下矩阵键盘Sn:LCD1602屏幕显示相应数字n;
思路如下:
(1)定义MatrixKey()函数:按键后给变量keynum赋相应的值并作为返回值输出;
(2)主函数调用LCD1602()函数中的LCD_ShowNum()函数,输出MatrixKey()函数的返回值;
定义函数MatrixKey.c如下:
#include
#include "Delay.h"
unsigned int Keynumber=0;
unsigned int MatrixKey(){
Keynumber=0;
P1=0xFF;
P1_3 = 0; //第一列
if(P1_7==0) //S1
{Delay (20);while(P1_7==0);Delay(20);Keynumber=1;}
if(P1_6==0) //S5
{Delay(20);while(P1_6==0);Delay(20);Keynumber=5;}
if(P1_5==0) //S9
{Delay(20);while(P1_5==0);Delay(20);Keynumber=9;}
if(P1_4==0) //S13
{Delay(20);while(P1_4==0);Delay(20);Keynumber=13;}
P1=0xFF;
P1_2=0; //第二列
if(P1_7==0) //S2
{Delay(20);while(P1_7==0);Delay(20);Keynumber=2;}
if(P1_6==0) //S6
{Delay(20);while(P1_6==0);Delay(20);Keynumber=6;}
if(P1_5==0) //S10
{Delay(20);while(P1_5==0);Delay(20);Keynumber=10;}
if(P1_4==0) //S14
{Delay(20);while(P1_4==0);Delay(20);Keynumber=14;}
P1=0xFF;
P1_1=0; //第三列
if(P1_7==0) //S3
{Delay(20);while(P1_7==0);Delay(20);Keynumber=3;}
if(P1_6==0) //S7
{Delay(20);while(P1_6==0);Delay(20);Keynumber=7;}
if(P1_5==0) //S11
{Delay(20);while(P1_5==0);Delay(20);Keynumber=11;}
if(P1_4==0) //S15
{Delay(20);while(P1_4==0);Delay(20);Keynumber=15;}
P1=0xFF;
P1_0=0; //第四列
if(P1_7==0) //S4
{Delay(20);while(P1_7==0);Delay(20);Keynumber=4;}
if(P1_6==0) //S8
{Delay(20);while(P1_6==0);Delay(20);Keynumber=8;}
if(P1_5==0) //S12
{Delay(20);while(P1_5==0);Delay(20);Keynumber=12;}
if(P1_4==0) //S16
{Delay(20);while(P1_4==0);Delay(20);Keynumber=16;}
return Keynumber;
}
依次加入定义和声明后主函数main.c如下:
#include
#include "Delay.h"
#include "LCD1602.h"
#include "MatrixKey.h"
unsigned char keynum;
void main(){
LCD_Init();
LCD_ShowString(1,1,"hello world");
while(1){
keynum=MatrixKey();
if(keynum){
LCD_ShowNum(2,1,keynum,2);
}
}
}
主函数如下:
注意每一次按键赋值之后,keynum要重新赋值为0;
#include
#include "Delay.h"
#include "LCD1602.h"
#include "MatrixKey.h"
unsigned int keynum=0;
unsigned int Password=0;
unsigned int count=0;
void main(){
LCD_Init();
LCD_ShowString(1,1,"hello:");
while(1){
keynum = MatrixKey();
if(keynum){
if(keynum<=10){
if(count<4){
Password=Password*10;
Password+=keynum;
keynum=0;
count++;
LCD_ShowNum(2,1,Password,4);
}
}
}
if(keynum==11){
if(Password==2431)
{
LCD_ShowString(2,7,"OK");
Password=0;
count=0;
}
else{
LCD_ShowString(2,7,"ERR");
Password=0;
count=0;
}
}
}
}
1.定时器介绍:
51单片机的定时器属于单片机的内部资源,其电路的连接和运转均在单片机内部完
2.定时器作用:
(1)用于计时系统,可实现软件计时,或者使程序每隔一固定时间完成一项操作
(2)使用Delay期间,单片机不工作,定时器可以替代长时间的Delay,提高CPU的运行效率和处理速度
3.STC89C52定时器资源
定时器个数:3个(T0、T1、T2)
T0和T1与传统的51单片机兼容,T2是此型号单片机增加的资源 注意:定时器的资源和单片机的型号是关联在一起的,不同的型号可能会有不同的定时器个数和操作方式,但一般来说,T0和T1的操作方式是所有51单片机所共有的。
4.定时器框图
定时器在单片机内部就像一个小闹钟一样,根据时钟的输出信号,每隔“一秒”,计数单元的数值就增加一,当计数单元数值增加到“设定的闹钟提醒时间”时,计数单元就会向中断系统发出中断申请,产生“响铃提醒”,使程序跳转到中断服务函数中执行
5.STC89C52的T0和T1均有四种工作模式:
模式0:13位定时器/计数器
模式1:16位定时器/计数器(常用)
模式2:8位自动重装模式
模式3:两个8位计数器
工作模式1框图:
SYSclk:系统时钟,即晶振周期,本开发板上的晶振为12MHz,若选择连接12T mode,连C/T=0,分频12MHz分为1M,每隔1微秒记一次时。
计数器:分为2个字节:TL0(低字节) TH0(高字节) 总共存储65535,即最大容量为65535。左边计数系统每提供一个脉冲,右边计数器加1,加到最大值(65535)时,在下一个脉冲时产生溢出,向中断系统申请中断,计数器数值归0。
控制位:TR0控制定时器启动或暂停
工作示意图:
作用:可以同时完成两个任务,可以提高效率。
中断源个数:8个(外部中断0、定时器0中断、外部中断1、定时器1中断、串口中断、定时器2中断、外部中断2、外部中断3)
中断号如下:
注意:中断的资源和单片机的型号是关联在一起的,不同的型号可能会有不同的中断资源,例如中断源个数不同、中断优先级个数不同等等
中断系统内部连接示意图:(TF0接ET0接EA接PT0)
单片机通过配置寄存器控制内部线路的连接。寄存器是连接软硬件的媒介,在单片机中寄存器就是一段特殊的RAM存储器,一方面,寄存器可以存储和读取数据,另一方面,每一个寄存器背后都连接了一根导线,控制着电路的连接方式,寄存器相当于一个复杂机器的“操作按钮”
示例:配置工作模式寄存器TMOD(不可位寻址:必须整体赋值):赋值0000 0001 即选择定时器0的M0模式(示意图如下)
示例:配置控制寄存器TCON(如下图)(可位寻址:可以单独赋值也可以整体赋值,类似LED灯的P2寄存器)如TF0=0;TR0=1;
中断系统寄存器:
理解:定时器的工作不需要单片机的执行,是独立的一部分,依靠外部晶振产生的脉冲自动计数,单片机只是控制开始和初始值,定时器就可以自动累加,这过程中程序可以继续运行,当定时器自动累加到溢出时,就会产生中断信号,使程序跳转到interrupt 1中执行中断程序。溢出后定时器从0开始累加,所以在中断后需要重新给计数器赋初值,定时器相当于在一直累加,和主程序同时运行。
原理:计时器容量为65535,每隔1us加1,从0开始增加到65535时就执行中断系统,故总共定时时间为65535微秒。当人为赋初值为64535,则1000微秒(1毫秒)后就执行中断,1000次中断即为1秒。
计时器赋初始值:高字节TH0=64535/256
低字节TL0=64535%256(16进制数字取位操作)
【类比10进制取位:百位234/100;后2位234%100】
示例:定时器T0工作在方式一,晶振频率为11.0592MHZ,需要定时时间0.5s
方法一:计算思路:
方法二:在烧录软件找到定时计算器,选好定时器、工作方式、时钟以及定时长度(初始值),就能自动得到初始值了
代码示意:实现LED闪烁,间隔1秒
先初始化定时器系统,主函数先运行,到达定时器限定时间后中断主函数,跳转执行void Timer0_Routine() interrupt 1之后再返回主函数。
#include
void Timer0Init(void) //外设配置
{
TMOD=0x01; //0000 0001
TF0=0;
TR0=1;
TH0=65435/256;
TL0=65435%256;
ET0=1;
EA=1;
PT0=0;
}
void main(){
Timer0Init(); //先初始化
while(1){
}
}
unsigned int T0Count=0;
void Timer0_Routine() interrupt 1
{
TH0=65435/256;
TL0=65435%256;
T0Count++;
if(T0Count>=1000){ //间隔1秒
P2_0=~P2_0;
T0Count=0;
}
}
代码缺陷:TMOD赋值0000 0001,若同时使用定时器1和定时器0则受影响
改进如下:
TMOD =TMOD & 0xF0; 低四位清零,高四位保持不变
如1010 0011 & 1111 0000——1010 0000
TMOD =TMOD & 0xF1; 低四位赋值1,高四位保持不变
如1010 0000 | 1111 0001——1010 0001
方便随时使用
定义Timer0.c
#include
void Timer0Init(void) //1微秒@12.000MHz
{
//AUXR &= 0x7F; //定时器时钟12T模式
TMOD &= 0xF0; //设置定时器模式
TMOD |= 0x01;
TL0 = 0x18; //设置定时初值
TH0 = 0xFC; //设置定时初值
TF0 = 0; //清除TF0标志
TR0 = 1; //定时器0开始计时
ET0 =1;
EA=1;
PT0=0;
}
声明Timer0.h
#ifndef _TIMER0_H_
#define _TIMER0_H_
void Timer0_Routine();
#endif
示例1:按键控制流水灯左右扭转
主函数如下:LED每个一秒移位,按下S1改变移动位方向;其中调用了_crol_函数要加头文件#include
#include
#include "Delay.h"
#include "MatrixKey.h"
#include
unsigned int keynum=0;
unsigned int T0Count=0;
unsigned int LCDMode=0;
void main()
{
P2=0xFE;
Timer0Init();
while(1){
keynum=MatrixKey();
if(keynum){
if(keynum==1){
LCDMode++;
keynum==0;
if(LCDMode>=2){
LCDMode=0;
keynum==0;
}
}
}
}
}
void Timer0_Routine() interrupt 1
{
TL0 = 0x18; //设置定时初值
TH0 = 0xFC;
T0Count++;
if(T0Count>=1000){
T0Count=0;
if(LCDMode==0){
P2=_crol_(P2,1);
}
if(LCDMode==1){
P2=_cror_(P2,1);
}
}
}
示例2:制作简单时钟,主函数代码如下
#include
#include "Timer0.h"
#include "Delay.h"
#include "LCD1602.h"
unsigned int hour=23;
unsigned int min=59;
unsigned int s=50;
void main(){
LCD_Init();
Timer0Init();
while(1){
LCD_ShowString(1,1,"time:");
LCD_ShowNum(2,1,hour,2);
LCD_ShowString(2,3,":");
LCD_ShowNum(2,4,min,2);
LCD_ShowString(2,6,":");
LCD_ShowNum(2,7,s,2);
}
}
void Timer0_Routine() interrupt 1
{
static unsigned int T0Count=0;
TL0 = 0x18; //ÉèÖö¨Ê±³õÖµ
TH0 = 0xFC;
T0Count++;
if(T0Count>=1000){
s++;
T0Count=0;
}
if(s>=60){
min++;
s=0;
}
if(min>=60){
hour++;
min=0;
}
if(hour>=24){
hour=0;
}
}