1、原来所有的代码都被编写在一个.c文件中。创建keil project(89C52)并且仿真流水灯
一旦代码复杂,会很难修改。而且如果延时函数常用,也不方便移植。将延时函数模块化,可以使延时函数变得容易移植。
#include
void delay_ms(unsigned int t);
unsigned char tab[]={0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f};
void main(void)
{
unsigned char i;
while(1)
{
for(i=0;i<8;i++)
{
P2=tab[i];
delay_ms(5000);
}
}
}
void delay_ms(unsigned int t)
{
unsigned int x,y;
for(x=t;x>0;x--)
for(y=50;y>0;y--);
}
2、将延时子函数delay_ms模块化。创建delay.c 和 delay.h。delay.c 存放子函数,delay.h 存放函数声明。并且将delay.c 添加到项目工程中,以及指明delay.h的路径。
2.1 delay.h
#ifndef __DELAY_MS_H__
#define __DELAY_MS_H__
void delay_ms(unsigned int t);
#endif
2.2 delay.c
#include"delay.h"
void delay_ms(unsigned int t)
{
unsigned int x,y;
for(x=t;x>0;x--)
for(y=50;y>0;y--);
}
2.3 并且将delay.c 添加到项目工程中,以及指明delay.h的路径。
2.3.1将delay.c 添加到项目工程中
2.3.2指明delay.h的路径。依次点击图中1,2,3,4,5,6,选择delay.h所在的文件夹”delay”
2.4在test.c 中添加头文件#include”delay.h”。test.c 代码为:
#include
#include "delay.h"
unsigned char tab[]={0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f};
void main(void)
{
unsigned char i;
while(1)
{
for(i=0;i<8;i++)
{
P2=tab[i];
delay_ms(5000);
}
}
}
改善——将延时函数delay 更换成调用定时器的功能
延时函数delay_ms的延时的时间是不准确的。调用单片机的定时器可以使延时函数的延时效果准确。
定时器的C语言模块如下:
timer.h
#ifndef __TIMER_H__
#define __TIMER_H__
void timer_ms(void);
#endif
timer.c
#include"timer.h"
#include
void timer_ms(void)
{
TMOD = 0x01;
TH0 = (65536-1000)/256;
TL0 = (65536-1000)%256;
TR0 = 1;
}
test.c就可以写成
#include
#include "timer.h"
unsigned char tab[]={0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f};
unsigned int a;
void main(void)
{
unsigned char i;
while(1)
{
for(i=0;i<8;i++)
{
P2=tab[i];
for(a=0;a<1000;a++)
timer_ms();
}
}
}
C51 单片机内部设置两个16位定时器/计数器T0和T1。它的本质是对脉冲计数。如果计数脉冲来自系统时钟(将C/T 置0),则为定时,每12个或者6个时钟得到一个计数脉冲。如果计数脉冲来自外部(将C/T 置1),则每个脉冲加一(每一个脉冲都是计数脉冲,不分频)。
如果使用定时器的功能,每来一个计数脉冲,TL0 会加1,一旦TL0加满,就会进位TH0。TH0进位,TF0/TF1就会为1,然后继续执行后面的程序,从而达到定时的效果。
TF1:定时器/计数器T1溢出标志。T1被允许计数后,从初值开始加1计数。当最高位产生溢出时,由硬件置“1” TF1,向CPU请求中断,一直保持到CPU响应中断时,才由硬件清0。TF0是T0 的溢出标志。TF0/TF1 也可以由程序清零。
TR1:定时器T1的运行控制位。如下图,当GATE = 0 , TR1 =1 时允许计数。而当GATE = 1 时,TR1 = 1 且 INT0 输入高电平的时候才可以计数。TR0 是T0的运行控制位。
GATE的作用如上述。
C/T =0 时,T1 用作定时器;C/T =1 时,T1 用作计数器;
M1 M0 定时器/计数器 模式选择
0 0 13 位定时器/计数器。低位(TL0/TL1)有5位,高位(TH0/TH1)有8位
0 1 16 位定时器/计数器。
1 0 8位自动重装载定时器,当溢出时将高位的值自动装入低位。
1 1 此定时器/计数器无效。
所以
TMOD = 0x01;
表示
GATE = 0 ,那么TR0/TR1 =1 时允许计数。
C/T = 0 , 工作为定时器。
M1 M0 为 0 1, 使用16 位定时器/计数器。TL0/TL1 8位,TH0/TH1 8位。
假设晶振型号的频率是12 MHz,使用12分频,则计数脉冲的频率为1 MHz,所以一个计数脉冲的时间间隔是1 微秒。所以要设置定时器定时1ms,只需要给TL0/TL1 或者 TH0/TH1 赋初值,使在计数1000次后溢出即可。所以将65536-1000截取高8位和低8位分别存储在 TH0 和 TL0 中。
TH0 = (65536-1000)/256;
TL0 = (65536-1000)%256;
最后,使TR0 = 1,开始计数。
调用一次timer_ms()延时1ms,那么调用1000次,延时1s,所以在for循环1000次。
for(a=0;a<1000;a++)
timer_ms();