视频地址:http://v.youku.com/v_show/id_XODkxMDQwMzU2.htm

操作系统:WIN8 64 位

需要rxtx jar包的支持,我的是64位,32位的百度下载.

rxtx jar包(64位)下载地址:

http://download.csdn.net/detail/h_hongchang/8428621

懒得复制粘贴,直接下载代码文件:http://download.csdn.net/detail/h_hongchang/8440181

使用方法:

1.修改 上位机界面类(SerialCorrespondenceClient)里面的 COMS 变量为你当前arduino的串口;

2.运行界面:

点击"开启监听",

硬件:arduino uno3,连线方式根据代码上调整就好,当然也可以自己定义,不影响上位机.

上位机使用java语言编写,界面功能很简单.类中很多方法没有使用到,是为以后扩展功能留存的.着急回家过年没怎么好好整理代码,大家可以改进.添加新功能.灵敏度稍欠缺,过年回来再优化吧.

有三个类文件:

1.上位机界面;

2.串口通信监听;

3.模拟键盘按键工具类.

1.上位机界面代码:

<span style="font-family:Microsoft YaHei;">package com.fnw.fruitkey;import java.awt.AWTException;
import java.awt.Color;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;public class SerialCorrespondenceClient extends JFrame{//********组件变量************private JButton switchListenBT;//打开/关闭监听按钮private JLabel statusLB;//状态//********组件文案变量************private String switchMsg ="开启监听";//按钮操作文案private String statusMsg ="当前状态为[关闭]";//当前状态文案private Color statusColor = Color.red;//********普通变量************private Boolean switchFlag = false;//打开或关闭标示,默认关闭private SerialCorrespondenceController pc;//串口监听private String COMS = "COM5";//此处修改为当前arduino的串口/*** 测试* @author hongchang.hu* @function * @date 2015-2-9 下午4:07:00 * @param @param args * @return void*/public static void main(String[] args) {SerialCorrespondenceClient sw = new SerialCorrespondenceClient();sw.Client();}public void Client(){//============模板设置============JPanel panel=new JPanel();setSize(250,80);//使其宽度为 width,高度为 height。 setVisible(true);//显示窗体setDefaultCloseOperation(3);//设置用户在此窗体上发起 "close" 时默认执行的操作。setResizable(false);//不可调整大小setLocationRelativeTo(null);//设置窗口相对于指定组件的位置。 //============组件文案============switchListenBT = new JButton(switchMsg);statusLB = new JLabel(statusMsg);//============组件位置============//statusLB.setBounds(100,350,30,50);//x,y,width,heightsetContentPane(panel);//switchListenBT.setBounds(70,100,100,100);//x,y,width,height//============组件样式============statusLB.setForeground(Color.red);statusLB.setFont(new Font("微软雅黑",Font.BOLD,16));//============加入组件============add(switchListenBT);add(statusLB);//============为组件添加监听器============pc = new SerialCorrespondenceController();//准备串口监听BTListener btListener=new BTListener();switchListenBT.addActionListener(btListener);}    //============按钮组件监听器============class BTListener implements ActionListener {public void actionPerformed (ActionEvent ae){//============状态显示============switchFlag=!switchFlag;//每次点击取反if(switchFlag){switchMsg = "关闭监听";statusMsg = "当前状态为[开启]";statusColor = Color.green;pc.openPort(COMS); // 开打arduino连接端口try {pc.startRead(0);// 设置为一直监听arduino发送过来的信息} catch (AWTException e) {e.printStackTrace();} }else{switchMsg = "开启监听";statusMsg = "当前状态为[关闭]";statusColor = Color.red;pc.closeRead(); // 立即关闭监听}   switchListenBT.setText(switchMsg);statusLB.setText(statusMsg);statusLB.setForeground(statusColor);}}
}</span>

2.串口监听代码:

<span style="font-family:Microsoft YaHei;"><span style="font-size:12px;">package com.fnw.fruitkey;import gnu.io.CommPortIdentifier;
import gnu.io.PortInUseException;
import gnu.io.SerialPort;
import gnu.io.SerialPortEvent;
import gnu.io.SerialPortEventListener;
import gnu.io.UnsupportedCommOperationException;import java.awt.AWTException;
import java.awt.Robot;
import java.awt.event.KeyEvent;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Enumeration;
import java.util.TooManyListenersException;public class SerialCorrespondenceController implements Runnable, SerialPortEventListener{private String appName = "串口通讯";private int timeout = 2000;//open 端口时的等待时间private int rate = 9600;//open 端口时的等待时间private int threadTime = 0;private Robot robot; //创建一个robot对象private SetKeyDownUtil sdc;//创建模拟按键对象private CommPortIdentifier commPort;private SerialPort serialPort;private InputStream inputStream;private OutputStream outputStream;/*** @方法名称 :listPort* @功能描述 :列出所有可用的串口* @返回值类型 :void*/@SuppressWarnings("rawtypes")public void listPort(){CommPortIdentifier cpid;//当前串口对象Enumeration en = CommPortIdentifier.getPortIdentifiers();System.out.print("列出所有端口:");while(en.hasMoreElements()){cpid = (CommPortIdentifier)en.nextElement();//检测端口类型是否为串口if(cpid.getPortType() == CommPortIdentifier.PORT_SERIAL){System.out.println(cpid.getName() + ", " + cpid.getCurrentOwner());}}}/*** @方法名称 :write* @功能描述 :向端口发送数据,请在调用此方法前 先选择端口,并确定SerialPort正常打开!* @返回值类型 :void*   @param message* @throws IOException */public void write(String message) throws InterruptedException {checkPort();try{outputStream = new BufferedOutputStream(serialPort.getOutputStream());outputStream.write(message.getBytes());log("消息:'"+message+"'发送成功!");outputStream.close();}catch(IOException e){throw new RuntimeException("向端口发送信息时出错:"+e.getMessage());}}/*** @方法名称 :openPort* @功能描述 :选择一个端口,比如:COM1 并实例 SerialPort* @返回值类型 :void* @param portName*/public void openPort(String portName){/* 打开该指定串口 */this.commPort = null;CommPortIdentifier cpid;Enumeration en = CommPortIdentifier.getPortIdentifiers();while(en.hasMoreElements()){cpid = (CommPortIdentifier)en.nextElement();if(cpid.getPortType() == CommPortIdentifier.PORT_SERIAL && cpid.getName().equals(portName)){this.commPort = cpid;break;}}/* 实例 SerialPort*/if(commPort == null)log(String.format("无法找到名字为'%1$s'的串口!", portName));else{log("当前端口:"+commPort.getName());try{// 应用程序名【随意命名】,超时的毫秒数serialPort = (SerialPort)commPort.open(appName, timeout);}catch(PortInUseException e){// 端口已经被占用 throw new RuntimeException(String.format("端口'%1$s'正在使用中!",commPort.getName()));}}}/*** @方法名称 :startRead* @功能描述 :开始监听从端口中接收的数据* @返回值类型 :void* @param time  监听程序时间,单位为秒,0 则是一直监听* @throws AWTException * @throws InterruptedException */public void startRead(int time) throws AWTException {robot = new Robot();sdc = new SetKeyDownUtil();checkPort();try{inputStream = new BufferedInputStream(serialPort.getInputStream());}catch(IOException e){throw new RuntimeException("获取端口的InputStream出错:"+e.getMessage());}try{serialPort.addEventListener(this);// 设置可监听 serialPort.notifyOnDataAvailable(true);Thread.sleep(2000);log(String.format("开始监听来自'%1$s'的数据--------------", commPort.getName()));// 波特率,数据位,停止位 ,无奇偶校验serialPort.setSerialPortParams(rate,SerialPort.DATABITS_8,SerialPort.STOPBITS_1,SerialPort.PARITY_NONE);}catch(TooManyListenersException e){throw new RuntimeException(e.getMessage()); //端口监听者过多;  } catch (UnsupportedCommOperationException e) {e.printStackTrace();//"端口操作命令不支持";  } catch(InterruptedException e){e.printStackTrace();//延迟出错}/* 关闭监听 */if(time > 0){this.threadTime = time*1000;Thread t = new Thread(this);t.start();log(String.format("监听程序将在%1$d秒后关闭。。。。", time));}}/*** @方法名称 :closeRead* @功能描述 :立即关闭监听* @返回值类型 :void* @param time  监听程序时间,单位为秒,0 则是一直监听* @throws InterruptedException */public void closeRead() {checkPort();serialPort.close();log(String.format("端口'%1$s'监听关闭了!", commPort.getName()));}/*** 日志打印* @author hongchang.hu* @function * @date 2015-2-10 下午2:22:02 * @param @param msg * @return void*/public void log(String msg){System.out.println(appName+" --> "+msg);}/*** 模拟键盘按键* @author hongchang.hu* @function * @date 2015-2-10 下午2:23:09 * @param  * @return void* @throws AWTException * @throws IOException */public void keyboard(String strs) throws AWTException, IOException{if(strs.equals("up_s")){sdc.keyPress(robot, KeyEvent.VK_UP); // 上}else if(strs.equals("up_e")){sdc.keyRelease(robot, KeyEvent.VK_UP);}if(strs.equals("down_s")){sdc.keyPress(robot, KeyEvent.VK_DOWN); // 下}else if(strs.equals("down_e")){sdc.keyRelease(robot, KeyEvent.VK_DOWN);}if(strs.equals("left_s")){sdc.keyPress(robot, KeyEvent.VK_LEFT); // 左}else if (strs.equals("left_e")){sdc.keyRelease(robot, KeyEvent.VK_LEFT);}if(strs.equals("right_s")){sdc.keyPress(robot, KeyEvent.VK_RIGHT); // 右}else if (strs.equals("right_e")){sdc.keyRelease(robot, KeyEvent.VK_RIGHT); }else if(strs.equals("shift_s")){sdc.keyPress(robot, KeyEvent.VK_SHIFT); // SHIFT}else if (strs.equals("shift_e")){sdc.keyRelease(robot, KeyEvent.VK_SHIFT);}else if(strs.equals("ctrl_s")){sdc.keyPress(robot, KeyEvent.VK_CONTROL); // CTRL}else if (strs.equals("ctrl_e")){sdc.keyRelease(robot, KeyEvent.VK_CONTROL);}}/*** @方法名称 :checkPort* @功能描述 :检查端口是否正确连接* @返回值类型 :void*/private void checkPort(){if(commPort == null)throw new RuntimeException("没有选择端口,请使用 " +"selectPort(String portName) 方法选择端口");if(serialPort == null){throw new RuntimeException("SerialPort 对象无效!");}}/*** 数据接收的监听处理函数*/@Overridepublic void serialEvent(SerialPortEvent arg0){switch(arg0.getEventType()){case SerialPortEvent.BI:/*Break interrupt,通讯中断*/ case SerialPortEvent.OE:/*Overrun error,溢位错误*/ case SerialPortEvent.FE:/*Framing error,传帧错误*/case SerialPortEvent.PE:/*Parity error,校验错误*/case SerialPortEvent.CD:/*Carrier detect,载波检测*/case SerialPortEvent.CTS:/*Clear to send,清除发送*/ case SerialPortEvent.DSR:/*Data set ready,数据设备就绪*/ case SerialPortEvent.RI:/*Ring indicator,响铃指示*/case SerialPortEvent.OUTPUT_BUFFER_EMPTY:/*Output buffer is empty,输出缓冲区清空*/ break;case SerialPortEvent.DATA_AVAILABLE:/*Data available at the serial port,端口有可用数据。读到缓冲数组,输出到终端*/byte[] readBuffer = new byte[1024];String readStr="";//从arduino发送过来的信息String s2 = "";try {while (inputStream.available() > 0) {inputStream.read(readBuffer);readStr += new String(readBuffer).trim();}keyboard(readStr);//模拟键盘按键} catch (Exception e) {throw new RuntimeException(e.getMessage());} }}@Overridepublic void run() {try{Thread.sleep(threadTime);serialPort.close();log(String.format("端口'%1$s'监听关闭了!", commPort.getName()));}catch(Exception e){e.printStackTrace();}}/*** 测试* @throws AWTException * */public static void main(String[] args) throws InterruptedException, AWTException {SerialCorrespondenceController sp = new SerialCorrespondenceController();// 列出所有端口sp.listPort();//开打相应端口sp.openPort("COM4");//设置为一直监听sp.startRead(0);// 首次连接后需暂停2秒再继续执行否则数据会有问题Thread.sleep(2000);sp.write("我");//之后发送信息前后间隔至少40ms,否则会将上条返返回信息合并为一条接收(视硬件情况调节)Thread.sleep(40);sp.write("你");Thread.sleep(5000);sp.write("我们");}
}</span><span style="font-size:14px;">
</span></span>

3.模拟按键工具类代码:

<span style="font-family:Microsoft YaHei;">package com.fnw.fruitkey;import java.awt.Robot;
import java.awt.Toolkit;
import java.awt.datatransfer.Clipboard;
import java.awt.datatransfer.StringSelection;
import java.awt.datatransfer.Transferable;
import java.awt.event.KeyEvent;public class SetKeyDownUtil {/*** 测试* */public static void main(String[] args) throws Exception{Robot robot = new Robot(); //创建一个robot对象Runtime.getRuntime().exec("D:\\Program Files (x86)\\Tencent\\QQ\\Bin\\QQ.exe");//打开qqrobot.delay(2000);        //等待 2秒//窗口最大化keyPressWithAlt(robot, KeyEvent.VK_SPACE); //按下 alt+ 空格keyPress(robot, KeyEvent.VK_X);  //按下x键keyPress(robot, KeyEvent.VK_ENTER); // 按下 enter 换行robot.delay(2000);  //等待 2秒keyPressWithCtrl(robot,KeyEvent.VK_A); //按下 ctrl+A 全选robot.delay(2000);  //等待 2秒keyPress(robot,KeyEvent.VK_DELETE); //清除}// shift+ 按键public static void keyPressWithShift(Robot r, int key) {r.keyPress(KeyEvent.VK_SHIFT);r.keyPress(key);r.keyRelease(key);r.keyRelease(KeyEvent.VK_SHIFT);r.delay(100);}// ctrl+ 按键public static void keyPressWithCtrl(Robot r, int key) {r.keyPress(KeyEvent.VK_CONTROL);r.keyPress(key);r.keyRelease(key);r.keyRelease(KeyEvent.VK_CONTROL);r.delay(100);}// alt+ 按键public static void keyPressWithAlt(Robot r, int key) {r.keyPress(KeyEvent.VK_ALT);r.keyPress(key);r.keyRelease(key);r.keyRelease(KeyEvent.VK_ALT);r.delay(100);}//打印出字符串public static void keyPressString(Robot r, String str){Clipboard clip = Toolkit.getDefaultToolkit().getSystemClipboard();//获取剪切板Transferable tText = new StringSelection(str);clip.setContents(tText, null); //设置剪切板内容keyPressWithCtrl(r, KeyEvent.VK_V);//粘贴r.delay(100);}//单个按键按下public static void keyPress(Robot r,int key){r.keyPress(key);//r.delay(100);}//单个按键抬起public static void keyRelease(Robot r,int key){r.keyRelease(key);//r.delay(100);}
}
</span>

arduino 板代码:

<span style="font-family:Microsoft YaHei;">int buzzer = 12;//蜂鸣器管脚
int LED=7;//LED管脚
int UP = 10;
int DOWN = 8;
int LEFT = 6;
int RIGHT = 4;
int CTRL = 2;
int SHIFT = 12;/*** 初始化*/
void setup() {//pinMode(buzzer, OUTPUT);pinMode(7,OUTPUT);Serial.begin(9600);
}/*** 主循环体*/
void loop() {int up = readCapacitivePin(UP);int down = readCapacitivePin(DOWN);int left = readCapacitivePin(LEFT);int right = readCapacitivePin(RIGHT);int ctrl = readCapacitivePin(CTRL);int shift = readCapacitivePin(SHIFT);if (up > 2) { Serial.println("up_s");//按下}else{Serial.println("up_e");//抬起}
delay(50);if (down > 2) { Serial.println("down_s");}else{Serial.println("down_e");}
delay(50);if (left > 2) { Serial.println("left_s");}else{Serial.println("left_e");}
delay(50);if (right > 2) {Serial.println("right_s");}else{Serial.println("right_e");}
delay(50);if (ctrl > 2) { Serial.println("ctrl_s");}else{Serial.println("ctrl_e");}
delay(50);if (shift > 2) { Serial.println("shift_s");}else{Serial.println("shift_e");}delay(50);
}/** 读取管脚电容方法*/
uint8_t readCapacitivePin(int pinToMeasure) {volatile uint8_t* port;volatile uint8_t* ddr;volatile uint8_t* pin;/* 输入Arduino 端口号 到 AVR 的PORT, PIN, DDR 寄存器DDR寄存器用来控制数据的方向,1为数据出,0为数据入。PORT就跟51的Px口一样,直接读或直接写。PIN是用来读出io口的逻辑电平值。不能对它写操作*/byte bitmask;port = portOutputRegister(digitalPinToPort(pinToMeasure)); //直接读或直接写。ddr = portModeRegister(digitalPinToPort(pinToMeasure));//用来控制数据的方向,1为数据出,0为数据入。pin = portInputRegister(digitalPinToPort(pinToMeasure));//读出io口的逻辑电平值。不能对它写操作bitmask = digitalPinToBitMask(pinToMeasure); //位掩码// 设置下拉一个输出 (就是按下的时候)*port &= ~(bitmask);*ddr |= bitmask;delay(1);// 设置上拉一个输入(就是抬起的时候)*ddr &= ~(bitmask);*port |= bitmask;// 检测下拉值uint8_t cycles = 17;if (*pin & bitmask) { cycles = 0;}else if (*pin & bitmask) { cycles = 1;}else if (*pin & bitmask) { cycles = 2;}else if (*pin & bitmask) { cycles = 3;}else if (*pin & bitmask) { cycles = 4;}else if (*pin & bitmask) { cycles = 5;}else if (*pin & bitmask) { cycles = 6;}else if (*pin & bitmask) { cycles = 7;}else if (*pin & bitmask) { cycles = 8;}else if (*pin & bitmask) { cycles = 9;}else if (*pin & bitmask) { cycles = 10;}else if (*pin & bitmask) { cycles = 11;}else if (*pin & bitmask) { cycles = 12;}else if (*pin & bitmask) { cycles = 13;}else if (*pin & bitmask) { cycles = 14;}else if (*pin & bitmask) { cycles = 15;}else if (*pin & bitmask) { cycles = 16;}*port &= ~(bitmask);*ddr |= bitmask;return cycles;
}</span>

水果做键盘控制跑跑卡丁车相关推荐

  1. python秒表代码_斌哥教你自制千分秒表(键盘控制)

    上节课我们绘制了用鼠标控制的千分秒表,还指出了一个隐藏的bug及其解决方案.今天我们来绘制使用键盘控制的千分秒表,请大家比较它与上节课代码的区别. 话不多说,上代码. 素材准备: 不需要任何素材,只需 ...

  2. 关于ROS+Gazebo通过cmd_vel或键盘控制节点发布速度消息时,仿真小车运动速度相反问题

    本人初学ros,在做仿真小车的时候,通过soildworks2018建立四轮小车模型,并通过插件soildworks to urdf导出urdf文件. 将该文件移入虚拟机中,并将urdf修改为xacr ...

  3. openGL绘制带纹理地球,并实现鼠标键盘控制

    openGL系列文章目录 文章目录 openGL系列文章目录 前言 一.绘制球体 二.关键代码 球体类(Sphere) 主函数 顶点着色器 片元着色器 显示效果 源码下载 参考 前言 openGL绘制 ...

  4. Python自动化 | 通过键盘控制鼠标来玩赛尔号

    最近心血来潮回归赛尔号(十年铁皮常不请自来) 做剧情任务的时候有个小游戏,拖动黄色的按钮到达终点,白色的是存档点,途中如果碰到墙壁需要对战野怪,打赢了可以从存档点出发,但是由于刚回归,精灵跟不上时代, ...

  5. (程序员必备技能)基于Python的鼠标与键盘控制实战扩展与源码

    (程序员必备技能)基于Python的鼠标与键盘控制实战与源码 文章目录 (程序员必备技能)基于Python的鼠标与键盘控制实战与源码 一.序言 二.配置环境 1.下载pyautogui包 三.鼠标控制 ...

  6. ROS通信机制--键盘控制乌龟运动线速度角速度XYZ值的解释

    目录 前言 案例实现 线速度角速度X.Y.Z值的取值和作用 (END) 前言 在学习ros之初,想必大家运行的第一个案例就是键盘控制乌龟运动.这是ros内置的小案例,采用的通信机制为话题通信.本文介绍 ...

  7. three.js加载obj模型 键盘控制模型局部动作

    先贴上我前无古人后无来者的宇宙无敌搅拌机 我想用键盘控制框框中各部分分别有各自的动作,我这模型虽然是简单几何体堆积的,但是这是在blender里制作了模型,导出obj格式的模型再导进页面的,主要是测试 ...

  8. ubuntu14.04+windows双系统安装Ros indigo 与pioneer (测试的是3at和3dx) 键盘控制

    1.安装Linux系统,通过软件UltraISO 下载软件,打开文件,找到linux.iso文件,配置硬盘,写入 安装方式(WIn10+Linux论坛找的,win7直接分出50G,插u盘装就可以,如果 ...

  9. 一套鼠标键盘控制两台电脑-绝!

    Oliver's R&D Lab C/C++/Linux 一套鼠标键盘控制两台电脑-绝! 这个工具是推荐给双电脑工作人员的,不是的就不用往下看了,嗯. synergy-----按照它主页( h ...

最新文章

  1. BigdCIMAL类型数据的使用选择
  2. pxe+kickstart实现无人值守网络安装rhel5.4
  3. STM32 CJSON解析说明
  4. 全卷积网络FCN详解
  5. 视频生产环境下的音视频解决方案
  6. 浙江省第6届程序设计竞赛结题报告汇总 zoj3202-3212
  7. vivo应用商店电脑版_VIVO应用商店代理商江湖的那些关系
  8. [css] css的user-select:all 有什么用处?
  9. python入门第三天
  10. 【转载】10个有用的du命令行
  11. 字节输入流-InputStream demo3
  12. PKU3259-Wormholes(SPFA判断负环,含题意)
  13. L2-020. 功夫传人(STL+深搜)
  14. antDesign Drawer
  15. 安全优雅的RESTful API签名实现方案(手机端)
  16. Kuma是什么? Kuma1.0 GA 发布了包含70+新特性和改进
  17. 联想笔记本电脑insert键占用,当鼠标变成小方块时,如何解决
  18. POI导入Excel文件(包含.xsl和.xslx文件兼容问题)
  19. 河南的抗疫英雄,给出一系列抗疫英雄的姓名和来自的省份,现在请你帮忙统计来自河南的抗疫英雄有多
  20. SPSS简单数据分析之分类汇总数据

热门文章

  1. 2013年EI 新目录中新增的期刊
  2. 仿qq跨三端app uni-app+springboot+mybatis+websocket(springboot+mybatis)
  3. 思摩尔:中国电子烟行业领导企业致力于探索电子烟减害
  4. 电影放映时,电影院里很黑,你有什么办法知道这个放映厅里用Android手机的人多,还是用iOS手机的人多?
  5. 视频大数据的三大发展趋势
  6. 服务器Ubuntu常用命令汇总
  7. CentOS7配置VNC远程桌面
  8. LCD 调试总结(ZZ加实践)
  9. 基于python pyvisa模块控制GPIB设备识别不到设备资源号问题
  10. 汇编语言笔记(10)CALL和RET指令