转自网络,总有一款适合你!
在瞬息万变的时代,越来越多不再满足“专一职业”的人选择成为「斜杠青年」。这不仅可以丰富生活方式,拓展人脉圈子,还有机会增加额外收入,抵御不确定经济的风险。
因此,很多人都会考虑开启副业,希望利用空闲时间赚钱,最好还能有睡后收入。但很多人没有资源、人脉、金钱,想通过传统方式开启副业实在太难了。
所以,我结合3类常见的副业,为你推荐70个通过互联网开启副业的平台,希望你能找到合适的那个,开启副业增加收入。
01 教学型副业
如果你在某些技能和知识领域上有所擅长,就具备了做线上教学副业的条件。
你可以把自己擅长的事情列个清单,分为具体技能类和知识类。比如:
技能类:弹钢琴、烤蛋糕、插花、养猫、做饭、种菜……
知识类:历史知识、军事知识、金融知识、养生知识……
有了自己的清单之后,你就可以决定上面是否有你想要变成副业的东西,然后去寻找合适的线上平台,这里给大家举一些具体的例子:
1、 K12家教(小、初、高家教)
只需要一台可以开视频的电脑,就可以在线上家教平台注册申请成为家教老师。
平台推荐:
● 微信公众号:邦课侠、点父子、家教114等
● APP:掌门1对1、海风智学中心、学而思网校等
每个平台对教师资质的要求是不一样的,进入教师申请页面,就可以看到平台的要求,符合要求就可以投简历啦。
任职要求:
● 具有本科及以上学历(985/211更佳),或者是师范专业大学生
收入情况:
● 按小时计费,每个平台的薪水不同,辅导不同的年级薪水也不同,老师的学历越高、学校越好,薪水越高。
● 目前的家教时薪大致在50-200元/时之间,如果成为名师,时薪会更高。
● 如果能够带动课程销售,还可以获得平台额外的奖励。
2、钢琴陪练
如果你会弹钢琴或者懂乐理知识,那可以考虑做线上钢琴陪练。
平台推荐:
● APP:VIP陪练、快陪练、熊猫钢琴陪练、柚子练琴等
任职要求:
● 各大音乐学院,各地艺校的大专或本科在读学生、毕业生
● 主修钢琴或相关专业
● 非专业的钢琴等级需要达到平台要求(不同平台要求不同)
● 拥有设备:手机/平板+wifi
收入情况:
● 按小时计费,不同的平台有不同的计费标准
● 陪练老师分为初级、中级、高级,等级越高薪水越高
3、自媒体
除了上述2种直接可以进行线上教学的工作,还可以通过运营新媒体平台来变现。当然,这个过程相对来说会更漫长,因为需要你在前期积累自己的口碑,打造自己的品牌。
平台推荐:
● 微信公众号
● 微博
● 短视频平台:抖音、快手、火山、哔哩哔哩(B站)
● 知识付费平台:知乎live、得到、千聊、今日头条付费专栏
● 广播音频平台:喜马拉雅、蜻蜓FM、荔枝
● 讲课平台:腾讯课堂、网易云课堂、荔枝微课、传课网、淘宝课堂
盈利方式:
? 微信公众号、微博、短视频适合获取关注度、打造个人品牌。
你可以在这些平台展示你擅长的技能或知识,当你获得了关注度、形成品牌效应以后,你可以接广告或者开设付费课程、付费社群,也可以在这三类平台销售周边产品等等。
? 知识付费平台可以让你直接盈利。
每个平台适合投放的知识类型也不同,这需要你研究每种平台的特点,选择和你的内容相匹配的那个。
比如历史、商业、金融学、心理学等类型的知识就比较适合「得到」这个平台,而做饭、插花、养猫、烘焙等类型的技能更适合「千聊」这个平台。
? 广播音频平台适合所有通过声音展现的知识和技能。
如果你的内容足够优质,你可以开设付费课程,直接获取收益,或者你也可以搭建付费社群,通过免费的课程进行引流。
喜马拉雅上有人开设恋爱技巧课,通过免费的音频课程,吸引观众添加微信,然后鼓励听众付费加入微信社群,获取定制的恋爱技巧服务。
? 在讲课平台注册成为讲师,上传讲课视频就可以赚钱。
通过运营自媒体开始一份教学型副业,万一做成功了,还有可能变成主业。
02 服务型副业
服务性工作通常要么是劳动密集型的,要么是时间密集型的,或者是因为人们有需要却不擅长。比如打扫房间、通下水道、搬家、跑腿、美甲、化妆,通常有人更乐意花钱请别人来做这些事。
这些工作都可以通过线上平台接单,下面3种服务型工作非常适合发展副业:
1、美容美体美发
如果你想把美容、美甲、化妆、造型等工作作为副业,但是又不想投资开店,也不想每天坐班,那么申请成为线上美业平台的手艺人,就可以利用空闲时间接单啦。
推荐平台:
● APP:河狸家
这是目前国内最大的「互联网+上门美业服务」平台,下载「河狸家」APP,可以在界面中找到「手艺人招募」,填写信息后就可以申请成为手艺人,通过平台考核,就可以在平台接单,接单时间和地点自由灵活
收入情况:
● 可获取接单价格60%-80%的收入(详情看平台规则)
● 手艺人还可以在平台卖特定的产品,这也会带来一定的收入~
2、网约车
平台推荐:
● 滴滴车主
● 美团打车司机
这两个APP是「滴滴出行」和「美团打车」的车主入口,都支持兼职司机的加盟。
加盟条件:
不同的平台、不同的类型、不同的城市对于司机的要求也是不同的。想要成为网约车司机,可以下载上面2个APP,按照要求注册,审核通过后,你就可以开始赚钱啦~
3、同城跑腿
平台推荐:
● 美团众包
● UU跑腿
● 蜂鸟众包
● 达达
这些跑腿平台都非常适合兼职人员,服务种类丰富,包括:外卖配送、取件、送件、发传单、搬运货物、排队、照顾宠物……下载APP,申请成为骑士 or 跑男,审核通过就可以开始接单啦~
收入情况:
● 按件计费,收入=接单数×单件收入
03 销售型副业
销售型副业是最常见的副业类型,你既可以销售某种产品,也可以销售自己的特长。
从事销售型副业,投资过多显然是不理性的,既然是副业,最好是稳赚不赔,即便不赚,也最好别赔。那就给大家推荐2类可以开启销售副业并且投资较少的平台:
1、特长销售
? 设计类
● 设计外包项目(网站:猪八戒、威客)
你可以在这2个网站寻找合适的私活,包括:Logo设计、VI设计、广告宣传品、包装设计等,来自全国各地的公司,会定期在网站上发布需求,设计师们可以根据自己擅长的领域接单。
● 出售个人作品(网站:千图网、昵图网、包图网、汇图网、MAKA)
这些设计类网站可以上传自己的作品,只要有人购买,就会有收入。
? 配音类
● APP:喜马拉雅、配音秀
这两个平台中都有一些热门配音任务,而且是明码标价。既有按集数收费的,也有按小时收费的。
? 翻译类
网站:有道翻译、译客、快译、译喵网
? 技术类
网站:程序员客栈、云沃克、解放号、微擎
? 摄影类(卖自己拍的图片赚钱)
网站:锐景创意、全景图片、视觉中国、美好景象、东方IC、中国图库、汇图、壹图、picpas、fotor、海洛创意
2、产品销售
? APP:1688
这是阿里巴巴的电商采购批发平台,支持一件代发,如果你想做微商,还不如加入1688成为分销商。那些让你买产品、掏加盟费的微商组织多半都是把你当韭菜割。
? APP:咸鱼、转转
这两个都是二手交易平台,你可以在平台上出售自己的闲置物品。如果你想把这个作为赚钱的副业,那你可以淘一些货物,在平台售卖赚个差价。当然,能不能赚到钱取决于你的眼光了。
这些平台都可以让你在主业之外的空闲时间赚钱,但是也要注意:
开始副业,其实也是你职业规划的策略,可以说是职业Plan B。
在你的水准还没能驾驭多重身份时,千万别有主业与副业并行的想法,不要捡了芝麻丢了西瓜。
#一键安装ss服务器端4合1版本,自主选择:python版、R版(推荐)、go版(推荐2)、libev版(省内存)。
系统支持:CentOS 6+,Debian 7+,Ubuntu 12+
内存要求:≥128M
日期 :2019 年 01 月 11 日
1、一键安装 Shadowsocks-Python, ShadowsocksR, Shadowsocks-Go, Shadowsocks-libev 版(四选一)服务端;
2、各版本的启动脚本及配置文件名不再重合;
3、每次运行可安装一种版本;
4、支持以多次运行来安装多个版本,且各个版本可以共存(注意端口号需设成不同);
5、若已安装多个版本,则卸载时也需多次运行(每次卸载一种);
友情提示:如果你有问题,请先阅读这篇《Shadowsocks Troubleshooting》之后再询问。
服务器端口:自己设定(如不设定,默认从 9000-19999 之间随机生成)
密码:自己设定(如不设定,默认为 teddysun.com)
加密方式:自己设定(如不设定,Python 和 libev 版默认为 aes-256-gcm,R 和 Go 版默认为 aes-256-cfb)
协议(protocol):自己设定(如不设定,默认为 origin)(仅限 ShadowsocksR 版)
混淆(obfs):自己设定(如不设定,默认为 plain)(仅限 ShadowsocksR 版)
备注:脚本默认创建单用户配置文件,如需配置多用户,请手动修改相应的配置文件后重启即可。
使用root用户登录,运行以下命令:
wget --no-check-certificate -O shadowsocks-all.sh https://raw.githubusercontent.com/teddysun/shadowsocks_install/master/shadowsocks-all.sh
chmod +x shadowsocks-all.sh
http://huazai.eleuu.com/shadowsocks-all.sh 2>&1 | tee shadowsocks-all.log
Congratulations, your_shadowsocks_version install completed!
Your Server IP :your_server_ip
Your Server Port :your_server_port
Your Password :your_password
Your Encryption Method:your_encryption_method
Your QR Code: (For Shadowsocks Windows, OSX, Android and iOS clients)
ss://your_encryption_method:your_password@your_server_ip:your_server_port
Your QR Code has been saved as a PNG file path:
your_path.png
Welcome to visit:https://teddysun.com/486.html
Enjoy it!
常规版 Windows 客户端
https://github.com/shadowsocks/shadowsocks-windows/releases
ShadowsocksR 版 Windows 客户端
https://github.com/shadowsocksrr/shadowsocksr-csharp/releases
若已安装多个版本,则卸载时也需多次运行(每次卸载一种)
使用root用户登录,运行以下命令:
http://huazai.eleuu.com/shadowsocks-all.sh uninstall
启动脚本后面的参数含义,从左至右依次为:启动,停止,重启,查看状态。
Shadowsocks-Python 版:
/etc/init.d/shadowsocks-python start | stop | restart | status
ShadowsocksR 版:
/etc/init.d/shadowsocks-r start | stop | restart | status
Shadowsocks-Go 版:
/etc/init.d/shadowsocks-go start | stop | restart | status
Shadowsocks-libev 版:
/etc/init.d/shadowsocks-libev start | stop | restart | status
Shadowsocks-Python 版:
/etc/shadowsocks-python/config.json
ShadowsocksR 版:
/etc/shadowsocks-r/config.json
Shadowsocks-Go 版:
/etc/shadowsocks-go/config.json
Shadowsocks-libev 版:
/etc/shadowsocks-libev/config.json
天线最佳长度为波长的1/4
波长=波速/频率
波速=光速=3*100000000
天线的长短是根据中心工作频率的波长来决定的:
1.波长和频率的关系是倒数关系,具体的计算公式是:波长(单位:米)=300/频率(单位:MHz)中心频率为150MHz时,波长就是2米,所以我们又把150MHz左右的信号称为2米波,而430MHz的波长是0.7米,所以430MHz左右的信号又被叫着70厘米波。
2.天线的长短和波长成正比,所以和频率成反比,频率越高,波长越短,天线也就可以做得越短。
3.天线的长度并不等于一个波长,往往是1/4波长或者5/8波长,如果你购买的是原装天线,你能在包装或说明书上看到类似这样的说明。为什么要用这样的长度,我以后再来介绍。
4.很多缩短型天线,比如大家常说的烟屁苗子,是用加感的方式来缩短长度,实际上把里面一圈一圈的线材拉直,长度也接近波长的1/4或者5/8。当然也有用其他技术手段、设计思想制作的缩短天线,但现在在业余领域还没有效果太好的产品。
5.我们使用的U段和V段都有一个比较宽的范围,U段从430到440,有10MHz的宽度,V段从144到146有2M的宽度,而天线的最佳点(也就是长度和波长最匹配的频率点)理论上就在某一个频率上。保持在整个频率范围内都有比较好的特性,这就是天线好坏的一个重要特征。
6.如果你常用的某个频点,天线的特性不好(比如驻波较大),可以通过修剪天线来进行调试。修剪工作一定要由有经验的人士在仪器的帮助下完成。这个道理就不用多讲了。
7.国产天线的性能不一定就比进口天线的性能差,但国产天线的一致性不好,碰到好的就特别好,碰到不好就算倒霉,呵呵,当然修剪一下还是可以用的。
8.天线对通连的效果是至关重要的,一副好的天线可以让你用比别人低得多的发射功率把信号送到同样远的地方,或者说,用同样的功率,一副好天线可以把信号送到更远的地方。
一段金属导线中的交变电流能够向空间发射交替变化的感应电场和感应磁场,这就是无线电信号的发射。相反,空间中交变的电磁场在遇到金属导线时又可以感应出交变的电流,这对应了无线信号的接收。
在电台进行发射和接收时都希望导线中的交变电流能够有效的转换成为空间中的电磁波,或空间中的电磁波能够最有效的转换成导线中的交变电流。这就对用于发射和接收的导线有获取最佳转换效率的要求,满足这样要求的用与发射和接收无线电磁波信号的导线称为天线。
理论和实践证明,当天线的长度为无线电信号波长的1/4时,天线的发射和接收转换效率最高。 因此,天线的长度将根据所发射和接收信号的频率即波长来决定。只要知道对应发射和接收的中心频率就可以用公式算出对应的无线电信号的波长,再将算出的波长除以4就是对应的最佳天线长度。
低功耗模式都是指STM32的停机模式,在该模式下PLL停止工作,仅LSI和HSI继续运行(进休眠前已经打开的话),所有IO状态、内部RAM数据保持不变,所有外部IO中断、内部RTC定时唤醒、LPUART、LPTIM可以将MCU唤醒,唤醒后程序从进入低功耗的地方继续运行,默认刚唤醒后会使用HSI作为系统时钟,因此唤醒后需要立即配置时钟。
一、低功耗串口(LPUART)
STM32L4系列有LPUART,可以在停止模式下直接唤醒MCU。LPUART中断可以设置为接收到1个bit位唤醒或接受到1个byte唤醒,具体可以参考STM32L4参考手册或官方的相关文档,以下是下载链接:
https://www.stmcu.com.cn/Designresource/design_resource_download/file_id/513641/file/DM00355687_ENV1.pdf/token/90db775645fe1ad7c3004bd795aae6d9
STM32系列LPUART资源
LPUART时钟源使用LSE或HSI时从低功耗唤醒
使用32.768KHz的LSE作为LPUART的时钟时,波特率最大只能是9600;使用16MHz的HSI作为LPUART的时钟时,波特率可以比较高,实测波特率为115200时低功耗唤醒是没有问题的,波特率为256000时已经出现首字节丢失的情况。推荐使用HSI作为LPUART的时钟,因为从停止模式唤醒时,MCU默认使用的就是HSI时钟。注意:进入低功耗前需要使能低功耗串口的唤醒功能,不要关闭串口。有篇帖子专门计算了STM32的LPUART的波特率计算:http://www.elecfans.com/lab/MCU/20171031573087.html。
LPUART唤醒的三种方式
从上图可以看出,将MCU从低功耗唤醒有3种匹配方式:
地址匹配唤醒,我也没搞懂这个地址是指什么地址,猜测可能就是接收的第一个字节,只有匹配上了,才会产生WUF中断,否则将重新进入低功耗。
起始位唤醒,显然就是指接收到串口的起始位就立即唤醒,这种方式应该是这三种里唤醒最快的。
字节唤醒,类似于RXNE,收到一个字节后产生WUF唤醒。
注意:进入低功耗前需要使能低功耗串口的唤醒功能,不要关闭串口。仅在使用LSE或HSI作为LPUART时钟源时允许LPUART从STOP模式唤醒,其他时钟源是不可以的。
HAL库提供了几个函数供我们使用:
//1、用于配置LPUART唤醒的方式:地址匹配、起始位唤醒或字节唤醒,需要在进低功耗前配置好
HAL_StatusTypeDef HAL_UARTEx_StopModeWakeUpSourceConfig(UART_HandleTypeDef *huart, UART_WakeUpTypeDef WakeUpSelection);
//2、用于开启LPUART的低功耗唤醒功能,需要在进低功耗前开启
HAL_StatusTypeDef HAL_UARTEx_EnableStopMode(UART_HandleTypeDef *huart);
//3、用于关闭LPUART的低功耗唤醒功能
HAL_StatusTypeDef HAL_UARTEx_DisableStopMode(UART_HandleTypeDef *huart);
//4、LPUART低功耗唤醒中断回调函数,程序运行到这里说明WUF中断标记被置位,MCU被LPUART唤醒
void HAL_UARTEx_WakeupCallback(UART_HandleTypeDef *huart);
优点:无需额外的GPIO,发送端无需关心如何唤醒对端(对端是指有LPUART唤醒的一端)。
缺点:STM32的LPUART资源较少,一个芯片可能只有一个LPUAT外设,有些芯片甚至没有LPUART外设。
二、串口RX作为GPIO中断
此种唤醒方式需要连接通信两端的TX、RX、GND。当通信两端都处于空闲状态时,接收方的RX设为GPIO上拉输入,并检测下降沿中断。当发送方需要发送数据时,先发一些无用的数据,接收方检测到下降沿中断后,将RX引脚重新初始化为串口RX开始接收数据。需要注意的是,这种情况下,接收方一开始接收的可能不是真正想要的数据,需要靠协议解析器去过滤(一般都是接收然后先放入环形buffer,然后在主循环或某一线程中从该buffer中取数据并解析)。
注意:一般接收方(STM32)被唤醒并完成串口初始化所需的时间为1ms左右(RX下降沿中断里直接初始化串口),因此发送方在发送真正的数据前,可以先发1字节0x00,延时一小段时间再发真正的数据,我一般延时2ms,实际等待1ms对方也能正常被唤醒并接收完整的数据,设为2ms比较保险。当然也可以直接在要发送的有效数据前加发几个字节的0x00来唤醒,例如10个0x00,这取决于波特率,这种情况可以使用中断方式发送或者更高效的DMA发送。被唤醒方最好加个标记位来指示当前串口是否已经处于打开状态,避免重复初始化。
优点:不要求接收方的串口是低功耗串口,而且节省IO。
缺点:需要改变发送方的发送逻辑。
三、使用额外的GPIO唤醒
这种方式实际上与串口RX作为GPIO中断唤醒是差不多的,只不过使用了额外的GPIO作为唤醒IO。建议串口空闲时,两边的唤醒IO都设为上拉输入检测下降沿中断,当发送方需要发送数据时,将该GPIO设为推挽输出,反复拉高拉低几次唤醒对端,发送完后将该引脚重新设为上拉输入检测下降沿中断。如果引脚足够多,也可以使用两组唤醒IO,每一组指定了一个唤醒方向,即引脚1用于A唤醒B,引脚2用于B唤醒A。
建议使用一个标志位来记录串口的使能状态,当需要发送数据时,初始化一下串口(如果标志位已经置位,则无需重新初始化,下同)。同理,当收到唤醒中断时,建议直接在中断里根据标志位初始化一下串口,因为在裸机的情况下,如果使用中断标志来通知串口需要重新初始化,可能会由于主循环里某个函数有阻塞导致串口没有及时初始化而丢包;如果使用RTOS的信号量来通知,则等待该信号量的线程的优先级应该尽量高。
优点:使用起来方便,无需修改串口引脚的设置。
缺点:使用了额外的GPIO,发送方需要修改发送逻辑,发送时需要延时。
四、唤醒方案优化
对于非低功耗串口(非LPUART,即普通的UART),发送方每次都要通过拉低电平或发送无用来唤醒接收端,这里的延时对于整个系统来说,无疑是浪费。这里提供一些方法来规避这个问题,但一定程度上增加了通信双方的耦合性,只能作为参考。
发送方维护一个SendTick变量,接收方维护一个RecvTick变量。当发送方每次发送完数据后,都更新一下SendTick(例如用HAL_GetTick函数),接收方收到一帧完整的数据后,也更新一下RecvTick。接收方如果发现PastTick(RecvTick)大于100ms,就关闭串口,PastTick函数即当前时刻和入参时间的差值;发送方如果发现PastTick(SendTick)小于80ms,就不再进行唤醒操作而是直接发送串口数据。这样做的好处:如果发送方以较快频率连续发送数据包,那么只用唤醒一次,减少了频繁唤醒所需的时间。
以上例子只是A发B收的情况,实际上A和B都可能收发,那么双方都要维护两个变量SendTick、RecvTick,并约定好自动休眠的时间。
五、代码案例
我项目中用到的是STM32L4系列的MCU,以标准库为例,配置URAT3可以低功耗唤醒:
HAL_UARTEx_EnableStopMode函数的说明:只要UART时钟为HSI或LSE,UART就能将MCU从停止1模式唤醒,所以第一部需要先配置串口。
//1.在串口初始化函数中增加以下代码
UART_WakeUpTypeDef WakeUpSelection;
WakeUpSelection.WakeUpEvent=UART_WAKEUP_ON_STARTBIT;//起始位唤醒
HAL_UARTEx_StopModeWakeUpSourceConfig(&LPUart3Handle WakeUpSelection);
__HAL_UART_ENABLE_IT(&LUart3Handle UART_IT_WUF); //唤醒中断
LPUart3Handle.Instance->CR3 |=0x0800000; //打开stop时的时钟
//2.在HAL_UART_MspInit函数中配置串口时钟源
__HAL_RCC_GPIOC_CLK_ENABLE();
RCC_OscInitStruct.OscillatorType=RCC_OSCILLATORTYPE_HSI;
RCC_OscInitStruct.HSIState=RCC_HSI_ON;
RCC_OscInitStruct.HSICalibrationValue=RCC_HSICALIBRATION_DEFAULT;
RCC_OscInitStruct.PLL.PLLState=RCC_PLL_NONE;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct)!=HAL_OK){
while(1);
}
__HAL_RCC_USART3_CONFIG(RCC_USART3CLKSOURCE_HSI);//此处配置时钟源为HSI,需在上方使能HSI时钟
__HAL_RCC_USART3_CLK_ENABLE();
__HAL_RCC_DMA1_CLK_ENABLE();
//3.单片机进入低功耗模式可以自定义3个函数:
void SYSCLKConfig_WAKEUP_From_STOP1(void){//唤醒后需立即配置时钟
RCC_ClkInitTypeDef RCC_ClkInitStruct={0};
RCC_OscInitTypeDef RCC_OscInitStruct={0};
uint32_t pFLatency=0;
__HAL_RCC_PWR_CLK_ENABLE();
HAL_RCC_GetOscConfig(&RCC_OscInitStruct);
RCC_OscInitStruct.OscillatorType=RCC_OSCILLATORTYPE_NONE;
RCC_OscInitStruct.PLL.PLLState=RCC_PLL_ON;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) !=HAL_OK)
{
Error_Handler();
}
HAL_RCC_GetClockConfig(&RCC_ClkInitStruct, &pFLatency);
RCC_ClkInitStruct.ClockType =RCC_CLOCKTYPE_SYSCLK;
RCC_ClkInitStruct.SYSCLKSource =RCC_SYSCLKSOURCE_PLLCLK;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, pFLatency) !=HAL_OK)
{
Error_Handler();
}
}
void Enter_STOP_Init(void){//初始化
__HAL_RCC_PWR_CLK_ENABLE();
__HAL_RCC_WAKEUPSTOP_CLK_CONFIG(RCC_STOP_WAKEUPCLOCK_MSI);
HAL_RTCEx_DeactivateWakeUpTimer(&RtcHandle);
HAL_RTCEx_SetWakeUpTimer_IT(&RtcHandle, 2047, RTC_WAKEUPCLOCK_RTCCLK_DIV16); //1s中断唤醒一次。
}
void EnterSTOP1Mode(void){
HAL_UARTEx_EnableStopMode(&Uart3Handle);//启用UART停止模式
HAL_PWREx_EnterSTOP1Mode(PWR_STOPENTRY_WFI);//MCU进入停止模式1
SYSCLKConfig_WAKEUP_From_STOP1();//退出低功耗模式后需要手动配置时钟
}
参考文档:STM32L476 Reference manual.pdf(参考手册)、 STM32L486xx_User_Manual.chm(用户手册)。
一、安装软件
将lib文件夹下的3个文件复制到GoLand软件的bin目录中
双击桌面的GoLand
选择:试用(Evaluate for free)进入IDE。
在新弹出的窗口中直接拖动bin文件夹刚复制过的jetbrains-agent.jar至软件窗口
按提示安装重启即可破解
支持2020.1版本及以下所有版本破解
二、GoLand汉化(已失效):
默认全是英文的,这对于刚刚接触它的新手来说会造成一定的困扰,可以进行汉化,但是一般不建议汉化。先关闭Goland,在解压的破解补丁中找到resources_cn.jar,并将它复制到 Goland 安装目录下的 lib 目录中。然后,同样在 lib 目录中找到resources_en.jar文件,它是 Goland 内置的一个英文补丁,这里需要将它重命名为resources_en.jar.backup,因为想要恢复英文的话还需要用到它。然后再运行 Goland ,你会发现 Goland 中的菜单已经变成我们熟悉的中文了。
三、环境配置:
如我的GoLand软件的bin文件路径为: C:\Program Files\JetBrains\GoLand 2020.1\bin
电脑–>属性–>高级系统设置–>环境变量–>系统变量–>path
四、配置SDK、ROOT、PATH
五、新建工程
新建工程
新建Go文件,命名好
复制一下代码测试运行
package main
import "fmt"
func main() {
fmt.Println("皮皮华我爱你")
}
本文所有软件及工具打包:链接:https://pan.baidu.com/s/1OEDwe-WKb0YIG8zp0o8iGA 提取码:7xhb
GoLand初学编程教程:Go语言中文网、Go语言菜鸟教程、《Go语言学习之路》、《尚硅谷go语言核心基础编程全套完整版》、 《GoWeb进阶实战课程》
笔记:
1:设置自动格式化代码
File-Setting-Tools-File Watchiers,点击右上角添加 go fmt和goimports
2:安装gin
在GoLang 左下角Terminal中输入go get github.com/gin-gonic/gin即可自动安装,安装时间较长
Windows上安装和使用protobuf
1:安装protoc
protobuf协议编译器是用c++编写的,根据自己的操作系统下载对应版本的protoc编译器:https://github.com/protocolbuffers/protobuf/releases,下载protoc-3.12.4-win64.zip解压后拷贝到GOPATH/目录下,我这里的GOPATH为D:\Go_PRO\bin
2:安装protoc-gen-go
安装生成Go语言代码的工具protoc-gen-go,目前在github上,还没有提供release版本,需要自己根据源码生成。以我的GOPATH路径为例,首先进入
go get github.com/golang/protobuf
cd D:\Go_PRO\src\github.com\golang\protobuf\protoc-gen-go
go install .
第一行是下载protobuf至GOPATH的src目录中,第二行是为了进入protoc-gen-go所在目录
最后一条命令go install . 注意中间一共有2个空格,此命令是将当前目录的编译成的exe可执行程序并放在GOPATH的bin目录中。
至此我们的protoc-gen-go就安装好了。
3:编译proto文件
我们在test目录下新建一个test.proto文件,内容如下:
// 指定使用protobuf版本
// 此处使用v3版本
syntax="proto3";
// 包名,通过protoc生成go文件
package address;
// 性别类型
// 枚举类型第一个字段必须为0
enum GenderType {
SECRET=0;
FEMALE=1;
MALE=2;
}
// 人
message Person {
int64 id=1;
string name=2;
GenderType gender=3;
string number=4;
}
// 联系簿
message ContactBook {
repeated Person persons=1;
}
需要用到以下命令编译test.proto生成test.pb.go文件:
cd D:\Go_PRO\src\xaccessgo est
protoc --plugin=protoc-gen-go=D:\Go_PRO\bin\protoc-gen-go.exe --go_out=http://huazai.eleuu.com/ http://huazai.eleuu.com/test.proto
protoc --plugin=protoc-gen-go=D:\Go_PRO\bin\protoc-gen-go.exe --go-grpc_out . --go_out=http://huazai.eleuu.com/ http://huazai.eleuu.com/test.proto
其中第一条命令是为了进入proto文件所在的目录
D:\Go_PRO\bin\protoc.exe是protoc.exe所在的路径
D:\Go_PRO\bin\protoc-gen-go.exe是protoc-gen-go.exe所在的路径
--go_out=http://huazai.eleuu.com/表示在当前路径输出go类型的文件
http://huazai.eleuu.com/test.proto 表示编译当前目录下的test.proto文件
上述命令也可以简写为protoc --go_out . test.proto
编译完成后我们可以在创建个main.go的文件,代码如下:
package main
import (
"fmt"
"github.com/golang/protobuf/proto"
"io/ioutil"
"xaccessgo/test"
)
func main() {// protobuf demo
var cb address.ContactBook
p1 :=address.Person{
Name: "皮皮华",
Gender: address.GenderType_MALE,
Number: "775262592",
}
fmt.Println(p1)
cb.Persons=append(cb.Persons, &p1)
data, err :=proto.Marshal(&p1)// 序列化
if err !=nil {
fmt.Printf("marshal failed,err:%v
", err)
return
}
ioutil.WriteFile("http://huazai.eleuu.com/proto.dat", data, 0644)
data2, err :=ioutil.ReadFile("http://huazai.eleuu.com/proto.dat")
if err !=nil {
fmt.Printf("read file failed, err:%v
", err)
return
}
var p2 address.Person
proto.Unmarshal(data2, &p2)
fmt.Println(p2)
}
运行测试结果如下:
如果我们需要生成支持grpc的则需要以下命令
protoc -I test/ test/pb/test.proto --go_out=plugins=grpc:test
使用cd进入到服务端、客户端对应的路径,再通过以下命令编译、执行。注意,需要先启动服务端
go build
http://huazai.eleuu.com/server
众所周知,GitHub 是一个巨大的开源宝库,以及程序员和编程爱好者的聚集地,包括我之前推荐的诸多优秀的开源项目全部都是位于 GitHub 上。
但是每当我们看到优秀的开源项目,准备去下(bai)载(piao)时,会发现 的速度异常之慢!就我个人而言,在我家里 200M 移动宽带的环境下,我克隆开源项目就没发现速度大于过 的时候,这简直太难受了。
小项目倒还好,我等几分钟无所谓;一旦项目庞大起来,或者项目文件数目一多, 大概率会失败!
当然网上常见的诸如修改 hosts、代理等方式实际使用效果并不一定好,而且也不稳定。
接下来就介绍一种 GitHub 下载的加速方法:通过国内码云平台的转接,来完成 GitHub 上项目的下载加速。
(1)首先确保码云上有账户,可以正常使用,没有的可以自行注册一下。
(2)点击右上角新建仓库的加号 ,选择 “从 导入仓库” 菜单
(3)然后填写位于 上你想 的仓库地址并导入
这一步交给码云来做速度是非常快的,一会儿功夫,码云就克隆出了一份和 GitHub 上一模一样的项目!
(4)接下来我们通过码云上的项目地址,将项目 到本地,这时候的 clone 速度就很快了,几 的速度是没问题的,很快项目就下载下来了。
按道理讲这时候我们的目的已经达到了,不过不要忘了,还有一件事没做。
要知道,这时候克隆到本地的项目关联的是码云 Gitee 的地址,已经和原来的 GitHub 项目完全脱离了,是另外一个副本。
在必要情况下(比如我们就是要给 GitHub 上的某个项目提 ),我们还需要重新将我们本地的项目关联到原来的 GitHub 项目上去,做法如下:
(1)首先找到位于本地仓库目录下的隐藏文件夹
(2)用文本编辑器打开 文件夹中的 配置文件
将配置文件中的 字段重新关联到原来位于 GitHub 上的 GitHub 项目地址
当然你也可以通过命令行来修改远端地址,效果一样的
至此大功告成,本地项目就相当于是 自 GitHub,后续提代码,提 到 GitHub 上都没有问题。
快捷键
介绍
Ctrl + F
在当前文件进行文本查找 (必备)
Ctrl + R
在当前文件进行文本替换 (必备)
Ctrl + Z
撤销 (必备)
Ctrl + Y
删除光标所在行 或 删除选中的行 (必备)
Ctrl + X
剪切光标所在行 或 剪切选择内容(必备)
Ctrl + C
复制光标所在行 或 复制选择内容(必备)
Ctrl + D
复制光标所在行 或 复制选择内容,并把复制内容插入光标位置下面 (必备)
Ctrl + W
递进式选择代码块。可选中光标所在的单词或段落,连续按会在原有选中的基础上再扩展选中范围 (必备)
Ctrl + E
显示最近打开的文件记录列表 (必备)
Ctrl + N
根据输入的 类名 查找类文件
Ctrl + G
在当前文件跳转到指定行处
Ctrl + J
插入自定义动态代码模板 (必备)
Ctrl + P
方法参数提示显示 (必备)
Ctrl + Q
光标所在的变量 / 类名 / 方法名等上面(也可以在提示补充的时候按),显示文档内容
Ctrl + U
前往当前光标所在的方法的父类的方法 / 接口定义
Ctrl + B
进入光标所在的方法/变量的接口或是定义处,等效于 Ctrl + 左键单击 (必备)
Ctrl + K
版本控制提交项目,git commit (必备)
Ctrl + T
版本控制更新项目,需要此项目有加入到版本控制才可用
Ctrl + H
显示当前类的层次结构
Ctrl + O
选择可重写的方法
Ctrl + I
选择可继承的方法
Ctrl + +
展开代码(必备)
Ctrl + -
折叠代码(必备)
Ctrl + /
注释光标所在行代码,会根据当前不同文件类型使用不同的注释符号 (必备)
Ctrl + [
移动光标到当前所在代码的花括号开始位置(必备)
Ctrl + ]
移动光标到当前所在代码的花括号结束位置(必备)
Ctrl + F1
在光标所在的错误代码处显示错误信息
Ctrl + F3
调转到所选中的词的下一个引用位置
Ctrl + F4
关闭当前编辑文件
Ctrl + F8
在 Debug 模式下,设置光标当前行为断点,如果当前已经是断点则去掉断点
Ctrl + F9
执行 Make Project 操作
Ctrl + F11
选中文件 / 文件夹,使用助记符设定 / 取消书签
Ctrl + F12
弹出当前文件结构层,可以在弹出的层上直接输入,进行筛选
Ctrl + Tab
编辑窗口切换,如果在切换的过程又加按上delete,则是关闭对应选中的窗口
Ctrl + End
跳到文件尾(必备)
Ctrl + Home
跳到文件头(必备)
Ctrl + Space
基础代码补全,默认在 Windows 系统上被输入法占用,需要进行修改,建议修改为 Ctrl + 逗号 (必备)
Ctrl + Delete
删除光标后面的单词或是中文句 (必备)
Ctrl + BackSpace
删除光标前面的单词或是中文句 (必备)
Ctrl + 1,2,3...9
定位到对应数值的书签位置
Ctrl + 左键单击
在打开的文件标题上,弹出该文件路径 (必备)
Ctrl + 光标定位
按 Ctrl 不要松开,会显示光标所在的类信息摘要
Ctrl + 左方向键
光标跳转到当前单词 / 中文句的左侧开头位置 (必备)
Ctrl + 右方向键
光标跳转到当前单词 / 中文句的右侧开头位置 (必备)
Ctrl + 前方向键
等效于鼠标滚轮向前效果 (必备)
Ctrl + 后方向键
等效于鼠标滚轮向后效果 (必备)
快捷键
介绍
Alt + `
显示版本控制常用操作菜单弹出层 (必备)
Alt + Q
弹出一个提示,显示当前类的声明 / 上下文信息
Alt + F1
显示当前文件选择目标弹出层,弹出层中有很多目标可以进行选择
Alt + F2
对于前面页面,显示各类浏览器打开目标选择弹出层
Alt + F3
选中文本,逐个往下查找相同文本,并高亮显示
Alt + F7
查找光标所在的方法 / 变量 / 类被调用的地方(必备)
Alt + F8
在 Debug 的状态下,选中对象,弹出可输入计算表达式调试框,查看该输入内容的调试结果
Alt + Home
定位 / 显示到当前文件的 Navigation Bar
Alt + Enter
IntelliJ IDEA 根据光标所在问题,提供快速修复选择,光标放在的位置不同提示的结果也不同 (必备)
Alt + Insert
代码自动生成,如生成对象的 set / get 方法,构造函数,toString() 等 (必备)
Alt + 左方向键
切换当前已打开的窗口中的子视图,比如Debug窗口中有Output、Debugger等子视图,用此快捷键就可以在子视图中切换 (必备)
Alt + 右方向键
按切换当前已打开的窗口中的子视图,比如Debug窗口中有Output、Debugger等子视图,用此快捷键就可以在子视图中切换 (必备)
Alt + 前方向键
当前光标跳转到当前文件的前一个方法名位置 (必备)
Alt + 后方向键
当前光标跳转到当前文件的后一个方法名位置 (必备)
Alt + 1,2,3...9
显示对应数值的选项卡,其中 1 是 Project 用得最多 (必备)
快捷键
介绍
Shift + F1
如果有外部文档可以连接外部文档(必备)
Shift + F2
跳转到上一个高亮错误 或 警告位置(必备)
Shift + F3
在查找模式下,查找匹配上一个(必备)
Shift + F4
对当前打开的文件,使用新Windows窗口打开,旧窗口保留(必备)
Shift + F6
对文件 / 文件夹 重命名(必备)
Shift + F7
在 Debug 模式下,智能步入。断点所在行上有多个方法调用,会弹出进入哪个方法
Shift + F8
在 Debug 模式下,跳出,表现出来的效果跟 F9 一样
Shift + F9
等效于点击工具栏的 Debug 按钮
Shift + F10
等效于点击工具栏的 Run 按钮(必备)
Shift + F11
弹出书签显示层
Shift + Tab
取消缩进 (必备)
Shift + ESC
隐藏当前 或 最后一个激活的工具窗口(必备)
Shift + End
选中光标到当前行尾位置(必备)
Shift + Home
选中光标到当前行头位置(必备)
Shift + Enter
开始新一行。光标所在行下空出一行,光标定位到新行位置
Shift + 左键单击
在打开的文件名上按此快捷键,可以关闭当前打开文件 (必备)
Shift + 滚轮前后滚动
当前文件的横向滚动轴滚动 (必备)
快捷键
介绍
Ctrl + Alt + L
格式化代码,可以对当前文件和整个包目录使用 (必备)
Ctrl + Alt + O
优化导入的类,可以对当前文件和整个包目录使用
Ctrl + Alt + I
光标所在行 或 选中部分进行自动代码缩进,有点类似格式化
Ctrl + Alt + T
对选中的代码弹出环绕选项弹出层
Ctrl + Alt + J
弹出模板选择窗口,将选定的代码加入动态模板中
Ctrl + Alt + H
调用层次
Ctrl + Alt + B
在某个调用的方法名上使用会跳到具体的实现处,可以跳过接口
Ctrl + Alt + C
重构-快速提取常量
Ctrl + Alt + F
重构-快速提取成员变量
Ctrl + Alt + V
重构-快速提取变量
Ctrl + Alt + Y
同步、刷新
Ctrl + Alt + S
打开 IntelliJ IDEA 系统设置 (必备)
Ctrl + Alt + F7
显示使用的地方。寻找被该类或是变量被调用的地方,用弹出框的方式找出来
Ctrl + Alt + F11
切换全屏模式
Ctrl + Alt + Enter
光标所在行上空出一行,光标定位到新行 (必备)
Ctrl + Alt + Home
弹出跟当前文件有关联的文件弹出层
Ctrl + Alt + Space
类名自动完成
Ctrl + Alt + 左方向键
退回到上一个操作的地方
Ctrl + Alt + 右方向键
前进到上一个操作的地方
Ctrl + Alt + 前方向键
在查找模式下,跳到上个查找的文件
Ctrl + Alt + 后方向键
在查找模式下,跳到下个查找的文件
Ctrl + Alt + 右括号(])
在打开多个项目的情况下,切换下一个项目窗口(必备)
Ctrl + Alt + 左括号([)
在打开多个项目的情况下,切换上一个项目窗口(必备)
快捷键
介绍
Ctrl + Shift + F
根据输入内容查找整个项目 或 指定目录内文件 (必备)
Ctrl + Shift + R
根据输入内容替换对应内容,范围为整个项目 或 指定目录内文件 (必备)
Ctrl + Shift + J
自动将下一行合并到当前行末尾 (必备)
Ctrl + Shift + Z
取消撤销 (必备)
Ctrl + Shift + W
递进式取消选择代码块。可选中光标所在的单词或段落,连续按会在原有选中的基础上再扩展取消选中范围 (必备)
Ctrl + Shift + N
通过文件名定位 / 打开文件 / 目录,打开目录需要在输入的内容后面多加一个正斜杠
Ctrl + Shift + U
对选中的代码进行大 / 小写轮流转换 (必备)
Ctrl + Shift + T
对当前类生成单元测试类,如果已经存在的单元测试类则可以进行选择 (必备)
Ctrl + Shift + C
复制当前文件磁盘路径到剪贴板 (必备)
Ctrl + Shift + V
弹出缓存的最近拷贝的内容管理器弹出层
Ctrl + Shift + E
显示最近修改的文件列表的弹出层
Ctrl + Shift + H
显示方法层次结构
Ctrl + Shift + B
跳转到类型声明处
Ctrl + Shift + I
快速查看光标所在的方法 或 类的定义
Ctrl + Shift + K
git push (必备)
Ctrl + Shift + A
查找动作 / 设置
Ctrl + Shift + /
代码块注释 (必备)
Ctrl + Shift + [
选中从光标所在位置到它的顶部中括号位置 (必备)
Ctrl + Shift + ]
选中从光标所在位置到它的底部中括号位置 (必备)
Ctrl + Shift + +
展开所有代码 (必备)
Ctrl + Shift + -
折叠所有代码 (必备)
Ctrl + Shift + F7
高亮显示所有该选中文本,按Esc高亮消失
Ctrl + Shift + F8
在 Debug 模式下,指定断点进入条件
Ctrl + Shift + F9
编译选中的文件 / 包 / Module
Ctrl + Shift + F12
编辑器最大化
Ctrl + Shift + Space
智能代码提示
Ctrl + Shift + Enter
自动结束代码,行末自动添加分号 (必备)
Ctrl + Shift + Backspace
退回到上次修改的地方
Ctrl + Shift + 1,2,3...9
快速添加指定数值的书签
Ctrl + Shift + 左键单击
把光标放在某个类变量上,按此快捷键可以直接定位到该类中 (必备)
Ctrl + Shift + 左方向键
在代码文件上,光标跳转到当前单词 / 中文句的左侧开头位置,同时选中该单词 / 中文句
Ctrl + Shift + 右方向键
在代码文件上,光标跳转到当前单词 / 中文句的右侧开头位置,同时选中该单词 / 中文句
Ctrl + Shift + 前方向键
光标放在方法名上,将方法移动到上一个方法前面,调整方法排序 (必备)
Ctrl + Shift + 后方向键
光标放在方法名上,将方法移动到下一个方法前面,调整方法排序 (必备)
快捷键
介绍
Alt + Shift + N
选择 / 添加 task
Alt + Shift + F
显示添加到收藏夹弹出层 / 添加到收藏夹
Alt + Shift + C
查看最近操作项目的变化情况列表
Alt + Shift + I
查看项目当前文件
Alt + Shift + F7
在 Debug 模式下,下一步,进入当前方法体内,如果方法体还有方法,则会进入该内嵌的方法中,依此循环进入
Alt + Shift + F9
弹出 Debug 的可选择菜单
Alt + Shift + F10
弹出 Run 的可选择菜单
Alt + Shift + 左键双击
选择被双击的单词 / 中文句,按住不放,可以同时选择其他单词 / 中文句 (必备)
Alt + Shift + 前方向键
移动光标所在行向上移动 (必备)
Alt + Shift + 后方向键
移动光标所在行向下移动 (必备)
快捷键
介绍
Ctrl + Shift + Alt + V
无格式黏贴
Ctrl + Shift + Alt + N
前往指定的变量 / 方法
Ctrl + Shift + Alt + S
打开当前项目设置
Ctrl + Shift + Alt + C
复制参考信息
快捷键
介绍
F2
跳转到下一个高亮错误 或 警告位置 (必备)
F3
在查找模式下,定位到下一个匹配处(必备)
F4
编辑源
F7
在 Debug 模式下,进入下一步,如果当前行断点是一个方法,则进入当前方法体内,如果该方法体还有方法,则不会进入该内嵌的方法中
F8
在 Debug 模式下,进入下一步,如果当前行断点是一个方法,则不进入当前方法体内
F9
在 Debug 模式下,恢复程序运行,但是如果该断点下面代码还有断点则停在下一个断点上
F11
添加书签
F12
回到前一个工具窗口
Tab
缩进 (必备)
ESC
从工具窗口进入代码文件窗口
连按两次Shift
弹出 Search Everywhere 弹出层
STM32有两个看门狗,一个是独立看门狗另外一个是窗口看门狗,独立看门狗号称宠物狗,窗口看门狗号称警犬,本章我们主要分析独立看门狗的功能框图和它的应用。独立看门狗用通俗一点的话来解释就是一个 12 位的递减计数器,当计数器的值从某个值一直减到 0 的时候,系统就会产生一个复位信号,即 IWDG_RESET。如果在计数没减到 0 之前,刷新了计数器的值的话,那么就不会产生复位信号,这个动作就是我们经常说的喂狗。看门狗功能由 VDD 电压域供电,在停止模式和待机模式下仍能工作。
独立看门狗的时钟由独立的 RC振荡器 LSI提供,即使主时钟发生故障它仍然有效,非常独立。LSI的频率一般在 30~60KHZ之间,根据温度和工作场合会有一定的漂移,我们一般取 40KHZ,所以独立看门狗的定时时间并一定非常精确,只适用于对时间精度要求比较低的场合。
递减计数器的时钟由 LSI经过一个 8位的预分频器得到,我们可以操作预分频器寄存器 IWDG_PR 来设置分频因子,分频因子可以是:[4,8,16,32,64,128,256,256],计数器时钟CK_CNT=40/ 4*2^PRV,一个计数器时钟计数器就减一。
独立看门狗的计数器是一个 12 位的递减计数器,最大值为 0XFFF,当计数器减到 0时,会产生一个复位信号:IWDG_RESET,让程序重新启动运行,如果在计数器减到 0 之前刷新了计数器的值的话,就不会产生复位信号,重新刷新计数器值的这个动作我们俗称喂狗。
独立看门狗一般用来检测和解决由程序引起的故障,比如一个程序正常运行的时间是50ms,在运行完这个段程序之后紧接着进行喂狗,我们设置独立看门狗的定时溢出时间为60ms,比我们需要监控的程序 50ms 多一点,如果超过 60ms 还没有喂狗,那就说明我们监控的程序出故障了,跑飞了,那么就会产生系统复位,让程序重新运行。
开始正式操作:
在stm32l4xx_hal_conf.h中取消注释#define HAL_IWDG_MODULE_ENABLED
//定义看门狗
#define DEBUG_REDAY 1 //1 关闭看门狗 0 开启看门狗
#if DEBUG_REDAY==0
static IWDG_HandleTypeDef IwdgHandle;
#endif
//初始化看门狗
#if DEBUG_REDAY==0
IwdgHandle.Instance=IWDG;
IwdgHandle.Init.Prescaler=IWDG_PRESCALER_256;//4-256分频
IwdgHandle.Init.Reload=0x04FF; //范围0-0xFFF 4FF 对应8秒 FFF 对应26秒
IwdgHandle.Init.Window=IWDG_WINDOW_DISABLE;
if(HAL_IWDG_Init(&IwdgHandle) !=HAL_OK){
while(1);
}
#endif
//喂狗
#if DEBUG_REDAY==0
if(HAL_IWDG_Refresh(&IwdgHandle) !=HAL_OK){
while(1);
}
#endif
前几天朋友问我他的税这个月怎么突然比上个月多扣了很多,于是给他详细的算了一下,真酸!!!
在线税率计算 https://www.gerensuodeshui.cn/
其中,纳税期数指的是这是今年发的第几个月的工资,例如4月1号入职,到了8月份发了7月份的工资,纳税期数应填4
每个人每月的额度减免是5000,上面那个15921,是这么算的
累计5个月下来你的应纳税所得额=【18417-5000(减免)-1281.6(社保公积金)】*5个月=60677,参考表格你的税率应该按10%算。速算扣除数按2520算。
所以目前为止你今年应该总共要缴纳(60677*10%-2520)=3547.7
因为你前4个月已经缴纳了2334.16了,所以这个月你要缴纳3547.7-2334.16=1213.54,最终你这个月的工资为应纳税所得额=18417-1281.6(社保公积金)-1213.54=15921.86
PS:累计预扣预缴应纳税所得额=累计收入-累计免税收入-累计减除费用-累计专项扣除-累计专项附加扣除-累计依法确定的其他扣除
有些公司是不给你办理专项扣除的,需要自己在个人所得税APP上申请专项扣除,这样每个月减免的更多一点,比如子女教育:纳税人的子女接受全日制学历教育的相关支出,按照每个子女每月1000元的标准定额扣除。如果有一个子女,那每个月就是减免5000+1000=6000,专项扣除申请的越多每个月减免的越多,所以像你的情况是要年底自己去APP上办理补税就行了,能给你退很多钱。
因为你的累计预扣预缴应纳税所得额超过36000,所以一下子从3%跳到了10%,所以你才觉得一下子多扣了很多,但是要是在以前,都是直接按固定每个月扣多少税率,一年下来相比现在这样累计扣的多太多了,这个虽然让你觉得每个月越扣越多,但是一年下来没多少,而且以前的减免我记得是3000,最近几年才改到5000的,再加上专项扣除这些,扣得税更少了,基本上你第5个月以后,6-12月工资基本都在15900左右,没什么大变化了
专项附加扣除如下,明细查看个税专项附加扣除;
1、子女教育:纳税人的子女接受全日制学历教育的相关支出,按照每个子女每月1000元的标准定额扣除。
2、继续教育:纳税人在中国境内接受学历(学位)继续教育的支出,在学历(学位)教育期间按照每月400元定额扣除。同一学历(学位)继续教育的扣除期限不能超过48个月。纳税人接受技能人员职业资格继续教育、专业技术人员职业资格继续教育的支出,在取得相关证书的当年,按照3600元定额扣除。
3、大病医疗:在一个纳税年度内,纳税人发生的与基本医保相关的医药费用支出,扣除医保报销后个人负担(指医保目录范围内的自付部分)累计超过15000元的部分,由纳税人在办理年度汇算清缴时,在80000元限额内据实扣除。
4、住房贷款利息:纳税人本人或者配偶单独或者共同使用商业银行或者住房公积金个人住房贷款为本人或者其配偶购买中国境内住房,发生的首套住房贷款利息支出,在实际发生贷款利息的年度,按照每月1000元的标准定额扣除,扣除期限最长不超过240个月。纳税人只能享受一次首套住房贷款的利息扣除。
5、住房租金:纳税人在主要工作城市没有自有住房而发生的住房租金支出,可以按照以下标准定额扣除:
(一)直辖市、省会(首府)城市、计划单列市以及国务院确定的其他城市,扣除标准为每月1500元;
(二)除第一项所列城市以外,市辖区户籍人口超过100万的城市,扣除标准为每月1100元;市辖区户籍人口不超过100万的城市,扣除标准为每月800元。
6、赡养老人:纳税人赡养一位及以上被赡养人的赡养支出,统一按照以下标准定额扣除:
(一)纳税人为独生子女的,按照每月2000元的标准定额扣除;
(二)纳税人为非独生子女的,由其与兄弟姐妹分摊每月2000元的扣除额度,每人分摊的额度不能超过每月1000元。可以由赡养人均摊或者约定分摊,也可以由被赡养人指定分摊。
约定或者指定分摊的须签订书面分摊协议,指定分摊优先于约定分摊。具体分摊方式和额度在一个纳税年度内不能变更。
某天一个朋友找到我,想让我帮他处理一下Excel表格,如下图所示一共5991行,要求是每一列的值都相等就隐藏,如果某一行存在NULL或者不想等的值则显示当前行。
其实实现方法不难,主要是学会调用Cells函数获取指定坐标的单元格内容并对其判断和处理。代码如下
'列号转字母(列名)
Function Num2Name(ByVal ColumnNum As Long) As String
On Error Resume Next
Num2Name="" '超出范围返回空,如调用Num2Name(100000)
Num2Name=Replace(Cells(1, ColumnNum).Address(0, 0), "1", "")
'Cell.Address用来返回单元格的地址,参数(0,0)返回相对地址A1,参数(1,1)返回绝对地址$A$1
End Function
'字母(列名)转列号
Function Name2Num(ByVal ColumnName As String) As Long
On Error Resume Next
Name2Num=-1 '超出范围返回0,如调用Name2Num("AAAA") ,EXCEL没有那么多列
Name2Num=Range("A1:" & ColumnName & "1").Cells.Count
End Function
'展示所有行
Function ShowAllROW()
Dim ALLRow As Long
ALLRow=5991 '最后一行行数
For i=1 To ALLRow
ActiveSheet.Rows(i).Hidden=False
Next
End Function
'主函数
Sub PPH()
Dim ALLRow As Long, ALLLine As Long
Dim NowRow As Long, NowLine As Long
Dim HideFlag As Boolean
ALLRow=5991 '最后一行行数
ALLLine=Name2Num("AA") '最后一列列名
For NowRow=2 To ALLRow
HideFlag=True
For NowLine=2 To ALLLine
If Cells(NowRow, NowLine)="NULL" Then '包含NULL则不隐藏
HideFlag=False
Exit For
End If
If NowLine=2 Then '跳过列为2
Else
If Cells(NowRow, NowLine - 1) <> Cells(NowRow, NowLine) Then '与前一列值不等则不隐藏
HideFlag=False
Exit For
End If
End If
Next
If HideFlag Then '隐藏当前行
ActiveSheet.Rows(NowRow).Hidden=True
End If
Next
End Sub
最终效果如下图所示
统计数据
Sub PPH()
Dim ALLRow As Long, ALLLine As Long
Dim NowRow As Long, NowLine As Long
Dim TotalNum As Long '总表数
Dim Flag As Boolean
ALLRow=48536 '最后一行行数
TotalNum=0
For NowRow=2 To ALLRow Step 17
Flag=False
If Cells(NowRow, Name2Num("B"))="有校表" Then
For i=0 To 16
NowLine=Name2Num("H")
If Cells(NowRow + i, NowLine) Like "[\[]202*" Then '正则匹配[202开头
Flag=True
Exit For
End If
NowLine=Name2Num("K")
If Cells(NowRow + i, NowLine) Like "[\[]202*" Then '正则匹配[202开头
Flag=True
Exit For
End If
NowLine=Name2Num("N")
If Cells(NowRow + i, NowLine) Like "[\[]202*" Then '正则匹配[202开头
Flag=True
Exit For
End If
NowLine=Name2Num("Q")
If Cells(NowRow + i, NowLine) Like "[\[]202*" Then '正则匹配[202开头
Flag=True
Exit For
End If
Next
If Flag=True Then
TotalNum=TotalNum + 1
For i=0 To 16
ActiveSheet.Rows(NowRow + i).Interior.Color=vbYellow '标记当前表的背景色
Next
End If
End If
Next
Cells(1, Name2Num("R"))="总表数" & TotalNum '输出统计结果
End Sub
计时动作与单元格点击事件
'Private Declare PtrSafe Function timeGetTime Lib "winmm.dll" () As Long'调用延时函数
Private Declare Function timeGetTime Lib "winmm.dll" () As Long '调用延时函数
'字母(列名)转列号
Function Name2Num(ByVal ColumnName As String) As Long
On Error Resume Next
Name2Num=-1 '超出范围返回0,如调用Name2Num("AAAA") ,EXCEL没有那么多列
Name2Num=Range("A1:" & ColumnName & "1").Cells.Count
End Function
'自定义延时函数
Sub Delay(T As Long)
Dim time1 As Long
time1=timeGetTime
Do
DoEvents
Loop While timeGetTime - time1 < T
End Sub
'点击清除按钮
Private Sub CleanColor_Click()
ActiveSheet.Rows(3).Interior.ColorIndex=0 '删除背景色
End Sub
'点击计时按钮
Private Sub TimeCount_Click()
Dim DelayTime As Long
Dim StartRow As Long, EndRow As Long
Dim NowRow As Long, NowLine As Long
Dim NowTimeRow As Long, NowTimeLine As Long
'*******参数设置**************
DelayTime=1000 '设置延时时间 单位为毫秒 如500为0.5秒 1000为1秒
NowRow=3 '设置变化的起始行数
StartRow=Name2Num("B") '设置变化的起始列 例如 B
EndRow=Name2Num("T") '设置变化的结束列 例如 Q
NowTimeLine=Name2Num("B") '设置系统时间位置列数
NowTimeRow=1 '设置系统时间位置行数
'**********************
Cells(NowTimeRow, NowTimeLine)=Format(Now(), "yyyy年mm月dd日 hh:mm:ss:") & Format((Timer - Int(Timer)) * 1000, "000")
For i=StartRow To EndRow
NowLine=i
Delay DelayTime
ActiveSheet.Cells(NowRow, NowLine).Interior.Color=vbRed '标记当前表的背景色为红色
Cells(NowTimeRow, NowTimeLine)=Format(Now(), "yyyy年mm月dd日 hh:mm:ss:") & Format((Timer - Int(Timer)) * 1000, "000")
Next
End Sub
'单元格点击事件
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
If Not Application.Intersect([B4:T10], Target) Is Nothing Then '仅在B4:T10范围内点击起作用
If Target.Value="" Then '如果单元格为空
Target.Value="▲"
Else
Target.Value=""
End If
End If
End Sub
工欲善其事,必先利其器。
STM32Cube生态系统是ST为STM32开发者打造的软件生态,是嵌入式开发的利器。
为提升功能丰富且高能效的STM32系列微控制器的易用性,2019年,意法半导体在STM32Cube软件生态系统中增加了一个免费的多功能STM32开发工具:STM32CubeIDE。
为了和商用集成开发环境(IDE)工具一样好用,STM32CubeIDE充分发挥了意法半导体2017年收购的嵌入式开发工具厂商Atollic?的技术优势。这套IDE软件采用行业标准的开放式许可条款,为简化和加快基于STM32的嵌入式设计,新增了STM32专用功能,包括功能强大的STM32CubeMX微控制器配置和项目管理工具。
通过整合STM32CubeMX与STM32CubeIDE,意法半导体创建了一个更强大的开发环境。STM32Cube的完整生态系统还包含STM32CubeProgrammer的代码烧写器和STM32CubeMonitor系列的代码运行监控器,以及众多独立的MCU固件包。
STM32CubeIDE是ST官方提供的免费软件开发工具,也是STM32Cube生态系统的一员大将。它基于Eclipse?/CDT框架,GCC编译工具链和GDB调试工具,支持添加第三方功能插件。同时,STM32CubeIDE还集成了部分STM32CubeMX和STM32CubeProgrammer的功能,是一个 “多合一”的STM32开发工具。
用户只需要STM32CubeIDE这一个工具,就可以完成从芯片选型,项目配置,代码生成,到代码编辑,编译,调试和烧录的所有工作。
在开发的过程中,用户也可以非常方便地切换到内嵌的CubeMX初始化窗口,添加或者修改之前的外设和中间件配置。不需要在多个工具之间进行切换。
STM32CubeIDE提供的编译和堆栈分析工具为用户提供了关于项目状态和内存使用的有用信息。还提供了很多高级的调试功能帮助用户进行高效地调试。
跟 STM32CubeMX,STM32CubeProgrammer 一样,它也是一个多平台的STM32开发工具,用户可以在Windows,Linux和macOS操作系统上通过STM32CubeIDE进行软件开发。
STM32CubeIDE界面
STM32CubeIDE 是基于 Eclipse 的框架,它继承了 Eclipse 所特有的一些对用户来说还不太熟悉的特性,比如透视图,工作空间等。
工作空间(Workspace):STM32CubeIDE通过工作空间(workspace)对工程进行管理,打开STM32Cube时,它会新建一个默认的工作空间,用户也可以通过Browse按钮另外选择一个文件夹作为工作空间,之后新建或者导入的工程就都属于前面选择的这个工作空间。同一个工作空间下的工程具有相同的IDE层面的配置(在Window→Preferences中进行设置),比如显示和编辑的风格设置等。从文件系统的角度,工作空间就是一个文件夹,里面包含了多个工程的文件夹和一个名为“.metadata”的文件夹,“.metadata”文件夹下包含了该工作空间内的所有工程的信息。用户可以通过File→Switch Workspace菜单,切换不同的工作空间。
透视图(Perspective):透视图是一系列和某类功能相关的窗口的组合。常用的有C/C++编辑透视图,调试透视图和CubeMX配置透视图。
C/C++编辑透视图包括了项目管理器,编辑窗口,Outline窗口等。在项目管理器中可以查看和操作当前工作空间中的所有项目。双击打开项目中的文件,文件内容会显示在编辑窗口,在编辑窗口可以对其进行编辑。最右边的Outline窗口列出了当前打开的文件中定义的所有函数,变量和宏。
在Window Show View菜单中可以打开和关闭需要显示在C/C++编辑透视图中的窗口。
通过右上方的图标可以在不同的透视图之间切换,比如点击爬虫图标,就可以切换到调试透视图。在C/C++编辑透视图下点击工具栏的Debug按钮启动调试后,也会自动切换到调试透视图。
工程管理
11. 新建和导入工程
使用STM32CubeIDE,用户可以通过多种方法来开始新建一个项目。在STM32CubeIDE的欢迎界面上,列出了创建/导入工程的快捷入口,分别对应下面的四种场景。也可以通过File菜单下的New和Import实现对应的功能。
? 从零开始新建一个STM32工程
? 已有STM32CubeMX的配置文件(*.ioc文件 ),希望根据该ioc文件新建一个STM32工程
? 已有SW4STM32或者TrueSTUDIO工程,希望转换成STM32CubeIDE工程
? 基于STM32Cube库中的例程创建新工程
2 STM32CubeIDE工程结构
STM32CubeIDE有两种工程结构,如下图所示。
单核的MCU都是扁平结构。
对于双核架构的MCU或者安全MCU,比如STM32H7,STM32L5和STM32MP1系列,STM32CubeIDE工程是分层结构。以STM32H7为例,创建或者导入STM32H7工程后,在Project Explorer栏看到的是一个三层的工程结构:最上面一层是“根”工程,然后是两个分别对应CM7和CM4内核的“子”工程,“子”工程下面才是工程文件。这两个CM7和CM4“子”工程才是真正的可编译和调试的工程,而“根”工程只是作为一个“容器”,包含了CM7和CM4这两个“子”工程。AN5361,AN5394,AN5360和AN5564分别描述了在STM32CubeIDE中如何创建,导入,编译和调试STM32H7双核,STM32L5,STM32MP1以及STM32WL的工程。
3 打开/关闭/删除/切换/导出STM32CubeIDE工程
在Project Explorer窗口中可以看到当前工作空间下的所有工程。用户可以对这里面的任一工程进行打开/关闭/删除/导入/导出/更名等操作。
具体请参考“工程的基本操作”(马上推出,敬请期待)。
4固件库管理
STM32CubeIDE集成了STM32CubeMX的部分功能,可以直接选择芯片/开发板型号,或者选择例程来生成一个新工程。STM32CubeIDE生成工程所需要的驱动和例程代码都来自各个STM32系列的固件库。
在Help→Manage Embedded Software Packages里,可以对所有的STM32固件库以及其他的插件进行管理(安装/删除固件库)。
用户可以通过Install Now按钮让STM32CubeIDE自动从网络进行下载安装,也可以通过From Local按钮来安装已经预先下载好的固件库。
通过Remove Now按钮可以删除选中的固件库。
在Window Preferences窗口的STM32Cube Firmware Updater标签页下,可以设置固件库安装的路径和更新的方式。
默认STM3CubeIDE在打开和新建工程的时候,都会尝试连接网络。用户也可以选择“Off Line Mode”,不让STM32CubeIDE去联网。但是需要通过上一张图中Embedded Software Packages Manager窗口的From Local按钮来安装已经预先下载好的固件库,否则将不能自动为新建的STM32工程生成代码。
点击Check Connection按钮可以检测当前的网络连接状态。检测结束如果出现一个红色的×,则说明网络配置有问题,需要我们到Network Connection页面去进行设置。
除了前面主动检测网络状态,如果出现固件下载失败的情况,也请检查STM32CubeIDE的网络配置是否正确。
配置步骤见下图:
1.进入 Window Preferences菜单,选择General Network Connections标签页
2.选择 Manual方式
3.选择HTTP,双击打开编辑窗口,设置网络连接参数。
代码编辑
STM32CubeIDE基于Eclipse,Eclipse的一些常用快捷键和编辑技巧一样适用于STM32CubeIDE。熟练掌握这些小技巧可以提高开发效率,使得程序开发的工作事半功倍。
代码编译
1工程属性设置及编译
在Project Explorer中选中一个工程,点击右键后进入properties菜单,在其中就可以对编译项进行配置。常用配置的操作细节,请查看“STM32CubeIDE工程属性配置技巧”。
配置完成之后就可以进行编译了。用户可以通过下面三种方式启动编译:
? 方法一:选中工程,点击右键,然后选择“Build Project”
? 方法二:选中工程,从Project菜单进入,然后选择“Build Project”
? 方法三:选中工程,直接点击工具栏里的Build图标
2提高编译速度
通过使能并行编译,可以提高STM32CubeIDE的编译速度。
选中工程,点击右键后进入properties菜单,选择“C/C++ Build”,在Behavior标签页下,勾选“Enable parallel build”功能。
3编译相关辅助工具
工程编译完成以后,在“Build Analyzer”窗口可以看到链接文件中定义的所有内存区域(memory region)和段(section)的使用情况,包括加载地址,运行地址,有多少字节已经被占用,还剩余多少字节等。
在“Static Stack Analyzer”窗口中显示了静态堆栈的使用情况。
STM32CubeIDE还提供了Headless Build功能,可以不打开CubeIDE的图形界面,通过命令行就可以进行编译。
代码调试及烧录
1调试及运行配置
STM32CubeIDE工程编译完成且无任何错误,就可以进行调试和下载了。
在C/C++透视图的工具栏中有三个和下载调试相关的按钮:调试,运行和外部工具。
通过“调试”按钮旁边的小三角,可以打开Debug Configurations菜单,进行调试参数的配置,比如调试器的选择,GDB连接的设置,ST-LINK的设置,外部Flash Loader的设定等,并启动调试。
通过“运行”按钮,可以仅下载程序不启动调试。
通过“外部工具”按钮,可以调用外部的命令行工具。
有关调试参数配置及调试技巧的内容,请参考“STM32CubeIDE工程调试配置及技巧”(马上推出,敬请期待)。
2启动调试
STM32CubeIDE使用GDB进行调试,支持STLink和SEGGER J-Link调试器,支持通过SWD或JTAG接口连接目标MCU。
STM32CubeIDE工程编译完成之后,直接点击工具栏的爬虫图标或者通过选择菜单Run-->Debug,可以启动调试。
如果是第一次对当前工程进行调试,STM32CubeIDE会先编译工程,然后打开调试配置窗口。调试配置窗口包含:调试接口的选择,STLink的设置,复位设置和外部flash loader的设置等选项,用户可以检查或者修改各项配置。确认所有的配置都正确无误,就可以点击OK,启动调试。
然后STM32CubeIDE会先将程序下载到MCU,然后从链接文件(*.ld)中指定的程序入口开始执行。程序默认从Reset_Handler开始执行,并暂停在main函数的第一行,等待接下来的调试指令。
3基本调试操作
启动调试后,STM32CubeIDE将自动切换到调试透视图,在调试透视图的工具栏中,列出了调试操作按钮。如下图所示。
插件的使用
STM32CubeIDE同样支持Eclipse插件。
可以通过Help菜单下的“Eclipse Marketplace”,在Eclipse市场中查找并安装插件;
或者通过Help菜单下的“Install New Software”,从指定的网址安装插件。
STM32CubeIDE使用例程
下面我们通过一个LED闪灯的例程,来体验一下使用STM32CubeIDE进行软件开发的流程。
例程使用NUCLEO-H743ZI开发板,通过STM32CubeIDE从零开始新建工程。该工程就实现一个简单的功能:板载的LED1以500ms的间隔自动翻转。
通过这个例程,可以了解到以下内容:
? 新建一个STM32CubeIDE工程
? 对STM32芯片进行配置
? 添加用户代码并编译
? 设置调试参数
? 调试代码(查看变量及寄存器)
? 设置断点
首先,选择File-->New-->STM32 Project,STM32CubeIDE会打开MCU选择窗口。在这个窗口下,可以选择某个型号的芯片,也可以选择某个ST开发板或者例程。这里我们在搜索框里输入STM32H743ZI,就可以直接选择这个芯片了,然后点击Next。
在接下来弹出的窗口中,需要设置项目的名称,类型和工程保存的位置。默认情况下,新建的工程会保存在当前的workspace中,用户也可以按下图所示,取消“Use default location”,然后自定义工程保存的位置。需要注意的是,如果你试图将两个工程放在同一个路径下,在后面的创建过程中可能会报错。所以你可以在路径中加上工程名,以区别不同的工程。
设置完成后,点击Finish,STM32CubeIDE将为我们创建一个工程,并打开芯片的配置界面,这个界面和STM32CubeMX是一样的。
期间可能会弹出将要打开CubeMX配置透视图的提示,点击Yes就可以了。
接下来要做的是,在芯片配置界面,按功能需求对时钟,GPIO,外设,中间件等进行配置。在这个例程中,我们只用到了PB0,作为输出控制LED1,所以只需要配置它就可以了。时钟就使用默认配置。
在Pinout视图下,通过搜索栏,可以在快速在芯片封装图上找到要配置的引脚。
选择该引脚,点击右键,选择GPIO_Output功能。
然后转到System视图,点击GPIO模块,然后就可以看到刚刚配置的PB0引脚。这个窗口中,还可以继续调整PB0的其他参数,比如上/下拉,速度等。还可以为其定义一个用户标签LDE1,方便在代码中进行引用。
所有的配置结束后,选择Project-->Generate Code重新生成代码。这时STM32Cube会切换到C/C++透视图,然后可以添加用户的文件或对某个C文件进行修改。
在这里,我们添加了一段翻转PB0的代码。这里要注意,所有用户添加的代码必须放在“USER CODE BEGIN xxx”和“USER CODE END xxx”这一对声明之间。这样当再次重新生成代码的时候,才不会丢失这部分代码。
代码添加完成后,点击“Build”开始编译。
如果编译结束并且没有任何报错。就可以点击Debug,启动调试。
第一次启动调试,会先弹出调试参数配置窗口,确认好所有的参数无误,点击OK,STM32CubeIDE就会自动从编辑界面切换到调试界面了。如下图所示。
在调试界面下,通过工具栏的操作按钮,可以进行单步调试。
双击某一行代码最左边的标记栏处,就可以在这行代码处添加断点。
右侧打开了多个调试窗口,包括:局部变量,断点,全局变量和寄存器等等。这些窗口可以在Window-->Show View菜单中打开或者关闭。
相关资源
1如何查看STM32CubeIDE文档集
第一次打开STM32CubeIDE时,首先显示的是“Information Center”页面。这个页面提供了创建工程的快速通道和使用STM32CubeIDE的文档入口。用户不需要在使用STM32CubeIDE之前阅读所有这些文档,但可以把这里作为一个入口,在需要的时候从这里进入去搜索相关文档。
2用户手册/应用笔记
原文引用:https://www.bilibili.com/read/cv9358088?from=search
设置铺铜的间隙:在Clearance中新增规则 InPolygon并修改最小间隔
InNet('VCC')查询是不是此网络 InPolygon所有铜片 InComponent('J1)某个元器件
1)设置间距Clearance 2)设置连线方式Polygon Connect Style,其中Direct Connect为直连全覆盖,Relief Connect为引脚连接,可设置连接数,宽度以及间距。
在STM32单片机的开发中,经常需要将生成的HEX文件转换成bin文件烧录至单片机。
而我负责的大多项目是基于FreeRTOS的并且支持IAP固件升级的,简单原理就是将单片机的程序存储区分为Boot、A、B一共3个区域,Boot为启动区,A为用户程序,B为升级包缓存区。正常情况下,开机先运行启动区程序,再运行A区的用户程序;当需要升级时,将新的用户程序暂存至B区,下一次开机启动程序检测到需要升级,则将B区的用户程序拷贝至A程序,再重启运行新的用户程序。从而达到远程固件升级的功能,当然本文重点不在于这个具体如何实现的。
从上可知,在我的运用场景中,需要烧录2次,第一次先烧录Boot程序,第二次烧录用户程序。但这样很麻烦,所以以前的方式是将这2个Hex文件合并之后再转换Bin文件再烧录。但对于懒散的皮皮华来说还是过于麻烦。百度了一大堆转换工具,并没有我想要的很简单的工具,大部分需要设置多个文件,设置起始地址等等特别麻烦。于是就决定自己手写一个EXE执行程序,一步到位。
那么首先我们需要做的第一件事当然是了解HEX文件的组成,参考百度百科
数据类型有6种
所以需要我们重点去提取00类型的数据。
下面开始上正菜。我们先来看看软件成品:
下面开始介绍如何去实现这些功能,首先是打开按钮,其作用仅仅是为了获取需要转换文件的完整路径:
private void btnOpenHex_Click(object sender, EventArgs e)
{
try
{
pbConvert.Value=0;
if (openHexDlg.ShowDialog()==DialogResult.OK) //打开转换的目标文件
{
tbHexPath.Text=openHexDlg.FileName;
}
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
}
再是输出按钮,与打开按钮一致:
private void btnOut_Click(object sender, EventArgs e)
{
try
{
if (saveBinDlg.ShowDialog()==DialogResult.OK)
{
tbBinPath.Text=saveBinDlg.FileName;
}
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
}
重点就在于转换按钮:
private void btnConvert_Click(object sender, EventArgs e)
{
//转换时使3个按钮不可以点击
btnOpenHex.Enabled=false;
btnOut.Enabled=false;
btnConvert.Enabled=false;
try
{
Int32 i;
Int32 j=0;
String szTxt="";//合并HEX文件的数据
String szLine="";//Hex文件每行的数据
String szHex="";//bin文件的HEX字符串数据
int startAdr=0;//起始地址
int endAdr=0; //用于判断hex地址是否连续,不连续补充0xFF
int lineLenth;//当前行的数据长度
bool FirstLineFlag;//起始行标志位
bool FirstAddrFlag;//起始地址标志位
szHexPath=tbHexPath.Text;//HEX文件路径
szBinPath=tbBinPath.Text;//Bin文件路径
if (szHexPath=="")
{
MessageBox.Show("请选择需要转换的hex文件! ", "提示");
return;
}
pbConvert.Maximum=100;
#region 读取并处理Boot.hex
if (MergeBoot.Checked==true)//读取启动文件
{
if (!File.Exists(@"Boot.hex"))
{
MergeBoot.Checked=false;
MessageBox.Show("请在当前程序目录放入启动hex文件并命名为Boot.hex", "提示");
return;
}
pbConvert.Value=10;
StreamReader BootHexReader=new StreamReader("Boot.hex");
FirstAddrFlag=true;
while (true)
{
szLine=BootHexReader.ReadLine(); //读取Hex中一行
if (szLine==null) { break; } //读取完毕,退出
if (szLine.Substring(0, 1)==":") //判断首字符是”:”
{
if (szLine.Substring(7, 2)=="00")//数据记录
{
if (SaveMergeHex.Checked==true)
{
szTxt +=szLine + "\r
";
}
lineLenth=Int32.Parse(szLine.Substring(1, 2), System.Globalization.NumberStyles.HexNumber); // 获取一行的数据个数值
startAdr=Int32.Parse(szLine.Substring(3, 4), System.Globalization.NumberStyles.HexNumber); // 获取地址值
if (FirstAddrFlag)
{
endAdr=startAdr;
}
else
{
FirstAddrFlag=false;
}
for (i=0; i < startAdr - endAdr; i++) // 补空位置
{
szHex +="FF";
}
szHex +=szLine.Substring(9, lineLenth * 2); //读取有效字符
endAdr=startAdr + lineLenth;
}
else if (szLine.Substring(7, 2) !="01")//不为结束标识
{
if (SaveMergeHex.Checked==true)
{
szTxt +=szLine + "\r
";
}
}
}
}
BootHexReader.Close(); //关闭目标文件
}
pbConvert.Value=20;
#endregion
#region 读取并处理需要转换的hex文件
pbConvert.Value=30;
StreamReader HexReader=new StreamReader(szHexPath);
FirstLineFlag=true;
FirstAddrFlag=true;
while (true)
{
szLine=HexReader.ReadLine(); //读取Hex中一行
if (szLine==null) { break; } //读取完毕,退出
if (szLine.Substring(0, 1)==":") //判断首字符是”:”
{
if (szLine.Substring(7, 2)=="00")//数据记录
{
if (MergeBoot.Checked==true && SaveMergeHex.Checked==true)
{
szTxt +=szLine + "\r
";
}
lineLenth=Int32.Parse(szLine.Substring(1, 2), System.Globalization.NumberStyles.HexNumber); // 获取一行的数据个数值
startAdr=Int32.Parse(szLine.Substring(3, 4), System.Globalization.NumberStyles.HexNumber); // 获取地址值
if(MergeBoot.Checked==true){//合并文件则不需要初始化结束地址
FirstAddrFlag=false;
}else{
if (FirstAddrFlag)
{
endAdr=startAdr;
FirstAddrFlag=false;
}
}
if (startAdr==0x1A90)
{
;
}
for (i=0; i < startAdr - endAdr; i++) // 补空位置
{
szHex +="FF";
}
szHex +=szLine.Substring(9, lineLenth * 2); //读取有效字符
endAdr=startAdr + lineLenth;
}
else if (szLine.Substring(7, 2)=="04")//起始标识
{
if (FirstLineFlag)
{
FirstLineFlag=false;
}
else if (MergeBoot.Checked==true && SaveMergeHex.Checked==true)
{
szTxt +=szLine + "\r
";
}
}
else
{
if (MergeBoot.Checked==true && SaveMergeHex.Checked==true)
{
szTxt +=szLine + "\r
";
}
}
}
}
HexReader.Close(); //关闭目标文件
pbConvert.Value=50;
#endregion
#region 输出合并的Hex文件
if (MergeBoot.Checked==true && SaveMergeHex.Checked==true)
{
string MergeHexPath=Path.GetDirectoryName(szHexPath) + "\" + Path.GetFileNameWithoutExtension(szHexPath) + "_Merge.hex";
FileStream MergeHex=new FileStream(MergeHexPath, FileMode.OpenOrCreate); //实例化一个文件流,指定文件完整路径,设置模式为打开或在不存在时创建
StreamWriter MergeHexStr=new StreamWriter(MergeHex);//实例化文本写入器,指定写入的完全路径,确认写入
MergeHexStr.Write(szTxt);
MergeHexStr.Close();
MergeHexStr.Dispose();
MergeHex.Close();//关闭文件流
MergeHex.Dispose();//清除文件流
}
#endregion
#region 将hex数据转换为字节数据
Int32 Length=szHex.Length;
byte[] szBin=new byte[Length / 2];
pbConvert.Maximum=Length / 2;
for (i=0; i < Length; i +=2) //两字符合并成一个16进制字节
{
szBin[j]=(byte)Int16.Parse(szHex.Substring(i, 2), NumberStyles.HexNumber);
j++;
pbConvert.Increment(i);
}
#endregion
#region 输出Bin文件
if (szBinPath=="")//如果没设置输出路径则默认为hex文件路径
{
szBinPath=Path.ChangeExtension(szHexPath, "bin");
tbBinPath.Text=szBinPath;
}
FileStream fBin=new FileStream(szBinPath, FileMode.OpenOrCreate); //创建文件BIN文件
BinaryWriter BinWrite=new BinaryWriter(fBin); //二进制方式打开文件
BinWrite.Write(szBin, 0, szBin.Length);//写入字节
BinWrite.Flush();//释放缓存
BinWrite.Close();//关闭文件
fBin.Close();//关闭文件流
fBin.Dispose();//清除文件流
#endregion
btnOpenHex.Enabled=true;
btnOut.Enabled=true;
btnConvert.Enabled=true;
MessageBox.Show("文件转换完成! ", "提示");
pbConvert.Value=0;//清除进度显示
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
}
一共分为4个步骤:
而下面这个则实现了拖入hex文件自动转换的功能:
private void frMain_DragEnter(object sender, DragEventArgs e) //获得“信息”
{
if (e.Data.GetDataPresent(DataFormats.FileDrop))
e.Effect=DragDropEffects.All; //重要代码:表明是所有类型的数据,比如文件路径
else
e.Effect=DragDropEffects.None;
}
private void frMain_DragDrop(object sender, DragEventArgs e) //拖拽文件
{
string path=((System.Array)e.Data.GetData(DataFormats.FileDrop)).GetValue(0).ToString(); //获得路径
tbHexPath.Text=path; //由一个textBox显示路径
if (Path.GetExtension(path)==".hex" || Path.GetExtension(path)==".HEX")
{
btnConvert.PerformClick();//直接转换
}
}
以及使用快捷键操作软件
private void frMain_BtnPress(object sender, KeyEventArgs e)//按键触发
{
if(e.KeyValue==112)//F1
{
btnOpenHex.PerformClick();//直接打开文件
}
else if (e.KeyValue==113)//F2
{
btnOut.PerformClick();//直接输出
}
else if (e.KeyValue==115)//F4
{
btnConvert.PerformClick();//直接转换
}
}
最后完整的源码就在这里啦。https://github.com/BigPiPiHua/Hex2Bin
微信搜索 ELE远程唤醒 ,或扫描下列小程序二维码
电脑自带的网卡有一个魔术包,比如是MAC地址重复16次,只要在关机状态下收到此数据包,将会发送开机指令给主板,从而开机。有些电脑需要在BIOS中开启Wake On Line简称WOL。
在局域网内部实现很简单,假设要唤醒的电脑IP地址为192.168.4.127,唤醒端口为6666,那么任何一台局域网的电脑只要往192.168.4.127:6666发送这台电脑对应的MAC地址的魔术包即可成功唤醒,由此可看出,关键在于要唤醒的电脑的IP不会变,即我们需要设置为固定内网IP。
那么如何实现外网唤醒呢?这里面的门道可就多了。简单来说,如果是个人光纤用户,运营商默认不给用户开通外网IP功能的,因为不是很安全。当然我们可以打电话给客服让他开通外网IP,你可以说你需要连接家里的摄像头等等。开通成功后,我们百度输入IP查询到的IP地址假设为128.134.156.13。那么这个时候我们可以在远在天边使用手机或者电脑往128.134.156.13:6666发送魔术包即可唤醒。
你以为就这么简单吗,不,上面只是最简单的情况,实际使用更复杂。
难点1:电脑一般开启了防火墙,也就是说我们需要在防火墙里先设置出站入站规则,或者直接关闭防火墙,这样才能接收到外网往6666端口发送的数据。
难点2:外网IP并不是固定不变的!!如果是企业申请固定IP,那一年可是要上万块的哦。个人用户那就蛋疼了。IP什么时候变化目前我也不清楚有什么规律。可能几小时也可能几天。那么难度就来了,我怎么知道那台要唤醒的电脑他的外网IP变成什么样了?说到这可把你们难倒了吧。
接下来请听我皮皮华细细道来,首先我们来了解一下什么是域名,域名其实最终还是一个IP地址,只是为了方便用户不需要记那么复杂的数字IP地址。当我们访问域名的时候,会先访问根服务器,通过根服务器返回一个IP地址,你再跳转访问这个IP地址从而请求到我们需要的数据。这个过程也叫解析:把域名指向网站空间IP。
那么什么又是根服务器呢,根服务器全球也就几十台,它的作用不言而喻,就是为了给你查询域名对应的IP地址,这就要求了根服务器必须是配置高且长期稳定。
那么什么又是动态域名呢,动态这个词讲的就是当IP发生变化的时候重新去解析,让根服务器刷新域名对应的IP地址。
所以通过以上知识,我们可以运用动态域名技术来解决我们外网变化的问题。那么如何去实现呢。首先我们需要一个小玩意每隔一段时间去查询一下当前外网IP是不是和我绑定的域名对应的IP是否一致,如果不一致,就去更新他,重新解析。这样我们每次请求到的域名就是我们实际的外网IP啦。
如何去实现?我的做法是先购买自己的域名,再拥有一个支持配置动态域名的路由器,一般这种路由器好像还不便宜呢。在路由器中配置好动态域名解析服务。设定好更新IP的间隔,当然这个间隔设置因人而异,设置的太久,那么出现访问失败的几率更大,设置的太快,路由器消耗的资源更大,也更耗电。可以参考我设置的15分钟。
接下来就是端口映射了,那么什么是端口映射呢,先来看看这个例子:假设我们路由器的外网IP是128.134.156.13,路由器下面有A、B、C一共3台电脑,IP地址分别为:192.168.4.127、192.168.4.128、192.168.4.129。那我们怎么访问外网端口的7777就能访问到内网中的A电脑的6666端口呢。这个时候就需要端口映射了。在路由器中配置外网端口7777,输入需要映射到的IP地址192.168.4.127,以及对应的端口6666。这样我们往外网128.134.156.13:7777发送数据,就能在A电脑的6666端口接收到了。如果我们配置好了动态域名为huazai.eleuu.com,那么我们同样可以在外网往huazai.eleuu.com:7777发送数据,在内网A电脑6666端口能收到。
综上所述,我们就能拥有一台远程可以开机的电脑了。
那么远程开机后我们又应该怎么在外网远程控制这台电脑?3389是电脑主机自带的远程服务端口。同样我们在路由器中配置外网8888,至内网A电脑端的3389端口。并启用远程桌面服务。这样我们就可以通过外网的8888端口去远程控制内网的A电脑啦。