将一个用for循环实现的流水灯C程序模块化

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 添加到项目工程中

将一个用for循环实现的流水灯C程序模块化_第1张图片

将一个用for循环实现的流水灯C程序模块化_第2张图片

2.3.2指明delay.h的路径。依次点击图中1,2,3,4,5,6,选择delay.h所在的文件夹”delay”

将一个用for循环实现的流水灯C程序模块化_第3张图片

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,然后继续执行后面的程序,从而达到定时的效果。


将一个用for循环实现的流水灯C程序模块化_第4张图片
定时器/计数器相关的寄存器:

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();






你可能感兴趣的:(stm32单片机)