/*
by
机械键盘吧
ID emdyu
*/
byte yanshitime=2;//定义一个按键消抖延时参数
const byte hang =4;//设置行的数量
const byte lie= 4;//设置列的数量
const byte xiaodouyanshi=1;//定义按下延时循环次数
const byte taiqiyanshi=1;//定义抬起消抖延时循环次数
const byte yanshi=1;//定义一个程序运行的中间休息时间。单位us
int loopCount=0;//定义循环参数用于串口反馈扫描率
byte blkey=1 ;//定义蓝牙功能是否激活,1为是,0为否,2单独激活蓝牙,停用usb
byte blhang=0;//定义蓝牙键对应的行
byte bllie=3;//定义fn键对应的列
byte hangliejuzhenbl[hang][lie]={ //蓝牙第一按键层
{'a','8','9',KEY_BACKSPACE},//设置第1行对应的按键
{'4','5','6',0},//设置第2行对应的按键
{'1','2','3',0x94},//设置第3对应的按键
{0xA1,NULL,0x8C,0},//设置第4对应的按键
};
byte hangliejuzhen[hang][lie] = { //usb第一按键层
{'7','8','9',KEY_BACKSPACE},//设置第1行对应的按键
{'4','5','6',0},//设置第2行对应的按键
{'1','2','3',KEY_RETURN},//设置第3对应的按键
{'0',NULL,KEY_BACKSPACE,0},//设置第4对应的按键
//设置第5行对应的按键
};
byte hangliejuzhenfn[hang][lie]={ //usb第二按键层
{KEY_F1,KEY_F2,KEY_F3,NULL},
{KEY_F4,KEY_F5,KEY_F6,NULL},
{KEY_F7,KEY_F8,KEY_F9,KEY_F10},
{KEY_F11,NULL,KEY_F12,NULL}
};
byte fnkey=0 ;//定义fnkey是否激活,1为是,0为否
byte fnhang=0;//定义fn键对应的行
byte fnlie=3;//定义fn键对应的列
char* hangliejuzhenpnt[hang][lie]={ //usb字符串层,只能是字符串
{"","emdyu","99391047",NULL},
{"wangyu@hecz.cn","
www.baidu.com","6274199",NULL},
{"emdyu@163.com","
www.taobao.com","",NULL},
{NULL,NULL,".",NULL}
};
byte pntkey=1 ;//定义pntkey是否激活,1为是,0为否
byte pnthang=0;//定义pnt键对应的行
byte pntlie=3;//定义pnt键对应的列
/*
上面usb使用功能按键根据arduino官网代码如下:
KEY_LEFT_CTRL KEY_LEFT_SHIFT KEY_LEFT_ALT KEY_LEFT_GUI KEY_RIGHT_CTRL KEY_RIGHT_SHIFT KEY_RIGHT_ALT KEY_RIGHT_GUI
KEY_UP_ARROW KEY_DOWN_ARROW KEY_LEFT_ARROW KEY_RIGHT_ARROW KEY_BACKSPACE KEY_TAB KEY_RETURN KEY_ESC
KEY_INSERT KEY_DELETE KEY_PAGE_UP KEY_PAGE_DOWN KEY_HOME KEY_END KEY_CAPS_LOCK
KEY_F1
KEY_F2
直到
KEY_F12
____________________________________________________
上面使用的蓝牙功能键如下:填16进制的
#define F1_KEY 0x80
#define F2_KEY 0x81
#define F3_KEY 0x82
#define F4_KEY 0x83
#define F5_KEY 0x84
#define F6_KEY 0x85
#define F7_KEY 0x86
#define F8_KEY 0x87
#define F9_KEY 0x88
#define F10_KEY 0x89
#define F11_KEY 0x8A
#define F12_KEY 0x8B
#define CAPS_LOCK_KEY 0x8C
#define NUM_LOCK_KEY 0x8D
#define PRINT_SCREEN_KEY 0x8E
#define SCROLL_LOCK_KEY 0x8F
#define ESCAPE_KEY 0x90
#define TAB_KEY 0x91
#define BACKSPACE_KEY 0x92
#define DELETE_KEY 0x93
#define ENTER_KEY 0x94
#define PAUSE_KEY 0x95
#define INSERT_KEY 0x96
#define HOME_KEY 0x97
#define END_KEY 0x98
#define PAGE_UP_KEY 0x99
#define PAGE_DOWN_KEY 0x9A
#define RIGHT_ARROW_KEY 0x9B
#define LEFT_ARROW_KEY 0x9C
#define DOWN_ARROW_KEY 0x9D
#define UP_ARROW_KEY 0x9E
#define LEFT_CONTROL_KEY 0x9F
#define RIGHT_CONTROL_KEY 0xA0
#define LEFT_SHIFT_KEY 0xA1
#define RIGHT_SHIFT_KEY 0xA2
#define LEFT_ALT_KEY 0xA3
#define RIGHT_ALT_KEY 0xA4
#define LEFT_GUI_KEY 0xA5
#define RIGHT_GUI_KEY 0xA6
#define SELECT_KEY 0xA7
#define CUT_KEY 0xA8
#define COPY_KEY 0xA9
#define PASTE_KEY 0xAA
#define UNDO_KEY 0xAB
*/
byte hangduankou[hang] = {6,7,8,9}; //定义行用的端口
byte lieduankou[lie] = {16,15,10,14};//定义列用的端口
byte ledduankou[lie]={A0,A1,A2,A3};//定义led的pwm端口
/*
为前沿和后沿消抖循环参数都赋值为0
*/
int ledliangdu=128;//定义led的pwm
byte ledpwmhigh[6]={175,180,185,190,195,200};//定义3v电压灯亮度
byte ledpwmlow[6]={150,160,165,170,175,180};//定义2.2v电压灯亮度
byte anxiaxiaodou[hang][lie];//定义前沿消抖参数1
byte taiqixiaodou[hang][lie];//定义后沿消抖参数1
unsigned long time=millis();//获取系统起始运行时间
unsigned long startTime=0;//获取系统起始运行时间
unsigned long anxiatime[]={};//按下时间数组
unsigned long taiqitime[]={};//抬起时间数组
byte ledoff=0;//定义判断执行灭灯的条件参数
void setup(){
for(byte hangi =0;hangi<hang;hangi++){
pinMode (hangduankou[hangi],OUTPUT);//为行端口定义为输出口,用于矩阵扫描时输出
pinMode(A0, OUTPUT);//定义ledpwm输出端口
pinMode(A1, OUTPUT);//定义ledpwm输出端口
pinMode(A2, OUTPUT);//定义ledpwm输出端口
pinMode(A3, OUTPUT);//定义ledpwm输出端口
for(byte liei=0;liei<lie;liei++)
{
pinMode (lieduankou[liei], INPUT_PULLUP);//为列端口定义为上拉输入口,用于矩阵扫描时读取状态
}
Keyboard.begin();
Serial1.begin(38400);//开启为蓝牙串口输出用的串口并等待打开后执行以后的语句
while (!Serial1) ;
}
}
void loop() {
byte hango;
byte lieo;
for(hango=0;hango<hang;hango++){
pinMode(hangduankou[hango],OUTPUT);//设置该行为输出行
digitalWrite (hangduankou[hango],LOW);//为该行端口输出低电平
for (lieo=0;lieo<lie;lieo++){
if ( digitalRead(lieduankou[lieo])==LOW){//检测该列是否低电平(本来是高电平的,如果按键按下和列的低电平连接上,则变为低电平)
if(anxiaxiaodou[hango][lieo]<xiaodouyanshi){
anxiaxiaodou[hango][lieo]++;
break;
}
taiqixiaodou[hango][lieo]=0;
//判断是按下,如果消抖延时循环次数,未达到则为循环次数+1,同时无论是不是,都将该按键的抬起延时按下循环次数清0
}
else {
if (taiqixiaodou[hango][lieo]<xiaodouyanshi && anxiaxiaodou[hango][lieo]>0){
taiqixiaodou[hango][lieo]++;
//anxiaxiaodou[hango][lieo]--; //为按下消抖计数器-1
}
//如果没有判断出低电平,再次判断之前这个按键是否已经按下,如果是则为抬起延时+1延时清0,如果不是则不执行操作
}
}
digitalWrite (hangduankou[hango],HIGH);//为该行端口输出高电平
pinMode (hangduankou[hango],INPUT); //为停止该行输出高电平
// pinMode (lieduankou[lieo], INPUT_PULLUP);//为列端口定义为上拉输入口,用于矩阵扫描时读取状态
}
//以上是矩阵扫描和消抖部分,原理就是循环一次,检测到行列线连通了,就为该行列线对应的消抖循环参数自+1,然后达到一个预设值(需要实测)后用下面的输出部分输出这个值
//以下输出部分
if (millis()-time>yanshitime); //消抖延时为ms
{
for (byte hanga=0;hanga<hang;hanga++){
for(byte liea=0;liea<lie;liea++){
if (anxiaxiaodou[hanga][liea]==xiaodouyanshi){
taiqixiaodou[hanga][liea]=0;
if (anxiaxiaodou[fnhang][fnlie]==xiaodouyanshi && fnkey==1) //判断是否启动 fn 层
{
if (blkey !=0){
Serial1.write(hangliejuzhenfn[hanga][liea]);}
if (blkey!=2){
Keyboard.press(hangliejuzhenfn[hanga][liea]);}
}
else if (anxiaxiaodou[pnthang][pntlie]>xiaodouyanshi-1 && pntkey==1 ) //判断是否启动 pnt 层
{
//Keyboard.print(hangliejuzhenpnt[hanga][liea]);
if (blkey !=0){
Serial1.write(hangliejuzhenpnt[hanga][liea]);}
if (blkey !=2){
Keyboard.print(hangliejuzhenpnt[hanga][liea]);}
}
else{
analogWrite(ledduankou[0],ledliangdu);
analogWrite(ledduankou[1],ledliangdu);
analogWrite(ledduankou[2],ledliangdu);
analogWrite(ledduankou[3],ledliangdu);
startTime = millis();
//Serial1.write(hangliejuzhen[hanga][lie]);
//
if (blkey !=0){
Serial1.write(hangliejuzhenbl[hanga][liea]);}
if (blkey !=2){
Serial.print(hangliejuzhen[hanga][liea]);
Keyboard.press(hangliejuzhen[hanga][liea]);}
}
anxiaxiaodou[hanga][liea]=xiaodouyanshi+1;//将输出用按下消抖变成比延时+1,直到按键抬起激活才归0
}
if (taiqixiaodou[hanga][liea]==taiqiyanshi){
Keyboard.release(hangliejuzhen[hanga][liea]);
Keyboard.release(hangliejuzhenfn [hanga][liea]);
ledoff=2;//定义led关闭状态启动
anxiaxiaodou[hanga][liea]=0;
taiqixiaodou[hanga][liea]=taiqiyanshi+1;
//这里是输出按键用的,循环判断消抖是否达到预设值,达到则输出对应矩阵下的按键码操作。
}
}
}
time=millis();
/*analogWrite(A0,0);
analogWrite(A1,0);
analogWrite(A2,0);
*/
}
if (ledoff==2){
if ( millis()-startTime>500 && analogRead(ledduankou[3])>0)
{
analogWrite(ledduankou[3],0);//每过1秒,熄灭灯
ledoff=0;
}
if ( millis()-startTime>300 && analogRead(ledduankou[2])>0)
{
analogWrite(ledduankou[2],0);//
}
if ( millis()-startTime>200 && analogRead(ledduankou[1])>0)
{
analogWrite(ledduankou[1],0);//每过1秒,熄灭灯
}
if ( millis()-startTime>100 && analogRead(ledduankou[0])>0 )
{
analogWrite(ledduankou[0],0);//每过1秒,熄灭灯
}
}
loopCount++;// 自循环计数器+1
if ( millis()-startTime>5000 )
{// Serial.write("Scan Rate : ");
//Serial.println(loopCount/5);
}
//以下为串口调试部分
int val=Serial.read();
if (val>0)
{
Serial1.write(val);
Serial1.print(val);
Serial.write(val);
Serial.println(val);
val=0;
}
}