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

目录

一、效果展示

二、创作灵感

三、硬件电路

注意事项

工作原理

四、源码

main.c

五、附录

CH9328工作原理

CH9328的模式选择

[​编辑 全键盘键码值表](#编辑 全键盘键码值表)

参考链接


一、效果展示

该小键盘具有三种功能:

1、自动输入开机密码

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

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

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

建码值见附录

二、创作灵感

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

三、硬件电路

注意事项

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

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

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

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

提取码:tone

晶振最好选用11.0592MHz。

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

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

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

工作原理

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

四、源码

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

main.c

cpp 复制代码
#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博客https://blog.csdn.net/qishi3250/article/details/83344176

原理篇4、CH9328使用-CSDN博客https://blog.csdn.net/qq_44817843/article/details/112124822

相关推荐
智商偏低4 小时前
单片机之helloworld
单片机·嵌入式硬件
青牛科技-Allen6 小时前
GC3910S:一款高性能双通道直流电机驱动芯片
stm32·单片机·嵌入式硬件·机器人·医疗器械·水泵、
森焱森8 小时前
无人机三轴稳定控制(2)____根据目标俯仰角,实现俯仰稳定化控制,计算出升降舵输出
c语言·单片机·算法·架构·无人机
白鱼不小白8 小时前
stm32 USART串口协议与外设(程序)——江协教程踩坑经验分享
stm32·单片机·嵌入式硬件
S,D8 小时前
MCU引脚的漏电流、灌电流、拉电流区别是什么
驱动开发·stm32·单片机·嵌入式硬件·mcu·物联网·硬件工程
芯岭技术11 小时前
PY32F002A单片机 低成本控制器解决方案,提供多种封装
单片机·嵌入式硬件
youmdt12 小时前
Arduino IDE ESP8266连接0.96寸SSD1306 IIC单色屏显示北京时间
单片机·嵌入式硬件
嘿·嘘12 小时前
第七章 STM32内部FLASH读写
stm32·单片机·嵌入式硬件
Meraki.Zhang12 小时前
【STM32实践篇】:I2C驱动编写
stm32·单片机·iic·驱动·i2c
几个几个n14 小时前
STM32-第二节-GPIO输入(按键,传感器)
单片机·嵌入式硬件