编者按:近年来,低代码以燎原之势席卷而来,面对这种情况,很多人都想尝试,那么我们在选择低代码时需要注意什么呢?本文将5个低代码平台综合比较,为大家提供参考建议。
低代码近年来成了“香馍馍”,在中美地区几乎每周都有一家新的AI平台或无代码(No-Code)的公司融资。Gartner的报告显示,低代码或无代码的市场,仅在2021年就增长了25%,分析软件市场也在一年内成长了20%。放眼国内市场,也是发展得如火如荼。
2018年,低代码快速应用开发领域公司OutSystems获得3.6亿美元融资;同年,西门子宣布以6亿欧元收购低代码应用开发领域的领导者Mendix;
2019年,阿里集团董事局主席张勇首次提出了“商业操作系统”;
2020年,用友发布的低代码平台YonBuilder; 2020年,钉钉宣布推出低代码应用开发平台“App Store”;
2021年初,阿里发布钉钉6.0版本,会议中提及最多的关键词就是“低代码”;
随后,软件网发布的低代码/无代码行业研究报告。
……
低代码市场百花齐放的局面,势必也造成了良莠不齐的后果,那么,如何在这其中选出靠谱的低代码平台呢?下面就为大家带来了5个值得一试的低代码平台,大家放心冲!
1.天翎——MyApps低代码平台
天翎作为国内最早从事快速开发平台研发和应用的厂商之一,自2003年开发研发,至今已经18年历史,平台源代码已达200万行,客户累计授权超10万+,拥有丰富的低代码开发经验。
特点:
(1)可视化操作界面设计,让企业业务人员也可以参与到软件的开发中,业务人员只需要专注于业务逻辑,而不需要注重代码的编写.
(2)平台支持私有化部署,将重要数据都部署在本地,极大地保证了信息的安全。同时支持多种不同的部署方案,可以根据不同的用户在线数量及并发数量选择具体的部署方式,通常系统各操作响应时间在0.5-3S以内。
(3)低代码+BPM+KM相结合的三位一体平台,可以轻松实现OA协同办公、督办管理、项目管理等业务管理系统。
(4)全面适配国产化,能兼容市面上国产的绝大多数CPU、国产操作系统、国产中间件、国产数据库、国产文件管理等;在数据库和操作系统方面,它支持主流数据库,如MSQL SQL、SERVER、DB2、ORACLE等,与市面上大多数主流操作系统相互兼容,如中标麒麟操作系统、深度操作系统、优麒麟操作系统等。
(5)创新源码交付机制,保障用户在不同的应用阶段、不同层次和不同规模的服务需求都能得到满足,解决后顾之忧。
2.炎黄——盈动AWS PaaS
基于长期BPM PaaS项目管理和实践经验,总结提炼形成AWS PaaS平台项目实施方法论,专注于企业业务流程管理和运维。更适用于大中型企业,有更高的扩展性与继承性。2019年发布的易鲸云版本,支持对复杂业务应用的可视化构建,提供基于Java标准的开放编程框架,灵活满足复杂场景的扩展。
炎黄盈动推出的第六代平台产品,于2017年正式发布,完全自主研发并拥有核心技术,致力于为用户提供低代码和BPM结合的PaaS平台。
特点:
(1)专注BPM和PaaS开发研究,是面向大中型企业的PaaS平台。
(2)打通从流程管理到流程执行的轻量级低代码平台。
(3)涵盖了流程应用、移动应用、数据应用、集成应用、协同应用、API应用六大应用场景。
3.阿里——宜搭
由于上线时间不长,功能尚不完善,应用模板较少,对新手不够友好,从一些用户评价来看,整体体验还有待优化。
2019年3月宜搭上线,9月发布宜搭Plus低代码开发平台,2020年6月,宜搭上线专有云版。
特点:
(1)以表单模型驱动的应用可视化搭建,可根据业务灵活定制应用。
(2)集成钉钉,默认使用钉钉通讯录,搭建好的应用可接入企业工作台,可实现高效协同办公。
(3)提供DDoS攻击防御,WEB应用防火墙,接口安全检测等安全服务。
4.帆软——简道云
2015年就入局的零代码开发厂商,在数据管理与数据可视化分析上有出色表现。流程性应用配置需求,现也在挖掘核心应用需求的应用开发。作为无代码赛道的明星产品,在功能满足及使用体验上都较好。
帆软软件出品,国内第一家在线零代码应用搭建平台,主打表单、流程表单、数据管理与数据分析,为企业流程性业务管理与配置赋能,无需代码、全程拖拽,即可完成应用搭建。
特点:
(1)流程性业务配置应用轻松搭建,赋能业务人员,二次开发成本低。
(2)数据工厂、聚合表、仪表盘等功能助力数据管理与数据分析。
(3)提供OA/人事/绩效/ERP/CRM/进销存等解决方案。
(4)提供BPA(业务流程分析)工具,为企业优化、调整业务流程提供科学的统计方法和开箱即用的分析工具。
(5)可集成于钉钉,飞书;提供API & Webhook功能,可自主开发。
(6)提供知识库功能,可与工作流结合。
5.奥哲网络——氚云
获阿里战投,背靠阿里强势发展,钉钉四星级定制服务商,功能良好,报表美观度上略差。
奥哲旗下产品,2016年上线钉钉应用市场,是面向业务部门管理者或企业决策者的业务管理工具,以拖拽式的积木搭建的方式搭建应用。
特点:
(1)提供表单、流程引擎,报表等功能。
(2)积木式应用搭建,同时具备代码开发和外部系统集成能力。
(3)与钉钉集成,支持PC端与移动端使用。
经过综合比较,我们可以发现,天翎MyApps低代码平台历史悠久,产品体系相对完善,推荐优先尝试。
🟥 概念介绍 动画:
本章所讲的动画,是美术同学给fbx模型绑定的骨骼动画。
这个动画呢,导入Unity后需要进行设置。在Unity中可设置为三种模式:
None:不导入动画。
我们可以看到下图,将Boulder 1 骨骼设置为None模式,Project下,Boulder 1下仅有一个网格PolyBoulder01
Legacy:老版本动画系统
Generic:通用模式
Humanoid:人形动画
🟧 Generic与Humanoid动画的区别 Generic:
它是新的动画系统,支持非人形(怪物)动画,也支持人形动画。
但它无法使用Humanoid动画重定向功能。即美术给一个模型做的动画,这些做的动画只能给这个模型使用,不能给其他模型使用。而Humanoid的动画重定向功能,可以实现一个模型的动画,给其他模型使用。
Humanoid: Humanoid是人形动画,不支持非人形动画。并可使用动画重定向功能。
拓展:
基础知识讲解:
动画,是模型的动作。不是视频“动画片”。
模型动画,是美术同事给模型骨骼绑定动作。骨骼驱动着模型进行运动。
动画重定向功能实现的逻辑:Unity自带一套unity骨骼系统。美术给人物模型做的动画也有一套美术骨骼系统。当设置为Humanoid时,Unity自带的骨骼会自动识别美术给模型做的骨骼,并一一对应起来。
再有新人物模型时,新模型的骨骼也会和Unity骨骼对应起来。
这样用原模型的动画,就可驱动着原模型的骨骼,驱动unity内置骨骼,继而驱动与unity内置骨骼对应的新模型的骨骼,使新模型做出运动。
选择Generic或者Humanoid后,系统都自动为Perfab模型生成Avatar。这个Avatar可以提供给其他同Humanoid的骨骼用来共用Avator(动画重定向),这个例子就是FBX_Female_Hero共用了FBX_Biker的Avatar,记得取消勾选导入FBX_Female_Hero的动画:Animations—Inport Animation取消勾选,不导入动画
🟨 Humanoid导入方式 1、将模型转化为Humanoid格式。
选中FBX模型,Inspector—Rig—Humanoid—Create From This Model/(Copy from Other Avatar)—Apply—Configure
2、Humanoid属性讲解
绿色、白色都是Unity内置骨骼,会跟人物的骨骼节点映射,白色为未映射正确的。
实线为必须映射骨骼,虚线为非必须的
更改映射方法:点击Model里的白色骨骼,在Hierarchy里选择正确的骨骼节点,拖到它的Mapping(映射)对话框中
注意:Model里末端骨骼为上一级骨骼子节点,Hierarchy里面同理
3、可在Preview里设置运动范围
4、应用你做的设置
Apply—Done
🟩 骨骼映射 是将模型里的骨骼节点映射到Unity自带的骨骼模型上
Scene里白色、绿色骨骼为我们(美术)创建的骨骼,Mapping(映射)里面为Unity自带骨骼,我们创建的骨骼要映射到Unity自带的骨骼上
Hierarchy里面每个节点都与Scene模型一一对应,我们做的骨骼可能做得比Unity自带的多,也可能少,我们只需要将Unity必须要映射的骨骼映射过去就好了,保证逻辑关系
Scene里面有两块骨骼,左侧Hierarchy节点为长骨骼,它的父节点为短骨骼,他们两个都可以填入右侧Mapping,因为小骨骼带动大骨骼运动,两种方式都可以控制小臂运动。
大家还有什么问题,欢迎在下方留言!
如果你有 技术的问题 或 项目开发
都可以加下方联系方式
和我聊一聊你的故事🧡
🟥 动画属性类型的区别 None:不导入动画Animation ClipLegacy:用于早期动画设置,其不支持状态机Animator,无法对动画进行编辑,导入完后直接用Animation播放Generic:支持人形、非人形ModelHumanoid:只支持人形Model,导入后用Animator播放(设置后Hirearchy模型里面自动添加Animator组件)Generic一样 🟧 动画功能实现 1、动画循环播放
Assets模型Inspector—Wrap Mode ,选择Loop,使动画循环播放
2、动画自动播放
即完成当运行游戏,模型为显示且激活状态时,自动播放模型的默认动画。
Hierarchy模型Inspector—Play Automatically(自动),勾选则为自动播放
🟨 动画属性讲解 1、动画类型选择
动画类型选择Generic,点击后会生成一个动画和骨骼映射(Humanoid一样)。
2、属性介绍
a、Perfab的Inspector—Avatar Definition(骨骼映射定义)
Create From This Model:使用这个Model创建骨架
Copy From Other Avatar:使用其他骨骼(前提是和另一个模型的骨骼相同)
b、Root node(根节点):选择模型根节点
c、Optimize(优化) Game Objects:是否优化游戏物体,在发布游戏时勾选
大家还有什么问题,欢迎在下方留言!
如果你有 技术的问题 或 项目开发
都可以加下方联系方式
和我聊一聊你的故事🧡
问题:
播放模型动画时,模型位置锁死无法更改
解决办法:
勾选这个选项即可
大家还有什么问题,欢迎在下方留言!
如果你有 技术的问题 或 项目开发
都可以加下方联系方式
和我聊一聊你的故事🧡
1 上箭头
.drawJt{
border: 4rpx solid #c2c0c0;
width: 40rpx;
height: 40rpx;
border-left-color: transparent;
border-top-color: transparent;
transform: rotate(-135deg);//上箭头
margin: 0 auto;
margin-top: 20rpx;
}
2 下箭头
.drawJt{
border: 4rpx solid #c2c0c0;
width: 40rpx;
height: 40rpx;
border-left-color: transparent;
border-top-color: transparent;
//下箭头
//transform: rotate(45deg);
margin: 0 auto;
margin-top: 20rpx;
}
3 左箭头
.drawJt{
border: 4rpx solid #c2c0c0;
width: 40rpx;
height: 40rpx;
border-left-color: transparent;
border-top-color: transparent;
transform: rotate(135deg);//左箭头
margin: 0 auto;
margin-top: 20rpx;
注释:此离线安装方法非常简单,但前提是需要有安装盘,因为安装盘里一般都会有gcc,我们只需把安装盘当作一个本地yum源就可! (挂载本地镜像安装)
跟着下面的做就好啦哈!!!
1.设置光驱挂载点
mkdir -p /Application/cdrom 2. #挂载光驱
mount /dev/cdrom /Application/cdrom 这个是挂载后文件地址,你也可以自己选着路径 3. #备份原yum源
cp /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo.bak 4.#把光驱设为yum源
echo "[base]" > /etc/yum.repos.d/CentOS-Base.repo echo "name=CentOS-$releasever - Base" >> /etc/yum.repos.d/CentOS-Base.repo echo "baseurl=file:///Application/cdrom/" >> /etc/yum.repos.d/CentOS-Base.repo echo "gpgcheck=0" >> /etc/yum.repos.d/CentOS-Base.repo 5. #安装gcc
yum install gcc -y 6. #恢复原yum源
cp –f /etc/yum.repos.d/CentOS-Base.repo.bak /etc/yum.repos.d/CentOS-Base.repo 输入命令 gcc -v 即可查看gcc的版本(若安装成功就可以看到你的版本啦!)
安装成功显示如下图:
在使用SurfaceView+MediaPlayer播放视频,会使用到SurfaceHolder.Callback 并通过SurfaceHolder.addCallback添加到SurfaceView.getHolder()对象当中,其中SurfaceCallback为SurfaceHolder.Callback 的实例。
if (mSurfaceCallback == null) { SurfaceHolder holder = mSurfaceView.getHolder(); mSurfaceCallback = new SurfaceCallback(); holder.addCallback(mSurfaceCallback); } SurfaceCallback具体实现如下,其在SurfaceView变为可见状态(VISIBLE)时,会调用surfaceCreated方法,在改方法里面调用 mMediaPlayer.setDisplay(surfaceHolder)进行跟MediaPlayer的绑定,在SurfaceView变为不可见状态(INVISIBLE&GONE),会调用surfaceDestoryed方法,注意在surfaceDestoryed中,需要对应的解除绑定,这样在后续复用MediaPlayer播放纯音频文件时才不会报错。
private class SurfaceCallback implements SurfaceHolder.Callback { @Override public void surfaceCreated(SurfaceHolder surfaceHolder) { Log.d(TAG, "surfaceCreated"); if (mMediaPlayer != null) { mMediaPlayer.setDisplay(surfaceHolder); } } @Override public void surfaceChanged(SurfaceHolder surfaceHolder, int i, int i1, int i2) { Log.d(TAG, "surfaceChanged"); } @Override public void surfaceDestroyed(SurfaceHolder surfaceHolder) { Log.d(TAG, "surfaceDestroyed"); if (mMediaPlayer != null) { mMediaPlayer.
通过 source map 还原源代码
npm 上有一些从 sourcemaps 反编译成 JavaScript 和 CSS 源码的库,如 reverse-sourcemap。
执行步骤
第一步:全局安装 reverse-sourcemap
$ npm install -g reverse-sourcemap
1
第二步:找到相关 sourcemap,进行反编译
2、reverse-sourcemap --output-dir XXX(导出路径) XXX.js.map( .js.map文件名)
vue组件创建购物车列表
代码实现效果:
APP组件
vue组件创建todolist效果 <template> <div class="wai"> <One ref="one"></One> <Two></Two> </div> </template> <script> import One from '@/components/One.vue'; import Two from '@/components/Two.vue'; import { EventBus } from '@/EventBus.js'; export default { data(){ return { zg:"", } }, components:{ One, Two }, mounted(){ EventBus.$on("fa",({list})=>{ this.zg = list }) }, computed:{ } } </script> <style scoped> .wai{ width: 600px; height: 500px; margin: 0 auto; } </style> input框输入子组件
<template> <div class="one"> <input type="text" placeholder="
博主介绍:主攻JAVA,因不可逆的原因,被迫学PHP,刚人门多多关照
文章目录 前言
一、官网下载小皮
二、使用步骤
1.打开小皮页面
2.使用步骤如下
总结
前言 随着快爱情的发展,php也不是那么的繁琐,下载集成工具小皮就可以省去很多时间包含,更重要的是可视化快速部署,功能齐全,安全稳定、不断更新,当然也可以选择其他的集成工具,这边只介绍小皮的使用教程,萌新级教程
提示:以下是本篇文章正文内容,下面案例可供参考
一、官网下载小皮 1.下载的网址是: 小皮面板(phpstudy) - 让天下没有难配的服务器环境!
2.下载好之后点击.exe 文件进行安装
注: 安装路径不要有中文和空格,尽量别装到c盘(一般直接改默认路径的盘符,直接修改为d)
二、使用步骤 1.打开小皮页面 页面如下:
2.使用步骤如下
注: 点击确定会用一个提示
网站创建成功,即将重启服务以生效!
总结 提示:这里对其进行总结:
以上就是PHP小皮的使用教程,本文仅仅简单介绍了如何使用小皮,想了解更多的可以到这个官网手册phpStudy V8 简介 - phpStudy V8 使用手册 (xp.cn)暗网
1470. 重新排列数组【简单模拟】 8.29
思路 略
AC代码 class Solution: def shuffle(self, nums: List[int], n: int) -> List[int]: ans = [0] * (2 * n) pos = 0 i, j = 0, n while i < n and j < 2 * n: ans[pos] = nums[i] pos += 1 ans[pos] = nums[j] pos += 1 i += 1 j += 1 return ans 998. 最大二叉树 II 没读懂题
946. 验证栈序列 思路 将pushed里的元素压入栈(列表模拟栈)中,之后每次压入栈后,判断栈顶是否与poped相同,若相同继续弹出栈,poped往后移,最后判断栈是否为空。
IEEE双栏论文添加行号 在投稿的时候,对论文添加行号可以方便审稿人指出问题,也能方便作者回复审稿人。那么如何在IEEE双栏论文中添加行号呢?
代码 \documentclass[journal]{IEEEtran} \usepackage[switch]{lineno} \linenumbers \begin{document} ... 右栏的行号(默认在右栏左边),可能会和左边的文字重叠,因此添加[switch]选项使右栏的行号位于右边。
效果
vue2.x应vuex3.x版本 vue3.x对应vue4.x版本 如果不是这样的对应关系,我们无法在vue中使用vuex
jmeter编写脚本 一、准备事项 项目环境接口文档 http请求包括哪些部分 请求行
+ 请求方法,请求地址URI请求头
Content-Type
cookie
User-Agent空一行请求体
参数: 表单
消息体数据: json 、xml 二、写脚本 一个最简单的jmeter脚本,包括,线程组、取样器、监听器:
测试计划上右键, 添加 线程组线程组上右键,添加 取样器> http请求 (http协议簇)线程组上右键,添加 监听器 > 查看结果树 线程组: 性能测试中用于场景设计的,写脚本阶段不用改动
取样器: 根据不同的协议,编写不同的脚本。 填空
监听器: 调试脚本时使用,性能测试执行时,禁用
不管哪种监听器,都是对结果数据进行不同维度的展示,这些展示,是需要消耗本地资源的
8080端口,是tomcat的默认端口
http协议的默认端口:80
https协议默认端口: 443
jmeter的默认保存路径,jmeter的bin文件夹
三、注意事项 1. 请求头 当请求体为json, 一定要有请求头 Content-Type:application/json
2. json格式 3. 协议 协议: 当协议为http时,可以不写,如果是https,那就必须写
4. 服务器 服务器名称或IP:不能带有/
5. 路径: 不要带域名或ip,和端口 路径开头,用/
不要带有空格, 带有空格请求URL %20 urlencoded编码
URI 资源地址
URL: 带domain
6. 内容编码:utf8 请求内容出现乱码处理方法:
文章目录 🟥 目的:🟧 错误方法:🟨 正确方法: 🟥 目的: 想实现将该cube上的所有材质球New Material换成change材质球
🟧 错误方法: 获取到MeshRenderer,对GetComponent().materials[i]挨个进行赋值。
我们运行后发现,项目不报错,但材质球并没有替换为change。而是将原材质球实例化了一下。也并没什么用。
🟨 正确方法: 对materials的整个数组进行赋值。而不是它其中的单个值。
代码示例:
using UnityEngine; public class test : MonoBehaviour { [Tooltip("想赋的材质球")] public Material material; void Start () { Material[] tempMaterial = new Material[GetComponent<MeshRenderer>().materials.Length]; for (int i = 0; i < tempMaterial.Length; i++) { tempMaterial[i] = material; } GetComponent<MeshRenderer>().materials = tempMaterial; } } 大家还有什么问题,欢迎在下方留言!
如果你有 技术的问题 或 项目开发 都可以加下方联系方式
和我聊一聊你的故事🧡
foreach元素的属性
collection: 需做foreach(遍历)的对象,作为入参时,list、array对象时,collection属性值分别默认用"list"、“array"代替,Map对象没有默认的属性值。但是,在作为入参时可以使用@Param(“keyName”)注解来设置自定义collection属性值,设置keyName后,list、array会失效;
item: 集合元素迭代时的别名称,该参数为必选项;
index: 在list、array中,index为元素的序号索引。但是在Map中,index为遍历元素的key值,该参数为可选项;
open: 遍历集合时的开始符号,通常与close=”)“搭配使用。使用场景IN(),values()时,该参数为可选项;
separator: 元素之间的分隔符,类比在IN()的时候,separator=”,“,最终所有遍历的元素将会以设定的(,)逗号符号隔开,该参数为可选项;
close: 遍历集合时的结束符号,通常与open=”("搭配使用,该参数为可选项;
2.foreach时,collection属性值的三种情况
如果传入的参数类型为List时,collection的默认属性值为list,同样可以使用@Param注解自定义keyName;
如果传入的参数类型为array时,collection的默认属性值为array,同样可以使用@Param注解自定义keyName;
如果传入的参数类型为Map时,collection的属性值可为三种情况:(1.遍历map.keys;2.遍历map.values;3.遍历map.entrySet()),稍后会在代码中示例;
3.代码示例:
3.1 collection属性值类型为List:
使用@Param注解自定义keyName;
Mapper接口定义的方法:UserList为模拟返回的数据对象 List getUserInfo(@Param(“userName”) List userName);
Mapper.xml 动态sql构建,Mapper接口的方法名和xml文件的id值,必须一一对应,否则会报错:
-----建议做if test="xxxx !=null and xxxx.size()>0"的校验,比较严谨。array为.length();
SELECT * FROM user_info where USERNAME IN #{value} 使用默认属性值list作为keyname 对应的Dao中的Mapper文件是: public List selectByIds(List userIds);
xml文件代码片段:
select * from t_user where id in #{item} 3.2 collection属性值类型为Array: 使用@Param注解自定义keyName; Mapper接口定义的方法:UserList为模拟返回的数据对象 List getUserInfo(@Param(“userName”) String[] userName);
Mapper.xml 动态sql构建,Mapper接口的方法名和xml文件的id值,必须一一对应,否则会报错:
-----建议做if test="xxxx !=null and xxxx.
FreeFileSync功能简述 FreeFileSync是一款文件夹比较和同步软件,用于创建和管理所有重要文件的备份从而取代每次复制每个文件。利用它可确定源文件夹和目标文件夹之间的差异,只传输所需的最小数据量。FreeFileSync是一款开源软件,可用于Windows、macOS和Linux。
通过在设备A上配置环路检测功能,使系统能够自动关闭设备A上出现环路的端口,并通过打印日志信息来通知用户检查网络
dis mac-address mac-move查看MAC漂移的记录。
或者配置环路检测
[H3C]loopback-detection global enable vlan all //全局开启环路检测,并对所有的VLAN生效
[H3C]loopback-detection interval-time 250 //配置环路检测的时间间隔为250秒
[H3C]int gi 1/0/1 [H3C-GigabitEthernet1/0/1]loopback-detection enable vlan all //接口开启环路检测,并对所有的VLAN生效
[H3C-GigabitEthernet1/0/1]loopback-detection action shutdown //当检测到环路时,环路检测会将此端口关闭
查看环路检测的显示信息:
[H3C]dis loopback-detection Loopback detection is enabled. //环路检测已开启
Loopback detection interval is 250 second(s). //环路检测的时间间隔为250秒
No loopback is detected. //目前没有检测到环路
按键检测(状态机) 传统的按键检测 在单片机的应用中,利用按键实现与用户的交互功能是相当常见的,同时按键的检测也是很讲究的,众所周知,在有键按下后,数据线上的信号出现一段时间的抖动,然后为低,当按键释放时,信号抖动一段时间后变高,然而这段抖动时间要维持10ms~50ms,这个与按键本身的材质有一定的关系,在这个范围内基本上都可以确定的。如果按键检测的不好,单片机的运行效率将会大打折扣,严重影响到系统的性能,导致系统的运行出现异常,在教科书中,我们见到的按键处理程序都是以下这样的结构:
if(KEY_IO != 0xFF) //检测到有按键按下 { DelayNms (20); //延时20毫秒(严重影响单片机的运行效率) if (KEY_IO !=0xFF) //确认按键按下 { switch (KEY_IO) { case 0xFE: KeyValue=1 ; break; case 0xFD: KeyValue=2 ; break; default: KeyValue=0 ; break; } } } 弊端: 像这样的程序经常出现在大学的教科书中,在按键的扫描中,单片机的资源全部用来做按键的扫描,特别是当中的延时程序,对单片机来说,这个一个漫长的过程。例如,我们需要用动态扫描数码管来做一个电子时钟,如果在按键持续按下的过程中,由于延时程序对单片机资源的占用,单片机这个时候就不能做动态扫描,数码管的显示就会有问题;
除非当前程序搭载了实时系统,一旦当前任务要进行延时操作,系统会自动进行任务调度,执行其他任务,当之前的任务延时完毕,系统会自动执行之前的任务。遗憾的是传统8051系列单片机不推荐搭载实时系统的,毕竟其资源有限,而且又增加额外的成本,比如搭载ucos实时系统,传统的8051系列单片机完全不能满足该系统的要求,必须拓展外部存储器才能满足,这样就间接上增加了成本,同时ucos用于商业上要收费的,成本大大地增加了。因此当没有搭载实时系统做按键检测使用软件延时是不现实的,严重影响性能。
这样的教科书的按键处理程序是不实用的,在实际应用中是不可取的。所以这里介绍采用“状态机”的思想进行检测按键,不仅可以正确检测到按键,而且不会影响其他周边外设器件的运作。
有限状态机思想 有限状态机是一种概念思想,把复杂的控制逻辑分解成有限个稳定状态,组成闭环系统,通过事件触发,让状态机按设定的顺序处理事务。
状态机是软件编程中的一个重要概念,比这个概念更里要的定对它的灵活应用。在一个思路清晰而且高效的程序中,必然有状态机的身影浮现。
比如说一个按键命令解析程序,就可以被看做状态机:本来在A状态下,触发一个按键后切换到了B状态:再触发另一个键后切换到C状态,或者返回到A状态。这就是最简单的按键状态机例子。实际的按键解析程序会比这更复杂些,但这不影响我们对状态机的认识。
进一步看,击键动作本身也可以看做一个状态机。一个细小的击键动作包含了:按下、抖动、释放等状态。其实状态机思想不单只用在按键方面,数码管显示动态扫描、LED亮灭都是存在状态机的思想如亮与灭的状态。
使用状态机思想去进行单片机编程,比较通用的方法就是用swtich 的选择性分支语句来进行状态跳转,既然可以 switch 来判断,那么使用 if 同样可以,但是使用 switch 来判断状态可以使代码更加清晰。
按键动作示意图 状态图 说明:
整个状态机使用定时器来驱动,每隔10ms进入一次状态机进行判断,检测消抖的时间通常也是10ms;多任务时可以避免其他任务占用CPU 过多的时间;
状态1:按键处于弹起状态,为高电平,定时器每隔10ms扫描一次,如果检测到按键的IO口为低电平了,则切换到状态2
状态2:按键抖动检测,检测到IO口低电平从状态1切换到状态2后,下一个10ms进来如果检测到IO口变回了高电平,说明低电平是由抖动引起的,按键没有被完全按下,状态2切回到状态1;如果检测到IO口任然是低电平,说明按键被按下,状态2切换到状态3
状态3:此状态下按键已确认被按下,IO口会一直是低电平,如果长按,也一直是处于这个状态3;这个状态可以做一些按键动作的检测,如长按、双击;该状态下如果检测到IO口为高电平,则切换到状态4
状态4:进行弹起抖动检测,从状态3切到该状态时,在下一个10ms如果检测到IO口又变为低电平了,则说明上一步高电平是有抖动引起的,再将状态切回到状态3;如果检测到IO口继续为高电平,说明按键松开了,将状态切换到状态1
又开始下一个循环……
程序 实现效果 按键2单击指示灯电平翻转,长按2秒则闪一下,双击则闪三下
getBean getBean方法重载 一共有四种传参方式
第一种直接根据beanname去拿
第二种根据beanname并且指定类型,如果类型不匹配并且无法类型转换,则直接报错
第三种推断构造方法
第四种是合起来的
@Override public Object getBean(String name) throws BeansException { return doGetBean(name, null, null, false); } @Override public <T> T getBean(String name, Class<T> requiredType) throws BeansException { return doGetBean(name, requiredType, null, false); } @Override public Object getBean(String name, Object... args) throws BeansException { return doGetBean(name, null, args, false); } public <T> T getBean(String name, @Nullable Class<T> requiredType, @Nullable Object... args) throws BeansException { return doGetBean(name, requiredType, args, false); } getbean传进来的名字,做处理,去掉开头的&或者从存别名的map里找到真正的名字