【51单片机项目】基于51单片机自制多功能小键盘/模拟USB键盘【附源码】(STC89C52RC+CH9328)

目录

一、效果展示

二、创作灵感

三、硬件电路

注意事项

工作原理

四、源码

main.c

五、附录

CH9328工作原理

CH9328的模式选择 

​编辑 全键盘键码值表

参考链接


一、效果展示

d194e591f2204266ada26961a88b6c47.gif469a9f06125742b1aeb4a047315e965d.gif

该小键盘具有三种功能:

1、自动输入开机密码

2、每隔一段时间自动按下ctrl+s(即保存)

3、具有和电脑键盘的ctrl  c  v一样的功能,可组合使用(如ctrl+c是复制)

上述的三个键均、开机密码、自动保存时间均可自定义,修改键码值即可。

建码值见附录

二、创作灵感

由于本人是学校社团“仪光实践协会”技术部部长(技术部只有我一个人,既是部长,又是部员,哈哈哈🤣),需要给大一的学弟学妹们想一些有意思的项目,所以就做了这个。

三、硬件电路

注意事项

该电路的供电接口选用了micro-usb,之所以不用Type-C接口是因为该电路涉及数据传输,而用具有数据传输功能的Type-C接口较难焊接,故用micro–usb接口。

值得注意的是:目前micro–usb数据线使用得已经不太多了,在使用该键盘时一定要用具有数据传输功能的数据线。

有些数据线只有供电功能,不能进行通信!

cd4b594c69bd4d4297e2a9181144e96c.png

219d5c6349e34fb7806ac1fb0a9560af.png

8a3a185e424242478b1179c28b72d156.png

链接:https://pan.baidu.com/s/1L4SugrenjcNNLDxNhnBYWQ?pwd=tone 
提取码:tone

晶振最好选用11.0592MHz。

一开始我使用12MHz的晶振,但是在测试键盘时偶尔会识别错按键,如按下的是v键,但是电脑却显示按下了Capslock。

我对照键码值表发现如果出错(如上述CapsLock的例子),键值总是比按下的按键的键码值多一个固定的数。

我猜是由于12MHz产生的波特率不太精准,之后换成11.0592MHz发现果然是晶振的问题,完美解决识别错按键的问题。

工作原理

单片机不断地检测按键是否按下,如按下,则与CH9328进行通信,单片机向CH9328发送相对应的键码值,之后CH9328模拟键盘输入,最终电脑显示按键按下。

四、源码

此代码以开机密码是“wang”为例。

main.c

#include "reg52.h"

sbit k1 = P2^5;
sbit k2 = P2^6;
sbit k3 = P2^7;

void sendbyte(unsigned char b) // 串口发送字符
{
    SBUF = b;
    while (!TI);
    TI = 0;
}

void init() // 初始化函数
{
    SCON = 0x50; // 设置为工作方式1
    TMOD = 0x20; // 设置计数器工作方式2
    PCON = 0x80; // 波特率加倍
    TH1 = 0xFA; // 计数器初始值设置,波特率9600
    TL1 = TH1;
    TR1 = 1; // 打开计数器
}

void Timer0Init(void)
{
	TMOD &= 0xF0;		//设置定时器模式
	TMOD |= 0x01;		//设置定时器模式
	TL0 = 0xCD;		//设置定时初始值
	TH0 = 0xD4;		//设置定时初值
	TF0 = 0;		//清除TF0标志
	TR0 = 1;		//定时器0开始计时
	ET0=1;
	EA=1;
	PT0=0;
}

void delay(unsigned int xms)
{
    unsigned char i, j;
    while(xms--)
    {
        i = 2;
        j = 239;
        do
        {
            while (--j);
        } while (--i);
    }
}

void main(void) // 主函数
{		
    unsigned char key[8] = 0x00,P[8] = 0x00,i;
		Timer0Init();// 初始化
	  init(); // 初始化 
		delay(1500);
//以下是开机自动输入密码的程序,一直到第二个enter结束		
		P[2] = 0x00;
    P[2] = 0x28;
    for (i = 0; i < 8; i++) sendbyte(P[i]);
	  delay(100);//enter
    P[2] = 0x00; // 按键松开后
    for (i = 0; i < 8; i++) sendbyte(P[i]);
	
		delay(100);
	
		P[2] = 0x00;
    P[2] = 0x1A;
    for (i = 0; i < 8; i++) sendbyte(P[i]);
		delay(100);//w
	  P[2] = 0x00; // 按键松开后
    for (i = 0; i < 8; i++) sendbyte(P[i]);
	
		delay(100);
		
		P[2] = 0x00;
    P[2] = 0x04;
    for (i = 0; i < 8; i++) sendbyte(P[i]);
  	delay(100);//a
	  P[2] = 0x00; // 按键松开后
    for (i = 0; i < 8; i++) sendbyte(P[i]);
		
		delay(100);
		
		P[2] = 0x00;
	  P[2] = 0x11;
    for (i = 0; i < 8; i++) sendbyte(P[i]);
		delay(100);//n
	  P[2] = 0x00; // 按键松开后
    for (i = 0; i < 8; i++) sendbyte(P[i]);
	
		delay(100);
		
		P[2] = 0x00;
		P[2] = 0x0A;
    for (i = 0; i < 8; i++) sendbyte(P[i]);  
	  delay(100);//g
		P[2] = 0x00; // 按键松开后
    for (i = 0; i < 8; i++) sendbyte(P[i]);
		
		delay(100);

		P[2] = 0x00;
	  P[2] = 0x28;
    for (i = 0; i < 8; i++) sendbyte(P[i]);
   	delay(100);//enter
		P[2] = 0x00; // 按键松开后
    for (i = 0; i < 8; i++) sendbyte(P[i]);
 
    P2 = 0xFF;
    while (1) 
    {  
        delay(20); // 按键消抖处理
        if (k1 == 0) 
        {   delay(20);
            key[8] = 0x00;
			  		delay(1);
            key[0] = 0x01; // 按下ctrl键
            do {
                if(k2 == 0){
									  delay(20);  //消抖
                    key[2] = 0x00;
										delay(1);
                    key[2] = 0x06;
                    for (i = 0; i < 8; i++) sendbyte(key[i]);
                    while (k2 == 0);  //等待按键松开
                    delay(10);  //消抖
                    key[2] = 0x00; // 按键松开后
								  	delay(10);  //消抖
                    for (i = 0; i < 8; i++) sendbyte(key[i]);
                    while (!k2);
                }
								delay(100);
                if(k3 == 0){
									  delay(20);  //消抖
                    key[2] = 0x00;
				  					delay(1); 
                    key[2] = 0x19;
                    for (i = 0; i < 8; i++) sendbyte(key[i]);
                    while (k3 == 0);  //等待按键松开
                    delay(10);  //消抖
                    key[2] = 0x00; // 按键松开后
								  	delay(10);  //消抖
                    for (i = 0; i < 8; i++) sendbyte(key[i]);
                    while (!k3);	
                }            
                delay(20);  //消抖
                for (i = 0; i < 8; i++) sendbyte(key[i]);
            } while (k1 == 0);  //等待按键松开
            key[0] = 0x00; 
            key[2] = 0x00; // 按键松开后
            for (i = 0; i < 8; i++) sendbyte(key[i]);
            while (!k1);
        }
        
        delay(10);
				
        if (k2 == 0) 
        {   delay(20);
            key[0] = 0x00;
				  	delay(1); 
            key[2] = 0x00;
            delay(20);  //按键消抖
            key[2] = 0x06; // 按下c键
            for (i = 0; i < 8; i++) sendbyte(key[i]);
            while (k2 == 0);  //等待按键松开
            delay(10);  //消抖
            key[2] = 0x00; // 按键松开后
				  	delay(10);  //消抖
            for (i = 0; i < 8; i++) sendbyte(key[i]);
            while (!k2);
        }
        
        delay(10);
				
        if (k3 == 0) 
        {  	delay(20);
            key[2] = 0x00;
						delay(1); 
            key[0] = 0x00;
            delay(20);  //按键消抖
            key[2] = 0x19; // 按下v键
            for (i = 0; i < 8; i++) sendbyte(key[i]);
            while (k3 == 0);  //等待按键松开
            delay(20);  //消抖
            key[2] = 0x00; // 按键松开后
            for (i = 0; i < 8; i++) sendbyte(key[i]);
          

				while (!k3);
        }
   }
}

void Save() interrupt 1  //自动保存
{
	static unsigned int T0Count=0,i = 0;
	unsigned char SAVE[8] = 0x00;
	TL0 = 0xCD;		//设置定时初始值
	TH0 = 0xD4;	//设置定时初值
	T0Count++;
	if(T0Count>=40000)	//定时器分频,1s
	{
				T0Count=0;
				SAVE[0] = 0x01;//Ctrl
				SAVE[2] = 0x16;//S
				for (i = 0; i < 8; i++) sendbyte(SAVE[i]);
				SAVE[0] = 0x00;
				SAVE[2] = 0x00; // 按键松开后
				for (i = 0; i < 8; i++) sendbyte(SAVE[i]);
	}
}

五、附录

CH9328工作原理

键盘发送给PC的数据每次8个字节
BYTE1 BYTE2 BYTE3 BYTE4 BYTE5 BYTE6 BYTE7 BYTE8
定义分别是:
BYTE1 --
       |--bit0:   Left Control  是否按下,按下为1 
       |--bit1:   Left Shift  是否按下,按下为1 
       |--bit2:   Left Alt    是否按下,按下为1 
       |--bit3:   Left GUI    是否按下,按下为1 
       |--bit4:   Right Control是否按下,按下为1  
       |--bit5:   Right Shift   是否按下,按下为1 
       |--bit6:   Right Alt   是否按下,按下为1 
       |--bit7:   Right GUI   是否按下,按下为1 
BYTE2 -- 保留位,暂填0x00
BYTE3--BYTE8 -- 这六个为普通按键
例如:键盘发送一帧数据  02 00 04 00 00 00 00 00
表示同时按下了左Shift + ‘a’2个键;

效果:键盘无限循环显示大写字母A(因为包含了Shift键)

因为此时只模拟了按下,没有发送松开A键,所以会一直显示。因此自己模拟的时候再把松开按键也加上去。

CH9328的模式选择 

我用的是模式三。

 全键盘键码值表

参考链接

基于51单片机模拟键盘---超级简单-CSDN博客icon-default.png?t=N7T8https://blog.csdn.net/qishi3250/article/details/83344176

原理篇4、CH9328使用-CSDN博客icon-default.png?t=N7T8https://blog.csdn.net/qq_44817843/article/details/112124822

  • 4
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
首先,需要将4×4矩阵键盘和8个LED灯连接到STC89C52RC芯片的IO口上。然后,编写程序实现按下键盘对应的按键时,控制相应的LED灯亮。 以下是基本的程序框架: ```c #include <reg52.h> // 定义矩阵键盘的行和列 sbit ROW1 = P2^0; sbit ROW2 = P2^1; sbit ROW3 = P2^2; sbit ROW4 = P2^3; sbit COL1 = P2^4; sbit COL2 = P2^5; sbit COL3 = P2^6; sbit COL4 = P2^7; // 定义LED灯的IO口 sbit LED1 = P1^0; sbit LED2 = P1^1; sbit LED3 = P1^2; sbit LED4 = P1^3; sbit LED5 = P1^4; sbit LED6 = P1^5; sbit LED7 = P1^6; sbit LED8 = P1^7; void main() { while(1) { // 检测键盘是否有按键按下 // 如果有按键按下,则设置相应的LED灯亮起来 // 否则,关闭所有LED灯 } } ``` 在while循环中,需要不断地检测键盘是否有按键按下,如果有按键按下,则设置相应的LED灯亮起来,否则关闭所有LED灯。 接下来,需要编写检测键盘按键的代码。由于矩阵键盘是由行和列组成的,因此需要先设置行为输出,列为输入,然后逐行扫描,检测列的输入状态,以确定是否有按键按下。以下是检测键盘按键的代码: ```c int get_key() { int key = 0; ROW1 = 0; ROW2 = 1; ROW3 = 1; ROW4 = 1; if(COL1 == 0) key = 1; if(COL2 == 0) key = 2; if(COL3 == 0) key = 3; if(COL4 == 0) key = 4; ROW1 = 1; ROW2 = 0; ROW3 = 1; ROW4 = 1; if(COL1 == 0) key = 5; if(COL2 == 0) key = 6; if(COL3 == 0) key = 7; if(COL4 == 0) key = 8; ROW1 = 1; ROW2 = 1; ROW3 = 0; ROW4 = 1; if(COL1 == 0) key = 9; if(COL2 == 0) key = 10; if(COL3 == 0) key = 11; if(COL4 == 0) key = 12; ROW1 = 1; ROW2 = 1; ROW3 = 1; ROW4 = 0; if(COL1 == 0) key = 13; if(COL2 == 0) key = 14; if(COL3 == 0) key = 15; if(COL4 == 0) key = 16; return key; } ``` 该函数返回按键对应的数字值。如果没有按键按下,则返回0。 最后,需要编写控制LED灯亮起来的代码。根据键盘按键返回的值,设置相应的LED灯亮起来即可。以下是设置LED灯亮起来的代码: ```c void set_led(int key) { switch(key) { case 1: LED1 = 1; break; case 2: LED2 = 1; break; case 3: LED3 = 1; break; case 4: LED4 = 1; break; case 5: LED5 = 1; break; case 6: LED6 = 1; break; case 7: LED7 = 1; break; case 8: LED8 = 1; break; default: LED1 = 0; LED2 = 0; LED3 = 0; LED4 = 0; LED5 = 0; LED6 = 0; LED7 = 0; LED8 = 0; break; } } ``` 完成以上代码后,将程序下载到STC89C52RC芯片中,连接好矩阵键盘和LED灯,即可测试。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值