水果做键盘控制跑跑卡丁车
来源:互联网 发布:暴风云微交易源码 编辑:程序博客网 时间:2024/04/27 19:00
视频地址: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");//打开qq robot.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>
<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>
0 0
- 水果做键盘控制跑跑卡丁车
- 跑跑卡丁车
- 跑跑卡丁车
- 跑跑卡丁车,FT!
- FOJ 1685 跑跑卡丁车
- FZU 1685 跑跑卡丁车
- hdu 1494 跑跑卡丁车
- 数据结构 跑跑卡丁车
- hdu 1494 跑跑卡丁车~
- 跑跑卡丁车 hdu
- hdu 1494 跑跑卡丁车
- Hdu 1494 跑跑卡丁车
- 跑跑卡丁车 HUD
- HDU 1494跑跑卡丁车
- hdu1494 跑跑卡丁车dp
- HDU-1494-跑跑卡丁车
- HDU 1494 跑跑卡丁车
- 跑跑卡丁车解题报告
- 通过挂载磁盘解决SWAP分区和磁盘空间不足
- struts2学习54-68
- CSDN-Markdown编辑器使用简介
- git mergetool
- Swift:超炫的View Controller切换动画
- 水果做键盘控制跑跑卡丁车
- SEU寒假训练题解二 C Codeforces 445B
- hdu4044 树形dp+分组背包
- 从1点出发,经2n步到达5点有几种途径?
- 数据库连接池配置
- 学习资料
- Android studio mipmap图片资源文件夹
- CentOS7 查询已安装软件命令
- nefu 6 通宵教室 详解