-项目概述-
我需要一块手表,可自定义开发,可以编程,可以玩游戏,可以接收消息,可以规划日程,还有就是不要丢掉初心:时间日期显示是一个手表基本功能......当然了,最重要是装逼。
-成品预览-
-项目框架-
STC-8G因为接口比ESP-M2多很多,所以选择STC作为外设控制以及端口引出,ESP-M2作为主控,处理消息以及获取网络信息。
项目导图如下:
-硬件资料,代码-
主框架逻辑:
1 /********************************************* 2 * 创建一个结构体 3 * 存放界面标志位 4 */ 5 typedef struct 6 { 7 u8 Interface_Mark; //界面状态 8 u8 Task_Mark; //任务状态 9 u8 Run_Task; //开始运行任务 10 } Mark; 11 Mark Mark_Sign;//状态标志位 12 13 /********************************************* 14 * 创建一个枚举 15 * 存放界面变量 16 */ 17 enum 18 { 19 Main_Interface = 0x10, /****主界面*****/ 20 Menu_Interface = 0x20, /****菜单界面***/ 21 Task_Interface = 0x30, /****任务界面***/ 22 }; 23 24 25 switch(Mark_Sign.Interface_Mark) 26 { 27 //状态标志位 主界面 28 case Main_Interface: 29 Main_Interface_APP();//显示主界面 30 break; 31 32 //状态标志位 菜单界面 33 case Menu_Interface: 34 Menu_Interface_APP();//显示菜单界面 35 break; 36 case Task_Interface: 37 Function_Menu_APP();//显示功能界面 38 break; 39 default: 40 break; 41 } 42 43 44 // 每个篮框定义一个结构体存放:起始x,y,长和宽,图像指针 45 void Main_Interface_APP() 46 { 47 // 时间显示 48 49 // 日期显示 50 51 // 图标显示 52 53 // 气温,CO2显示 54 } 55 56 // 每个菜单选项具有独立的 1.位号,2.标题,3.图标指针 57 struct Table 58 { 59 unsigned char tab_num; 60 char *title; 61 BMP_Ptr *ptr; 62 } 63 64 // 菜单选项管理器:1.子项个数,3.当前选项指针,4.菜单项数组 65 struct Menu_argument 66 { 67 Table Tab_array[t_size]; 68 char t_size; 69 unsigned char *Tab_current; 70 } 71 72 // 屏幕初始化时,创建菜单管理器 73 // for循环加载各个菜单子项(位号,标题, 图标指针)进入菜单管理器 74 75 76 // 图像管理集:专门存放图像的文件,统一使用一个图像指针数组进行管理 77 78 void Menu_Interface_APP() //显示菜单选项界面 79 { 80 // 绘制隔断线 81 82 for(i = 0; i < 3; i++) 83 { 84 // 1.绘制第一栏 85 86 // 2.绘制第二栏(指定为当前指针栏居中,字体放大一号) 87 88 // 3.绘制第三栏 89 90 } 91 // 当前指针栏指示符号绘制 92 93 // 当前指针栏图标加载绘制 94 }
滚轮操作检测逻辑:
u8 Opera_array[OPERA_NUM];
这是一个操作队列数组,用来存储51发送过来的操作数据的
bool Busy_flag;
这是繁忙标志,当程序正在执行当前任务时,就不会读取下一个操作数。
实操代码: #pragma once #define SCAN_T_MS 10 #define OPERA_NUM 10 enum KEY_VALUE { KEY_FORWARD = 0xA0, // 滚轮前滚 KEY_BCKWARD = 0xB0, // 滚轮后滚 KEY_UP = 0xC0, // 滚轮上弹 KEY_DOWN = 0xD0, // 滚轮按下 }; // 定义操作结构体:操作数,忙标志,操作队列数组,当前操作数指针 typedef struct { // 有效操作数存在标志 bool Opera_have_flag; // 操作繁忙标志 bool Busy_flag; // 当前队列操作数个数 u8 Opera_Current_num; // 操作队列当前值 u8 Opera_Current_value; // 操作队列数组 u8 Opera_array[OPERA_NUM]; }Opera_argument; Opera_argument KeyArgument; // 按键操作数初始化 void Init_KeyScan() { // 所有值清0 KeyArgument.Opera_have_flag = 0; KeyArgument.Busy_flag = 0; // 默认不繁忙 KeyArgument.Opera_Current_num = 0; for (int i = 0; i < OPERA_NUM; i++) { KeyArgument.Opera_array[i] = 0; } } // 定时按键扫描函数: void Key_Scan() { // 有效操作数是否存在 if (KeyArgument.Opera_Current_num != 0) { // 当前是否存在操作繁忙 if (KeyArgument.Busy_flag != 1) { // 操作数赋值给主函数,繁忙标志开启 KeyArgument.Opera_Current_value = KeyArgument.Opera_array[0]; KeyArgument.Busy_flag = 1; Serial.println("in_scan"); // 当前值置零,数组整体前移,当前队列操作个数-1 // KeyArgument.Opera_array[0] = 0; for (int i = 0; i < OPERA_NUM; i++) { KeyArgument.Opera_array[i] = KeyArgument.Opera_array[i + 1]; } KeyArgument.Opera_Current_num--; } } }
三级菜单界面切换逻辑:
1 //按键滚轮一共会产生以下几种触发状态 2 /* 3 * 1.滚轮前滚 4 * 2.滚轮后滚 5 * 3.滚轮按下 6 * 4.滚轮按下前滚 7 * 5.滚轮按下后滚 8 * 6.滚轮长按 9 */ 10 11 // 中断程序操作伪代码 12 if(触发操作 == 滚轮按下) 13 { 14 if(息屏 == 当前屏幕状态) 15 { 16 当前屏幕状态 = 主界面; 17 } 18 else if(主界面 == 当前屏幕状态) 19 { 20 当前屏幕状态 = 菜单界面; 21 } 22 else if(菜单界面 == 当前屏幕状态) 23 { 24 当前屏幕状态 = 任务界面; 25 26 switch(当前带单界面任务编号) 27 { 28 case 任务编号1: 29 即将执行任务编号 = 当前带单界面任务编号;break; 30 case 任务编号2: 31 即将执行任务编号 = 当前带单界面任务编号;break; 32 case 任务编号3: 33 即将执行任务编号 = 当前带单界面任务编号;break; 34 case 任务编号4: 35 即将执行任务编号 = 当前带单界面任务编号;break; 36 default:break; 37 } 38 } 39 else if(任务界面 == 当前屏幕状态) 40 { 41 switch(即将执行任务编号) 42 { 43 case 任务编号1: 44 break; 45 case 任务编号2: 46 break; 47 case 任务编号3: 48 break; 49 case 任务编号4: 50 break; 51 52 } 53 } 54 } 55 else if(触发操作 == 滚轮滚动) 56 { 57 // 仍然判断当前屏幕状态 58 if(息屏 == 当前屏幕状态) 59 { 60 当前屏幕状态 =主菜单; 61 } 62 else if(主菜单 == 当前屏幕状态) 63 { 64 // 无操作响应 65 } 66 else if(菜单界面 == 当前屏幕状态) 67 { 68 // 定义滚动方向变量(0):上滚变量赋值-1;下滚变量赋值+1 69 70 // 菜单当前主任务指示指针+滚动方向变量 71 72 // 滚动操作变量复位0 73 } 74 else if(任务界面 == 当前屏幕状态) 75 { 76 // 定义滚动方向变量(0):上滚变量赋值-1;下滚变量赋值+1 77 switch(任务序号) 78 { 79 case 任务编号1: 80 // 1.编号1任务子选项指针,加滚动方向变量 81 break; 82 case 任务编号2: 83 // 1.编号2任务子选项指针,加滚动方向变量 84 break; 85 case 任务编号3: 86 // 1.编号3任务子选项指针,加滚动方向变量 87 break; 88 case 任务编号4: 89 // 1.编号4任务子选项指针,加滚动方向变量 90 break; 91 92 } 93 } 94 }
项目全部文件:
个人博客下方私信领取
http://potatoworld.top:5800/
-项目槽点-
文章最后更新时间为:2018年08月14日11:17:25需求最近在公司大数据处理部门实习,但是也没有什么事情,换了个地方学习而已。第一天给了我一个任务,将数据分类,虽然无聊但是答应了就开始干呗。好了之后需要对每种情况进行统计,首先根据C列数据分类,如果C列数据为空,那么就根据B列数据进行分类。如下图:B列和C列的数据都是0/1/2。也就是分成三种情况,建立三个sheet表用来存放每种情况。对excel操作不熟悉,思来想去还是用python吧。正好在公司也无聊。代码:#-*-coding:utf-8-*- importxlrd importxlwt #创建workbook和sheet1/2/3对象 workbook=xlwt.Workbook() sheet1=workbook.add_sheet('sheet1',cell_overwrite_ok=True) sheet2=workbook.add_sheet('sheet2',cell_overwrite_ok=True) sheet3=workbook.add_sheet('s
数字化推动钢铁工业转型升级数字时代,随着数字地球,数字中国,数字工厂等数字化建设的不断深入,以地理信息系统(GeographicInformationSystem,GIS)为基础,融合大数据可视化、云计算、物联网以及人工智能等新一代信息技术,颠覆传统GIS应用,激发了地理信息产业新的生命力,让地理信息应用越来越广泛,走向时代的舞台。界面简介及效果预览钢铁作为国民经济发展的重要基础原材料,钢铁行业的产品创新为中国经济的发展提供有力的支撑。“十三五”以来,中国的钢铁工业从顶层设计到落地生根,在全面部署、积极探索行业科技创新之路上取得了卓越的层级。“十四五”要把控钢铁工业的高质量发展,加快推进绿色发展和智能化制造,重点解决控产能扩张、促产业集中、保资源安全三大难点。通过图扑软件的可视化以及GIS相关技术,对钢铁厂能源和安全方面进行全方位的数字化建设,让钢铁厂的监控更为直观,控制更加精准,提高钢铁工厂的整体管理水平和炼钢效率,推进钢铁工业绿色化和智能化的转型升级进程。实现价值基于HTforWeb和GIS技术的数字钢铁厂建设主要有以下三部曲:数据获取:Ø钢铁厂三维场景数据获取方式主要有两种:一种
今天要分享的故事仍然是来自于医学生,我是看到他这半年从电脑都不会弄,到现在可以像模像样的处理单细胞数据,真的很不容易!前言:之前参加过几个生信培训班也听了一些视频,好几个老师们都是说R语言里面warning不用管,error才重要,我一直牢记于心。Warning从来不看。下面开始正文。1首先读入数据,并查看前几行,正常和单物种的不一样的是,因为是人鼠混样测序比对的是人鼠基因组,基因前面分别有个前缀hg38和mm10,前后几个名称分别看一下,可以看到基因名字和物种代号之间使用的是下划线连接起来的。2创建对象3计算线粒体基因百分比为了方便理解,我先把文件读取出来查看下线粒体基因有没有表达,可以看到如图下面的数字。write.table(pbmc,file=pbmc.txt) 复制嗯,那么来计算一下。 因为前面的物种代号和基因名字使用下划线连接,所以代码如下pbmc[["percent.mt"]]<-PercentageFeatureSet(pbmc,pattern="^hg38_MT-") 复制重点是:pattern="^hg38_M
前言androidsdk里面自带的uiautomatorviewer.bat可以查看手机app上的元素,但是不太好用,网上找了个大牛写的weditor,试用了下还是蛮不错的 python环境:3.6weditor环境准备使用pip安装weditor,github地址https://github.com/openatx/weditorpipinstall—preweditor创建桌面快捷图标python-mweditor—shortcut创建完成后,桌面会出现一个WEditor快捷图标,双击就能启动了也可以不创建图标,用命令行启动python-mweditor看到窗口出现如下信息,就是启动成功了(窗口别关掉了)C:\Users\dell>python-mweditor listeningonhttp://192.168.1.125:17310 [I19071723:50:55web:2246]304GET/(::1)7.98ms [I19071723:50:55web:2246]304GET/static/libs/css/buttons.css(::1)196.47ms [I19
首先推荐博客:spring-boot-maven-plugin安装本地jar包http://www.cnblogs.com/acm-bingzi/p/mavenSpringBootPlugin.htmlhttp://www.jianshu.com/p/bcf627a409f2 http://blog.csdn.net/dongdingzhuo/article/details/78731704由对接支付宝当面付接口的时候来引入第三方的jar是冒出的问题,如何在springboot项目中来引入第三方的jar呢,如何在maven中配置呢,网上介绍了很多方法,试了几次总是报错。还是老老实实的在maven私服或者maven本的仓库来添加吧。具体说下如何来做:(1)下载第三方的jar包。放在本地电脑的某个盘中。例如:然后进入某盘:在cmd命令下,进入某盘,执行命令mvn具体如下:1.环境变量添加: MAVEN_HOME:(maven位置) M2_HOME:(maven位置) PATH:%M2_HOME%\bin (验证maven是否配置成功cmd-->maven -versi
或许,中本聪在创立数字货币的第一天就已经预测到了人们对于这个新事物两极分化的态度,所以,他选择隐姓埋名。同人们对于数字货币的两极分化的态度一样,人们对于区块链同样充满了不同的认识。正是这个原因才造就了区块链当前的状态——高烧不在,寒冷异常。区块链一开始被人们认识并不是一个正向的印象。无论是李笑来、陈伟星还是徐小平,他们传播区块链的渠道并非是在正规的渠道上,而是通过小范围的会议、聊天群等相对较为私密的方式传播。尽管如此,区块链依然受到了人们的追捧,甚至到了人人皆言区块链的地步。随着人们对于区块链认识的逐步理性,区块链市场的发展同样开始降温。曾经风光无限的区块链论坛,现在变成了门可罗雀;曾经加持区块链的大妈、微商和网红,现在早已销声匿迹。区块链正在从一个人人吹捧,开始回归到一种相对理性的状态。对于区块链来讲,这其实并不是一件坏事,因为区块链本来就不需要有如此多的鼓噪。吹捧不是区块链的全部,冷静才是正道尽管区块链能给我们带来完全不同的想象空间,但是依然掩盖不了它是一个新生的底层技术的现实。如果在一个技术的新生阶段就去吹捧它如何之好,显然是不对的。因为对于新生技术来讲,它的最初阶段最应该具备的
在聊天中,表情占据了越来越重要的地位。它能够承载一些难以言说的情感,也让聊天显得更加生动活泼。项目实现:选取mp4文件或摄像头录制生成微信GIF表情,可添加文字和特效(制作中)等功能。流程图:使用的工具: GIF编码:https://jnordberg.github.io/gif.js/ 只使用核心:GIFEncoder.js复制Worker线程:详见推送《JavaScriptWorker另类玩法》线程编码每个Frame,然后合并成GIF文件选取、录像:兼容IOS,安卓平台varinput_file=document.createElement("input"); input_file.type="file"; input_file.multiple=false;//单选文件 input_file.accept="video/*"; input_file.style.display="none"; document.body.appendChild(input_file); ..... i
之前部署了Webvirtmgr平台管理kvm虚拟机,由于虚拟机在创建时名称是顺便起的,后续在虚拟机上部署了部分业务。为了便于管理,最好将虚拟机的名称重置下。现在说下如何修改kvm中虚拟机的名称:比如将vmserver003修改成test-huanqiu,修改方法如下:1)终端命令行下查看虚拟机 [root@kvm-server~]#virshlist IdNameState ---------------------------------------------------- 4vmserver004running 5vmserver003running 6vmserver005running2)关闭虚拟机(也可以直接在Webvirtmgr平台界面里关闭) [root@kvm-server~]#virshshutdownvmserver0033)导出xml文件 [root@kvm-server~]#cd/etc/libvirt/qemu [root@kvm-serverqemu]#ls networksvmserver003.xmlvmserver004.xmlvmserver005
作者:小林coding 图解计算机基础网站:https://xiaolincoding.com 大家好,我是小林。 周末的时候,有位读者疑惑为什么Linuxman手册中关于netstat命令中的tcplisten状态下的Recv-Q和Send-Q这两个信息的描述跟我的图解网络写的不一样? 我看了源码后,确认了这个man手册写的不对。没想到Linux的man手册也会出错。 首先,先给大家介绍下netstat命令。netstat命令是查看网络状态很常见的Linux命令。 比如,如果我们想查看系统中的进程监听了哪些TCP端口,则可以使用下面这个命令: 接下来,小林带大家分析,为什么我说man手册写错了netstat命令中Recv-Q和Send-Q的描述? 疑惑提出 读者提出的疑惑:我先给大家翻译一下,man手册(https://man7.org/linux/man-pages/man8/netstat.8.html)是怎么说的: Recv-Q:如果TCP连接状态处于Established,Recv-Q的数值表示接收缓冲区中还没拷贝到应用层的数据大小;如果TCP连接状态处于Listen
7-3素数对猜想(20分)让我们定义dn为:dn=pn+1−pn,其中pi是第i个素数。显然有d1=1,且对于n>1有dn是偶数。“素数对猜想”认为“存在无穷多对相邻且差为2的素数”。现给定任意正整数N(<105),请计算不超过N的满足猜想的素数对的个数。输入格式:输入在一行给出正整数N。输出格式:在一行中输出不超过N的满足猜想的素数对的个数。输入样例:20输出样例:4代码如下: #include<stdio.h> #include<math.h> intprime(intm) { if(m<=1) { return0; } else { inti; for(i=2;i<=sqrt(m);i++) { if(m%i==0) return0; } return1; } } intmain() { intn,i,x=2,y=3; scanf("%d",&n); for(i=4;i<=n;i++) { if(prime(i)) { x=y; y=i; if(
线索二叉树的定义为:一个二叉树通过如下的方法“穿起来”:所有应该为空的右孩子指针指向该节点在中序序列中的后继,所有应该为空的左孩子指针指向该节点的中序序列的前驱。 那么在有N个节点的二叉树中共有N+1个空指针,这些空指针就叫做“线索”。(提示:在一个有N个节点的二叉树中,每个节点有2个指针,所以一共有2N个指针,将这N个节点连接起来需要N-1条线,即使用了N-1个指针。所以剩下2N-(N-1)=N+1个空指针。) 基本操作的代码如下(以中序为例): 1//线索二叉树的基本操作 2 3//结点定义 4structNode{ 5chardata; 6Node*lchild=NULL,*rchild=NULL; 7//0meansitisnotathread,itpointstoitschild 8boollflag=0,rflag=0; 9}; 10 11 12//中序线索化 13voidthread(node*&cur,node*&pre){ 14if(cur==NULL){ 15return; 16} 17//按中序,先处理左子树 18thread(cur->l
link:相交链表 第一种:最巧妙的方法,把两个链表加起来,A+B的长度和B+A的长度是一样的,同时遍历这两个相加后的链表,如果有交点,必然会某个位置他们相等,如果没有交点,最后也会相等,因为链表的尾部都是null publicListNodegetIntersectionNode(ListNodeheadA,ListNodeheadB){ ListNodea=headA; ListNodeb=headB; while(a!=b){ if(a==null) a=headB; else a=a.next; if(b==null) b=headA; else b=b.next; } returna; } 复制 第二种:我自己想出来的,计算两个链表的长度,同时看最后一个节点是否相等,若不相等,必然无交点,若相等就说明有交点。计算链表长度的插值,用一个快指针先走这个插值的步数,然后慢指针开始走,二者指向相同节点的位置就是交点 publicListNodegetIntersectionNode(ListNodeheadA,ListNodeheadB){ if(headA==null||headB
问题描述: 在MacOS上,支持smb&nfs; 有个testcase与hardlink相关,hardlink只存在nfs上。 更不可详细描述的细节,类似于如下: globalparameter=smb defset_up(self): globalparameter parameter=nfs returnparameter 然后在unittest.SkipIf(parameter=smb,"notsupportonsmb") 导致无论参数是什么,都会取到smb,而在它skip的这个case内部,parameter已经是nfs了 最后查明unittest执行顺序: 先执行声明的全局变量----->unittest.skipif()------->setupClass()内容----->测试用例按字母排序执行 解决方法:另外定义一个变量,在函数内部判断,如果是smb,就打log,返回。
快速排序由C.A.R.Hoare在1962年提出。它的基本思想是:通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。 算法处理过程(截图参考 坐在马桶上看算法:快速排序): 代码: publicclassQuickSort{ publicstaticvoidsort(int[]arr,intlow,inthigh){ intl=low; inth=high; inttmp=0; if(l<=h){//扫描低位标小于高位标 tmp=arr[l]; while(l!=h){//从两边交替扫描,直到l=h while(h>l&&arr[h]>tmp)h--; //从右往左扫描,找到第一个比基准数据小的数,进行替换 arr[l]=arr[h]; while(l<h&&arr[l]<tmp)l++; //从左往右扫描,找到第一个比基准数据大的数,进行替换 arr[h]=a
HowtoremovethekeysizerestrictioninJava JDK? AreyoudevelopingyourbeautifulapplicationusingtheJavaCryptographyExtension,andusingakeylengthofmorethan128bitsyouencounterthefollowingerror? Causedby:java.security.InvalidKeyException:Illegalkeysizeordefaultparameters复制 Thereisnothingwrongthatyouaredoing:JDKhasadeliberatekeysizerestrictionbydefault,soyoucannotuseanencryptionwithkeymorethan128bits. FromOracle’sdocumentation: Duetoimportcontrolrestrictionsbythegovernmentsofafewcountries,thejurisdic
今天遇到个小问题:项目中要做一个换肤的效果(就是点击换肤改变tabbarItem的图片)但是通过断点能看到图片确实变了,但是界面的样式没变。如下: 结果界面上tabbar的图片就是没变化 查了下image的几个样式 typedef NS_ENUM(NSInteger, UIImageRenderingMode) { UIImageRenderingModeAutomatic, // Use the default rendering mode for the context where the image is used &n
Gerrit是用于Git版本控制系统的代码审核系统。 下载 当前最新版本的gerrit为2.8.1,从官方下载二进制war包即可。 数据库设置 gerrit可以使用H2,PostgreSQL,MySql和Oracle数据库。这个安装使用PostgreSQL数据库。 创建gerrit使用的用户和数据库: $ createuser --username=postgres -RDIElPS gerrit2 $ createdb --username=postgres -E UTF-8 -O gerrit2 reviewdb复制 这里使用PostgreSQL提供的shell工具,也可以登录PostgreSQL使用psql来CREATEROLE和CREATEDATABASE。 创建用户 为gerrit创建单独的用户gerrit2,用于运行gerrit,但是禁止gerrit2用户登录系统。 # adduser gerrit2 # passwd --d
经历过前端开发这个岗位“走红”的小伙伴都知道,前几年里网上层出不穷对前端开发这一职位的褒奖,集“钱景”和“前景”于一身,知乎上铺天盖地关于前端的各种问题,身边学前端开发的人越来越多,前端招聘市场繁荣无比。而16年之后的前端开发招聘市场逐渐回归理性,前端进入了大浪淘沙的“换血”时代,想做一个拿着高薪的前端,似乎不再那么容易.... 于是,又有人开始说,前端的人太多了,搞得我都找不到工作,学前端没前途了!然而同时也有很多hr在抱怨吐槽说前端多而难找到一个合适的,难道是薪酬吸引不到优秀的人才吗? 初级前端程序员供给泛滥,待遇恶化,发展遇冷。对于初级人员来说,前端市场的确已经进入全面清理期,面临着较大淘汰风险,优胜劣汰带来的是人才质量的整体提高,这就不难理解为什么有很多人抱怨找工作难了。 形成鲜明对比的是:中高级工程师议价能力向好,越来越吃香。由于前端技术栈的不断更新,效率提高,同样的前端人数,能完成比以前更多的职责范围。在不少企业,1个优秀的前端工程师就能搞定Web和移动端的开发,甚至负责一部分后端。在激烈竞争下,经受住考验的永远是那批更优秀的人。就成都市而
call和apply都是对函数的直接调用,而bind方法返回的仍然是一个函数 call的实现原理:在方法调用模式下,this 总是指向调用它所在方法的对象,this 的指向与所在方法的调用位置有关,而与方法的声明位置无关(箭头函数特殊) 利用 this 的机制来实现 call 1Function.prototype.mycall=function(thisArg){ 2if(typeofthis!=='function'){ 3throwTypeError(`${this}isnotafunction`); 4} 5constargs=[...arguments].slice(1); 6thisArg=thisArg||window; 7thisArg.fn=this; 8constresult=thisArg.fn(...args); 9deletethisArg.fn; 10returnresult; 11}复制 apply的实现: 1Function.prototype.myapply=function(thi