【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; // 设置为工作方式1TMOD = 0x20; // 设置计数器工作方式2PCON = 0x80; // 波特率加倍TH1 = 0xFA; // 计数器初始值设置,波特率9600TL1 = 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);//enterP[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);//wP[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);//aP[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);//nP[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);//gP[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);//enterP[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;//CtrlSAVE[2] = 0x16;//Sfor (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

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

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

相关文章

多模态大模型训练数据量以及训练方式

多模态大模型系列&#xff1a;LLaVALLaVA1.5/1.6LLaVA-Med - 知乎就在前两天LLaVA 1.6发布了&#xff0c;带来了更大的分辨率&#xff0c;更强的LLM&#xff0c;在最后补充了这一部分的介绍。 LLaVA repo&#xff1a;https://github.com/haotian-liu/LLaVA/ LLaVA 1.0&#xff…

《C语言深度解剖》(9):深度剖析数据在内存中的存储

&#x1f921;博客主页&#xff1a;醉竺 &#x1f970;本文专栏&#xff1a;《C语言深度解剖》 &#x1f63b;欢迎关注&#xff1a;感谢大家的点赞评论关注&#xff0c;祝您学有所成&#xff01; ✨✨&#x1f49c;&#x1f49b;想要学习更多数据结构与算法点击专栏链接查看&am…

操作系统安全:Windows与Linux的安全标识符,身份鉴别和访问控制

「作者简介」&#xff1a;2022年北京冬奥会中国代表队&#xff0c;CSDN Top100&#xff0c;学习更多干货&#xff0c;请关注专栏《网络安全自学教程》 操作系统有4个安全目标&#xff0c;也就是说想要保证操作系统的安全&#xff0c;就必须实现这4个需求&#xff1a; 标识系统…

系统安全与应用(1)

目录 1、账号安全管理 &#xff08;1&#xff09;禁止程序用户登录 &#xff08;2&#xff09;锁定禁用长期不使用的用户 &#xff08;3&#xff09;删除无用的账号 &#xff08;4&#xff09;禁止账号和密码的修改 2、密码安全管理 设置密码有效期 1&#xff09;针对已…

一句话或一张图讲清楚系列之——ISERDESE2的原理

主要参考&#xff1a; https://blog.csdn.net/weixin_50810761/article/details/137383681 xilinx原语详解及仿真——ISERDESE2 作者&#xff1a;电路_fpga https://blog.csdn.net/weixin_45372778/article/details/122036112 Xilinx ISERDESE2应用笔记及仿真实操 作者&#x…

K8S Prometheus Springboot Actuator ServiceMonitor配置

用于展示Springboot Actuator监控内容 引入Springboot相关的监控配置包 Springboot pom配置 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-actuator</artifactId></dependency><depende…

K8s: Ingress对象, 创建Ingress控制器, 创建Ingress资源并暴露服务

Ingress对象 1 &#xff09;概述 Ingress 是对集群中服务的外部访问进行管理的 API 对象&#xff0c;典型的访问方式是 HTTPIngress-nginx 本质是网关&#xff0c;当你请求 abc.com/service/a, Ingress 就把对应的地址转发给你&#xff0c;底层运行了一个 nginx但 K8s 为什么不…

modelsim波形高度异常,值为X

一、问题 波形高度异常&#xff0c;忽高忽低&#xff0c;正常波形高电平和低电平是统一高度的 timescale 1ns/1nsmodule key_test_tb();//parameter define parameter CLK_PERIOD 20; parameter CNT_MAX 25d25; //仅用于仿真,对应 500nsreg sys_clk; //周期 20ns reg d; wir…

ffmpeg初体验

一&#xff1a;安装 sudo yum install epel-release -y sudo yum update -ysudo rpm --import http://li.nux.ro/download/nux/RPM-GPG-KEY-nux.ro sudo rpm -Uvh http://li.nux.ro/download/nux/dextop/el7/x86_64/nux-dextop-release-0-5.el7.nux.noarch.rpmyum -y install …

Vs Code npm install 报错解决方法

用的人家的前端框架发现是封装过的&#xff0c;要修改人家前端的话还得把前端源码放在Vs Code 上运行&#xff0c;后端放在IDEA上运行&#xff0c;然后前后端并行开发&#xff0c;在配置前端环境时遇到&#xff1a; npm install 这个的原因是我把node下载到D盘了权限不够框框爆…

android学习笔记(五)-MVP模式

1、MVP模式demo的实现&#xff0c;效果下&#xff1a; 2、创建一个Fruit类&#xff1a; package com.example.listview; //Fruit类就是Model&#xff0c;表示应用程序中的数据对象。 public class Fruit {private int imageId;private String name;private String price;publi…

代码随想录算法训练营Day6 | 242.有效的字母异位词 ●349. 两个数组的交集 ● 202. 快乐数● 1. 两数之和

基础&#xff1a; 1.哈希表是根据关键值进行直接访问的数据结构&#xff0c;时间复杂度是O(1)&#xff0c;也就是通过数组的索引下标&#xff0c;直接访问数组中的元素哈希表的作用就是用来快速判断一个元素是否出现在集合里。 2.常见的哈希结构&#xff1a; 数组set &#…

计算机视觉 | 交通信号灯状态的检测和识别

Hi&#xff0c;大家好&#xff0c;我是半亩花海。本项目旨在使用计算机视觉技术检测交通信号灯的状态&#xff0c;主要针对红色和绿色信号灯的识别。通过分析输入图像中的像素颜色信息&#xff0c;利用OpenCV库实现对信号灯状态的检测和识别。 目录 一、项目背景 二、项目功能…

CalcPad(2) 单位设置和绘制图表

CalcPad(2) 单位设置和绘制图表 Hi uu们&#xff0c;CalcPad用的还好吗&#xff1f;有发现一些问题吗&#xff1f; 在我的使用中&#xff0c;经常需要指定一些计算结果的符号&#xff0c;比如说我希望ADC最小分辨率的计算结果是以uV展示&#xff0c;那我们该怎么操作呢&#…

DB索引B+树SQL优化

数据库的索引就像一本书的目录&#xff0c;查数据快人一步&#xff0c;快速定位&#xff0c;精准打击&#xff01; 什么是数据库的索引&#xff1f; 官方介绍索引是帮助MySQL高效获取数据的数据结构。更通俗的说&#xff0c;数据库索引好比是一本书前面的目录&#xff0c;能加…

入坑 Node.js 1

原文&#xff1a;https://blog.iyatt.com/?p14717 前言 前面刚刚对 Spring Boot 有了个概念&#xff0c;再来学学 Node.js&#xff0c;顺便当学 JavaScript&#xff0c;为后面入前端做准备。 环境 Node.js 20.12.2 官方 API 文档&#xff1a;https://nodejs.org/docs/lat…

IBM SPSS Statistics for Mac:强大的数据分析软件

IBM SPSS Statistics for Mac是一款功能强大的数据分析软件&#xff0c;专为Mac用户设计&#xff0c;提供了一系列专业的统计分析和数据管理功能。无论是科研人员、数据分析师还是学生&#xff0c;都能从中获得高效、准确的数据分析支持。 IBM SPSS Statistics for Mac v27.0.1…

day_8题解

利用最大公约数求最小公倍数 #include<iostream> using namespace std;int gcd(int a,int b) {return b?gcd(b,a%b):a; }int main() {long long a,b;cin>>a>>b;long long ansgcd(a,b);cout<<(a*b)/ans<<endl;return 0; }排序遍历&#xff0c;记…

支持中文繁体,支持同时配置并启用飞书和Lark认证,JumpServer堡垒机v3.10.8 LTS版本发布

2024年4月22日&#xff0c;JumpServer开源堡垒机正式发布v3.10.8 LTS版本。JumpServer开源项目组将对v3.10 LTS版本提供长期的支持和优化&#xff0c;并定期迭代发布小版本。欢迎广大社区用户升级至v3.10 LTS最新版本&#xff0c;以获得更佳的使用体验。 在v3.10.8 LTS版本中&…

一款支持串口、网口自定义协议的调试软件

ComMax通讯调试软件是一款支持自定义串口&#xff0c;网口通讯协议的调试软件&#xff0c;用户可以根据需要&#xff0c;自定义协议包&#xff0c;然后根据接受的数据选择要发送的数据包。是一款强大、好用的调试软件。 点击下载 提取码&#xff1a;wmfg 不用安装 下载解压即…