学习笔记|回顾(1-12节课)|应用模块化的编程|分时复用|STC32G单片机视频开发教程(冲哥)|阶段小结:应用模块化的编程(下)

搜索功能

如果想排量修改SEG_Fre,可以使用搜索功能。
在这里插入图片描述
双击选中SEG_Fre,选查找替换,范围选择整个project,替换3处为:SEG_LED_Show()。
在这里插入图片描述

寻址变量bdata

在头文件中已经定义了一个LED的一个8位的状态,实际使用时想单独控制LED的某一个位,可以使用寻址变量bdata。
在 extern u8 bdata LED_DATA; //LED的显示变量,使用寻址变量形式
u8 bdata LED_DATA = 0xff;
和原来定义的地方都加上bdata修饰,之后就可以用sbit进行定义:
比如:

sbit LED0 = LED_DATA^0;				//LED0引脚定义
sbit LED1 = LED_DATA^1;				//LED1引脚定义
sbit LED2 = LED_DATA^2;				//LED2引脚定义
sbit LED3 = LED_DATA^3;				//LED3引脚定义
sbit LED4 = LED_DATA^4;				//LED4引脚定义
sbit LED5 = LED_DATA^5;				//LED5引脚定义
sbit LED6 = LED_DATA^6;				//LED6引脚定义
sbit LED7 = LED_DATA^7;				//LED7引脚定义

如果需要在其他文件中调用,需要在头文件中声明,利用shift+alt竖向选择,复制:

extern bit LED0
extern bit LED1
extern bit LED2
extern bit LED3
extern bit LED4
extern bit LED5
extern bit LED6
extern bit LED7

在头文件中增加LED总控和数码管的单独控制变量,修改后的seg_led.h文件为:

#ifndef __SEG_LED_H
#define __SEG_LED_H

#include "COMM/stc.h"			//调用头文件
#include "COMM/usb.h"

extern u8 Show_Tab[8];			//数码管的内码显示变量
extern u8 bdata LED_DATA;		//LED的显示变量,使用寻址变量形式

//------------------------引脚定义------------------------//
#define SEG_SEG P6
#define SEG_COM P7
#define LED_POW P40 			//P40是led的电源开关

#define LED LED_DATA			//8个LED的控制变量,8个2进制

#define SEG0 Show_Tab[0]		//数码管的单独控制变量
#define SEG1 Show_Tab[1]
#define SEG2 Show_Tab[2]
#define SEG3 Show_Tab[3]
#define SEG4 Show_Tab[4]
#define SEG5 Show_Tab[5]
#define SEG6 Show_Tab[6]
#define SEG7 Show_Tab[7]

extern bit LED0;				//LED的单独状态控制
extern bit LED1;
extern bit LED2;
extern bit LED3;
extern bit LED4;
extern bit LED5;
extern bit LED6;
extern bit LED7;


void SEG_LED_Show(void);  		//仅声明

#endif

Tips:missing declaration specifiers错误的解决

这里第一次编译的时候出现错误,提示

Demo.c(29): warning C138: expression with possibly no effect
Demo.c(29): error C25: syntax error near '='
Demo.c(30): warning C34: 'Show_Tab': missing declaration specifiers
Demo.c(30): error C25: syntax error near '='

仔细观察发现,
错误1:头文件的定义中,#define SEG0 Show_Tab[0]的定义后面加了“;”结尾,预编译将空格以后的“Show_Tab[0];"当成了整体,不应该加“;”
错误2:“extern bit LED0;”语句后面缺少了“;”,不完整,影响编译。extern等IDE蓝色字体显示的关键字每行是一条完整的语句,结束时必须加“;”。
尝试一下单独控制,在demo.c中对main.c进行修改:

	//数码管初始化,显示0-7:
	SEG0 = 0;
	SEG1 = 1;
	Show_Tab[2] = 2;
	Show_Tab[3] = 3;
	Show_Tab[4] = 4;
	Show_Tab[5] = 5;
	Show_Tab[6] = 6;
	Show_Tab[7] = 7;


    LED_DATA = 0x0f;	//赋初值,亮一半灭一半,可以写8位的变量.从7开始数到0

	LED0 = 0;			//

LED0应该写0,写最低位(0x0f二讲制是00001111是高位也就是第七位本来就是0,所以我们应该是把最低位去改0)
(初始状态是)第0位到第3位之间我们给他写了个1,现在就给他写二个第0位。
编译下载完成,下载完成数码管显示01234567,下面这里4个灯和最后一个灯点亮,实现了我们的功能
因为是初始化的时候给它控制了一个LED的灯,可以用这几个按键来模拟一下,是不是真的可以通过给定义的这个LED0控制。
增加按键测试代码,在demo.c的main函数前增加函数声明:void delay_ms(u16 ms);,main函数中测试代码:

		if(KEY1 == 0) //P32
		{
			delay_ms(10);
			if(KEY1 == 0)
			{
				while(KEY1 == 0); //一直等待直到松开后再执行
					LED0 =! LED0;
			}

		}
		if(KEY2 == 0) //P33
		{
			delay_ms(10);
			if(KEY2 == 0)
			{
				while(KEY2 == 0); //一直等待直到松开后再执行
					LED1 =! LED1;
			}

		}

按键控制倒数第1,2个灯。

分时复用的简单应用

当单独控制P6, 如果想LED点亮,就需要写P60=0,如果再刷新数码管,那么那它是不是这个P60一写进去,数码管就乱码了。
如果要控制,单独控制变量就可以实现操作。程序里用了循环刷新的办法(专业术语叫分时复用)。每次刷新前8个毫秒是刷新数码管,
第9个毫秒是刷新LED,第10个ms全部熄灭,然后循环,就做到了LED和数码管同时显示,而且不会存在干扰。每一次控制就只控制这几个变量。
切换变量,就不会对引脚进行直接操作,比如下一次换了个板子,这个数码管的引脚可能不是P6了,P3或者P2,只需局部修改就行。
头文件中的定义,上面是引脚定义,下面是变量声明和函数声明,.c文件中进行变量定义。
seg_led.c和seg_led.h可以在后期直接复制目录调用。这个就是一个简单的一个通过工程文件去处理,下次使用的时候直接复制黏贴。

二、按键处理

在hardware-key目录中,新建key.c和key.h,添加引用路径:
在这里插入图片描述
key.h插入模板:

#ifndef __KEY_H
#define __KEY_H

#include "COMM/stc.h"			//调用头文件
#include "COMM/usb.h"

//------------------------引脚定义------------------------//


//------------------------变量声明------------------------//


//------------------------函数声明-----------------------//


#endif

key.c和demo.c中调用key.h:#include “key.h” //调用头文件
增加引脚定义:

//------------------------引脚定义------------------------//
#define KEY P3 			//定义一个按键 引脚选择P32-P36

#define KEY1 2		//按键1
#define KEY2 3		//按键2
#define KEY3 4		//按键3
#define KEY4 5		//按键4

如果要更换按键的端口,可以直接修改P3。
有没有什么办法可以代替之前的按键操作?

思路分析

原有程序实现的功能:

按键要满足的功能
1.按键消抖 10ms
2.按键按下的瞬间
3.按键松开的瞬间
在这里插入图片描述

需求分析:

在这里插入图片描述

定义功能码,功能定义为:

在这里插入图片描述
状态 功能
按键未按下 0
消抖 1
单击 2
单击结束 3
长按3s 4
长按结束 5
按键松开 6
变量声明:

//------------------------变量声明------------------------//
//状态	功能
#deine KEY_NOPRESS 0 	//按键未按下	0
#deine KEY_FLCKER 1 	//消抖	1
#deine KEY_RESS 2		//单击	2
#deine KEY_PRESSOVER 3 	//单击结束	3
#deine KEY_LONGPRESS 4 	//长按3s	4
#deine KEY_LONGOVER 5 	//长按结束	5
#deine KEY_RELAX 6 	//按键松开	6

可以避开while一直等待的状态。
既然上面定义了返回值,那么需要编写一个有返回值的函数:u8 KEY_ReadState(u8 keynum); //读取指定按键的状态
再编写一个检查所有的按键状态的函数: void KEY_Deal(void); //检查所有的按键状态

key的取值示例

在这里插入图片描述

在key.c中实现,先将声明复制入key.c:

void KEY_Deal(void) 			//检查所有的按键状态
{

}

u8  KEY_ReadState(u8 keynum) 	//读取指定按键的状态
{

}

对比功能需求,8位的变量,判断时间小于30ms或者等于30ms。首先进行按键状态的计数,时间是多久,
新建变量,u16 Count[8] = {0,0,0,0,0,0,0,0}; //按键的时间状态变量初始化8位
修改KEY_Deal函数,使用for循环,格式为:

	u8 i = 0;
	for(i=0;i<8;i++)			//for循环变量
	{

	}

假设P3有8个位,检查所有的按键状态代码:

void KEY_Deal(void) 			//检查所有的按键状态
{
	u8 i = 0;
	,or(i=0;i<8;i++)			//for循环变量 循环8次,i取值为0-7,代表P30-P37的状态查询
	{
		if(^KEY & {1<<i} )					//如果持续按下,变量加1
		{
			if(Count[i] < 60000)			// Count是u16类型,最大值小于65535,故增加限定条件。
			Count[i] ++;					//如果持续按下,这个变量加1
		}
		else					//如果按键松开,变量清0
		{
			Count[i] = 0;					//如果松开,计数变量清0
		}
	}

}

判断按钮的状态,我们用户要读到的个按键状态,
在这里插入图片描述
首先函数的模板为:

u8  KEY_ReadState(u8 keynum) 	//读取指定按键的状态
{
	if(Count[8] > 0)			//判断按键是按下的
	{

	}
	else						//按键已经松开了
	{

	}
}

根据之前的逻辑表格,编写响应的函数判断代码:

void KEY_Deal(void) 			//检查所有的按键状态,10ms执行一次
{
	u8 i = 0;
	for(i=0;i<8;i++)			//for循环变量 循环8次,i取值为0-7,代表P30-P37的状态查询
	{
		if(~KEY & (1<<i) )					//如果持续按下,变量加1
		{
			if(Count[i] < 60000)			// Count是u16类型,最大值小于65535,故增加限定条件。
			Count[i] ++;					//如果持续按下,这个变量加1
		}
		else					//如果按键松开,变量清0
		{
			if(Count[i] > 0 )	//如果这个按键是按下过的,
			{
				LastState |= (1<<i);	//这个变量相应的标志位置1,单独写对应位
			}
			else
			{
				LastState &= ~(1<<i);	//仅操作这个变量相应的标志位清0
			}
			Count[i] = 0;					//如果松开,计数变量清0
		}
	}

}

u8  KEY_ReadState(u8 keynum) 	//读取指定按键的状态,10ms执行1次
{
	if(Count[8] > 0)			//判断按键是按下的
	{
		if(Count[keynum] < 3)		//按下小于30ms,返回消抖状态
		{
			return KEY_FLCKER;
		}
		else if(Count[keynum] == 3)	//按正好等于30ms,返回单击状态
		{
			return KEY_RESS;
		}
		else if(Count[keynum] < 300 ) //按下小于3000ms,返回单击结束
		{
			return KEY_PRESSOVER;
		}
		else if(Count[keynum] == 300 ) //按下正好等于3000ms,返回长按
		{
			return KEY_LONGPRESS;
		}
		else					//长按结束
		{
			return KEY_LONGOVER;
		}
	}
	else						//按键已经松开了,返回KEY_RELAX状态
	{
		if(LastState &(1<<keynum))			//按键之前按下过,要判断上1s是不是高电平,如果上1s是低电平,说明是按键按下
											//例如,要判断P32,P30,31,32,左移2位,
											//按键已经松开了
		{
			return KEY_RELAX;
		}
		else			//按键之前没有按下过,返回未按下
		{
			return KEY_NOPRESS;
		}
	}
}

demo.c中进行调用,先删除原有的按键控制代码和按键define,并在while(1)主循环中增加:

		delay_ms(10);           //延时10ms扫描一次
		KEY_Deal();				//P3上所有端口都需要执行一遍
		if(KEY_ReadState(KEY1)== KEY_RESS)	//判断KEY1按钮是否为单击
		{
			LED0 = 0;
		}
		else if(KEY_ReadState(KEY1)== KEY_LONGPRESS) //判断KEY1按钮是否为长按
		{
			LED1 = 0;
		}
		else if(KEY_ReadState(KEY1)== KEY_RELAX)	//判断KEY1按钮是否为松开
		{
			LED = 0XFF;
		}

编译完成,下载,上面的数码管显示正常进行,KEY1按钮单击点亮第1个灯,长按点亮第2个灯,松开熄灭,功能正常。
等待松开也不需要等待。这个按键也可以看做是一个状态机,因为是实时读取key的状态,而不是死在那里。
增加函数头,编写简要介绍。
完整代码如下:
main.c

#include "COMM/stc.h"		//调用头文件
#include "COMM/usb.h"
#include "seg_led.h"
#include "key.h"			//调用头文件


#define BEEP P54		//定义一个按键 引脚选择P54

#define MAIN_Fosc 24000000UL	//定义主时钟

char *USER_DEVICEDESC = NULL;
char *USER_PRODUCTDESC = NULL;
char *USER_STCISPCMD = "@STCISP#";


void sys_init();	//函数声明
void Timer0_Init(void);
void delay_ms(u16 ms);




void main()					//程序开始运行的入口
{

	sys_init();				//USB功能+IO口初始化
	usb_init();				//usb库初始化
	Timer0_Init();

	EA = 1;					//CPU开放中断,打开总中断。


	//数码管初始化,显示0-7
	SEG0 = 0;
	SEG1 = 1;
	Show_Tab[2] = 2;
	Show_Tab[3] = 3;
	Show_Tab[4] = 4;
	Show_Tab[5] = 5;
	Show_Tab[6] = 6;
	Show_Tab[7] = 7;

	LED_DATA = 0x0f;	//赋初值,亮一半灭一半,可以写8位的变量.从7开始数到0

	LED0 = 0;			//

	while(1)		//死循环
	{
//		if( DeviceState != DEVSTATE_CONFIGURED ) 	//
//			continue;
		if( bUsbOutReady )
		{
			usb_OUT_done();
		}
		delay_ms(10);
		KEY_Deal();				//P3上所有端口都需要执行一遍
		if(KEY_ReadState(KEY1)== KEY_RESS)	//判断KEY1按钮是否为单击
		{
			LED0 = 0;
		}
		else if(KEY_ReadState(KEY1)== KEY_LONGPRESS) //判断KEY1按钮是否为长按
		{
			LED1 = 0;
		}
		else if(KEY_ReadState(KEY1)== KEY_RELAX)	//判断KEY1按钮是否为松开
		{
			LED = 0XFF;
		}

	}
}

void sys_init()		//函数定义
{
    WTST = 0;  //设置程序指令延时参数,赋值为0可将CPU执行指令的速度设置为最快
    EAXFR = 1; //扩展寄存器(XFR)访问使能
    CKCON = 0; //提高访问XRAM速度

	P0M1 = 0x00;   P0M0 = 0x00;   //设置为准双向口
    P1M1 = 0x00;   P1M0 = 0x00;   //设置为准双向口
    P2M1 = 0x00;   P2M0 = 0x00;   //设置为准双向口
    P3M1 = 0x00;   P3M0 = 0x00;   //设置为准双向口
    P4M1 = 0x00;   P4M0 = 0x00;   //设置为准双向口
    P5M1 = 0x00;   P5M0 = 0x00;   //设置为准双向口
    P6M1 = 0x00;   P6M0 = 0x00;   //设置为准双向口
    P7M1 = 0x00;   P7M0 = 0x00;   //设置为准双向口

    P3M0 = 0x00;
    P3M1 = 0x00;

    P3M0 &= ~0x03;
    P3M1 |= 0x03;

    //设置USB使用的时钟源
    IRC48MCR = 0x80;    //使能内部48M高速IRC
    while (!(IRC48MCR & 0x01));  //等待时钟稳定

    USBCLK = 0x00;	//使用CDC功能需要使用这两行,HID功能禁用这两行。
    USBCON = 0x90;
}


void delay_ms(u16 ms)	//unsigned int
{
	u16 i;
	do
	{
		i = MAIN_Fosc/6000;
		while(--i);
	}while(--ms);
}

void Timer0_Init(void)		//1毫秒@24.000MHz
{
	AUXR &= 0x7F;			//定时器时钟12T模式
	TMOD &= 0xF0;			//设置定时器模式
	TL0 = 0x30;				//设置定时初始值
	TH0 = 0xF8;				//设置定时初始值
	TF0 = 0;				//清除TF0标志
	TR0 = 1;				//定时器0开始计时
	ET0 = 1;				//使能定时器0中断
}

KEY.C:

#include "key.h"			//调用头文件
u16 Count[8] = {0,0,0,0,0,0,0,0};	//按键的时间状态变量初始化8位
u8 LastState = 0;					//8位变量,b0=1 则表示key0上一次按下过


//========================================================================
// 函数名称:KEY_Deal
// 函数功能:按键状态的获取
// 入口参数:无
// 函数返回:无
// 当前版本: VER1.0
// 修改日期: 2023-1-1
// 当前作者:
// 其他备注:循环读取8个端口的状态,并将按下的时间赋值给Count数组,然后按下的状态赋值给变量LastState
//========================================================================
void KEY_Deal(void) 			//检查所有的按键状态,10ms执行一次
{
	u8 i = 0;
	for(i=0;i<8;i++)			//for循环变量 循环8次,i取值为0-7,代表P30-P37的状态查询
	{
		if(~KEY & (1<<i) )					//如果持续按下,变量加1
		{
			if(Count[i] < 60000)			// Count是u16类型,最大值小于65535,故增加限定条件。
			Count[i] ++;					//如果持续按下,这个变量加1
		}
		else					//如果按键松开,变量清0
		{
			if(Count[i] > 0 )	//如果这个按键是按下过的,
			{
				LastState |= (1<<i);	//这个变量相应的标志位置1,单独写对应位
			}
			else
			{
				LastState &= ~(1<<i);	//仅操作这个变量相应的标志位清0
			}
			Count[i] = 0;					//如果松开,计数变量清0
		}
	}

}
//========================================================================
// 函数名称:KEY_ReadState
// 函数功能:读取指定的按钮的状态
// 入口参数: @keynum; 按钮的端口号,例如P32的端口号是2,
// 函数返回:见KEY的返回值的各种状态,看其他备注
// 当前版本: VER1.0
// 修改日期: 2023-1-1
// 当前作者:
// 其他备注: 函数返回值如下:
状态	功能
//#define KEY_NOPRESS 0 	//按键未按下	0
//#define KEY_FLCKER 1 		//消抖	1
//#define KEY_RESS 2		//单击	2
//#define KEY_PRESSOVER 3 	//单击结束	3
//#define KEY_LONGPRESS 4 	//长按3s	4
//#define KEY_LONGOVER 5 	//长按结束	5
//#define KEY_RELAX 6 		//按键松开	6
//========================================================================

u8  KEY_ReadState(u8 keynum) 	//读取指定按键的状态,10ms执行1次
{
	if(Count[8] > 0)			//判断按键是按下的
	{
		if(Count[keynum] < 3)		//按下小于30ms,返回消抖状态
		{
			return KEY_FLCKER;
		}
		else if(Count[keynum] == 3)	//按正好等于30ms,返回单击状态
		{
			return KEY_RESS;
		}
		else if(Count[keynum] < 300 ) //按下小于3000ms,返回单击结束
		{
			return KEY_PRESSOVER;
		}
		else if(Count[keynum] == 300 ) //按下正好等于3000ms,返回长按
		{
			return KEY_LONGPRESS;
		}
		else					//长按结束
		{
			return KEY_LONGOVER;
		}
	}
	else						//按键已经松开了,返回KEY_RELAX状态
	{
		if(LastState &(1<<keynum))			//按键之前按下过,要判断上1s是不是高电平,如果上1s是低电平,说明是按键按下
											//例如,要判断P32,P30,31,32,左移2位,
											//按键已经松开了
		{
			return KEY_RELAX;
		}
		else			//按键之前没有按下过,返回未按下
		{
			return KEY_NOPRESS;
		}
	}
}

KEY.H:

#ifndef __KEY_H
#define __KEY_H

#include "COMM/stc.h"			//调用头文件
#include "COMM/usb.h"

//------------------------引脚定义------------------------//
#define KEY P3 			//定义一个按键 引脚选择P32-P36

#define KEY1 2			//按键1
#define KEY2 3			//按键2
#define KEY3 4			//按键3
#define KEY4 5			//按键4

//------------------------变量声明------------------------//
//状态	功能
#define KEY_NOPRESS 0 		//按键未按下	0
#define KEY_FLCKER 1 		//消抖	1
#define KEY_RESS 2			//单击	2
#define KEY_PRESSOVER 3 	//单击结束	3
#define KEY_LONGPRESS 4 	//长按3s	4
#define KEY_LONGOVER 5 		//长按结束	5
#define KEY_RELAX 6 		//按键松开	6


//------------------------函数声明-----------------------//
void KEY_Deal(void);			//检查所有的按键状态
u8  KEY_ReadState(u8 keynum);	//读取指定按键的状态

#endif

三、按键处理

先在BEEP文件夹(\9.TIM多任务\HARDWARE\BEEP)中新建文件:beep.c和beep.h
beep.c:

#include "beep.h"

u16 Time_Beep;	//如果这个变量大于0,蜂鸣器打开,等于0关闭,每10ms这个数值减1

//========================================================================
// 函数名称:BEEP_RUN
// 函数功能:蜂鸣器运行函数,可以独立运行
// 入口参数:无
// 函数返回:无
// 当前版本: VER1.0
// 修改日期: 2023-1-2
// 当前作者:
// 其他备注:10ms执行一次,保证每次蜂鸣10ms
//========================================================================
void BEEP_RUN(void)
{
	if(Time_Beep > 0)			//如果这个变量大于0
	{
		BEEP = 0;				//打开蜂鸣器
		Time_Beep--;			//计时变量减1
	}
	else 						//如果这个变量等于0
		BEEP = 1;				//关闭蜂鸣器
}
//========================================================================
// 函数名称:BEEP_ON
// 函数功能:设置蜂鸣器响多少个10ms
// 入口参数: @time; 多少个10ms
// 函数返回: 无
// 当前版本: VER1.0
// 修改日期: 2023-1-2
// 当前作者:
// 其他备注:
//========================================================================
void BEEP_ON(u16 time)
{
	Time_Beep = time;
}
//========================================================================
// 函数名称:BEEP_OFF
// 函数功能:关闭蜂鸣
// 入口参数: 无
// 函数返回: 无
// 当前版本: VER1.0
// 修改日期: 2023-1-2
// 当前作者:
// 其他备注:
//========================================================================
void BEEP_OFF(void)
{
	Time_Beep = 0;
}

beep.h:

#ifndef __BEEP_H
#define __BEEP_H

#include "COMM/stc.h"			//调用头文件
#include "COMM/usb.h"

//------------------------引脚定义------------------------//
#define BEEP P54		//定义一个蜂鸣器 引脚选择P54

//------------------------函数声明-----------------------//
void BEEP_RUN(void);
void BEEP_ON(u16 time);
void BEEP_OFF(void);
#endif

demo.c中增加beep执行代码:

	while(1)		//死循环
	{
//		if( DeviceState != DEVSTATE_CONFIGURED ) 	//
//			continue;
		if( bUsbOutReady )
		{
			usb_OUT_done();
		}
		delay_ms(10);
		KEY_Deal();				//P3上所有端口都需要执行一遍
		BEEP_RUN();

		if(KEY_ReadState(KEY1)== KEY_RESS)	//判断KEY1按钮是否为单击
		{
			BEEP_ON(2);							//蜂鸣20ms
			LED0 = 0;
		}
		else if(KEY_ReadState(KEY1)== KEY_LONGPRESS) //判断KEY1按钮是否为长按
		{
			BEEP_ON(2);							//蜂鸣20ms
			LED1 = 0;
		}
		else if(KEY_ReadState(KEY1)== KEY_RELAX)	//判断KEY1按钮是否为松开
		{
			LED = 0XFF;
		}
    }

四、定时器

先在TIM文件夹(\9.TIM多任务\HARDWARE\TIM)中新建文件:tim0.c和tim0.h,增加头文件引用路径。
tim0.h:

#ifndef __TIM0_H
#define __TIM0_H

#include "COMM/stc.h"			//调用头文件
#include "COMM/usb.h"

//------------------------函数声明-----------------------//
void Timer0_Init(void);			//定时器初始化函数

#endif

将demo.c中的Timer0_Init移植至tim0.c:

#include "tim0.h"

void Timer0_Init(void)		//1毫秒@24.000MHz
{
	AUXR &= 0x7F;			//定时器时钟12T模式
	TMOD &= 0xF0;			//设置定时器模式
	TL0 = 0x30;				//设置定时初始值
	TH0 = 0xF8;				//设置定时初始值
	TF0 = 0;				//清除TF0标志
	TR0 = 1;				//定时器0开始计时
	ET0 = 1;				//使能定时器0中断
}
/*			//复制这个文件的时候,记得把这个中断函数复制到主程序
			//这个是属于用户型的一个文件(用户需要在里面编写自己的功能),建议将其放在主程序main函数之后,方便更好的引用
void Timer0_Isr(void) interrupt 1 //1ms进来执行一次,无需其他延时,重复赋值
{


}
*/

利用time0实现delay_ms:

利用void Timer0_Isr(void);中断实现10ms延时功能。
先设置10ms标志位:bit TIM_10MS_Flag; //10ms标志位
在Timer0_Isr中实现延时:

void Timer0_Isr(void) interrupt 1 //1ms进来执行一次,无需其他延时,重复赋值
{
	static timecount = 0;
	SEG_LED_Show();		//数码管刷新

	timecount++;		//1ms+1
	if(timecount>=10)	//如果这个变量大于等于10,说明10ms到达
	{
		TIM_10MS_Flag = 1;	//10ms到了
	}
}

用以下格式进行调用:

if(TIM_10MS_Flag == 1)   //将需要延时的代码部分放入
		{
			TIM_10MS_Flag = 0;		//TIM_10MS_Flag 变量清空置位
			//待延时程序部分
		}

时间间隔有误的分析

编译下载后,观察功能,时间好像不太对,第二个灯亮的非常快。
分析一下原因:缺少了timecount = 0;变量的清空,方便下一次从0数到10;说明10ms已经到达。
重新编译下载,功能正常。

扩展

后续工程可以直接拷贝.c和.h文件,实现相应的功能,并且KEY的功能是可以扩展的,在main函数中,按需要进行定义。
TIM_10MS_Flag变量,代表10ms延时,假设现在这里有8个LED灯(LED0-LED7),想要每200个毫秒点亮一个灯,或者每300ms
或者每400ms每个灯取反。

总结

1.学会模块化的编写程序

课后练习:

1.LED0给他200ms取反一次,LED1给他400ms取反一次,LED2给他800ms取反一次
2.将之前的电磁炉程序用今天的框架重新改写一遍,并且加入数码管定时的功能。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

打酱油的工程师

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值