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

news2025/1/9 15:13:59

文章目录

    • 搜索功能
    • 寻址变量bdata
    • Tips:missing declaration specifiers错误的解决
    • 分时复用的简单应用
  • 二、按键处理
    • 思路分析
      • 原有程序实现的功能:
      • 需求分析:
      • 定义功能码,功能定义为:
    • key的取值示例
  • 三、按键处理
  • 四、定时器
    • 利用time0实现delay_ms:
    • 时间间隔有误的分析
    • 扩展
  • 总结
  • 课后练习:

搜索功能

如果想排量修改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.将之前的电磁炉程序用今天的框架重新改写一遍,并且加入数码管定时的功能。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1002940.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【数据库】Navicate运行数据区sql文件 1046 no database selected

文章目录 前言一、现象二、解决 前言 要通过Navicat导入数据库文件&#xff0c;但是不成功报错1046 no database selected 一、现象 选中已经建立的连接&#xff0c;右键运行sql文件&#xff0c;报错 二、解决 1、先在建立的localhost中右键建立和要导入数据库同名的数据…

ipad手写笔什么牌子好?apple pencil二代平替笔推荐

近年来&#xff0c;电容笔越来越受到大家的青睐&#xff0c;已然成为人们提高生产效率的数码产品之一。然而&#xff0c;市面上的电容笔大多质量都参差不齐&#xff0c;很多人也不知道哪个品牌的电容笔比较好。针对这个问题&#xff0c;我来给大家分享几款电容笔&#xff0c;都…

斐波那契堆——怎么发明一种非常聪明的数据结构——学习笔记

我是目录 0. 前言1. Fibonacci Heap介绍1.1 简单回顾堆和优先队列1.2 二项树1.3 二项堆 2. 那怎么推导出Fibonacci Heap&#xff1f;2.1 实现GetMin2.2 实现Insert2.3 实现ExtractMin2.4 实现DecreaseKey2.5 关键部分 3. 那么&#xff0c;和斐波那契数列有什么关系&#xff1f;…

【nvm版本】控制node版本

使用nvm切换node版本 nvm安装开始安装选择安装路径选择node安装位置点击完成即可测试是否安装成功查询可下载的node版本如果没有node版本&#xff0c;就安装一下镜像地址 nvm安装 nvm安装路径 开始安装 选择安装路径 选择node安装位置 点击完成即可 测试是否安装成功 cmd中…

UI库DHTMLX Suite v8.2发布全新表单组件,让Web表单实现高度可定制!

DHTMLX Suite v8.2日前已正式发布&#xff0c;此版本的核心是DHTMLX Form&#xff0c;这个小部件接收了4个备受期待的新控件&#xff0c;如Fieldset、Avatar、Toggle和ToggleGroup。官方技术团队还为Grid和TreeGrid小部件中的页眉/页脚工具提示提供了一系列新的配置选项等。 在…

Scrum敏捷开发流程及关键环节

​Scrum是一种敏捷开发流程&#xff0c;它旨在使软件开发更加高效和灵活。Scrum将软件开发过程分为多个短期、可重复的阶段&#xff0c;称为“Sprint”。每个Sprint通常为两周&#xff0c;旨在完成一部分开发任务。 在Scrum中&#xff0c;有一个明确的角色分工&#xff1a; 产…

一个好玩的浏览器插件

背景 最近抽空开发了一个有意思的浏览器插件。背景是我们在开发过程中有时需要做一些测试验证&#xff0c;需要修改请求头字段和响应头字段的内容&#xff0c;有时需要在页面做测试&#xff0c;反复请求同一个接口&#xff0c;并修改一些字段。 如果此时使用nginx做代理转发再…

HashMap、HashTable、CurrentHashMap对比

&#x1f61c;作 者&#xff1a;是江迪呀✒️本文关键词&#xff1a;Java、集合、Map、CurrentHashMap☀️每日 一言&#xff1a;坚持自己的风格&#xff0c;面对未知的一切&#xff01; 一、HashMap、HashTable、CurrentHashMap对比 1.1 CurrentHashMap和HashMap…

9.多级缓存、JVM进程缓存、Lua语法

多级缓存 文章目录 多级缓存一、多级缓存介绍1.1 传统缓存的问题1.2 多级缓存方案 二、JVM进程缓存2.1 案例准备2.1.1 导入SQL2.1.2 导入item-service项目2.1.3 导入商品查询页面 2.2 初始 Caffeine2.2.1 基本用法 2.3 实现进程缓存 三、Lua语法3.1 初识Lua3.2 变量和循环3.2.1…

这篇文章是用AI大模型自动生成的

昨天用豆包AI大模型尝试生成了一段关于&#xff1a;企业转型、企业转型的要点、企业转型成功的标志&#xff0c;这样的文字。我又加了点自己的思考。 &#xff08;1&#xff09;企业转型的原因 企业转型的原因有很多&#xff0c;以下是一些常见的原因&#xff1a; 1. 市场变化&…

针对电子企业的WMS仓储管理系统解决方案

随着全球电子行业的快速发展&#xff0c;电子企业对于仓储管理的需求和挑战也日益增长。WMS仓储管理系统作为电子企业的核心管理工具&#xff0c;需要满足高效率、低成本、高灵活性以及精确控制库存等需求。本文将为电子企业提供一种针对WMS仓储管理系统的解决方案。 一、WMS仓…

Eclipse使用SFTP方式远程连接

安装插件 首先需要安装远程系统连接插件&#xff0c;安装方式可参考&#xff1a; Eclipse安装FTP连接工具_哭哭啼的博客-CSDN博客在过滤器字段中,键入"remote".选择Mobile and Device Development&#xff0c;并选择。找到Remote System Explorer->Connection。…

Outlook邮箱如何设置自动回复

很多小伙伴在刚开始使用Outlook邮箱的时候&#xff0c;不是很清楚Outlook邮箱如何设置自动回复&#xff0c;这里小编就给大家详细介绍一下Outlook邮箱设置自动回复的方法&#xff0c;有需要的小伙伴可以来看一看。 Outlook邮箱设置自动回复的方法&#xff1a; 1、打开软件&am…

ARM-M0内核MCU,内置24bit ADC,采样率4KSPS,传感器、电子秤、体脂秤专用,国产

ARM-M0内核MCU 内置24bit ADC &#xff0c;采样率4KSPS flash 64KB&#xff0c;SRAM 32KB 适用于传感器&#xff0c;电子秤&#xff0c;体脂秤等等

QML android 采集手机传感器数据 并通过udp 发送

利用 qt 开发 安卓 app &#xff0c;采集手机传感器数据 并通过udp 发送 #ifndef UDPLINK_H #define UDPLINK_H#include <QObject> #include <QUdpSocket> #include <QHostAddress>class UdpLink : public QObject {Q_OBJECT public:explicit UdpLink(QObjec…

Win10无法访问你可能没有权限使用网络资源怎么解决

当我们使用Win10电脑打开文件时&#xff0c;弹出提示无法访问你可能没有权限使用网络资源&#xff0c;这是怎么回事&#xff0c;遇到这种问题应该怎么解决呢&#xff0c;下面小编就给大家详细介绍一下Win10无法访问你可能没有权限使用网络资源的解决方法&#xff0c;有需要的小…

使用亚马逊云科技人工智能内容审核服务,打造安全的图像生成和扩散模型

生成式人工智能技术发展日新月异&#xff0c;现在已经能够根据文本输入生成文本和图像。Stable Diffusion 是一种文本转图像模型&#xff0c;可让您创建栩栩如生的图像应用。您可以通过 Amazon SageMaker JumpStart&#xff0c;使用 Stable Diffusion 模型轻松地从文本生成图像…

继续聊聊API接口

什么是API接口 API接口(Application Programming Interface Interface)是应用程序与开发人员或其他程序互相通信的方式。它允许开发者访问应用程序的数据和功能。 API接口,软件的“握手”与“交流”之道,软件世界的“好基友”。想让软件聊得来?想开发App却无从下手?API来相救…

一文讲清楚:SaaS系统是什么?优势在哪?盘点国内行业龙头SaaS系统!

SaaS系统究竟是什么&#xff1f;应该如何了解SaaS系统&#xff1f;在SaaS系统飞速发展的2023年&#xff0c;国内涌现出了一大批优秀的SaaS系统公司&#xff0c;都有哪些企业位列其中呢&#xff1f;SaaS系统有着什么样独特的竞争力&#xff0c;能够不断发展&#xff0c;成为目前…

无涯教程-JavaScript - NPER函数

描述 NPER函数基于定期,固定付款和固定利率返回投资的期数。 语法 NPER (rate,pmt,pv,[fv],[type])争论 Argument描述Required/OptionalRateThe interest rate per period.RequiredPmt 在每个期间付款。 在年金的使用期限内,它不能改变。 通常,pmt包含本金和利息,但不包含其…