STC8单片机的按键单击、双击、长按的代码实现

前言

这是做车窗自动升降模块时做的按键程序,感觉做的不错记录一下防止以后找不着了
在这里插入图片描述

代码实现

#include "key.h"
#define U1 P17
#define D1 P54
#define U2 P55
#define D2 P32
//#define KEY_QUANTITY 4 //按键数量

#define LONG_TIME 50   //长按时间50,时间乘以定时器时间
#define CLICK_TIME 10  //单击时间
#define POP_UP_TIME 50 //按键弹起时间
#define FILTEER_TIME 5 //滤波时间

#define LONG_PRESS 3   //长按
#define DBLCLICK 2	   //双击
#define CLICK 1		   //单击

static uchar Key_Num[KEY_QUANTITY] = {0};	 //存放按键io的值
static uint KeyDown[KEY_QUANTITY] = {0};	 //按键按下计数
static uchar KeyRelease[KEY_QUANTITY] = {0}; //按键释放计数
static uchar Key_Flag[KEY_QUANTITY] = {0};	 //按键是否按下过计数
//uchar Key_Value[KEY_QUANTITY] = {0};		 //存放按键键值,不记录按下时间用节省内存
uint Key_Value[KEY_QUANTITY] = {0};		 //存放按键键值,记录按键按下时间用,

static void key() //获取io的值
{
	int i = 0;
	Key_Num[i++] = U1;
	Key_Num[i++] = D1;
	Key_Num[i++] = U2;
	Key_Num[i++] = D2;
}

/*
	按键键值:1:单击
			2:双击
			3:长按
	键值单击和双击需要手动清零,长按松开自动置零
	返回值:指向按键键值的指针,记录按下时间时由于是int数组,使用时需要强转一下uint *key=(uint*)Key_Read()
*/
uchar *Key_Read(void)
{
	int i = 0;
	key(); //获取io的值
	for (i = 0; i < KEY_QUANTITY; i++)
	{
		if (Key_Num[i] == 0)
		{
			KeyDown[i]++; //按下计数自加
			if (KeyRelease[i] == 0)
				KeyRelease[i] = 1; //没有被按下过设置为1
			if (KeyDown[i] > LONG_TIME)
				/*按下时间超过LONG_TIME认为是长按,定时器时间,不会记录按下时间*/
				//Key_Value[i] = LONG_PRESS; 
				/*记录长按时间,Key_Value*定时器时间=按下时间,最大值65535,溢出最小值3,没溢出最小值LONG_TIME*/
				Key_Value[i] = KeyDown[i]>LONG_PRESS?KeyDown[i]:LONG_PRESS;
			else if (KeyDown[i] > CLICK_TIME && KeyRelease[i] > CLICK_TIME)
				Key_Flag[i] = 1; //按下计数超过设定,同时松开时间也超过设定认为是双击
		}
		else if (KeyRelease[i]) //松开时间计数
		{
			if (Key_Value[i] >= 3 || KeyDown[i] < FILTEER_TIME)
			{					   //长按松开或按下时间太短清零计数
				KeyRelease[i] = 0; //??????????
				KeyDown[i] = 0;
				Key_Value[i] = 0;
				continue; //退出不执行下面的if
			}
			if (KeyRelease[i]++ > POP_UP_TIME) //按键松开时间计数超过设定值
			{
				KeyRelease[i] = 0; //??????????
				KeyDown[i] = 0;
				if (Key_Flag[i]) //按键被按下过2次
				{
					Key_Value[i] = DBLCLICK; //设定为双击
					Key_Flag[i] = 0;
				}
				else
					Key_Value[i] = CLICK; //否则单击
			}
		}
	}
	return Key_Value;
}

按键的扫描是由定时器完成的

void tm1_isr() interrupt 3
{
	time_flag=1;//通知外面按键扫描完成
	Key_Read();
}

代码更改移植

  • 代码非常简介(至少是我认为的)就不到80行,其中一半还是定义,代码需要改的地方只有3个
    1. 按键端口的定义:#define D2 P32,增加或者减少都可以
    2. 按键数量的定义:#define KEY_QUANTITY 4 //按键数量,改成实际的按键数量
    3. 更改函数实现:key(),只需要复制前面一句更改"="后面的值就可以前面不用改
  • 稍微高级一点的功能更改:长按记录按下时间(代码就是),可以改成不记录时间的节省内存
    1.更改数组声明
//uchar Key_Value[KEY_QUANTITY] = {0};		 //存放按键键值,不记录按下时间用节省内存
uint Key_Value[KEY_QUANTITY] = {0};		 //存放按键键值,记录按键按下时间用,
  1. 更改函数实现
/*按下时间超过LONG_TIME认为是长按,定时器时间,不会记录按下时间*/
//Key_Value[i] = LONG_PRESS; 
/*记录长按时间,Key_Value*定时器时间=按下时间,最大值65535,溢出最小值3,没溢出最小值LONG_TIME*/
Key_Value[i] = KeyDown[i]>LONG_PRESS?KeyDown[i]:LONG_PRESS;
  • 这一堆东西可以尝试改改找到合适的手感,我的定时器10ms中断
#define LONG_TIME 50   //长按时间50,时间乘以定时器时间
#define CLICK_TIME 10  //单击时间
#define POP_UP_TIME 50 //按键弹起时间
#define FILTEER_TIME 5 //滤波时间
  • 移植到其他单片机
    只需要更改引脚定义和key()函数即可

文件下载

keill5文件

### 回答1: 在 TURBO C 2.0 中,您可以使用 biosdisk() 函数来格式化软盘。 下面是一段代码示例: ``` #include <stdio.h> #include <dos.h> int main() { // 定义扇区的大小 unsigned int sector_size[3] = {512, 512, 1024}; // 定义填充字节 unsigned char fill_char[3] = {0xF6, 0xF6, 0x48}; // 格式化磁道 70 面 0 的前三个扇区 for (int i = 0; i < 3; i++) { int result = biosdisk(2, 0, 70, 0, i + 1, 1, sector_size[i], fill_char[i]); if (result != 0) { printf("格式化扇区 %d 失败,返回码: %d\n", i + 1, result); } } return 0; } ``` 请注意,在使用 biosdisk() 函数之前,需要包含 dos.h 头文件。 希望这能帮到您! ### 回答2: 使用TURBO C 2.0语言,可以通过以下代码格式化软盘的70磁道0面,并分别格式化3个扇区,大小分别为512字节、512字节和1024字节。其中,前两个扇区使用F6填充,第三个扇区使用48填充。 ```c #include<stdlib.h> #include<stdio.h> #include<dos.h> void formatFloppyDisk(){ union REGS regs; regs.h.ah = 0x0;// To format a floppy disk, we set AH=0 regs.h.dl = 0;// Drive number (0=A, 1=B, etc.) regs.x.cx = 0;// Track number to format regs.h.dh = 0;// Head number regs.h.al = 0;// Sector size (0=default, 1=512 bytes, 2=1024 bytes, 3=2048 bytes etc.) int FILL_BYTE = 0;// The byte value to fill the sectors with during formatting int NUM_SECTORS = 3;// Number of sectors to format // To format 70th track 0th head regs.x.ax = 0x1301; // 0x13 = Reset disk system, 01H = Reset only specified drive int86(0x13, &regs, &regs); // BIOS interrupt to reset disk system for (int i=0; i<NUM_SECTORS; i++){ regs.x.ax = 0x3101; // 0x31 = Write Format, 01H = Format only current track regs.x.bx = 0x0001; // 0x00 = Drive A:, 01H = Head 1, 0 = Generate ID Field depending on the disk in the drive 1 = Keep the ID Field all zeros regs.x.cx = 0x0170; // Track number=70(0-79 range) regs.h.dh = 0x00; // Head number=0 or 1 regs.h.al = 0x02; // Control byte=always zero regs.x.dx = i+1; // Sector number starting from 1 regs.x.si = 0x0000; // segment and offset of read/write buffer regs.x.di = 0x0000; // segment and offset of result if(i == 2){ FILL_BYTE = 0x48; // Fill the third sector with 48 regs.x.ax = 0x3102; // 0x31 = Write Format, 02H = Format sequential tracks immediately following the one being formatted }else{ FILL_BYTE = 0xF6; // Fill the first two sectors with F6 } regs.h.ah = FILL_BYTE; // Fill the sector with specified byte int86(0x13, &regs, &regs); // BIOS interrupt to format the specified sector } } int main(){ formatFloppyDisk(); return 0; } ``` 上述代码使用了INT 0x13,即BIOS中断服务例程,来执行软盘格式化操作。通过设置寄存器的不同参数,可以指定要格式化的磁道、面、扇区大小和填充字节。在这个例子中,我们格式化了软盘70磁道0面的3个扇区,前两个扇区使用F6填充,第三个扇区使用48填充。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值