本帖最后由 littleshrimp 于 2014-9-12 15:33 编辑
使用NXP LPC1549做的一个超好玩的USB键盘
1、做的是什么
这是一个非常有意思的东西,是一个防止别人偷偷使用你电脑的小装置,它的实际作用并不大,可以说根本没有实用价值,但是可以通过它让像我这样的小菜们更好的熟悉这款单片机,熟悉USB HID方面的开发,通过设计一个小项目来带动学习是很好玩的一件事。
2、它有什么功能
它是通过LPC1549实现的一个具有特殊功能的USB键盘,可以捕获使用者按下caps lock按键的状态,并通过判断按下的次数决定是否解锁,没解锁的时候此键盘通过不断发送win+l按键组合来锁定windows 系统,通过发送backspace 按键来干扰用户输入密码。只有解锁后此键盘才能消停。
3、它可以有什么功能(留给想玩的朋友开发)
a 可以增加判断每次按键的间隔时间功能来增加密码难度
b 可以增加RTC电池,便于记录每次开机的时间,用户通过发出特定指令让键盘把开机记录(开机时间,使用多长时间,什么时候关机)输出到记事本上(以后再也不用担心别人看没看我电脑啦)
c 玩过蓝牙的朋友也可以用CC2540做一个这样的键盘,把复杂的密码写到单片机里,当检测到用户手机并且验证成功时自动把密码输入到登录界面里,检测不到手机就一顿乱输入,把系统锁死。这样就再也不用怕密码级别不够和密码太难记不住了,而且还能防止别人偷看你密码,防止通过键盘声或键盘痕迹破解密码呢!哈哈,这可真是安全部门必备神器。
4、为什么要做这个
a 为了骗开发板,这是我最喜欢这些活动的地方(各种开发板没少骗),为了多接触一些器件,方便时间产品时选型。因为自己申请样品画板比较费时间,做出来的东西还不一定行不行,买官方的还太贵。
b 为了骗奖品,不提做设计就要收回开发板,就做吧,既然做了就尽量好好做吧,骗点奖品也是好的。
c 为了学习、进步,自从参加活动以来我已经研究出一套如何骗开发板方法了,哈哈(还能有点出息不),还有看过我发帖的朋友能够发现我发帖的质量也比以前有了小小的进步,很多东西也规范化了点,我是一个乐于分享的人,但是碍于自己写的东西太拿不出手,所以这点进步对我来说挺重要的。
d 顺便给和我一样的小菜起个头,有机会可以一起交流我的qq是1440507229
e 就是不为了产品本身要实现的功能
5、我是怎么做的
在NXP官方例程里有一个usbd_rom_hid_keyboard的例程,里边基本功能已经实现,我呢只是给
lpcopen_2_08c_keil_iar_nxp_lpcxpresso_1549\applications\lpc15xx\examples\usbd_rom\usbd_rom_hid_keyboard\hid_keyboard.c
做了一个小小的外科手术。
不过避免医疗事故发生在动手术前还要了解一下usb hid的小常识。TI有个资料比较不错SLAA514.pdf Application Report
别的我也没细看,最关心的还是下边这张表,里边说明Report(我理解为键盘通过USB给电脑发送的数据)的格式。
Report 的第0个字节代表键盘的功能按键,LeftCtrl ,Left Shift,Left Alt,Left GUI分别代表键盘左边的CTRL键,SHIFT键,ALT键和Window图标的那个键(锁定windows就是使用这个按键配合L键来实现的)。
Report 的第1个字节保留不使用。Report第2至第7可以设置6个按键,实现除功能键以外的6个按键同时按下,按下的顺序是从数据的低字节到高字节,比如在byte2里设置了’c’ byte3里设置了’a’,这时往记事本里输入的顺序是’c’,’a’。
知道原理以后剩下的就是简单的逻辑问题了,首先要找到处理caps lock状态的地方,它在
lpcopen_2_08c_keil_iar_nxp_lpcxpresso_1549\applications\lpc15xx\examples\usbd_rom\usbd_rom_hid_keyboard\hid_keyboard.c
文件的Keyboard_SetReport函数内:
- /* we will reuse standard EP0Buf */
- if (length == 0) {
- return LPC_OK;
- }
- /* ReportID = SetupPacket.wValue.WB.L; */
- switch (pSetup->wValue.WB.H) {
- case HID_REPORT_OUTPUT:
- /* If the USB host tells us to turn on the NUM LOCK LED,
- * then turn on LED#2.
- */
- if (**pBuffer & 0x02) {//判断caps lock指示灯状态
- Board_LED_Set(0, 1);
- if(caps_lock_flag == 0)//如果caps lock为1会反复执行此处,计数让其只在caps lock状态发生一次变化时才加1
- {
- caps_lock_flag = 1;//更新标志
- caps_lock_counter++;
- }
- }
- else {
- caps_lock_flag = 0;//更新标志
- Board_LED_Set(0, 0);
- }
- break;
- case HID_REPORT_INPUT: /* Not Supported */
- case HID_REPORT_FEATURE: /* Not Supported */
- return ERR_USBD_STALL;
- }
- return LPC_OK;
复制代码
我定义一个变量caps_lock_counter
,记录caps lock
状态改变的次数。Keyboard_SetReport这个函数会被频繁的执行所以要在只有caps lock改变时才对caps_lock_counter加加。
在Keyboard_UpdateReport里添加一段代码,当caps_lock_counter小于5时就向电脑输入指定按键,锁定并干扰电脑。
否则就点亮开发板上的绿灯,指示锁定解除。
- /* Routine to update keyboard state */
- static void Keyboard_UpdateReport(void)
- {
- HID_KEYBOARD_CLEAR_REPORT(&g_keyBoard.report[0]);//清数据
- if(caps_lock_counter<5)//
- {
- if(lock_flag == 0)
- {
- lock_flag = 1;
- g_keyBoard.report[0] = 0x08;
- g_keyBoard.report[2] = 0x0F;
- }
- else if(lock_flag == 1)
- {
- lock_flag = 2;
- //g_keyBoard.report[0] = 0xff;
- g_keyBoard.report[2] = 0x2A;
- //g_keyBoard.report[3] = 0x0F;
- //g_keyBoard.report[4] = 0x0F;
- }
- else
- {
- lock_flag = 0;
- }
- }
- else
- {
- Board_LED_Set(1, 1);
- }
- }
复制代码
在Keyboard_UpdateReport
函数中,没解锁时首先是发送win+l
锁定windows
的组合键,这时如果是在windows
登录以后才执行的话,系统肯定是被锁上了(
如果电脑有密码的话,否则是退到登录界面)
,然后防止别人输入你的密码只按win+l
是不行的,还要反复切换成backspace
键删除别人输入的密码(
够损的)
。0x08
对应WIN
键0x0F
对应L
键0x2A
对应BACKSPACE
键。
另外附上按键对应文件,里边已经定义好键盘会用到的所有按键。
我是不会告诉你它是在TI USB开发包的
MSP430_USB_Developers_Package_3_0_0_0\MSP430_USB_API_Stacks\examples\hidExamples\hidTraditional\IAR\keyboard_H8_Example\main.h
下发现的。
TI USB开发包MSP430_USB_Developers_Package-3.0-Installer.rar软件太大不能上传,谁喜欢自己下吧。
最后在上电配置完USB后加一段时间的延时再发送按键好让用户有足够多的时间解锁,防止刚开机时乱按影响系统启动。
另外还有一个是判断数据正忙的标志,这个是通过一个回调函数清除的,但是在开机的过程中乱输入按键会导致不能执行回调函数,不清零就不会执行下一次发送按键指令,所以加了这么一句话
- /* send report data */
- if (g_keyBoard.tx_busy == 0) {
- g_keyBoard.tx_busy = 1;
- busy_counter = 0;
- USBD_API->hw->WriteEP(g_keyBoard.hUsb, HID_EP_IN, &g_keyBoard.report[0], KEYBOARD_REPORT_SIZE);
- }
- else
- {
- //重新开机无法执行Keyboard_EpIN_Hdlr函数,使g_keyBoard.tx_busy一直为1
- //如果不判断g_keyBoard.tx_busy一直往里写的话会导致系统错误HardFault_Handler
- if(busy_counter++ > 10)//当busy10次以后复位g_keyBoard.tx_busy
- {
- busy_counter = 0;
- g_keyBoard.tx_busy = 0;
- }
- }
复制代码
在一段时间还忙的话g_keyBoard.tx_busy
就清零,有人说能不能不判断g_keyBoard.tx_busy
标志,就是一顿写行吗?不行,完全不顾单片机的感受只顾乱写会气死单片机的,HardFault_Handler
就是它要对你说的话,不信你就试试。6、作品展示
7、设计文件