为啥会想到改计算器按键呢?因为原来的按键实在是不好按,怎么都没有机械键盘来的舒服。在网上找了一圈,没有卖这种计算器的存在。倒是有一个很火的青轴的,但青轴比赛的话按着太累,而且只有8位数,按键排列也不舒服,根本没法比赛用。所以就只能给自己打造一个了。 材料很简单,一些茶轴加导线即可。 首先拆开计算器,分析了下电路板上的矩阵排列,把路线和轴重复的地方先焊接好,再一一对应接好即可。看着简单,实际接起来还挺费事的。 本来想保留一些原有的功能的,但拆了之后原来的按键都不能用了,所以最终放弃了,需要用到的键都改了,包括开机键。最终就呈现了一个专门用来百张传票翻打的计算器。 下一步的目标就是开发一个专门的银行专用的计算器,在DL-2135的基础上把按键都改为茶轴,数字部分保持和电脑同步,这样就不用去互相适应了,其余不变。再增加一个模式,用来一键屏蔽掉不需要的按键,这样比赛的时候就不用扣按键了,哈哈。希望这个产品最终能够面世吧。
之前在网上买的那种用18650电池的强光手电,便宜好用,但有一点烦人的是它有三个挡。分别是强、弱、爆闪。每次开机都是上次用过的档位下一挡,很烦。然后就拆开看了下,结构很简单,起控制作用的 就一个三极管加一个电容,问题就在这个电容上。 只需把它拆掉,就可以让它不再具有这种烦人的记忆功能,每次打开就能保持上次关闭时的状态了。目前还是能够调节三种模式的,不过方法要变,每次开机之前长按按键停留一会就能变成下一个模式。 新增:还是受不了带档位的了,直接把那个三极管也扣了,只留下那几个限流电阻,开关只控制开关,完美了。
一个很简单的天气显示系统,采用lcd2004作为显示器,能够显示当前联网获得的天气,配合之前室内的那个温度来用,绝配啊。 连线很简单,只需将2004按IIC方式连接在esp8266上即可。 代码: #include <ESP8266WiFi.h> #include <ArduinoJson.h> #include <Wire.h> //GPIO4(SDA) GPIO5(SCL) //I2C LCD: #include <Wire.h> // Comes with Arduino IDE #include <LiquidCrystal_I2C_DS3231.h> // Set the LCD I2C address #define I2C_ADDR 0x27 // Define I2C Address for the PCF8574T //---(Following are the PCF8574 pin assignments to LCD connections )---- // This are different than earlier/different I2C LCD displays #define Rs_pin 0 #define Rw_pin 1 #define En_pin 2 #define BACKLIGHT_PIN 3 #define D4_pin 4 #define D5_pin 5 #define D6_pin 6 #define D7_pin 7 #define LED_OFF 0 #define LED_ON 1 /*-----( Declare objects )-----*/ LiquidCrystal_I2C lcd(I2C_ADDR,En_pin,Rw_pin,Rs_pin,D4_pin,D5_pin,D6_pin,D7_pin); #define ledPin 14 // 定义ledPin连接到GPIO14 //年 byte Nian[8] = {0b01000,0b01111,0b10010, 0b01111, 0b01010, 0b11111, 0b00010, 0b00010}; //月 byte Yue[8] = {0b01111, 0b01001, 0b01111, 0b01001, 0b01111, 0b01001, 0b10011, 0b00001}; //日 byte Ri[8] = {0b01111, 0b01001, 0b01001, 0b01111, 0b01001, 0b01001, 0b01111, 0b00000}; //摄氏度 byte du[8] = {0b11000,0b11011,0b00100, 0b00100, 0b00100, 0b00100, 0b00011, 0b00000}; const char* ssid = " XXXXXX"; // XXXXXX -- 使用时请修改为当前你的 wifi ssid const char* password = " XXXXXX"; // XXXXXX -- 使用时请修改为当前你的 wifi 密码 const char* host = "api.seniverse.com"; const char* APIKEY = "wcmquevztdy1jpca"; //API KEY const char* city = "nanjing"; const char* language = "en";//zh-Hans 简体中文 会显示乱码 const unsigned long BAUD_RATE = 115200; // serial connection speed const unsigned long HTTP_TIMEOUT = 5000; // max respone time from server const size_t MAX_CONTENT_SIZE = 1000; // max size of the HTTP response // 我们要从此网页中提取的数据的类型 struct UserData { char city[16];//城市名称 char weather[32];//天气介绍(多云...) char temp[16];//温度 char udate[32];//更新时间 }; WiFiClient client; char response[MAX_CONTENT_SIZE]; char endOfHeaders[] = "\r\n\r\n"; /** * @Desc 初始化操作 */ void setup() { lcd.begin(20, 4); // Switch on the backlight lcd.setBacklightPin(BACKLIGHT_PIN,POSITIVE); lcd.setBacklight(LED_ON); lcd.createChar(0, Nian); lcd.createChar(1, Yue); lcd.createChar(2, Ri); lcd.createChar(3, du); WiFi.mode(WIFI_STA); //设置esp8266 工作模式 Serial.begin(BAUD_RATE); delay(10); Serial.println(); Serial.println(); Serial.print("Connecting to ");//写几句提示,哈哈 Serial.println(ssid); WiFi.begin(ssid, password); //连接wifi while (WiFi.status() != WL_CONNECTED) { //这个函数是wifi连接状态,返回wifi链接状态 delay(100); Serial.print("."); } Serial.println(""); Serial.println("WiFi connected"); delay(100); Serial.println("IP address: "); Serial.println(WiFi.localIP());//WiFi.localIP()返回8266获得的ip地址 client.setTimeout(HTTP_TIMEOUT); } /** * @Desc 主函数 */ void loop() { while (!client.connected()){ if (!client.connect(host, 80)){ Serial.println("connection...."); delay(100); } } if (sendRequest(host, city, APIKEY) && skipResponseHeaders()) { clrEsp8266ResponseBuffer(); readReponseContent(response, sizeof(response)); UserData userData; if (parseUserData(response, &userData)) { printUserData(&userData); } } delay(300);//每5s调用一次 } /** * @发送请求指令 */ bool sendRequest(const char* host, const char* cityid, const char* apiKey) { // We now create a URI for the request //心知天气 String GetUrl = "/v3/weather/now.json?key="; GetUrl += apiKey; GetUrl += "&location="; GetUrl += city; GetUrl += "&language="; GetUrl += language; // This will send the request to the server client.print(String("GET ") + GetUrl + " HTTP/1.1\r\n" + "Host: " + host + "\r\n" + "Connection: close\r\n\r\n"); Serial.println("create a request:"); Serial.println(String("GET ") + GetUrl + " HTTP/1.1\r\n" + "Host: " + host + "\r\n" + "Connection: close\r\n"); delay(100); return true; } /** * @Desc 跳过 HTTP 头,使我们在响应正文的开头 */ bool skipResponseHeaders() { // HTTP headers end with an empty line bool ok = client.find(endOfHeaders); if (!ok) { Serial.println("No response or invalid response!"); } return ok; } /** * @Desc 从HTTP服务器响应中读取正文 */ void readReponseContent(char* content, size_t maxSize) { size_t length = client.peekBytes(content, maxSize); delay(100); Serial.println("Get the data from Internet!"); content[length] = 0; Serial.println(content); Serial.println("Read data Over!"); client.flush();//这句代码需要加上 不然会发现每隔一次client.find会失败 } /** * @Desc 解析数据 * 数据格式如下: * { * "results": [ * { * "location": { * "id": "WX4FBXXFKE4F", * "name": "北京", * "country": "CN", * "path": "北京,北京,中国", * "timezone": "Asia/Shanghai", * "timezone_offset": "+08:00" * }, * "now": { * "text": "多云", * "code": "4", * "temperature": "23" * }, * "last_update": "2017-09-13T09:51:00+08:00" * } * ] *} */ bool parseUserData(char* content, struct UserData* userData) { // -- 根据我们需要解析的数据来计算JSON缓冲区最佳大小 // 如果你使用StaticJsonBuffer时才需要 // const size_t BUFFER_SIZE = 1024; // 在堆栈上分配一个临时内存池 // StaticJsonBuffer<BUFFER_SIZE> jsonBuffer; // -- 如果堆栈的内存池太大,使用 DynamicJsonBuffer jsonBuffer 代替 DynamicJsonBuffer jsonBuffer; JsonObject& root = jsonBuffer.parseObject(content); if (!root.success()) { Serial.println("JSON parsing failed!"); return false; } //复制我们感兴趣的字符串 strcpy(userData->city, root["results"][0]["location"]["name"]); strcpy(userData->weather, root["results"][0]["now"]["text"]); strcpy(userData->temp, root["results"][0]["now"]["temperature"]); strcpy(userData->udate, root["results"][0]["last_update"]); // -- 这不是强制复制,你可以使用指针,因为他们是指向“内容”缓冲区内,所以你需要确保 // 当你读取字符串时它仍在内存中 return true; } // 打印从JSON中提取的数据 void printUserData( struct UserData* userData) { Serial.println("Print parsed data :"); lcd.clear(); lcd.setCursor(0,0); lcd.print("Update time:"); lcd.setCursor(0,1); lcd.print(userData->udate); lcd.setCursor(0,2); lcd.print("City:"); lcd.print(userData->city); lcd.print(" Out:"); lcd.print(userData->temp); lcd.write(byte(3)); lcd.setCursor(0,3); lcd.print("Now:"); lcd.print(userData->weather); delay(4*1000); } // 关闭与HTTP服务器连接 void stopConnect() { Serial.println("Disconnect"); client.stop(); } void clrEsp8266ResponseBuffer(void){ memset(response, 0, MAX_CONTENT_SIZE); //清空 } lcd2004的使用基本参照1602来,库也是一样的,只要改变下显示位置就行了。获取网络天气的代码来自:http://bbs.doit.am/forum.php?mod=viewthread&tid=442&extra=。没有自己去申请api,直接用了原作者的。哪一天失效了再自己改吧。 成品图:
因为usb接口坏了,所以需要直接使用GPIO接口来烧录程序。 别的没啥要注意的,主要把GPIO0口接地就行了。别的按照usb模块来接就行了。
之前的那个键盘因为用的鼠标主控(见http://blog.readgroup.cn/post/40),会和数位板产生冲突,禁掉鼠标按键的话使用上又不方便,所以就还是换键盘的主控吧。本来想用digispark做主控的,但是延迟啥的没处理好,这个方案以后再说吧。目前用digispark来控制LED呼吸灯。 成品如图: 接口上也改为了microusb接口,更加方便携带。所有焊接处都用热熔胶封死,不小心漏了,导致有点多了。 键盘主控如图: 只焊接了ZX两个按键,打OSU足够了。
因为需要实时了解服务器状态,所以需要一个能够查看服务器在线状态的软件。找了几个,效果都不太行,不如用网页版的,还方便。最终选择了Server Monitor,下载地址:http://www.phpservermonitor.org。 环境要求就基本的php就行了,需要数据库以及cURL扩展。安装没啥问题,跟着步骤走就行。刚开始可能遇到配置文件无法写入的情况,手动把配置文件内容复制过去即可。同时config.php.sample改为config.php,保存再回到安装界面点击继续即可。安装完成登录就可以用啦。添加自己的服务器配置,一般用服务吧,检测端口比较好用。ping的功能好像不太行,试了几次没作用,暂时没找到原因。 然后要注意的是设置中的刷新时间是页面的刷新时间,不是检测代码的刷新时间,设置这个还没法自动检测。这里我们就需要用到crontab定时任务了,一般Linux中都集成了。 进入编辑界面: sudo crontab -e 在最下面添加如下代码: */5 * * * * php /var/www/cron/status.cron.php 后面的路径根据实际修改。 重启crontab: sudo /etc/init.d/cron restart 之后就可以正常使用了,现在是5分钟检测一次,可以自己修改时间,具体crontab的使用可以参见相关文档。
虽然说买一个简易的手柄也就几十块钱,效果还比这个好很多,但总是想自己做一个玩玩。 所用材料: arduino leonardo板子一个, arduino mega2560外壳一个, JoyStick Shield手柄扩展板一个。 将上述物品组装在一起,如图: 接着就是能够实现手柄功能的代码: #include <Joystick.h> #define RANGE 30 Joystick_ Joystick(JOYSTICK_DEFAULT_REPORT_ID,JOYSTICK_TYPE_GAMEPAD, 7, 0, // Button Count, Hat Switch Count true, true, false, // X and Y, but no Z Axis false, false, false, // No Rx, Ry, or Rz false, false, // No rudder or throttle false, false, false); // No accelerator, brake, or steering void setup() { // Initialize Button Pins pinMode(2, INPUT_PULLUP); pinMode(3, INPUT_PULLUP); pinMode(4, INPUT_PULLUP); pinMode(5, INPUT_PULLUP); pinMode(6, INPUT_PULLUP); pinMode(7, INPUT_PULLUP); // Initialize Joystick Library Joystick.begin(); Joystick.setXAxisRange(-1, 1); Joystick.setYAxisRange(-1, 1); Serial.begin(115200); } // Last state of the buttons int lastButtonState[7] = {0,0,0,0,0,0,0}; int X,oldX; int Y,oldY; void loop() { // Read pin values for (int index = 0; index < 7; index++) { int currentButtonState = !digitalRead(index + 2); if (currentButtonState != lastButtonState[index]) { Joystick.setButton(index, currentButtonState); lastButtonState[index] = currentButtonState; } } X=analogRead(A0); Y=analogRead(A1); if ((X!=oldX) || (Y!=oldY)) { if ((X>=512-RANGE) && (X<=512+RANGE)) {Joystick.setXAxis(0);} else if (X>512+RANGE) {Joystick.setXAxis(-1);} else {Joystick.setXAxis(1);} if ((Y>=512-RANGE)&&(Y<=512+RANGE)) {Joystick.setYAxis(0);} else if (Y>512+RANGE) {Joystick.setYAxis(-1);} else {Joystick.setYAxis(1);} oldX=X; oldY=Y; } delay(10); } 所用到的库文件:https://github.com/MHeironimus/ArduinoJoystickLibrary 其中有些参数可以根据需要酌情修改。 扩展版引脚定义: X值接A0口 Y值接A1口 A接D2 B接D3 C接D5 D接D4 E接D6 F接D7 下载完程序,连上电脑就能识别成一个手柄了,但现在还没有按键映射,这里还需要另一个工具Xpadder(点击下载),利用这个来完成按键的映射。推荐使用提供的这个老版本,功能够用操作简单,新版在win10上好像有点问题。软件使用很简单,新建配置文件和映射文件即可。 最后一切搞定,来吧小时候的魂斗罗~ 参考连接: https://www.arduino.cn/thread-46192-1-2.html https://www.jianshu.com/p/9fc765524050
偶然看到别人的博客页面上有个萌萌的看板娘,好可爱,还能跟着鼠标动,还有各种提示语,很想要一个。 然后就找了些资料,首先是博客的,发现有一个现成的插件:https://www.wikimoe.com/?post=75 这个插件基本是可以直接使用的,我只改动了下它在页面的位置。图灵聊天的功能暂时没加,感觉用不到,就先没管了,后续加上一些简单的提示语来模拟聊天的功能吧。 然后就是直接调用的网页版,给neoblog用的。源码在这:https://www.fghrsh.net/post/123.html 这个用原博的api的接口,支持的种类还挺多的,用起来也方便,稍微改下参数啥的就行了。 后续准备根据原博的后端代码自己搭建api来实现一些自定义的功能( •̀ ω •́ )y
之前抽奖得到一个向日葵的开机棒,可以用来远程开机,后来不知道啥原因不好使了,就想到利用树莓派来远程开机,反正树莓派24小时一直不关。我这里的树莓派是安装了树莓派系统的台式机,不过方法是通用的。 首先开启主板的网卡唤醒功能(注意把本地硬盘的启动顺序放第一,不要把网卡放第一,不然会起不来),查到自己电脑的mac地址,这个很简单就不说了。 ssh登陆树莓派,安装etherwake: apt-get install etherwake 安装完成拿另一台局域网的主机登陆树莓派测试一下: etherwake MAC地址(xx:xx:xx:xx:xx:xx) 正常的话不会有任何报错,并且主机也启动了。到这一步如果树莓派能够外网访问的话直接用ssh登陆下开一下就好了,后面的可以不弄,但是为了方便,下一步开始我配置了网页shell命令的方式来快速执行指令。 使用https://github.com/b374k/b374k这一php工具,把它放在服务器上,第一次使用的时候需要自定义生成一个文件,根据页面提示选择模块,我们这里不需要别的模块,可以都不要,然后设置密码后点击pack后就生成了一个b374k.php文件。然后把除了这个文件外的别的文件都删除,以免带来隐患。(注意,这个文件可操作性较高,请一定重命名文件和设置高强度密码) 然后在相同目录新建一个wake.sh脚本: #!/bin/sh sudo etherwake MAC地址 echo "已执行远程开机命令" 给与777权限。然后查看下网页端执行shell命令的用户是谁,我们要给它一个免输密码权限,不然无法执行需要root权限的脚本。在ssh中输入以下命令: lsof -i:80 找到自己网页服务的名称,我用的是lighttpd,对应的用户为www-data。 接下来给www-data免密码执行脚本权限: nano /etc/sudoers 添加以下语句: www-data ALL = NOPASSWD: ALL 然后重启服务器。 之后网页访问相应文件,输入密码,在命令行输入./wake.sh回车即可,看到提示即表明命令发送成功。我是使用的frp加443端口来外网访问的,这样安全性要好一点。 至此,利用树莓派来远程开机就实现了。并且,这样一来就可以开启局域网内任意一台主机了,相比向日葵局域网版,成本可以说大大降低,因为用nanopineo的话总共硬件才几十块钱。
给女朋友的电脑重装office,电脑是win7的系统,结果安装到一半就开始报错没有任何错误代码,然后就显示"Microsoft setup Bootstrapper已停止工作",根据网上的方法绕了一圈也没弄好。 但后来发现,系统服务(运行services.msc)中Task Scheduler没有启动,手动也开启不了,就怀疑和这个有关。然后找到一个指令,在cmd中执行:netsh winsock reset 之后重启,发现服务可用了,再安装office就一切正常了!