diff --git a/_posts/@eaDir/CMD-replace-for-Cmder.md@SynoEAStream b/_posts/@eaDir/CMD-replace-for-Cmder.md@SynoEAStream new file mode 100644 index 0000000..02a838e Binary files /dev/null and b/_posts/@eaDir/CMD-replace-for-Cmder.md@SynoEAStream differ diff --git a/_posts/@eaDir/C函数指针.md@SynoEAStream b/_posts/@eaDir/C函数指针.md@SynoEAStream new file mode 100644 index 0000000..5b74afe Binary files /dev/null and b/_posts/@eaDir/C函数指针.md@SynoEAStream differ diff --git a/_posts/@eaDir/ESP8266工程的导入.md@SynoEAStream b/_posts/@eaDir/ESP8266工程的导入.md@SynoEAStream new file mode 100644 index 0000000..6b26c35 Binary files /dev/null and b/_posts/@eaDir/ESP8266工程的导入.md@SynoEAStream differ diff --git a/_posts/@eaDir/ESP8266工程的裁剪和编译.md@SynoEAStream b/_posts/@eaDir/ESP8266工程的裁剪和编译.md@SynoEAStream new file mode 100644 index 0000000..2ca0728 Binary files /dev/null and b/_posts/@eaDir/ESP8266工程的裁剪和编译.md@SynoEAStream differ diff --git a/_posts/@eaDir/ESP8266开发前言.md@SynoEAStream b/_posts/@eaDir/ESP8266开发前言.md@SynoEAStream new file mode 100644 index 0000000..1214dfd Binary files /dev/null and b/_posts/@eaDir/ESP8266开发前言.md@SynoEAStream differ diff --git a/_posts/@eaDir/ESP8266开发环境的搭建.md@SynoEAStream b/_posts/@eaDir/ESP8266开发环境的搭建.md@SynoEAStream new file mode 100644 index 0000000..aa656ef Binary files /dev/null and b/_posts/@eaDir/ESP8266开发环境的搭建.md@SynoEAStream differ diff --git a/_posts/@eaDir/KeXueShangWangJiaoCheng.md@SynoEAStream b/_posts/@eaDir/KeXueShangWangJiaoCheng.md@SynoEAStream new file mode 100644 index 0000000..1281807 Binary files /dev/null and b/_posts/@eaDir/KeXueShangWangJiaoCheng.md@SynoEAStream differ diff --git a/_posts/@eaDir/Linux-Subsystem-Gui.md@SynoEAStream b/_posts/@eaDir/Linux-Subsystem-Gui.md@SynoEAStream new file mode 100644 index 0000000..eaee3ce Binary files /dev/null and b/_posts/@eaDir/Linux-Subsystem-Gui.md@SynoEAStream differ diff --git a/_posts/@eaDir/STM32-Flash-Write-Read.md@SynoEAStream b/_posts/@eaDir/STM32-Flash-Write-Read.md@SynoEAStream new file mode 100644 index 0000000..ca02ad5 Binary files /dev/null and b/_posts/@eaDir/STM32-Flash-Write-Read.md@SynoEAStream differ diff --git a/_posts/@eaDir/STM32-UART-CustomPrintf.md@SynoEAStream b/_posts/@eaDir/STM32-UART-CustomPrintf.md@SynoEAStream new file mode 100644 index 0000000..634969d Binary files /dev/null and b/_posts/@eaDir/STM32-UART-CustomPrintf.md@SynoEAStream differ diff --git a/_posts/@eaDir/STM32-UART-IDLE-IT-md.md@SynoEAStream b/_posts/@eaDir/STM32-UART-IDLE-IT-md.md@SynoEAStream new file mode 100644 index 0000000..a3bbb29 Binary files /dev/null and b/_posts/@eaDir/STM32-UART-IDLE-IT-md.md@SynoEAStream differ diff --git a/_posts/@eaDir/Win10-Linux-Subsystems.md@SynoEAStream b/_posts/@eaDir/Win10-Linux-Subsystems.md@SynoEAStream new file mode 100644 index 0000000..353489c Binary files /dev/null and b/_posts/@eaDir/Win10-Linux-Subsystems.md@SynoEAStream differ diff --git a/_posts/@eaDir/file system.md@SynoEAStream b/_posts/@eaDir/file system.md@SynoEAStream new file mode 100644 index 0000000..b971668 Binary files /dev/null and b/_posts/@eaDir/file system.md@SynoEAStream differ diff --git a/_posts/@eaDir/一种分层高扩展性通信协议的总结.md@SynoEAStream b/_posts/@eaDir/一种分层高扩展性通信协议的总结.md@SynoEAStream new file mode 100644 index 0000000..1b25d8e Binary files /dev/null and b/_posts/@eaDir/一种分层高扩展性通信协议的总结.md@SynoEAStream differ diff --git a/_posts/@eaDir/多系统grub引导丢失修复.md@SynoEAStream b/_posts/@eaDir/多系统grub引导丢失修复.md@SynoEAStream new file mode 100644 index 0000000..b3bdd04 Binary files /dev/null and b/_posts/@eaDir/多系统grub引导丢失修复.md@SynoEAStream differ diff --git a/_posts/@eaDir/大小端.md@SynoEAStream b/_posts/@eaDir/大小端.md@SynoEAStream new file mode 100644 index 0000000..2f38081 Binary files /dev/null and b/_posts/@eaDir/大小端.md@SynoEAStream differ diff --git a/_posts/@eaDir/树莓派—云服务器-EMQTT-环境搭建.md@SynoEAStream b/_posts/@eaDir/树莓派—云服务器-EMQTT-环境搭建.md@SynoEAStream new file mode 100644 index 0000000..2c8e901 Binary files /dev/null and b/_posts/@eaDir/树莓派—云服务器-EMQTT-环境搭建.md@SynoEAStream differ diff --git a/_posts/@eaDir/树莓派—花生壳-内网穿透.md@SynoEAStream b/_posts/@eaDir/树莓派—花生壳-内网穿透.md@SynoEAStream new file mode 100644 index 0000000..fed091a Binary files /dev/null and b/_posts/@eaDir/树莓派—花生壳-内网穿透.md@SynoEAStream differ diff --git a/_posts/@eaDir/树莓派安装系统和配置.md@SynoEAStream b/_posts/@eaDir/树莓派安装系统和配置.md@SynoEAStream new file mode 100644 index 0000000..3f3326a Binary files /dev/null and b/_posts/@eaDir/树莓派安装系统和配置.md@SynoEAStream differ diff --git a/_posts/@eaDir/测试编译器是否支持嵌套注释.md@SynoEAStream b/_posts/@eaDir/测试编译器是否支持嵌套注释.md@SynoEAStream new file mode 100644 index 0000000..cdba195 Binary files /dev/null and b/_posts/@eaDir/测试编译器是否支持嵌套注释.md@SynoEAStream differ diff --git a/_posts/CMD-replace-for-Cmder.md b/_posts/CMD-replace-for-Cmder.md new file mode 100644 index 0000000..88bc827 --- /dev/null +++ b/_posts/CMD-replace-for-Cmder.md @@ -0,0 +1,79 @@ +--- +title: Cmder 更好的选择 +tags: + - cmder +categories: + - Tools +comments: true +images: 'http://begild-one.top/cmder%E5%B0%81%E9%9D%A2%E5%9B%BE.png' +abbrlink: ef68d1d8 +date: 2018-04-19 14:35:31 +--- +###### 就如同封面一样,Cmder 看着就令人赏心悦目。微软自带 CMD 就不谈了好吧,不过Windows本身就不是擅长用控制台和用户打交道的系统,所以这样也无可厚非吧。不过现在有了更好的选择:Cmder。 + +## Cmder安装 +- 这是[Cmder](http://cmder.net/)官网,Cmder你可以选择两种版本,Mini和Full 这俩的区别我也不是很清楚,看网上说的也没有什么说服力🤔。我下载Full版本(zip100M)。[下载地址](https://github.com/cmderdev/cmder/releases/) + +- 下载完毕之后直接解压到你喜欢的目录下面就 OK 了(自己建一个根目录啊他自己没有外封根目录的😅),点击软件根目录下面的'Cmder.exe'即可启动 Cmder 软件。 + + ![cmder初始打开图](http://begild-one.top/cmder%E5%88%9D%E5%A7%8B%E6%89%93%E5%BC%80%E5%9B%BE.png) + +## 添加 Cmder 环境变量 +1. 操作流程:此电脑--->右键--->属性(控制面板\所有控制面板项\系统)--->侧边栏高级系统设置--->右下角环境变量; + +2. 根据你的需要,是作为本用户使用还是作为全局其他用户也能使用选择添加为用户变量还是系统变量。找到`Path`变量条。 + a. 双击,在弹出来的编辑窗口选择新建按钮,然后输入 'Cmder.exe' 所在的路径; + b. 如果是win7貌似是直接编辑文本的吧,那就直接在最后面添加`;Cmder.exe 所在的路径` 我把 Cmder 安装在 `D:\cmder\` 下,结合起来就是`;D:\cmder\`。切记分号不能少🙂。 + ![添加环境变量cmder](http://begild-one.top/%E6%B7%BB%E5%8A%A0%E7%8E%AF%E5%A2%83%E5%8F%98%E9%87%8Fcmder.png) + + +## 添加右键 Cmder Here +这个是方便我们在任何文件夹直接打开 Cmder 。 +1. 用管理员身份运行系统自带的 CMD,运行命令:`Cmder.exe /REGISTER ALL` (没有报错)。 +2. 任意 Cmder 窗口--->标题栏--->右键--->Settings...--->Startup--->Task ; +3. 依次点击命令组下所有的命令任务在右下方的编辑框后面加` -new_console` (前导空格别忘了) ; +4. 关闭设置窗口~,设置完毕。在任意目录下右键即可看到 Cmder Here 字样的菜单。 +![Cmder Here设置](http://begild-one.top/cmder%20here%E8%AE%BE%E7%BD%AE.png) + +## 自定义终端符号 +这是个花里胡哨的操作😬。分为两个: powershell 和 cmd . +1. 修改 cmd 的提示符:用文本编辑软件打开 软件根目录\vendor\clink.lua 文件, + - 找到大概47行左右,两句话 ` lambda = "λ"` 和 `lambda = "("..env..") λ"` + - 替换 λ 为你喜欢的,我替换成 ღ (可以用搜狗特殊字符找一下自己喜欢的😹)。 +2. 修改 powershell 的提示符:打开 clink.lua同级目录下的profile.ps1 文件。 + - 找到大概121行,Utility\Write-Host "`nλ " -NoNewLine, + - 找到157行左右,两句话 `λ ` 和 `λ ` + - 将 λ 替换为你想要的。 +3. 重启软件完成设置。 + +## 设置终端背景 +1. 任意 Cmder 窗口--->标题栏--->右键--->Settings...--->Main--->Background ; +2. 勾选使用背景图像,在路径里找一张你喜欢的背景图片设置为背景 ; +3. 在暗化调整(Darking)选项,可以调整图片的防止掩盖终端字体显示不清楚 ; +4. 在放置方式管理(Placement)列表里可以选择你想把图片作何种放置(我设置的伸缩铺满窗口Stretch-Fill)。 +你也可以通过背景插件 Far Manager 进行设置。 +![cmder设置背景](http://begild-one.top/cmder%E8%AE%BE%E7%BD%AE%E8%83%8C%E6%99%AF.png) + +## 解决中文乱码 +使用默认的 cmder 中文会被识别为 `\数字` 的组合 根本没法看。 +1. 任意 Cmder 窗口--->标题栏--->右键--->Settings...--->Environment ; +2. 在右侧编辑框里另起一行写入`set LC_ALL=zh_CN.UTF-8` +3. 完成设置,重启 cmder 生效。、 +远程ssh连接服务器中文依然会乱码...。 + +## 配色主题 +1. 任意 Cmder 窗口--->标题栏--->右键--->Settings...--->Features--->Colors ; +2. 上方 Schemes 列表里选择你喜欢的配色方案~。 + +## alias功能 +Cmder提供的 alias 功能可以让我们用较为简短易记的单词指令替代很长的语法指令。在终端输入指令 `alias` 即可查看别名对应的真正语法指令,可以通过`软件根目录\config\user-aliases.cmd` 写人自己需要用到的却又难记的语法指令和别名的对应式子。 +比如我想要去我bolg所在的目录。每次都 cd 慢慢过去很烦,我就可以用 `blog =cd /d "E:\GitHome\blog"` 添加到 user-aliases.cmd 文件里,之后再终端直接输入blog就切换到blog的目录里。 +登录服务器可以用这个配合putty实现`Tencent="D:\Program Files\PuTTY\plink.exe" 255.255.255.255 -l root -pw "12346578" `。 + +## 后记 +1. cmder直接支持 ctrl+c 和 ctrl+v,在终端里双击选中即已经复制不需要用ctrl+c。 +2. 支持 vim 编辑器,同样的编辑方式和语法。 +3. 其他的一些设置诸如文字大小,默认启动也可以自行了解一下。 +4. Cmder 核心就是基于 ConEmu 做的,不过外面加了大量的Linux下的工具命令。很多Linux的命令在上面都可以运行。 + +cmder github地址: [https://github.com/cmderdev/cmder](https://github.com/cmderdev/cmder) diff --git a/_posts/C函数指针.md b/_posts/C函数指针.md new file mode 100644 index 0000000..df63f51 --- /dev/null +++ b/_posts/C函数指针.md @@ -0,0 +1,56 @@ +--- +title: C函数指针 +date: '2017-10.28 10:59:10' +tags: + - 指针 +categories: + - c语言 +abbrlink: 364cc1f5 +--- +当我们看到如下所示的代码怎么去理解它的意义呢。 +```C +(* ( void (*) () ) 0) () +``` +解析这个函数需要下面几个知识 + +1. 函数申明包含返回值,函数名,参数列表。 + - 如返回值是'int' 函数名为'fun',参数列表为'void'。 + - ```C + int fun(void); + ``` +2. 函数指针和返回值为指针的函数 + - 函数指针:函数指针pfun指向的是一个返回值为int类型,参数列表为空的函数。只要是符合这个'形状'的函数都可以吧地址赋给pfun。 + - ```c + int (*pfun) (void); + ``` + - 返回值为指针的函数:返回值为int*类型的指针,参数列表为空的函数fun1。它表示fun1是一个确定的函数。不像pfun是可以指向任何符合模板的函数。 + - ```c + int* fun1 (void); + ``` + 所以在书写的时候必须注意是否需要加括号。 +3. 类型转化符。就像我们平时说的怎么把一个int强制转化为char呢,就是 + ```C + int a = 48; + char b = (char) a; + ``` + 我们怎么构建一个类型转化符呢,就是把目标类型用括号括起来,那么一个函数模板的类型转化符是怎么样的呢,就是把函数名去掉,然后用括号把他括起来。比如上面的函数指针pfun这个模板。我们只需要将pfun去掉,然后把剩下部分括起来。 + ```C + (int (*) (void) ) + ``` + 这就是一个返回值为int参数列表为空的函数指针的强制类型转化符。 +----- +完成上述理解之后,我们着手理解一下 +```C +(* ( void (*) () ) 0) () +``` +首先通过下面这个式子可以看出这是一个函数的调用,那么左括号里面的就是函名。 +```C +( funname ) () +``` +也就是 ```C + * (void (*) () ) 0 == funname + ``` + +把0强制类型转化为void (*) () 型的函数指针。也就是指向函数地址为0的指针 ```C + (void (*) () ) 0 + ``` diff --git a/_posts/ESP8266工程的导入.md b/_posts/ESP8266工程的导入.md new file mode 100644 index 0000000..c65ff93 --- /dev/null +++ b/_posts/ESP8266工程的导入.md @@ -0,0 +1,65 @@ +--- +title: ESP8266工程的导入 +categories: + - ESP8266 +abbrlink: 6b9c1836 +date: 2018-01-22 20:32:57 +tags: +--- +## 前言: +本篇文章主要讲一下,ESP8266的工程怎么导入到Eclipse里。 +## 准备一个SDK工程 +- 既然是导入那么你首先得有一个现有的工程(不存在建工程的,这辈子都不可能徒手建工程的),工程从网上找一个就OK了。 +- ESP8266的SDK有两种,一种是无系统(NON-OS SDK),另一种是运行了FreeRTOS的(RTOS SDK)。 + + + +
SDK类型描述优缺点
NOn-OS SDK1.主要使⽤定时器和回调函数的⽅式实现各个功能事件的嵌套,达到特定条件下触发特定功能函数的⽬的。
2.使⽤ espconn 接⼝实现⽹络操作,⽤户需要按照 espconn 接⼝的使⽤规则进⾏软件开发.
1.无系统,顺序执行好理解占用资源少,但是不能有while(1);
2.不能有超过10ms的阻塞(延时)发生,否则将会重启。
RTOS SDK1.用户可以使⽤FreeRTOS 的标准接⼝实现资源管理、循环操作、任务内延时、任务间信息传递和同步等⾯向任务流程的设计⽅式;
2.⽹络操作接⼝是标准 lwIP API,同时提供了 BSD Socket API 接⼝的封装实现,⽤户可以直接按照 Socket API 的使⽤⽅式来开发软件应⽤,也可以直接编译运⾏其他平台的标准 Socket 应⽤;
3.引⼊了 cJSON 库,使⽤该库函数可以更加⽅便的实现对 JSON 数据包的解析;
4.兼容 non-OS SDK 中的 Wi-Fi 接⼝、SmartConfig 接⼝、Sniffer 相关接⼝、系统接⼝、定时器接⼝、FOTA 接⼝和外围驱动接⼝,不⽀持 AT 实现。
1.有系统,通过任务的调度完成系统的运行,可以有延时。
2.但是资源占用较多。
+ +- 例子可以从乐鑫官方的[下载地址](http://espressif.com/zh-hans/support/download/sdks-demos)下载.在下图所在的网页上面有选项选择ESP8266EX之后可以从下图所示的界面选择你所需要的SDK。 +![乐鑫SDK下载](https://s1.ax1x.com/2018/01/22/p4Iub8.md.png) +- 点击右边的下载按钮会跳转到GitHub(需要你懂一点点的git的知识才能下载)。如果实在没办法的话(求求你学一点git吧),我把我写文章的时候的最新的上传到网盘,大家可以去下载 链接: [https://pan.baidu.com/s/1c39VpXQ](https://pan.baidu.com/s/1c39VpXQ) 密码: dup8 。 +- 下载下来解压到你想放置的目录,不要有中文和(空格?),这样工程就完成了初步的布置。接下来就是重头戏了。 +## 导入工程 +- 第一步:应该能想到吧,那就是打开Eclipe_IDE(不会打开就算了你不适合用电脑)。 +- 第二步:打开eclipse之后会出现欢迎界面:"Welcome to the Eclipse IDE for C/C++ Developers"。 +- 第三步:点击 工具栏->File->Import (如图)进入导入工程窗口。 +![导入工程1](https://s1.ax1x.com/2018/01/22/p5SChq.png) +- 第四步:在select窗口选择C/C++->Existing Code as Makefile Project->点击Next进行下一步 +![导入工程2](https://s1.ax1x.com/2018/01/22/p5ptMT.png) +- 第五步:Import Existing Code 窗口选择浏览你的工程路径(就是解压出来的文件的路径)->下方选择 Cygwin GCC 工具->再点击Finish按钮完成导入。如果在这一步发现没有Cygwin GCC选项回头去检查是否用Eclipse_IDE.exe选择了正确的 Cygwin 路径。 +![导入工程3](https://s1.ax1x.com/2018/01/23/p5AYtg.png) +- 第六步:这时候你会发现,什么都没出现!怎么办?,那就是把欢迎界面叉掉!这样在右边Project栏就能发现一个折叠的工程,点击可以展开,整个界面大致如下图。我的因为是用git直接克隆下来的,所以在工程名旁边会提示橙色的字。如果你是从百度云下载的那就没有,这个无需理会,都一样(牛逼吧,git)。这时候问题输出窗口应该是什么都没有的,如果提示什么找不到g++、make等等,返回去检查是否选择的工具是Cygwin GCC!!!。 +[![工程整体结构图](https://s1.ax1x.com/2018/01/23/p5ERIS.png)](https://imgchr.com/i/p5ERIS) +## 后记 +我们都是用别人的工程(Demo)上开发的,所以这一步属于比较基础的,我们导入进来之后应该是编译通不过的!为什么,因为我们的SDK路径和写Demo的人不一样。这个涉及到makefile的编写了,不过别人已经把整个makefile编写的比较"智能"了,我们只是想要编译成功的话其实是不需要懂makefile的。我们改一改SDK的路径就行了。这个下一节再讲。 + +## 附录 +乐鑫官方的快速上手指导文档在上一篇->后记 里有网盘链接在这里就不放了。里面有SDK文件目录的讲解7/31页,看一下便于后面理解。 我整理了一下: +1. RTOS SDK工程目录讲解 + - bin:编译⽣成的 BIN 文件,可直接下载到 Flash 中。 + - documents:SDK 相关的⽂档(RTOS api)或链接。 + - driver_lib:乐鑫官方提供的驱动示例代码。(IIC SPI GPIO等) + - examples:可供用户二次开发的示例代码。(我们把不要的删掉) + - openssl_demo:乐鑫官方提供的 OpenSSL 接口功能示例代码。 + - project_template:乐鑫官方提供的工程模板示例代码。(我们用这个,其他的以后再说) + - smart_config:乐鑫官⽅提供的 SmartConfig 功能示例代码。 + - spiffs_test:乐鑫官方提供的 SPIFFS 文件系统功能示例代码。 + - websocket_demo:乐鑫官方提供的 WebSocket 功能示例代码。 + - include:SDK 自带头文件,包含了用户可使⽤的相关 API 函数及其他宏定义,用户无需修改。 + - ld:链接时所需的脚本文件,如⽆特殊需求,用户无需修改。(根据这个可以生成多钟bin文件) + - lib:SDK 提供的库文件。(只能用api不能改不能看) + - third_party:乐鑫开放源代码的第三方库,当前包含FreeRTOS、JSON、LWIP,mbedTLS、noPoll、OpenSSL、SPIFFS 和 SSL。 + - tools:编译 BIN 文件所需的工程具,用户无需修改。 +2. Non-OS SDK工程目录讲解 + - bin:编译⽣成的 BIN 文件,可直接下载到 Flash 中。 + - documents:SDK 相关的⽂档或链接。 + - driver_lib:外设驱动的库文件,如:UART、I2C 和 GPIO 等。 + - examples:可供用户次开发的示例代码,如 IoT Demo 等。 + - include:SDK ⾃带头文件,包含了用户可使用的相关 API 函数及其他宏定义,用户无需修改。 + - ld:链接时所需的脚本文件,若无特殊需求,用户⽆需修改。 + - lib:SDK 提供的库文件。 + - tools:编译 BIN 文件所需的工具,用户无需修改。 + + + diff --git a/_posts/ESP8266工程的裁剪和编译.md b/_posts/ESP8266工程的裁剪和编译.md new file mode 100644 index 0000000..b7fd7c3 --- /dev/null +++ b/_posts/ESP8266工程的裁剪和编译.md @@ -0,0 +1,115 @@ +--- +title: ESP8266工程的裁剪和编译 +categories: + - ESP8266 +abbrlink: 2e11c696 +date: 2018-01-23 16:35:39 +tags: +--- +## 前言 +本篇文章主要讲一下,乐鑫官方给的ESP8266 Demo怎么裁剪成我们要的样子以及编译。 +## 模板工程所需文件 +由于官方给的工程是包含了全部的Demo和库所以我们直接使用是不能编译的。我们就从一个最基础的工程模板开始裁剪,因为其他的功能都可以通过工程模板添加库和代码来实现。首先亮一下官方原版的RTOS SDK的工程结构(下左图)。 + +![1.png](https://s1.ax1x.com/2018/01/23/pIQc7j.png) + +我们需要把这个工程做成一个最基本的模板那么就需要把里面冲突的和暂时不需的都给删除。如下图是需要裁剪的内容: 红色的是需要删除的。紫色的删了节省空间。 +![2.png](https://s1.ax1x.com/2018/01/23/pI1hOU.png) +所以我们把刚刚标记这些都全部删除(别忘了备份一个原版的以后用)之后,这样就会少了很多东西。 +那现在可以编译了吗?打扰了,并不行。因为makefile这个神奇的东西存在,所以我们需要做一些调整和更改使得makefile能正确的识别、编译、链接整个工程。至于makefile是什么东西大家上网搜查看!这里就不展开讲了,因为就那个就可以做一个专题23333。 +你暂时只需要知道编译整个工程需要它掌控整个工程的各个文件的信息和关系的,所以我们需要告诉它各个文件的信息和之间的关系,所幸的是官方给的makefile已经很通用了,我们稍微做改变就可以了(感谢ing...) + +## 模板工程文件的调整 +下面的操作就是属于比较灵性的,不要问我为什么因为我个人觉得这样比较好。先按照我的来,等你学会了就可以去装逼了。先约定"/"就是工程的根目录,用绝对路径目录有点长。 +1. 剪切 /driver_lib/driver ---> /examples/project_template/ +2. 剪切 /driver_lib/include/ 的所有头文件 ---> /examples/project_template/include/ +3. 改名 /examples/project_template ---> app +4. 复制 /examples/app ---> / +5. 删除 /app/sample_lib 目录 +6. 删除 /driver_lib 目录 +7. 删除 /examples 目录 + +这样就完成了工程文件的调整:把相关的硬件驱动移到app目录下面,并且删除了示例的库。调整完成之后的目录如下图(documents目录删不删不影响): +![3.png](https://s1.ax1x.com/2018/01/23/pouGqJ.png) + +## MakeFile文件的修改 +1. 修改/Makefile文件 + - 文件里添加两句话SDK_PATH=××× BIN_PATH=xxx 比如我的工程根目录在 " e:/esp8266/leixing/ESP8266_RTOS_SDK-1.5-project_template "那么我的文件修改如下: + ```makefile + .... + ifndef PDIR + + endif + + SDK_PATH=e:/esp8266/leixing/ESP8266_RTOS_SDK-1.5-project_template + BIN_PATH=e:/esp8266/leixing/ESP8266_RTOS_SDK-1.5-project_template/bin + + ifeq ($(COMPILE), xcc) + ... + ``` +2.修改/app/Makefile文件 + - 文件里添加一句话SDK_PATH=××× 添加在文件的17行左右,内容就是你工程的根目录。 + - 文件里的SUBDIR=××× 把所有包含了c文件的子目录都添加进去。('\'表示续一行),ctrl+f可快速查找,修改位置大概在23行左右。 + - 修改完成之后如下: + ```makefile + ...上续 + #FLAVOR = release + FLAVOR = debug + SDK_PATH=e:/esp8266/leixing/ESP8266_RTOS_SDK-1.5-project_template + #EXTRA_CCFLAGS += -u + + ifndef PDIR # { + GEN_IMAGES= eagle.app.v6.out + GEN_BINS= eagle.app.v6.bin + SPECIAL_MKTARGETS=$(APP_MKTARGETS) + SUBDIRS= \ + user \ + driver + endif # } PDIR + ...下续 + ``` + - 把COMPONENTS_eagle.app.v6=××× 需要的.a文件修改为子目录下生成对应的.a文件(听不懂没关系,看效果代码),大概在48行左右。 + ```makefile + ...上续 + ifeq ($(FLAVOR),release) + TARGET_LDFLAGS += -g -O0 + endif + + COMPONENTS_eagle.app.v6 = \ + user/libuser.a \ + driver/libdriver.a + LINKFLAGS_eagle.app.v6 = \ + -L$(SDK_PATH)/lib \ + -Wl,--gc-sections \ + ...下续 + ``` +这样就修改完成了。 + +## 工程的编译 +1. 左键点击工程名选中工程->右键弹出菜单->BuildProject 即可编译。如果出现BuildProject选项灰色就是你没选中。如果失败可以尝试CleanProject(就在BuildProject下面)一下工程再编译。 +2. 编译之后输出窗口大致如下,输出两个bin文件:eagle.flash.bin 和 eagle.irom0text.bin ,这样就完成了工程的编译。这个固件是不支持OTA升级的,所以也不需要boot。也没有user1.bin和user2.bin。所以不要觉得奇怪。 +```N +23:48:32 **** Incremental Build of configuration Default for project ESP8266_RTOS_SDK-1.5-project_template **** +make all +make[1]: Entering directory '/cygdrive/e/esp8266/leixing/ESP8266_RTOS_SDK-1.5-project_template/app' +make[2]: Entering directory '/cygdrive/e/esp8266/leixing/ESP8266_RTOS_SDK-1.5-project_template/app/user' +make[2]: Leaving directory '/cygdrive/e/esp8266/leixing/ESP8266_RTOS_SDK-1.5-project_template/app/user' +make[2]: Entering directory '/cygdrive/e/esp8266/leixing/ESP8266_RTOS_SDK-1.5-project_template/app/driver' +make[2]: Leaving directory '/cygdrive/e/esp8266/leixing/ESP8266_RTOS_SDK-1.5-project_template/app/driver' + +!!! +SDK_PATH: e:/esp8266/leixing/ESP8266_RTOS_SDK-1.5-project_template +BIN_PATH: e:/esp8266/leixing/ESP8266_RTOS_SDK-1.5-project_template/bin + +No boot needed. +Generate eagle.flash.bin and eagle.irom0text.bin successully in BIN_PATH +eagle.flash.bin-------->0x00000 +eagle.irom0text.bin---->0x20000 +!!! +make[1]: Leaving directory '/cygdrive/e/esp8266/leixing/ESP8266_RTOS_SDK-1.5-project_template/app' + +23:48:37 Build Finished (took 4s.472ms) +``` + +## 后记 +这篇说的可能看起来有点云里雾里。因为和平时大家用的的不需要自己编写编译规则的IDE不同。像keil的话你添加的头文件也需要的手动添加到工程的IncludePath里面去。但是用这个eclipse开发esp8266完全使用makefile控制的,你的目录,头文件,c文件都是需要你手动配置makefile的,道理都一样都是要告诉编译器怎么去编译链接文件。不过是你自己找到makefile添加而已。之后会专门有一篇大概说一下整个工程如果我们想添加新的功能文件夹(比如实现一个tcp客户端功能),我们怎么去修改makefile。有什么疑问欢迎联系我。 \ No newline at end of file diff --git a/_posts/ESP8266开发前言.md b/_posts/ESP8266开发前言.md new file mode 100644 index 0000000..bc10d3c --- /dev/null +++ b/_posts/ESP8266开发前言.md @@ -0,0 +1,18 @@ +--- +title: ESP8266开发历程前言 +categories: + - ESP8266 +images: 'https://s1.ax1x.com/2018/03/01/9Dh6oR.jpg' +abbrlink: c1690bc8 +date: 2018-01-21 14:43:23 +tags: +--- + +## 意义: + +这算是第一个教程吧,ESP8266从大三到现在学了到现在,但是没有什么记录。回头又得拿着代码一点一点看,所以打算记录一下。同时也会兼顾一些解释和教程性质的东西,给能找到这的人看看吧,希望能给你一点帮助。 + +## 更新: + +更新的话,不定时。至于内容的顺序,就先按照一个hello world的实现来写,从引脚,IDE,下载工具,接线到写hello world,到下载查看。这些讲完的话打开你也就懂怎么做了。但是我不会写IO的使用因为我觉得他的定位作为wifi芯片比较好,就不要掺杂其他的的东西了(个人看法)。后面的软件层面的实现(主要是网络通信的应用)的话,也会写一部分。不过感觉网上其实挺多的教程(比较零散),所以不排除会直接把比较好的搬运过来然后配合自己的理解说一下。 + diff --git a/_posts/ESP8266开发环境的搭建.md b/_posts/ESP8266开发环境的搭建.md new file mode 100644 index 0000000..0134646 --- /dev/null +++ b/_posts/ESP8266开发环境的搭建.md @@ -0,0 +1,40 @@ +--- +title: ESP8266开发环境的搭建 +categories: + - ESP8266 +abbrlink: 5bce99c +date: 2018-01-21 21:54:35 +tags: +--- +## 前言: +本篇文章主要讲一下,ESP8266的开发环境怎么搭建。 + +## 开发工具下载: +对于ESP8266的开发工具我们采用的是eclipse搭建的一个IDE。这是安信可公司开发出来的,他们公司还出了一款付费的,只需要点一点就能生成基础代码的工具(不付费只能生成代码不能编译)。[点击这里](http://pan.baidu.com/s/1skRvR1j)下载最新的IDE。这里最新更新是2016年,应该已经停止了更新。防止链接失效,我转存到我的网盘:[ESP8266开发环境](https://pan.baidu.com/s/1c3OitUw) 密码: qnkh。如果我的失效了请联系我更换。 +## 开发环境搭建步骤 +当你忍受了百度云限速下载完成后恭喜你最艰难的一步完成!下载之后的会有四个文件: + +文件 |说明 +--- |--- +cygwin.exe | cygwin和xtensa编译器环境 +Eclipse.exe | eclipse c/c++ 开发工具打包 +ESP_IDE.exe | 一体化开发环境(配置)工具 +下载前读我!!!.txt|就是说明文档和教程(我的教程意义何在!!!) +1. 我们要把下载的文件放到你想要放的位置该位置必须不能有空格(cygwin目录不能有空格),我一开始放在了放在了"D:\Program Files\ESP8266IDE\" 目录下导致后面没法选择 cygwin。最后我选择放在 "D:\ESP8266IDE\", +2. 点击打开cygwin.exe和Eclipse.exe进行自解压到当前目录,解压完成之后会在生成两个目录,"cygwin 和 eclipse"。 +3. 点击ESP_IDE.exe运行,选择cygwin目录和eclipse目录。同时右下角的Not Ask也勾选,这样下次就不会再次弹出来让你选择path。如果出问题了删除ESP_IDE.exe同级目录->config->cfg.xml,再次打开就会提示你选择。 +![选择工具路径](https://s1.ax1x.com/2018/01/21/pfHHkF.png) +4. 首次运行会提示选择工作空间的路径。自己建一个目录选择就OK了,我选择"D:\ESP8266IDE\workspaces",勾选下面的选项下次就不会弹出来让你选了。(备注:一个工作空间可以同时打开很多个工程,不是每一个工程都需要打开一次IDE)。 +![选择工作空间](https://s1.ax1x.com/2018/01/21/pfHbY4.png) + +## 完成搭建 +这样就完成了开发环境的配置了,是不是感觉有点简单的过分。把cygwin.exe、Eclipse.exe删除节省空间。最后,别忘了把ESP_IDE.exe创建一个快捷方式到桌面(不懂的...),这样你下次直接点击就能打开eclipseIDE了。 + +## 后记 +1. 还有另外一种使用ubuntu镜像进行编译的方式,不过没有这种方便所以就不介绍了(官方有一个文档可自行去乐鑫下载也可下载我上传到网盘的链接:[https://pan.baidu.com/s/1ggMazRl](https://pan.baidu.com/s/1ggMazRl) 密码: g3y3 ,在第9/31页开始讲。所以感谢[安信可公司](https://www.ai-thinker.com)的奉献,让我们可以省去使用官方ubuntu镜像编译的开发方式!撒花ing... +2. arduino IDE工具,这个也可以开发,不过我并不喜欢arduino所以我一眼都没看过23333。 + +## 附录 + 1. 乐鑫公司官方文档资料、工具、demo下载地址:[http://espressif.com/zh-hans/support/download/overview](http://espressif.com/zh-hans/support/download/overview). + 2. 安信可公司官方的资料地址:[http://wiki.ai-thinker.com/esp8266](http://wiki.ai-thinker.com/esp8266). + 3. 开发快公司提供免费的ESP8266模组的申请:[http://bbs.kaifakuai.com/thread-981-1-1.html](http://bbs.kaifakuai.com/thread-981-1-1.html),注册之后就可以申请(我当时就是因为申请到了才开始玩ESP8266的,虽然很便宜但是抵不住他不要钱啊!!!).当然他们公司资料也很多的也很活跃,大家可以到处逛逛。开发快官方开发平台:[http://developer.kaifakuai.com](http://developer.kaifakuai.com)。QQ群:445880047。 diff --git a/_posts/KeXueShangWangJiaoCheng.md b/_posts/KeXueShangWangJiaoCheng.md new file mode 100644 index 0000000..c8d9056 --- /dev/null +++ b/_posts/KeXueShangWangJiaoCheng.md @@ -0,0 +1,367 @@ +--- +title: 科学上Google +tags: + - 科学上网 +password: 209445 +comments: true +abbrlink: 710edebb +date: 2018-04-22 15:28:42 +images: +--- + +## 写在前面 +- 如果你在在搜索资料方面在百度遇到了巨大挫折,我相信google能解决你问题。 +- 在我个人看来百度适用于找贴近于生活常识简单的东西(当然你必须具备一定的辨识能力不要盲目相信,莆田系的惨剧不是不能重演),就这些知识而言相对于google来说是比较好的。 +- 在专业的知识方面百度对于google来说就是个孤儿。搜索来的东西词不达意,胡扯一通或者根本就没有相关有用的东西(有用的怕就是 CSDN 了其他的都是狗屁不通)。 +- google搜索来的,基本如果是教程,数据手册,书本什么的前4条就能找到你要结果,属于比较专业的。我第一用google搜资料是因为百度实在是找不到那个芯片的数据手册(或许是我太菜了没能拨开那层层的迷雾),那时候改一改 host 还是上了 google 的,一搜索第2条就是角标一个pdf字样,直接下载就是数据手册,从那以后我越发的觉得百度就是个傻逼。 +- 后来 [老D博客](https://laod.cn/) 给的 host 也时常不能用,不过后来有幸免费得了一个绿皮车的账号福利,滴滴滴成功上车。 +- 用了没多久觉得也不是很稳定,后来就决定自己学习搭一下然后就上google搜了一下[搭建教程(境外访问)](https://docs.google.com/document/d/1FHdq9srvpYqdcsvKfZnPqZQ1-pRaXeUrfz3mrOf-eeE/edit#) 通过这个教程也成功的自己开了车~,然后在这里记一下。 +- [刘冰洋一审刑事判决书](http://wenshu.court.gov.cn/content/content?DocID=36f0191f-c617-4796-a271-a85600c6ad27) 科学上网胖虎劝你谨言慎行,头脑清晰,高举社会主义伟大旗帜,坚决拥护中国共产党。 + +## 关于中国的互联网 +网络审查在各个国家都普遍存在着,它并不仅存在于中国。在全球的局势对中国都不利的当下,当局会过滤掉影响、危害到中国长远发展的信息,此时国家安全的意义更加重大。 + +互联网上存在着大量终究不现实的、不客观的,甚至自相矛盾的抹黑当局政府言论,它们背后一般有西方政府或非政府组织资金支持。这些媒体包括但不限于一些港媒、境外网站。 + +我们希望您能在遇到此类言论和见解时,不要不加思考地、情绪一度被煽动而不能克制地、盲目地相信这些片面或者歪曲事实的东西,而是要事实求是地思考,要摆脱情绪绑架的怪诞思维去理解。 + +我们需要了解到,中国的发展总基调是“稳中求进”,中国社会的最核心问题就是稳定。失去稳定的中国将会是一盘散沙,面临分裂和肢解的危险。我们希望您了解当今中国发展的根本保证是什么,发展的过程中哪部分是主旋律,哪些是噪音;哪些是进取的,哪些是会开历史倒车的。我们需要维新,而不是革命。 + +我们应该清醒和全面地认识问题,偏信西方媒体的言论、缺乏对国家的信任是不可取的。您的数据安全和隐私对您尤为重要。若这些信息不应当被西方掌握时,它对国家和民族的命运更为重要。出于此原因,当局可能会限制您的行为,我们不会也无法干预当局的任何政策和决定。 + +所以,我们希望您在使用此服务时,不要盲目地攻击当局的做法。 +原文([https://github.com/racaljk/hosts/wiki/关于中国的互联网](https://github.com/racaljk/hosts/wiki/关于中国的互联网)) + +## 搭建步骤1 购买vps +1. 购买一台 Vultr 主机,便宜😉稳定😉。[https://www.vultr.com/?ref=7288720](https://www.vultr.com/?ref=7288720) 点击这个链接即可注册(注意:如果关闭网页再从历史记录中打开则无效,所以如果不小心关闭了可以再点击上面的链接注册),在你通过这个链接注册并在30天内充值10美元的话我也会得10美元。vultr支持支付宝支付,最少面额是10美元🤙 。 +![注册界面](http://begild-one.top/%E6%B3%A8%E5%86%8C%E7%95%8C%E9%9D%A2.png) +密码必须包含大写字母小写字母数字,长度至少10位。注册完毕即可登录。第一次登录会发送一个验证邮箱的邮件到邮箱。 +2. 登录成功,点击在侧边栏的 Billing ,在主页面的支付选项里可以选择多种方式,在这里可以使用 Alipay 支付,也就是我们所说的支付宝。点击右边会有快捷金额出现,最小的面额就是10美元,点击下方支付按钮会自动生成支持二维码,扫描即可支付。到账有可能有延迟,等一下就好了。到账之后会在右上角出现你的余额。 +3. 完成支付之后。点击在侧边栏的 Servers ,选择服务器在的位置(我选的Miami);运行的系统(Debian 7 x64 不要选错了);配置(2.5美元档位) ;附加功能勾选使能 IPV6。点击最下方的 Deploy Now 就成功购买了服务器了。 + 这个2.5美元的配置属于最低的,有可能Maimi买不到,你得尝试尝试其他地点看有没有该配置。都没有就尝试5美元的吧。他这个扣费并不是一次性扣费一个月,是按照使用时长的,比如你先买了5美元的用了1个小时后发现可以买2.5美元的,那么你把这个服务器销毁了他就只扣费1个小时的钱,这点还是比较好的。 +4. 点击侧边的 Servers ,在主页面就会出现你刚购买的服务器了,等到显示绿色的 running 时候就部署完成了。点击下图所指的Debian OS图标即可进入服务器的详情界面,。 +![Servers界面](http://begild-one.top/Servers%E7%95%8C%E9%9D%A2.png) +5. 详情界面可以看到详细的 IP、用户名、登录密码、CPU、RAM、硬盘大小、流量使用情况等等。我们主要用到用户名和密码待会远程登录需要使用。 + +## 搭建步骤2 远程登录 +1. 任何一个支持远程的工具都可以,这里选择 putty [点击下载](https://www.chiark.greenend.org.uk/~sgtatham/putty/latest.html) 体积很小,安装选项默认就行了,位置随便你。然后会在开始菜单有一个 PuTTY 图标,点击即可打开 putty +![putty添加连接](http://begild-one.top/putty%E6%B7%BB%E5%8A%A0%E8%BF%9E%E6%8E%A5.png) +2. 在①填服务器的IP、②填你想要保存的名字,比如科学上网;点击save保存下次就不用输入了;双击即可弹出登录窗口。可能界面比较难看,字还很小,将就一下或者自己改一下。 +3. 在弹出的 login as: 填写上面服务器详情页显示的 Username (默认就是 root) ,密码填一下详情页的 Password 点击详情页那里的复制按钮即可复制,在 putty界面 右键一下自动粘贴,不需要一个一个输入,如果失败那就是你操作有问题,实在不行老老实实的输,不过这里是看不到任何的密码提示的连 * 都没有。 +4. 登录成功即显示出linux终端的样式 `root@vultr:~#` 。 + +## 搭建步骤3 刷入Shadowsocks +1. 第一段代码,下载一键安装脚本。直接复制到 putty 里,右键直接粘贴,后回车运行即可, +``` +wget --no-check-certificate -O shadowsocks-all.sh https://raw.githubusercontent.com/teddysun/shadowsocks_install/master/shadowsocks-all.sh +``` + 结果展示: +``` +Resolving raw.githubusercontent.com (raw.githubusercontent.com)... 151.101.4.133 +Connecting to raw.githubusercontent.com (raw.githubusercontent.com)|151.101.4.133|:443... connected. +HTTP request sent, awaiting response... 200 OK +Length: 44802 (44K) [text/plain] +Saving to: `shadowsocks-all.sh' + +100%[======================================>] 44,802 --.-K/s in 0.002s + +2018-04-22 13:43:08 (17.3 MB/s) - `shadowsocks-all.sh' saved [44802/44802] +``` +2. 第二段代码如下,赋予下载来的脚本执行权限。同样复制右键粘贴到 putty 回车运行。没有任何报错即可。 +``` +chmod +x shadowsocks-all.sh +``` +3. 第三段代码如下,执行一键安装脚本(感谢 [秋水逸冰](https://teddysun.com/) 提供)。 +``` +./shadowsocks-all.sh 2>&1 | tee shadowsocks-all.log +``` +4. 执行的选择过程大致如下 已经标注了需要注意的点和注释: +``` +Which Shadowsocks server you'd select: +1) Shadowsocks-Python +2) ShadowsocksR +3) Shadowsocks-Go +4) Shadowsocks-libev +Please enter a number (Default Shadowsocks-Python):2 (选择 ShadowsocksR) + +You choose = ShadowsocksR + +Please enter password for ShadowsocksR +(Default password: teddysun.com):(密码) + +password = *** + +Please enter a port for ShadowsocksR [1-65535] +(Default port: 9555):(端口) + +port = *** + +Please select stream cipher for ShadowsocksR: +1) none +2) aes-256-cfb +3) aes-192-cfb +4) aes-128-cfb +5) aes-256-cfb8 +6) aes-192-cfb8 +7) aes-128-cfb8 +8) aes-256-ctr +9) aes-192-ctr +10) aes-128-ctr +11) chacha20-ietf +12) chacha20 +13) salsa20 +14) xchacha20 +15) xsalsa20 +16) rc4-md5 +Which cipher you'd select(Default: aes-256-cfb):12 +(选择chacha20 rc4-md5速度较快不过相对于aes安全性不高,chacha20效率比aes高加密性相当) +cipher = chacha20 + + +Please select protocol for ShadowsocksR: +1) origin +2) verify_deflate +3) auth_sha1_v4 +4) auth_sha1_v4_compatible +5) auth_aes128_md5 +6) auth_aes128_sha1 +7) auth_chain_a +8) auth_chain_b +9) auth_chain_c +10) auth_chain_d +11) auth_chain_e +12) auth_chain_f +Which protocol you'd select(Default: origin):3 + (使用 auth_sha1_v4 协议 较高安全性,混淆强度大) +protocol = auth_sha1_v4 + +Please select obfs for ShadowsocksR: +1) plain +2) http_simple +3) http_simple_compatible +4) http_post +5) http_post_compatible +6) tls1.2_ticket_auth +7) tls1.2_ticket_auth_compatible +8) tls1.2_ticket_fastauth +9) tls1.2_ticket_fastauth_compatible +Which obfs you'd select(Default: plain):2 +(混淆采用 http_simple) +obfs = http_simple + +Press any key to start...or Press Ctrl+C to cancel (按下任意键开始刷入 ctrl+C 取消) +``` +5. 执行成功结束会吧你整个 Shadowsocks 的配置打印出来,大致如下,将这段东西复制粘贴在记事本里备份一下免得以后忘了。 +``` +Starting ShadowsocksR success + +Congratulations, ShadowsocksR server install completed! +Your Server IP : ************* (服务器IP) +Your Server Port : ***** (服务端口) +Your Password : ********* (使用的密码) +Your Protocol : auth_sha1_v4 (使用的协议) +Your obfs : http_simple (混淆协议) +Your Encryption Method: chacha20 (加密方式) + +Your QR Code: (For ShadowsocksR Windows, Android clients only) + ss://****************************************************** + (SS配置信息代码,复制到小飞机右键剪切板批量导入) +Your QR Code has been saved as a PNG file path: + /root/shadowsocks_r_qr.png + (SS配置信息二维码) +Welcome to visit: https://teddysun.com/486.html +Enjoy it! +``` +6. 本地 SSR 客户端的配置,[下载地址](https://softs.fun/?dir=%E7%A7%91%E5%AD%A6%E4%B8%8A%E7%BD%91/PC/Shadowsocks/Windows/ShadowsocksR)。 + 1. 下载完成之后,解压到你想放置的文件夹下就好了。会有两个启动程序 2.0 和 4.0,分别是依赖于 NET Framework v2.0 和 v4.0 ,功能无区别随便打开一个就OK。 + 2. 打开在任务栏会有小飞机图标显示。这时候复制上面服务器输出的 SSR 配置信息代码,也就是`ssr://******` 那一大串,全部复制。在小飞机上右键弹出的菜单里找到 `剪切板批量导入ssr://地址...` 选项,点击该选项即完成导入配置。 + 3. 这时候的配置大致如下,可以看到混淆参数、备注和群组都是空的。混淆方式选择的是 http_simple 的话,参数里就填你要伪装的域名,也就是你的流量会被伪装成向你填写的域名请求的流量,减少被检测的风险,我填的是`cdn.4g.play.cn,4gmv.music.189.cn,dl.music.189.cn`。备注和群组就不多说了就是一些方便分类记忆的信息(毕竟有些人有很多车)。填写完成你的整个 `ssr://` 也会改变,以后分享给别人就直接复制这个 ssr代码,别人贴上去是和你的一模一样的。 +![SSR导入配置](http://begild-one.top/SSR%E5%AF%BC%E5%85%A5%E9%85%8D%E7%BD%AE.png) +6. 这样就完成了搭建。访问 [Google](https://www.google.com/ncr) 试一下,没问题的话等下就加载出来了。 + +## 搭建步骤4 刷入锐速进行提速 +首先你可以尝试运行这个命令,如果没有报错。那么你很幸运不用执行下面复杂的操作。如果有报错不支持你的内核那么你就得需要执行后续的步骤。 +``` +wget -N --no-check-certificate https://raw.githubusercontent.com/91yun/serverspeeder/master/serverspeeder.sh && bash serverspeeder.sh +``` +错误信息大致如下: +``` +===============System Info======================= +Debian +3.2.0-5-amd64 +x64 +================================================= +巴拉巴拉。。。 +2018-04-22 15:05:11 (21.0 MB/s) - `serverspeederbin.txt' saved [96179/96179] + +>>>This kernel is not supported. Trying fuzzy matching... + +Serverspeeder is not supported on this kernel! View all supported systems and kernels here: https://www.91yun.org/serverspeeder91yun +``` +上面代码执行出问题参照下面步骤解决。 +1. 锐速并不是支持所有的内核,支持列表见 [锐速支持内核列表](https://www.91yun.co/serverspeeder91yun) 该列表里找到 Debian7 x64 部分的内核列表大致如下,该列表仅供参考,具体的到上面的链接内核支持列表里查看: +``` +Debian/7/3.12-1-amd64/x64/3.10.54.8/0/serverspeeder_2483 +Debian/7/3.12-1-amd64/x64/3.10.61.0/0/serverspeeder_2609 +Debian/7/3.2.0-4-amd64/x64/3.10.39.8/0/serverspeeder_2010 +Debian/7/3.2.0-4-amd64/x64/3.10.53.0/0/serverspeeder_2323 +Debian/7/3.2.0-4-amd64/x64/3.10.54.8/0/serverspeeder_2466 +Debian/7/3.2.0-4-amd64/x64/3.10.61.0/0/serverspeeder_2626 +Debian/7/3.2.0-4-amd64/x64/3.9.10.41/0/serverspeeder_1662 +Debian/7/3.2.32/x64/3.10.45.0/0/serverspeeder_2154 +Debian/7/3.2.32/x64/3.10.53.0/0/serverspeeder_2289 +Debian/7/3.2.32/x64/3.10.54.8/0/serverspeeder_2443 +Debian/7/3.2.32/x64/3.10.61.0/0/serverspeeder_2599 +``` +2. 执行如下代码查看服务器的内核列表 。 +``` +dpkg -l|grep linux-image | awk '{print $2}' +``` + 我的结果如下: +``` +root@vultr:~# dpkg -l|grep linux-image | awk '{print $2}' +linux-image-3.2.0-4-amd64 +linux-image-3.2.0-5-amd64 +linux-image-amd64 +``` +3. 锐速支持的内核列表里有3.2.0-4 所以我这里直接找到对应的链接就行了,我选了个锐速版本最高的 3.10.61.0 。如果你的内核列表里没有与锐速所支持的内核所匹配的项,那你就需要刷入一个匹配的内核。 (内核问题参照于[笨猫博客](https://www.nbmao.com/archives/3036)) + 3.1 添加软件包源并更新软件包列表。 + ``` + echo -e "\ndeb http://ftp.debian.org/debian/ wheezy-backports main" >> /etc/apt/sources.list + apt-get update + ``` + 3.2 查看所有的内核列表 + ``` + root@vultr:~# aptitude search linux-image | awk '{print $2}' + 结果如下: + linux-image + linux-image-2.6-amd64 + linux-image-3.16.0-0.bpo.4-amd6 + linux-image-3.16.0-0.bpo.4-amd6 + linux-image-3.2.0-4-amd64 + linux-image-3.2.0-4-amd64-dbg + linux-image-3.2.0-4-rt-amd64 + linux-image-3.2.0-4-rt-amd64-db + linux-image-3.2.0-5-amd64 + linux-image-3.2.0-5-amd64-dbg + linux-image-3.2.0-5-rt-amd64 + linux-image-3.2.0-5-rt-amd64-db + linux-image-amd64 + linux-image-amd64-dbg + linux-image-rt-amd64 + ``` + 3.3 选择 linux-image-3.2.0-4-amd64 进行安装,这个会下载几百M的文件,耐心等待。 + ``` + apt-get -t wheezy-backports install linux-image-3.2.0-4-amd64 -y + ``` + 3.4 下载安装完成之后再查看一下服务器的内核列表,有 linux-image-3.2.0-4-amd64 就OK了。 +5. 卸载其他的内核版本。比如我的就卸载 `linux-image-3.2.0-5-amd64`和 `linux-image-amd64` 两个。 + ``` + apt-get purge 其余内核名称 + ``` + 卸载的时候会弹出一个选择框,该框是让你选择是否中断移除。一定要选择右边的取消!!!。如果出现卸载提示互斥 dkbg 被占用之类的,重启一下服务器(reboot 命令)重连 putty 再执行就OK了。 +6. 更新 grub 系统引导文件并重启(会断开putty) + ``` + root@vultr:~# update-grub && reboot + Generating grub.cfg ... + Found linux image: /boot/vmlinuz-3.2.0-4-amd64 + Found initrd image: /boot/initrd.img-3.2.0-4-amd64 + done + + Broadcast message from root@vultr.guest (pts/0) (Sun Apr 22 16:14:40 2018): + The system is going down for reboot NOW! + ``` +7. 当解决了内核的问题之后就到了安装了。因为经过上述步骤之后内核已经变更为 `linux-image-3.2.0-4-amd64` 所以我们执行下面的命令就可以了。如果是其他版本的内核请点击 [锐速支持内核列表](https://www.91yun.co/serverspeeder91yun) 找到对应项点击进去获取你的执行代码。 +``` +wget -N --no-check-certificate https://github.com/91yun/serverspeeder/raw/master/serverspeeder-v.sh && bash serverspeeder-v.sh Debian 7 3.2.0-4-amd64 x64 3.10.61.0 serverspeeder_2626 +``` + 安装过程如下: +``` +上接wget命令的输出 +===============System Info======================= +Debian +3.2.0-4-amd64 +x64 +================================================= + + +installing ServerSpeeder, please wait for a moment... + + +[Running Status] +ServerSpeeder is running! +version 3.10.61.0 + +[License Information] +License ***** (valid on current device) +MaxSession unlimited +MaxTcpAccSession unlimited +MaxBandwidth(kbps) unlimited +ExpireDate 2034-12-31 + +[Connection Information] +TotalFlow 1 +NumOfTcpFlows 1 +TotalAccTcpFlow 0 +TotalActiveTcpFlow 0 + +[Running Configuration] +accif eth0 +acc 1 +advacc 1 +advinacc 1 +wankbps 10000000 +waninkbps 10000000 +csvmode 0 +subnetAcc 0 +maxmode 1 +pcapEnable 0 +``` + +## 搭建步骤5 刷入 Finalspeed 加速 +FinalSpeed 根据用户设定的网络带宽省略了确认的步骤或是延长了确认的间隔,服务器按照用户设定的速率持续高速发包,所以可以达到更高的速度。不过现在改为收费使用了名字也改为 tcpspeed 想要支持一下作者使用收费版本的请点击 [http://www.tcpspeed.com/](http://www.tcpspeed.com/) ,省钱就使用旧版本的(作者已经删除)。91yun fork了一份并制作了一键安装包,[项目地址](https://github.com/91yun/finalspeed) +1. 一键安装 FinalSpeed ,安装完成无报错即在运行。 +``` +wget -N --no-check-certificate https://raw.githubusercontent.com/91yun/finalspeed/master/install_fs.sh && bash install_fs.sh +``` +2. 安装 FinalSpeed 客户端 + FinalSpeed 是双边加速,所以客户端这边也需要一个 FinalSpeed 客户端配合使用。[下载地址](https://raw.githubusercontent.com/RangiLyu/finalspeed/master/finalspeed_install1.0.exe) 下载下来安装就行,它需要使用 winpcap 如果没有安装会提示你安装的根据需要选择是否开机自启 winpcap ,剩下的一路 next 完成就行了。 + +3. 配置 FinalSpeed 客户端 + 1. 在地址栏填上服务器的 IP 地址、设置带宽设置你服务器的带宽,因为测试过我的下载大概能到3000多Kb/s,所以我这里设置的下行带宽30M,上行带宽20M(瞎设的)。 + 2. 点击右下的添加按钮,弹出的增加映射窗口。在名称编辑框填入你想要的描述、加速端口填你安装 SSR 时候写的端口、本地端口随便填一个,这个是用来和你的 SSR 客户端进行通信用的。填写完成自动生效的,关闭窗口就OK了。 +![FinalSpeed配置](http://begild-one.top/FinalSpeed%E8%AE%BE%E7%BD%AE%E7%95%8C%E9%9D%A2.png) + 3. 配置 SSR 客户端,经过上面 SSR 的导入和配置已经可以成功 Google了。 + 1.双击任务栏小飞机图标唤出配置窗口,点击左下角的`添加`按钮可以复制一份一刚刚导入的服务器配置信息。 + 2. 在右边的配置栏服务器IP这里勾选显示并改为`127.0.0.1` 也就是本地回环地址。 + 3. 服务器端口填写为你刚刚配置 FinalSpeed 的本地端口(这里 FinalSpeed 相当于是 SSR 的服务器)。 + 4. 其他的重要信息不要改,备注和群组改一些方便识别。 + 4. 这样就完成了 FinalSpeed 和 SSR 的联合配置,上网感觉可能不明显。但是看视频什么的就能看出差距了。没装 FinalSpeed 只能看 480P 装了之后,1080P 无压力。 + +## SSR 客户端的使用 +SSR 客户端任务栏图标右键包含了整个软件的设置。 +1. 右键-->选项设置-->右上角可以设置开机启动。 +2. 右键-->系统代理模式 选择各种不同的代理模式,IE代理,直连,PAC和全局,PAC指的是根据 PAC 列表选择是否通过 SSR 访问。全局就是所有访问均通过 SSR。我们选择 PAC 模式配合 PAC 文件进行使用。全局的话流量较高并且国内的访问用代理反而更慢。 +3. 右键-->PAC 可以看到PAC的各种配置,这里给一个 PAC 文件的URL [https://softs.fun/Other/pac.txt](https://softs.fun/Other/pac.txt) 点击 PAC 的配置里编辑本地 PAC 文件,将上述网页里的内容全选拷贝到改文件里覆盖保存即可。 +4. 右键-->代理规则 使用绕过局域网和大陆。整个过程首先通过域名和 PAC 列表里匹配是否需要 SS R,如果需要 SSR 的话再通过代理规则判断该 IP 是否需要代理,如果需要的话服务器最终进行代理。 +5. 右键-->服务器 选择你要的服务器。按照群组和备注来区分 默认是empty-group。该设置自动保存,下次打开自动使用。 +6. 其他的自己琢磨吧。可以看下[这个](https://doub.io/ss-jc10/) + +## 相关的一些指令 +``` +SSR 配置 vi /etc/shadowsocks-r/config.json(修改后需要重启SS) +SSR 重启 /etc/init.d/shadowsocks-r restart +SSR 状态 /etc/init.d/shadowsocks-r status +SSR 卸载 ./shadowsocks-all.sh uninstall +锐速 状态 service serverSpeeder status +锐速 流量速度 service serverSpeeder stats +锐速 卸载 chattr -i /serverspeeder/etc/apx* && /serverspeeder/bin/serverSpeeder.sh uninstall -f +Finalspeed 启动 /etc/init.d/finalspeed start +Finalspeed 停止 /etc/init.d/finalspeed stop +Finalspeed 状态 /etc/init.d/finalspeed status +Finalspeed 卸载 bash install_fs.sh uninstall +``` +如果遇到 锐速的状态查看 提示 "bc not found" 执行 `apt-get install bc` 即可。 + +## 写在后面 +![天安门](http://begild-one.top/天安门.png) diff --git a/_posts/Linux-Subsystem-Gui.md b/_posts/Linux-Subsystem-Gui.md new file mode 100644 index 0000000..5e1e20e --- /dev/null +++ b/_posts/Linux-Subsystem-Gui.md @@ -0,0 +1,54 @@ +--- +title: Linux子系统图形界面 +tags: + - Linux子系统图形界面 +categories: + - linux +comments: true +images: 'http://begild-one.top/Ubuntu%E6%A1%8C%E9%9D%A2.png' +abbrlink: 858a9730 +date: 2018-04-19 20:00:01 +--- +搞完Windows下Linux下子系统的启用,可以用命令行进行使用但是却是一个完全没有界面的系统。这样怎么能拼过虚拟机呢对吧。所以:图形界面启动!。 + +## Windows X Server +1. 下载 VcXsrv [https://sourceforge.net/projects/vcxsrv/files/latest/download](https://sourceforge.net/projects/vcxsrv/files/latest/download) 用迅雷下会快一些👀。 +2. 运行下载下来的 VcXsrv 安装程序,安装位置自己选,开心就好。 +3. 安装完成之后会有两个软件启动方式,选择用 XLaunch 启动,在启动界面选择 One large windows 方式,显示器编号:0,接下来一路 Next 到完成结束。然后会出现一个黑黑的界面。 +![XLunch启动设置](http://begild-one.top/XLunch%E5%90%AF%E5%8A%A8%E8%AE%BE%E7%BD%AE.png) + +## Ubuntu的桌面软件安装 +1. 安装 Ubuntu 桌面软件,unity,compiz配置软件,下载的软件很大。大概需要2.5个G的空间,耐心等待(我大概用了15分钟左右才装好)。 +``` +sudo apt-get install ubuntu-desktop unity compizconfig-settings-manager +``` + +## Ubuntu的桌面的配置 +1. 设置显示器 ; +``` +export DISPLAY=localhost:0 +``` +2. 设置桌面参数,勾选了Ubuntu Unity Plugin 和 Window Management 下的 Place Window选项,其他的根据自己需要修改。设置完毕之后关闭即可; +``` +ccsm +``` +![ccsm设置](http://begild-one.top/ccsm%E8%AE%BE%E7%BD%AE.png) + +3. 展示桌面,运行下面指令。就可以在上面说的黑黑的界面上绘出桌面了。看起来是不是毫无违和感23333。 +``` +compiz +``` + ![Ubuntu桌面](http://begild-one.top/Ubuntu%E6%A1%8C%E9%9D%A2.png) +4. 做一个脚本便于设置和启动桌面。新建一个脚本放在根目录 `cd / && sudo vi vcxsrv.sh` 将下面的代码粘贴到 vcxsrv.sh 里,再赋予执行权限 `chmod +x vcxsrv.sh` 。每次先用控制台进入 bash 运行脚本就OK了。 +``` +#! /bin/sh +export DISPLAY=localhost:0 #设置显示屏 +compiz +``` + +## 内存占用 +经过实测,8G内存,即使开启图形界面之后内存占用提升仅仅接近500M(31%-->37%),对比虚拟机(起码分配2G内存)少的就不止一点半点了好吧。确实是指的鼓捣的东西。 + +## 已知的一些问题 +1. 键盘的上下左右键值会被识别为数字8246,并且很鬼畜的识别为长按🤕,猜测原因:系统默认不开启数字键盘,导致识别错误但是识别为长按是什么鬼嘛。这一点很蛋疼。 +2. 刚启动桌面,桌面鼠标不可见或者会变成 × 号,解决办法:打开一个应用程序(非终端)后正常。 diff --git a/_posts/STM32-Flash-Write-Read.md b/_posts/STM32-Flash-Write-Read.md new file mode 100644 index 0000000..0046ca5 --- /dev/null +++ b/_posts/STM32-Flash-Write-Read.md @@ -0,0 +1,231 @@ +--- +title: STM32 Flash的读写 +tags: + - Flash读写 +categories: + - STM32 +comments: true +abbrlink: 31184d7e +date: 2018-03-07 23:26:39 +images: +--- +这里记一下STM32F4板子FLASH的读写操作以及需要注意的地方。 +## FLASH的写操作 +1. FLASH由 ‘1’ 变为 ‘0’ 不能由 ‘0’ 变为 ‘1’ ,所以在写入之间需要检测是否为 ‘1' ,并且擦除flash只能按照一个扇区来删除,由上可知,我们写入之前必须确保我们需要写入的地址读回来的值是0XFF,如果不是0XFF就需要将整个扇区擦除(扇区变为全 ‘1’ )。 +2. 写入操作(包括擦除)之前需要将FLASH解锁 `FLASH_Unlock()`,操作完成之后需要将FLASH上锁 `FLASH_Lock()` 。 + + +## [ 正点原子](http://www.alientek.com/)的例子 +- 写入流程: + - 解锁FLASH `FLASH_Unlock()`; + - 禁止数据缓存`FLASH_DataCacheCmd(DISABLE)`,根据你传入的起始地址 `WriteAddr` 和写入的字节数 `NumToWrite` 计算出结束地址 `endaddr`; + - 遍历整个写入范围,一旦发现非 ’1‘ 数据的出现就擦除整个扇区,他这里是字(Word)来检测的,所以地址 `addrx` 每次加4; + - 检测完毕并且擦除之后,进入写操作,每次写入一个字(4byte)的数据。所以 `WriteAddr` 每次加4, `u32 *pBuffer` 每次加1 ; + - 使能数据缓存`FLASH_DataCacheCmd(ENABLE)`,上锁FLASH `FLASH_Lock()`。 + +```c +//从指定地址开始写入指定长度的数据 +//特别注意:因为STM32F4的扇区实在太大,没办法本地保存扇区数据,所以本函数 +// 写地址如果非0XFF,那么会先擦除整个扇区且不保存扇区数据.所以 +// 写非0XFF的地址,将导致整个扇区数据丢失.建议写之前确保扇区里 +// 没有重要数据,最好是整个扇区先擦除了,然后慢慢往后写. +//该函数对OTP区域也有效!可以用来写OTP区! +//OTP区域地址范围:0X1FFF7800~0X1FFF7A0F +//WriteAddr:起始地址(此地址必须为4的倍数!!) +//pBuffer:数据指针 +//NumToWrite:字(32位)数(就是要写入的32位数据的个数.) +void STMFLASH_Write(u32 WriteAddr, u32 *pBuffer, u32 NumToWrite) +{ + FLASH_Status status = FLASH_COMPLETE; + u32 addrx = 0; + u32 endaddr = 0; + if(WriteAddr < STM32_FLASH_BASE || WriteAddr % 4)return; //非法地址 + FLASH_Unlock(); //解锁 + FLASH_DataCacheCmd(DISABLE);//FLASH擦除期间,必须禁止数据缓存 + + addrx = WriteAddr; //写入的起始地址 + endaddr = WriteAddr + NumToWrite * 4; //写入的结束地址 + if(addrx < 0X1FFF0000) //只有主存储区,才需要执行擦除操作!! + { + while(addrx < endaddr) //扫清一切障碍.(对非FFFFFFFF的地方,先擦除) + { + if(STMFLASH_ReadWord(addrx) != 0XFFFFFFFF) //有非0XFFFFFFFF的地方,要擦除这个扇区 + { + status = FLASH_EraseSector(STMFLASH_GetFlashSector(addrx), VoltageRange_3); //VCC=2.7~3.6V之间!! + if(status != FLASH_COMPLETE)break; //发生错误了 + } + else addrx += 4; + } + } + if(status == FLASH_COMPLETE) + { + while(WriteAddr < endaddr) //写数据 + { + if(FLASH_ProgramWord(WriteAddr, *pBuffer) != FLASH_COMPLETE) //写入数据 + { + break; //写入异常 + } + WriteAddr += 4; + pBuffer++; + } + } + FLASH_DataCacheCmd(ENABLE); //FLASH擦除结束,开启数据缓存 + FLASH_Lock();//上锁 +} +``` + +- 测试和分析 + 经过实验,擦除扇区的时间是很久的,擦除128KByte的扇区大概需要1s多。并且,不解锁虽然可以通过擦除函数并且返回 `FLASH_COMPLETE` 但是实际并没有擦除成功。我开始以为他这个耗时主要体现在读和判断,擦除操作比较快,😒但其实读120KByte的数据只需要3.9ms加上判断的时间也没多少主要的时间耗费在擦除操作上。😆另一个体现就是如果在 Keil 的工程选项里把擦除全部flash勾选,下载前的擦除的时间是很长的。下面是测试代码和解释结果。测试结果可以看出,擦除的时间并没有很大变化,因为都是需要一次性操作一个扇区,只要不超过一个扇区的长度都不会变化很大。写入和读出的时间保持线性变化。所有的测试都是用原子官方例程按照WORD(32bit)来写入的。 + +```c +int main(void) +{ +...上续代码 + STMFLASH_Write(FLASH_SAVE_ADDR, (u32 *)&txbuf, SIZE);//写入一些数据保证flash不全为'1' + uprintf(USART1, "扇区预先不为全 '1'时写入:\r\n"); + uprintf(USART1, "写入长度:%d\r\n", TEXT_LENTH); + //原子的例子擦除flash再写入数据 + STMFLASH_Write(FLASH_SAVE_ADDR, (u32 *)&txbuf, SIZE); + memset(readbuf,0,TEXT_LENTH);//清空数据读取 + StartTiming(); + STMFLASH_Read(FLASH_SAVE_ADDR, (u32 *)&readbuf, SIZE); + timems = GetTimeMs(); + uprintf(USART1, "读出耗时:%.3fms\r\n", timems); + uprintf(USART1, "读出长度:%d\r\n----\r\n", TEXT_LENTH, strlen((const char *)readbuf)); +...下续代码 +} + +void STMFLASH_Write(u32 WriteAddr, u32 *pBuffer, u32 NumToWrite) +{ +...上续代码 + FLASH_DataCacheCmd(DISABLE);//FLASH擦除期间,必须禁止数据缓存 + StartTiming();//开始计时擦除扇区耗时 +.....上续代码 + timems = GetTimeMs(); + uprintf(USART1,"擦除扇区耗时 :%.3fms\r\n",timems); + StartTiming();//开始写入计时 + if(status == FLASH_COMPLETE) + { +...上续代码 + FLASH_Lock();//上锁 + timems = GetTimeMs();//获取写入耗时 + uprintf(USART1, "写入耗时:%.3fms\r\n", timems); +} +/*测试结果 测试120、12K、120K(Byte)的数据*/ +扇区预先不为全 '1'时写入: +写入长度:120 +擦除扇区耗时 :1046.720ms +写入耗时:0.440ms +读出耗时:0.020ms +读出长度:120 +---- +扇区预先不为全 '1'时写入: +写入长度:12288 +擦除扇区耗时 :1050.220ms +写入耗时:45.700ms +读出耗时:0.380ms +读出长度:12288 +---- +扇区预先不为全 '1'时写入: +写入长度:122880 +擦除扇区耗时 :1051.860ms +写入耗时:458.700ms +读出耗时:3.880ms +读出长度:122880 +---- +``` +## 改进擦除方式 +- 改进的一点想法 + 根据正点原子的测试结果来看,擦除扇区的时间是不可避免的,无非就是暴力一点不检测直接擦除(因为通常来说,如果你存储在固定的flash地址除了第一次之后都会有数据)。这样搞了之后从测试的结果来看提升并不明显。写120KByte的数据下擦除时间少了4ms左右😔(少了读取和判断的时间)。所以擦除的方式并没有很好的改进方法(标题党😈)。 + +## 通用性考虑 +- 通过正点原子的例子熟悉了Flash的读写,但是只支持4字节对齐(WORD)的操作,我看了一下库的函数是可以支持 BYTE,HALFWORD,WORD, 和 DOUBLEWORD 的,不过 DOUBLEWORD 需要外部Vpp。所以想改进一些支持库函数里的各种byte(1-4) 的操作。 +- 修改好之后测试一下测试代码和上面原版的差不多。只是写入函数换成了修改之后的`STMFLASH_WriteWithErase`,测试结果如下,测试的时候用的是WORD方式写入。和原子基本没有差别。 +```c +扇区预先不为全 '1'时写入: +写入长度:120 +擦除扇区耗时 :1043.500ms +写入耗时:0.460ms +读出耗时:0.000ms +读出长度:120 +---- +扇区预先不为全 '1'时写入: +写入长度:12288 +擦除扇区耗时 :1046.580ms +写入耗时:45.700ms +读出耗时:0.400ms +读出长度:12288 +---- +扇区预先不为全 '1'时写入: +写入长度:122880 +擦除扇区耗时 :1050.860ms +写入耗时:459.140ms +读出耗时:3.900ms +读出长度:122880 +---- +``` +## 其他ByteSize方式写入 +相对于用WORD来说用其他方式写入flash是要慢一些的。采用 BYTE 方式需要 大概`1832ms`,采用HALFWORD方式需要`920ms`左右。因为擦除都是采用的`VoltageRange_3`也就是WORD方式所以擦除时间差不多。 + +## 分离操作的方式 +- 分离操作的意义 + 把擦除和写入分开。考虑到一个扇区是非常大的,一个扇区可能会存储多种数据。如果写入之前有数据就会导致整个扇区被擦除,数据就会丢失。所以采用分离的办法,把数据的写入和擦除分隔开,根据需要选择是否擦除扇区内的数据,保证在擦除的操作之前有相应的备份操作就OK了。这样即使忘记擦除那么也只是新的数据没法正确写到flash里面,其他部分的数据就不会被擦除,这样有利于更好的数据完整性。 +- 测试结果和测试代码,经过测试分离之后的操作和没分离的时间上基本没什么差别, +```c +分离操作方式写入flash: +擦除扇区耗时:1023.320ms +写入长度:120 byte +写入耗时:0.440ms +读出耗时:0.000ms +读出长度:120 byte +**** +分离操作方式写入flash: +擦除扇区耗时:1015.140ms +写入长度:12288 byte +写入耗时:45.940ms +读出耗时:0.400ms +读出长度:12288 byte +**** +合并操作方式写入flash: +写入长度:122880 +擦除扇区耗时 :1010.480ms +写入耗时:461.420ms +读出耗时:3.900ms +读出长度:122880 +**** +int main(void) +{ +...上续代码 + uprintf(USART1, "分离操作方式写入flash:\r\n"); + StartTiming(); + status = StmEraseFlashSector(FLASH_SAVE_ADDR, TEXT_LENTH); + //FLASH_DataCacheCmd(DISABLE);//FLASH擦除期间,必须禁止数据缓存 + //status = FLASH_EraseSector(STMFLASH_GetFlashSector(FLASH_SAVE_ADDR), VoltageRange_3); //VCC=2.7~3.6V之间!! + if(status != FLASH_COMPLETE) + { + uprintf(USART1, "擦除扇区失败:%d\r\n",status); //发生错误了 + while(1) {}; + } + timems = GetTimeMs(); + uprintf(USART1, "擦除扇区耗时:%.3fms\r\n", timems); + uprintf(USART1, "写入长度:%d byte\r\n", TEXT_LENTH); + StartTiming(); + //不需要擦除falsh直接写数据 + STMFLASH_WriteNoErase(FLASH_SAVE_ADDR, txbuf,TEXT_LENTH,ByteSize); + timems = GetTimeMs(); + uprintf(USART1, "写入耗时:%.3fms\r\n", timems); + memset(readbuf,0,TEXT_LENTH);//清空数据读取 + StartTiming(); + STMFLASH_Read(FLASH_SAVE_ADDR,readbuf, TEXT_LENTH,ByteSize); + timems = GetTimeMs(); + uprintf(USART1, "读出耗时:%.3fms\r\n", timems); + uprintf(USART1, "读出长度:%d byte\r\n****\r\n", TEXT_LENTH, strlen((const char *)readbuf)); +} +``` +## 后记 +搞了几天才把这个写完整。中途也进了好多的坑,浪费了好长时间。不过还是写完了。说一点注意的地方 + - flash的写入地址不是偶数就可以,得是4的倍数。 + - 无论是擦除还是写入都需要先解锁flash。读取则不需要。 + - 对于同一个扇区的建议用分离的操作,并且在操作前根据需要把其他的数据读出来备份一下在写进去。 + +关于本文的代码详见于[Coding项目](https://coding.net/u/BycCoding/p/stm32f4_flash/git)。 \ No newline at end of file diff --git a/_posts/STM32-UART-CustomPrintf.md b/_posts/STM32-UART-CustomPrintf.md new file mode 100644 index 0000000..64c2d89 --- /dev/null +++ b/_posts/STM32-UART-CustomPrintf.md @@ -0,0 +1,103 @@ +--- +title: STM32自定义串口printf +tags: + - 串口(UART) +categories: + - STM32 +comments: true +abbrlink: a854db16 +date: 2018-03-01 20:29:34 +images: +--- + +## 前言 +硬件的调试通常可分为两大类,一种是用调试器将芯片和电脑连接通过单步等方式逐步运行进行调试,另一种就是printf大法在程序运行过程中输出调试信息。第一种比较深入,可以了解每一个变量,栈堆,函数等等的变化是比较系统化的调试。但我通常都是用printf来调试的,因为快速简单属于非介入的方式,调试完毕直接注释掉相关部分就行了。 +**** +## 重定向 printf 函数 +对于STM32来说现在串口例程一般都配有一个printf重定向到串口1的代码,直接可以使用printf很方便的输出信息到串口上。 +```c +//重定义fputc函数 +int fputc(int ch, FILE *f) +{ + while((USART1->SR&0X40)==0);//循环发送,直到发送完毕 + USART1->DR = (u8) ch; + return ch; +} +``` + +## 自定义printf函数 +但是我们如果使用多个串口或者说串口输出不一定总从串口1输出怎么办呢。这时候这样就没法实现,后来上网查一下我们可以自己实现printf这个函数。命名为uprintf,接收至少两个参数,第1个参数是串口号;第2个是格式化字符串;第3-n ' ... ' 是参数匹配列表, 实现变长的参数列表接收。。 +```c +//用串口写一个printf函数 +void uprintf(USART_TypeDef *USARTx, const char *fmt, ...) +{ + va_list ap; //typedef char *va_list; va_list是char型的指针 + char *s_string = malloc(300); //申请缓冲区 + va_start(ap, fmt); //找第一个可变形参的地址,并把地址赋给ap + vsprintf(s_string, fmt, ap); //类似sprintf函数 + USART_String(USARTx, s_string); //发送和整个字符串 + va_end(ap); //结束 + free(s_string); +} +``` +上面这个函数里的过程: +1. 通过 va_start 函数获得参数列表里每个项和格式化字符里对应的位置,形成一个列表 ap 。 +2. 通过 vsprintf 把列表里每个参数转为字符串写到 s_string 字符串里。 +3. 通过 USART_String 发送到串口。 +4. 释放列表 ap 和 发送缓冲 s_string 。 + +## 完整的一个自定义printf实现文件 +```c +#include "uart_x.h" +#include "stdlib.h" +#include "stdarg.h" +//发送一个字节 +void SendByte(USART_TypeDef *USARTx, unsigned char dat) +{ + while((USARTx->SR & 0X40) == 0) {}; //循环发送,直到发送完毕 + USARTx->DR = (u8) dat; +} +//发送一个字符串 +void USART_String(USART_TypeDef *USARTx, char *s) +{ + while(*s != '\0') // '\0' 表示字符串结束标志 + { + SendByte(USARTx, *s); + s++; + } +} +//用串口写一个printf函数 +void uprintf(USART_TypeDef *USARTx, const char *fmt, ...) +{ + va_list ap; //typedef char *va_list; va_list是char型的指针 + char *s_string = malloc(300); //申请空间 + va_start(ap, fmt); /找第一个可变形参的地址,并把地址赋给ap + vsprintf(s_string, fmt, ap); //类似sprintf函数 + USART_String(USARTx, s_string); //发送和整个字符串 + va_end(ap); //结束 + free(s_string); +} + +``` +上面的函数已经能满足多个串口同时使用printf,根据自己的需求可以修改申请的缓冲区大小即可。 + +## 安全版本的自定义 printf 实现 +但上面的实现并不是安全的,如果你发送的字符串长度大于缓冲区长度就会造成内存溢出。所以你可以更改为一个安全的版本,接收一个缓冲区长度参数从而申请一个合适大小的空间。 +```c +//用串口写一个printf函数 +void uprintf_s(USART_TypeDef *USARTx, uint32_t BuffSize,const char *fmt, ...) +{ + va_list ap; //typedef char *va_list; va_list是char型的指针 + char *s_string = malloc(BuffSize); //申请空间 + va_start(ap, fmt); //找第一个可变形参的地址,并把地址赋给ap + vsprintf_s(s_string,BuffSize, fmt, ap); //类似sprintf_s函数 + USART_String(USARTx, s_string); //发送和整个字符串 + va_end(ap); //结束 + free(s_string); +} +``` + +## 后记 +1. 使用 printf 大法非常方便,但是尽量避免在中断里调用该函数(执行 printf 需要的时间比较久),以及调试完毕之后注释掉相关的代码,缩短功能代码的执行时间。 +2. 有兴趣的可以写 printf 到 OLED 之类的函数,原理都是一样,实现屏幕位置控制和最后的写一个字节的函数就能完成移植。 + diff --git a/_posts/STM32-UART-IDLE-IT-md.md b/_posts/STM32-UART-IDLE-IT-md.md new file mode 100644 index 0000000..017493b --- /dev/null +++ b/_posts/STM32-UART-IDLE-IT-md.md @@ -0,0 +1,141 @@ +--- +title: SMT32串口接收、空闲中断 +tags: + - 串口(UART) +categories: + - STM32 +comments: true +abbrlink: 977ab4d9 +date: 2018-03-01 15:20:12 +images: +--- +## 识别尾进行接收结束的验证 +1. 串口接收完毕标志可以利用识别特定字符(字符串)来检测,比如 "\r\n"、'\*#' 之类的。所以每次发数据都需要加上这些字符才能被识别为接收完毕,这样好处就是比较通用。无论是什么硬件平台都能用。代码也不复杂,在STM32平台上简单的例子如下代码段:当接收到 '\*' 时候就会置位接收完成标志位,就可以进行处理了。 +``` C +#define MAXUSART1BUFSIZE 200 +uint8_t Uart1_BUF[MAXUSART1BUFSIZE]; +void USART1_IRQHandler(void) //串口1中断服务程序 +{ + uint8_t RecByte; + static uint32_t pos = 0; + if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) + { + RecByte = USART1->DR;//读取接收到的数据 + if(pos < MAXUSART1BUFSIZE)//防止内存溢出 + Uart1_BUF[pos++] = RecByte; + if(RecByte == '*') + { + //TODO: 接收完毕相关处理 + pos = 0; + } + } +} +``` + +## 识别头尾进行数据段的保护 +2. 上面的方法就是发送的时候麻烦一点,每次都需要在后面加 '\*', 并且如果发送错一次(忘记加 '*')就会把缓冲区的内容累计到下一次(可以添加头识别进行解决)。这样就只会识别指定的数据段。一般这样适用于发送带有意义的控制数据保证数据不多收也不少收。验证的字符要保证不会出现在内容里,或者用多个字符进行验证。 +```c +#define MAXUSART1BUFSIZE 200 +uint8_t Uart1_BUF[MAXUSART1BUFSIZE]; +void USART1_IRQHandler(void) //串口1中断服务程序 +{ + uint8_t RecByte; + static uint32_t pos = 0; + if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) //接收中断(接收到的数据必须是0x0d 0x0a结尾) + { + RecByte = USART1->DR;//读取接收到的数据 + if(RecByte == '#') + pos = 1; //开始接收数据 + if(pos) + { + if(pos < MAXUSART1BUFSIZE)//防止内存溢出 + Uart1_BUF[pos - 1] = RecByte; + pos ++; + if(RecByte == '*') + { + //TODO: 接收完毕相关处理 + pos = 0; + } + } + + } +} +``` +## STM32空闲中断的配置 +1. 前几天做项目也要用到串口传输控制信息在STM32上的话可以利用串口空闲中断(接收完字符以后在下一个传输字符的时间内没有字符传来)来接收数据,这样就不用像上面那样做特定的识别,也比较方便。在这里备注一下,因为当时一开始配置完了并不起作用,后来上网查证了最后才找到解决办法。初始化的代码就不贴了,主要是最后配置完毕,开中断的代码贴一下。 +```c +...上续初始化的相关配置 +USART_Init(USART1, &USART_InitStructure); //初始化串口 +USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//开启中断 +USART_ITConfig(USART1, USART_IT_IDLE,ENABLE);//开启中断 +//USART_ClearITPendingBit(USART1, USART_IT_IDLE |USART_IT_RXNE);//清除中断 +USART_Cmd(USART1, ENABLE); //使能串口 +``` +2. 一开始我使用的是下面这条语句进行中断配置的,发现并不能触发空闲中断,后来才知道必须要分两次才能正确配置: +```c +USART_ITConfig(USART1, USART_IT_RXNE | USART_IT_IDLE, ENABLE);//开启中断 +``` +3. 查看了一下USART_ITConfig()函数的源码才看出来,他这个函数为了USART_IT_IDLE等中断宏定义的通用性,必须每次只能初始化一个中断标志。 +```c +void USART_ITConfig(USART_TypeDef *USARTx, uint16_t USART_IT, FunctionalState NewState) +{ +.... + /* Get the interrupt position */ + itpos = USART_IT & IT_Mask; + itmask = (((uint32_t)0x01) << itpos); +.... +} +/*相关计算 +#define USART_IT_IDLE ((uint16_t)0x0424) +#define IT_Mask ((uint16_t)0x001F) //!< USART Interrupt Mask +itpos = 0x0424 & 0x001F = 0x04; +itmask = (((uint32_t)0x01) << itpos) = 0x10; +0x10 = 0b00010000//bit[4]; +查阅官方的手册可以看到空闲中断使能也恰好就是bit[4]; +*/ +``` +4. 究其原因是因为itmask这个变量其实就是中断位于寄存器的位置,他是一个0bxx1xx的变量。只能表示一个中断标志位所以每次只能初始化一个标志位。 + +## STM32空闲中断服务函数 +1. 接下来就是中断服务函数了: +```c +uint8_t USART1RecBuf[USART1RecBufMaxSize];//接收缓冲区 +uint8_t sdfsdf = 0; +void USART1_IRQHandler(void) //串口1中断服务程序 +{ + static uint16_t pos = 0; + if(USART_GetITStatus(USART1, USART_IT_IDLE) != RESET) //接收完毕触发空闲中断 + { + pos = 0; + USART1->DR;//清除空闲中断标志位 + //TODO: 中断接收完成标志 + + } + if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) + { + uint8_t RecByte; + Res = USART1->DR; //读取接收到的数据 + if(pos >= USART1RecBufMaxSize) //超过范围返回 + return ; + USART1RecBuf[pos++] = RecByte; + } +} +``` +2. 这里需要注意的就是空闲中断的清除并不是调用USART_ClearITPendingBit()函数来清除,查看库的函数源码实现也可以看到注释里并没有说明 USART_IT_IDLE 该参数是可以被传入的,并且我们使用 USART1->DR 就能清除串口空闲中断。 +```c +/** +... + * @param USART_IT: specifies the interrupt pending bit to clear. + * This parameter can be one of the following values: + * @arg USART_IT_CTS: CTS change interrupt (not available for UART4 and UART5) + * @arg USART_IT_LBD: LIN Break detection interrupt + * @arg USART_IT_TC: Transmission complete interrupt. + * @arg USART_IT_RXNE: Receive Data register not empty interrupt. +... + */ +void USART_ClearITPendingBit(USART_TypeDef *USARTx, uint16_t USART_IT) +{ +···· + +``` +3. 到此完成了串口空闲中断的配置,之后只要两次接收数据之间的时间大于一个字符的时间(跟波特率有关),就能触发这个中断。 \ No newline at end of file diff --git a/_posts/Win10-Linux-Subsystems.md b/_posts/Win10-Linux-Subsystems.md new file mode 100644 index 0000000..dcb4078 --- /dev/null +++ b/_posts/Win10-Linux-Subsystems.md @@ -0,0 +1,120 @@ +--- +title: Win10下Linux子系统的启用 +tags: + - Win10下linux子系统 +categories: + - linux +comments: true +images: >- + http://begild-one.top/windows%E6%94%AF%E6%8C%81%E7%9A%84linux%E5%AD%90%E7%B3%BB%E7%BB%9F.png +abbrlink: 40bf05cc +date: 2018-04-19 12:19:13 +--- +##### 微软在win10系统上添加了Linux子系统的支持,方便我们可以在windows上使用Linux,省去了占内存的虚拟机和双系统切换的麻烦😎,具体有什么和普通安装的Linux有什么不同,抱歉...不知道😬。 + +## Linux子系统的获取 +- 在 '控制面板-->程序和功能(侧边栏)-->启用或关闭 Windows 功能-->勾选适用于 Linux 的 Windows 子系统选项'。这样就成功使能 Linux 子系统的功能。(需要重启生效更新,请保存你的Word文档☠️...)我看到网上的教程说明需要选中 '设置-->更新和安全-->针对开发人员-->开发人员模式' 但我的选项是 '旁加载应用' 也成功操作。 +- Linux子系统的获取可以用微软的应用商店进行安装。如下图是支持的子系统种类(2018.04.19),我选择了Ubuntu 要使用其他系统的也看看,以后会支持更多的系统~ ~。 +![windows支持的linux子系统](http://begild-one.top/windows%E6%94%AF%E6%8C%81%E7%9A%84linux%E5%AD%90%E7%B3%BB%E7%BB%9F.png) +- 就像装其他软件一样点击安装就会自动下载了。下载挺快的还📢,安装完毕之后就会显示启动这时候系统未被写入到磁盘里的。 +![下载ubuntu](http://begild-one.top/%E4%B8%8B%E8%BD%BDubuntu.png) +- 这样获取 Windows 下Linux子系统就完成了。点击启动会打开CMD运行然后将系统写入磁盘,所需时间并不长(SSD少于1分钟)长时间卡住尝试回车一下请求响应刷新界面。写入完毕会让你输入一个用户名(自定义哦不必须是 Windows 的用户名)和密码(不可见)。输入完毕就创建了一个用户,之后默认就是这个账户登录进系统。这个用户不具备管理员权限,如果你要默认使用管理员用户,那就直接关闭这个 CMD,就跳过这一步了。之后再打开就直接以 root 用户登录。 +```bash +Installing, this may take a few minutes... +Installation successful! +Please create a default UNIX user account. The username does not need to match your Windows username. +For more information visit: https://aka.ms/wslusers +Enter new UNIX username: begild +Enter new UNIX password: +Retype new UNIX password: +passwd: password updated successfully +Default UNIX user set to: begild +To run a command as administrator (user "root"), use "sudo ". + +begild@BeGild-PC:~$ +``` + +## Linux 子系统的位置 +- Linux子系统位于(Users == 用户 👎): + `C:\Users\用户名\AppData\Local\Packages\含有Linux子系统名字的文件夹\LocalState\rootfs` +- 我使用的账户是 Administrator 装的是 Ubuntu 那么位置就是: + `C:\Users\Administrator\AppData\Local\Packages\CanonicalGroupLimited.UbuntuonWindows_79rhkp1fndgsc\LocalState\rootfs` +- 其他的系统和这个差不多,在 Packages 目录下找一下含有你安装的 Linux 子系统名字的文件夹就能找到。 + +## Linux子系统位置的迁移 +因为linux子系统的位置式位于C盘的文件夹下面的,时间长了的话会产生大量的数据,C盘本来就装了Windows,现在加了一个Linux,两个系统的使用会导致C盘加速被塞满。所以,把C盘迁移到其他的数据盘是一个比较好的选择。当然你的C盘足够大任性选择也OK。 +```bat +robocopy "子系统所有数据所在的位置" "迁移的目的地址" /E /COPYALL /XJ +rmdir "子系统所有数据所在的位置" /S /Q +mklink /J "子系统所有数据所在的位置" "迁移的目的地址" +``` +我的子系统所有数据所在的位置是 +`C:\Users\Administrator\AppData\Local\Packages\CanonicalGroupLimited.UbuntuonWindows_79rhkp1fndgsc` +迁移的目的地址是 `D:\WSL` +所以代码就是 +```bat +robocopy "C:\Users\Administrator\AppData\Local\Packages\CanonicalGroupLimited.UbuntuonWindows_79rhkp1fndgsc" "D:\WSL" /E /COPYALL /XJ +rmdir "C:\Users\Administrator\AppData\Local\Packages\CanonicalGroupLimited.UbuntuonWindows_79rhkp1fndgsc" /S /Q +mklink /J "C:\Users\Administrator\AppData\Local\Packages\CanonicalGroupLimited.UbuntuonWindows_79rhkp1fndgsc" "D:\WSL" +``` +如果删除子系统数据目录的步骤(rmdir) 遇到不是空目录无法删除,重启电脑之后再执行就OK了。 +执行上面的东西用 cmder 使用 ls 命令可以看到已经建立一个符号链接到目标目录了。这样就把东西全部迁移到 D:\WSL 里去。 +```bash +C:\Users\Administrator\AppData\Local\Packages +ღ ls -l CanonicalGroupLimited.UbuntuonWindows_79rhkp1fndgsc +lrwxrwxrwx 1 Administrator 197121 6 4月 22 14:10 CanonicalGroupLimited.UbuntuonWindows_79rhkp1fndgsc -> /d/WSL/ +``` +## Linux子系统的打开 +1. 任意打开一个CMD窗口输入`bash` 启动一个Linux终端; +2. 将 Ubuntu 固定到开始菜单磁贴,每次点击都能打开一个新的Linux终端窗口。 + +## Linux子系统的一些信息 +1. 使用` lsb_release -a` 可以看到系统的信息安装的是16.04.3长期支持版本 +2. `cat /proc/version` 可以看到内核版本 4.4.0-43-Microsoft;编译器GCC版本5.4.0 +```bash + root@BeGild-PC:~# lsb_release -a + No LSB modules are available. + Distributor ID: Ubuntu + Description: Ubuntu 16.04.3 LTS + Release: 16.04 + Codename: xenial + root@BeGild-PC:~# uname -r + 4.4.0-43-Microsoft + root@BeGild-PC:~# cat /proc/version + Linux version 4.4.0-43-Microsoft (Microsoft@Microsoft.com) (gcc version 5.4.0 (GCC) ) #1-Microsoft Wed Dec 31 14:42:53 PST 2014 +``` + +## 换软件源 +emmm,将软件源换为国内源,这样更新和下载软件都会比较快一点。 +1. 备份软件源列表: +```bash +# mv /etc/apt/sources.list /etc/apt/sources.list.bak +``` +2. 编辑软件源。 +```bash +# vi /etc/apt/sources.list +``` +3. 替换为国内源(我选[清华大学源](https://mirrors.tuna.tsinghua.edu.cn/help/ubuntu/),可以去看看阿里源什么的)。 +```bash +# 默认注释了源码镜像以提高 apt update 速度,如有需要可自行取消注释 +deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ xenial main restricted universe multiverse +# deb-src https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ xenial main restricted universe multiverse +deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ xenial-updates main restricted universe multiverse +# deb-src https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ xenial-updates main restricted universe multiverse +deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ xenial-backports main restricted universe multiverse +# deb-src https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ xenial-backports main restricted universe multiverse +deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ xenial-security main restricted universe multiverse +# deb-src https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ xenial-security main restricted universe multiverse + +# 预发布软件源,不建议启用 +# deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ xenial-proposed main restricted universe multiverse +# deb-src https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ xenial-proposed main restricted universe multiverse +``` +4. 更新软件列表 +```bash +# apt-get update +``` +5. 更新软件,第一次会下载比较多的更新耐心等待。 +```bash +# apt-get upgrade +``` diff --git a/_posts/file system.md b/_posts/file system.md new file mode 100644 index 0000000..083af19 --- /dev/null +++ b/_posts/file system.md @@ -0,0 +1,75 @@ +--- +title: Linux系统目录讲解 +tags: + - linux目录 +categories: + - linux +abbrlink: 888300cc +date: 2017-12-06 20:45:30 +--- + +--- +## /bin 目录 +- 全称:Binary(Binaries) +- 作用:存放二进制可执行文件,例如命令行的cp命令。 +- 备注:/bin下的命令是所有用户都可以执行的。/sbin(Spuer Binary)目录下的命令只有超级用户权限才能执行,比如分区操作。 +--- +## /boot 目录 +- 全称 :Boot +- 作用 :存放操作系统的引导启动需要的文件。一般100M左右(50~200)。 +- 备注 :里面存放的vmlinuz...文件就是操作系统的内核文件,他名字就是版本号。通过bash运行 uname -r + 可以看到系统的版本。grub引导同样在/boot下。 +--- +## /dev 目录 +- 全称 :Device +- 作用 :把计算机的硬件抽象为文件存储在/dev下面。诸如硬盘(hd×),处理器(cpu),网卡(net),usb等等。 +--- +## /etc 目录 +- 全称 :Etcetera(其他)/Editable Text Configuration(可编辑配置文本) +- 作用 :保存几乎所有的配置文件,系统的各个服务、组件、软件的配置文件存放地方,一般以.cnf或.conf结尾(configure)。 +--- +## /home 目录 +- 全称 :Home +- 作用 :存放除root用户之外所有用户的'家目录'的目录。 + - 也就是每一个用户都会在/home下有一个对应用户名的目录,用于存放该用户的私有数据。比如系统里有一个begild用户,那么/home下必有一个Beild文件夹。/home/begild下存放自己的桌面、文档等。 +--- +## /lib 目录 +- 全称 :Library(Libraries) +- 作用 :linux系统运行需要的共享库文件,相当于windows的.DLl文件(动态链接库)。一般以 .so (shared object)结尾。 +- 备注:同样的还有/lib32、/lib64两个文件夹,作用和/lib相同,只是运用于32位还是64位。 +--- +## /lost+found 目录 +- 全称 :lost+found +- 作用 :用于存放系统发生错误的时候遗失的文件。 +- 备注 :只有root权限才能访问 +--- +## /mnt 目录 +- 全称 :Mount(挂载) +- 作用 :其他文件系统挂载的挂载点。使用mount命令挂载(手动挂载)。 +- 备注 :具备同样作用的还有/media目录,不过media目录一般用于实现自动挂载。 +--- +## /opt 目录 +- 全称 :Optional application software packages(可选的应用程序) +- 作用 :存放第三方、大型、版权保护的软件、游戏。 +- 备注 :安装到/opt目录下的程序,它所有的数据、库文件等等都是放在同个目录下面。 +--- +## /proc 目录 +- 全称 : +- 作用 :存放进程信息,内核信息,内存使用等等快速变化的'文件'的目录。 +- 备注 :它本身不存在于实际的文件系统里。他是一种虚拟的文件系统。例如我们通过cat /proc/cpuinfo命令可以打开cpuinfo文件。里面完整的描述了cpu的信息。 +--- +## /root 目录 +- 全称 :Root +- 作用 :root用户的家目录,其他的用户家目录位于/home下。 +--- +## /tmp 目录 +- 全称 :temp +- 作用 :存放系统的临时文件,例如压缩文件预览.关机会自动清理,手动清理用tmpwatch命令. +--- +## /usr 目录 +- 全称 :unix software resource +- 作用 :软件安装的目录. +--- +## /var 目录 +- 全称 :variable +- 作用 :存放系统/软件运行过程中产生的缓存,登录日志等等文件. diff --git a/_posts/一种分层高扩展性通信协议的总结.md b/_posts/一种分层高扩展性通信协议的总结.md new file mode 100644 index 0000000..5ef67d9 --- /dev/null +++ b/_posts/一种分层高扩展性通信协议的总结.md @@ -0,0 +1,85 @@ +--- +title: 一种分层、高扩展性通信协议的总结 +tags: + - 分层、高扩展通信协议 + - 串口(UART) +categories: + - 通信协议 +comments: true +abbrlink: cc12b1fd +date: 2018-07-22 09:59:34 +images: +--- +## 渊源 +大概因为自己专业是通信工程,所以一直以来对通信都还是很有兴趣的,通信协议的作用就是让通信的双方明确知道通信实体的意义。通信协议的范畴太大了,从最底层的硬件之间接口的协议到最上层的应用层的协议无一不是为了传输数据所做的工作 + +## 硬件的接口协议 + +- 硬件的接口协议主要是为了正确的传输数据的逻辑0和1,在不同的物理实体接口中通过不同的电平标准,不同的时序,不同的物理线数来完成整个工作。平时接触到最多的IIC、SPI、UART、USB他们都有着自己一套物理层的通信接口不过线数和时序比较简单,除此之外,SATA接口,RJ45网口,HDMI接口等也有自己的一套物理层的接口协议他们的接口线数和时序通常都比较复杂。如果你不按照物理层的接口协议来传输数据那么对方连获取正确数据的能力都不具备。 +- 当两种不同的接口间相互兼容时就需要转换器,这个转换器其实就是具备两种硬件接口协议的设备,将一种接口的数据正确接收回来转化为另外一种接口可以识别的物理电平数据然后通过时序和接口线发送出去。当然有些时候是需要进行取舍或填补的,像VGA和HDMI,他们都属于传输视频的接口,但是VGA并不具备传输音频的能力所以HDMI转VGA必然会丢失音频的数据,同时因为VGA传输的是模拟的数据当转为HDMI时必然会丢失细节数据。 +- 硬件的接口协议类比于声带和耳朵,声带发声,耳朵收听声音。声音可通过空气传播,空气就是物理线,声带和耳朵就是一套收发的物理设备,他们之间的通信通过声带震动空气发射,耳朵通过耳膜接收震动进行获取。 + +## 上层的通信协议 + +- 完成了硬件的接口协议就能正确的传输你想要发送的数据了对方也能正确的接收到你的数据,相当于你拥有一个完好的耳朵,能接收到各种符合人耳能听到的声音了(超声波次声波听不到). +- 此时你还是语言不通!因为在你眼里都是声音但是你无法知道对面所说的是什么意思,这时候你就需要一个学习的过程,学习对方的语言。这个语言其实就是规定了各种发音的组合构成的意义也就是"通信协议",我们只有知道每个发音以及构成的意义才能正确了解对方所说的含义. + +## 前言 + +促使本文产生的源头就是入职这段时间里负责的一个测试工具的开发中所用到的通信协议,因为之前自己也做过一些通信协议不过感觉看了项目组里大佬给的这个协议以及思想感觉很受用,所以在这里记录一下。这里说的是(串口)UART为通信硬件载体进行说明. + +## 自己做过的一些协议 + +- 之前自己在本科期间做过的一些项目也需要根据传输的东西制定一些通信协议,不过都比较简单考虑的点也没有那么多,有基于16进制传输的也有基于字符串传输的16进制传输的基本就是为了机器更好识别,解析效率也会高很多。字符串为载体的传输就是为了更好的观察,更加容易分析16进制的传输比如SDH,网络音视频流等;字符串传输比如JSON,HTTP包。 +- 一个简16进制传输的控制协议,16进制传输,通过解析头尾提取出帧,但是没有差错校验。这可以当成一个数组然后分析每一部分就可以进行解析了,因为实现的功能比较简单所以也用不着很复杂。这种方式在不易调试但是数据量小并且解析较快。 + +|帧头|受控设备类型| 受控设备编号| 网关设备识别号| 命令/数据| 帧尾 | +| :---: | :---: | :---: | :---: | :---: | :---: | :---: | +|0XAA |设备属性|网关分配| 网关| 控制和交互|0X55| +|8bit |8bit| 8bit| 16bit| 8bit| 8bit| + + - 一个简单的字符串传输的控制协议示例,用于控制指示灯的状态,诸如充电,语音交互等模式。采用JSON为载体,方便调试和查看,但是解析效率较16进制传输低。 + ![JSON载体通信协议实例](http://begild-one.top/%E4%B8%80%E7%A7%8D%E5%88%86%E5%B1%82%E9%AB%98%E6%89%A9%E5%B1%95%E6%80%A7%E9%80%9A%E4%BF%A1%E5%8D%8F%E8%AE%AE%E7%9A%84%E6%80%BB%E7%BB%93/JSON%E5%8D%8F%E8%AE%AE%E5%AE%9E%E4%BE%8B.png) +- 其实自己做的时候也有考虑过兼容和扩展的问题,不过其实都没有很好的解决办法,因为最好的就是变长的数据传输可以任意扩展数据的大小和数据形式,但是依然没有能解决后续扩展协议和前期协议之间的潜在冲突。但是接下来的这个协议组织方式很好的解决了这个麻烦。读完下面这个协议你就会觉得之前我做的,多捞哦。 + +## 分层、高扩展协议 + +- 分层:分层的思想类比于计算机网络分层,不同的层次负责不同的功能。不过这里没有那么复杂只是思想上一致,那就是将以协议帧分为不同的层次,便于数据的控制和分析。所有的数据都按1字节对齐 。 +1. 顶级:控制传输层,基本包括,帧识别头、帧校验(CRC)、命令码、操作码、数据段长度、数据段载体。根据需要可以增加目的地址,源地址,返回码,消息码等用作透传和反馈的字段。其展现结构示例为: + ```c + struct{ + type Head; //帧识别头,用于标识帧的开始 + type CRC; //CRC校验,用于验证帧的完整性 + type Cmd; //命令码,用于标识帧的类型或者帧的作用 +// type MsgID; //消息码,用于标识本通信协议帧的识别码。 + type Operat; //操作码,用于标识帧的一些使用操作,比如是否是需要接收方进行响应。 +// type SrcAddr; //源地址,用于存储发送方的识别号,因为可能存在多个设备进行数据交互。 +// type DstAddr; //目的地址,用于存储接收方的识别号,因为可能需要中间设备进行透传。 +// type Ret; //返回码,用于反馈接收方的处理结果是否成功或者错误码。 + type Reserve; //预留 + type Datalen; //数据段的长度,用于进行数据段的准确读取。 + type Data[1]; //数据段的载体,这里只标识数据段的第一个字节使其内存连续,可连续读取数据。 +}; + ``` + 2. 二级:用于统计三级数据子包的个数,因为每个帧可能包含若干个数据包,所以需要一个统计本次数据包的总数,便于数据包的分包。这里是不需要增加数据长度字段的因为每个数据包的长度是不一定的,其展现结构示例为: + ```c + struct{ + type CellCnt; //数据细胞单元数量,用于统计三级数据细胞单元的个数 + type Data[1]; //数据段的载体,这里只标识数据段的第一个字节使其内存连续,可连续读取数据。 +}; + ``` + 3. 三级:在该层级用于存储每个数据细胞单元的实体,包括一个数据包意义字段,一个数据长度字段,一个数据载体字段构成。这里是必须要使用数据长度字段的,因为每个数据包的长度是不定长的但是在内存里是连续的,如果没有该字段将无法进行下一个数据包的准确读取。其展现结构示例为: + ```c + struct{ + type CellCmd; //数据细胞单元的意义或命令,用于识别该数据包的具体意义,做相应具体的操作和处理。 + type Datalen; //数据段的长度,用于进行数据段的准确读取。 + type Data[1]; //数据段的载体,这里只标识数据段的第一个字节使其内存连续,可连续读取数据。 +}; + ``` +- 高扩展性 :因为分层之后每一个级别都有不同的作用,顶层和二层是不会变的,但是三层的数据结构是可以自由扩展并且不影响之前的已有的功能,可以根据需要增加四级五级等等,但是对于上层来说都是三级数据包都去按照 `CellCmd` 去识别是否是自己已有的,能处理的包,不能处理就丢弃,不会影响现有的功能。 + +## 抛砖引玉 +一开始读取这个协议的是否觉得晦涩难懂,明明就那么点功能还要大费周折,又是封装又是又是分层,解析的难度大大加大,直接用数组下标宏去解析不就OK了。 +后来搞通了,不得不说真的太有用了,无论你是多复杂的数据结构,按照这个来组包兼容性极强,并且代码阅读更加清晰。其传输采用16进制传输,找到帧头,强制类型转化为结构体指针,然后一层一层的剖析下去,扩展的数据包解析,就依次按照剥洋葱的方式层层递减。 +当然上面的这个只是一种思想,至于所有的数据的分层结构,体系都可以千变万化,比如二级的数据包个数就可以归在顶级里面从而取消二级结构。 +感谢安维大佬以及盛培大哥的代码、文档 diff --git a/_posts/多系统grub引导丢失修复.md b/_posts/多系统grub引导丢失修复.md new file mode 100644 index 0000000..05ffe8d --- /dev/null +++ b/_posts/多系统grub引导丢失修复.md @@ -0,0 +1,84 @@ +--- +title: 多系统GRUB引导丢失修复 +tags: + - grub +categories: + - Tools +comments: true +abbrlink: 6d520ba7 +date: 2018-05-10 12:27:11 +images: +--- + +## 前言(垃圾话) +这段话忽略不影响教程。本文主要记录一下我粗心大意之下造成的大出血事件。前几天做了一个给电脑供电的移动电源(???)听起来很奇怪但是这个需求确实发生了。emmmm 可能是我和电源有着不可理解的对立关系(成功在实验室造成了两次电池事故😪),因为要实际测试"充电宝"的续航和充电情况,所以我成功的献祭了我的电脑,我自认为已经检查了线路,接口,电压,保证电流不超过限额,但是我万万没有想到,极性搞错了。我TM🙃...把正负极搞反了接上去瞬间黑屏(完全不慌.jpg),所幸的是只是烧了笔记本的电源管理芯片,没有伤及无辜。送去电脑店,没有这种芯片,上淘宝买芯片发顺丰修修修,一来一去就是3天,期间只能勉强靠树莓派过过日子。但是修好了之后出现了新的问题,开不了机进不去系统,然后经过3个多小时的搜查改,终于修好了,所以在这里记录一下。 + +## 问题的具体描述 +这个问题的表现就是,开机自检能通过,但是出现不了引导界面反而出现的是一个叫做 grub rescue的界面,我这里因为修的时候并没有拍照,所以只能用文字大概描述一下。 +- 开机之后通过自检,然后检测引导什么的,但是他提示 `erro:file'/boot/grub/i386-pc/normal.mod' not found` 这个错误。 +- 接下来就是如下的一个命令行界面, +``` +grub rescue>>______________ +``` + +## 问题的原因 +这个问题本质上就是找不到引导的文件,迷路了找不到任何导航的东西。但是有两种不同的情况(据我搜索的结果)。 +1. grub 文件还在系统里,但是引导至该文件的设置出错,也就是这个文件的路径不见了。 +2. grub 的文件已经丢失了,也就是硬盘里不存在这个文件了。 + +## 验证是哪种情况 +下面几步即可完成。 +1. `grub rescue>>` 输入 `ls` 。可以看到输出了很多 hd\*,msdos\* 之类的东西,hd\* 就是第几块存储设备,msdos\*也就是分区。 +2. 通过 `ls (hd*,msdos*)/boot/grub` 可以查看是不是grub所在的分区以及文件是否存在。比如我查看 hd0,msdos5 那么命令就是 `ls (hd0,msdos5)/boot/grub`,这里我在网上看到有些直接输入`ls (hd0,msdos5)/grub` (grub摆放的位置不一样)。 + - 如果结果显示 `error:unknown filesystem` 代表并不是 grub 所在的分区。 + - 如果结果里有`i386-pc` 文件夹,那么代表你的是第一种情况。 + - 如果结果里没有错误提示但是也没有显示`i386-pc` 文件夹,那么你的情况就是第二种(我的恰好也就是第二种)。 + +## 设置 grub 路径 +我不知道第二种情况需不需要这样设置,经过我的后来思考觉得应该不需要的,但是还是建议设置一下防止出问题。 +1. 在`grub rescue>>` 输入 `set root=(hd*,msdos*)` 设置根目录。 +2. 在`grub rescue>>` 输入 `set prefix=(hd*,msdos*)/boot/grub` 设置 grub 目录。 +3. 通过在`grub rescue>>` 输入 `set`可以看到设置的结果。 + +## 第一种情况解决办法 +下面的步骤是网上搬过来的,因为我不是这个情况,原文见[博客](https://blog.csdn.net/peerless1994/article/details/52226169) +1. 输入 ` insmod normal` 回车 +2. 输入 `normal`回车 就能进入 grub 引导菜单界面。 +3. 如果你能选择 linux 并启动那么跳到第5步否则第4步。 +4. 在 grub 界面按下键盘 `C` 进入命令行模式输入如下命令。\* 就是你刚找到的正确的引导分区的相关序号。 +``` +set root=(hd*,msdos*) +Set prefix=(hd*,msdos*) +``` +5. 启动 linux 在终端输入如下命令,(其实我更推荐使用 boot-repair 更傻瓜,更安全~ ~)。 +``` +sudo update-grub +sudo grub-install /dev/sda (通过 ls /dev/sd* 查看磁盘情况) +``` + +## 第二种情况解决办法 +对于二种情况稍显复杂。需要通过一个 liveCD 来拯救。 +1. 需要 + 硬件:一个可以用的电脑、一个U盘(会格式化注意备份); + 软件:一个 Ubuntu 系统镜像、UltraISO软碟通(亲测U深度一键装机没用)。 +2. 打开软碟通菜单栏-->文件-->打开下载来的iso镜像。 +3. 软碟通菜单栏-->启动-->写入硬盘镜像,在弹出的选项里选择U盘然后点击格式化,格式化完成之后点击写入。等待写入完成。 +4. 插入U盘,进入你电脑的 bios ,我的是在按下电源键启动之后狂按 F2 这里你需要上网搜一下你电脑对应的按键是啥,进去时候找到 boot 设置将U盘列为第一启动项(这里因电脑而异希望你有点灵性),这里不懂的话上网搜一下怎么开机进入U启动盘。 +5. 顺利的话就进入了一个 linux 的安装界面。在右边的语言列表里滑到最下面选择中文。然后在右边的两个大图标选项里选择试用 Ubuntu ,这样就进入了一个看起来和正常安装没有区别的 Ubuntu 系统。 +6. `Ctrl+alt+T` 呼出终端,输入以下命令安装 boot-repair 并启动。 +``` +sudo add-apt-repository ppa:yannubuntu/boot-repair //添加 boot-repair 软件源 +sudo apt-get update //更新软件列表 +sudo apt-get install -y boot-repair //安装 boot-repair +boot-repair //启动 boot-repair +``` +7. 按照提示傻瓜式的操作即可完成修复,耐心等待。 + - 在过程中如果提示某个硬盘是否是可拆卸的选择否,如果是移动硬盘就选择是。 + - 修复完成会问你是否选择生成报告,点击是,生成报告然后给你一个网址,复制网址到浏览器即可访问结果,可以看到你的分区和引导以及引导的系统。 +8. 关闭计算机,拔掉U盘,重启计算机即可进入引导~ ~。windows 和 linux 都可以进入了,美滋滋。 +9. 启动 windows 可能会提示是否要跳过系统检查,这个很快的,也就20几秒就好了。 + +## 后话 +1. 我这里出现一个情况,我原本的默认引导是用那种黑白屏的引导,然后如果点击 Ubuntu 会跳转到 grub 引导但是经过这个操作之后,grub变成了默认的引导点击windows之后会跳到黑白屏的引导。 + 解决办法:下载EasyBCD编辑引导菜单删除 Ubuntu 的引导选项就OK了,就默认使用 grub 引导(之前就想这么搞来着误打误撞美滋滋)。 +2. grub默认的不是windows启动,通过该[教程](https://jingyan.baidu.com/article/f71d60379e16021ab641d1ab.html) 即可调整默认的启动系统,如果链接失效搜索一下 grub 调整启动顺序~ ~。 \ No newline at end of file diff --git a/_posts/大小端.md b/_posts/大小端.md new file mode 100644 index 0000000..4603f17 --- /dev/null +++ b/_posts/大小端.md @@ -0,0 +1,69 @@ +--- +title: 处理器大小端存储模式 +tags: + - 大小端存储 +categories: + - c语言 +abbrlink: c25386f8 +date: 2017-09-13 17:01:49 +--- +大端模式:是指数据的**高字节**保存在内存的**低地址**中,而数据的**低字节**保存在内存的**高地址**中。 + +小端模式:是指数据的**高字节**保存在内存的**高地址**中,而数据的**低字节**保存在内存的**低地址**中。 + +例如:一个数据无符号32位整数0x12345678,其中0x12属于高字节(权值大)而0x78属于低字节(权值小),在不同的模式下存储的方式如下表: + +内存地址 | 0x1000 | 0x1001 | 0x1002 | 0x1003 | +--- | --- | --- | --- | --- | +大端模式 | 0x12 | 0x34 | 0x56 | 0x78 | +小端模式 | 0x78 | 0x56 | 0x34 | 0x12 | + +我们可以看得出来大端模式和我们的阅读习惯相同,权值从左往右是高位->低位而地址则是低位->高位。小端模式则是随着地址从左往右增大权值增大。地址就代表了权值的大小。 + + + +利用下面c代码可以看到运行环境是如何存储一个uint数据的。 + +```c +#include +int endian(void); +int main(int argc,char arg[]) +{ + unsigned int a=0x12345678; + char *ap=&a; + int i=0; + printf("0x%x storage in system is:\r\n",a); + for(i=0;i<4;i++) + printf("addr:0x%x,value:0x%x\r\n",ap+i,ap[i]); + printf("system storage by %s_endian",endian()? "Big":"Little"); + return 0; +} +``` +运行的结果如下,可以看出该系统是小端系统。 + +[![](https://s1.ax1x.com/2017/10/01/1Md81.png)](https://imgchr.com/i/1Mp4A) + +我们如何简单的判断一个系统的大小端呢。我们知道**共用体(联合体)**存储在内存里是共用一块地址的,其占用空间决定于最大成员所需的空间,他们的起始地址相同。所以我们可以利用一个共用体,成员分别是一个int和一个char。通过给int赋值1,然后检测char对应的值是多少,如果是1代表系统将数据1放到了int的起始地址(因为char是一个字节必然在起始地址)。而起始地址是低地址,低地址存放的1(权值小)推出该系统是小端系统。否则该系统是大端系统。 + +C代码如下 +```C +int endian() +{ + union{ + int a; + char b; + }endunion; + endunion.a=1; + if(endunion.b==1)//如果成员b是1则证明随地址顺序和数字权值顺序相同是小端模式 + return 0;//小端 + return 1;//大端 +} +``` +还可以用一个更加简洁的办法(原理都是检测int的起始地址存放的是什么值),代码如下 +```C +int endian() +{ + int a=1; + return !(*((char *)&a));//取a的地址,将其强制转化为char指针,然后取出该地址存放的值并取反; +} +``` \ No newline at end of file diff --git a/_posts/树莓派—云服务器-EMQTT-环境搭建.md b/_posts/树莓派—云服务器-EMQTT-环境搭建.md new file mode 100644 index 0000000..8070e84 --- /dev/null +++ b/_posts/树莓派—云服务器-EMQTT-环境搭建.md @@ -0,0 +1,502 @@ +--- +title: 树莓派|云服务器-MQTT环境搭建 +tags: + - MQTT +categories: + - 树莓派 +password: 209445 +comments: true +abbrlink: 64c79d1b +date: 2018-08-26 15:13:24 +images: http://begild-one.top/%E6%A0%91%E8%8E%93%E6%B4%BE-%E4%BA%91%E6%9C%8D%E5%8A%A1%E5%99%A8-EMQTT-%E7%8E%AF%E5%A2%83%E6%90%AD%E5%BB%BA/%E6%A0%91%E8%8E%93%E6%B4%BE+%E4%BA%91%E6%9C%8D%E5%8A%A1%E5%99%A8+emqtt.png +--- +## 树莓派之 MQTT 搭建 +每天出门总怀疑自己灯没关、空调没关,晚上睡觉的时候躺下才意识到灯没关、然而开关却理我特别远,这我可接受不了 2333 ,所以产生了这种刚需🤣,这里记录一下搭建[MQTT](https://baike.baidu.com/item/MQTT/3618851)环境的过程。 + + +## 搭建的两种方法 +1. 树莓派作为 MQTT 服务器,用花生壳映射端口( 6 块钱)可以供给外网访问,这个方法的话最便宜的方案吧,不过外网的端口是不固定的,如果被改变了就得打开花生壳管理器查看分配的公网端口,嫌麻烦的话可以买固定的端口,得差不多 100 块这样子。不过这两个都是永久的加起来 100 多一点。当然如果不嫌麻烦,那就只要 6 元了。结构大概就是这样子,23333 画的不太好将就看。 + 树莓派同时运行一个 MQTT 服务器和一个 MQTT 客户端。手机运行一个 MQTT 客户端,通过访问花生壳映射之后的域名和端口来访问内网的树莓派 MQTT 服务器进行通信。树莓派运行的 MQTT 客户端直接通过内网和服务器进行通信。 +![](http://begild-one.top/%E6%A0%91%E8%8E%93%E6%B4%BE-%E4%BA%91%E6%9C%8D%E5%8A%A1%E5%99%A8-EMQTT-%E7%8E%AF%E5%A2%83%E6%90%AD%E5%BB%BA/%E6%A0%91%E8%8E%93%E6%B4%BEMQTT%E6%9C%8D%E5%8A%A1%E5%99%A8.jpg) +2. 云主机作为 MQTT 服务器,这个方案的话因为我之前买了腾讯云的服务器 120 一年,续了三年。闲置着也是没有用,所以利用了起来。这个方法的话比较容易实现,不折腾那些个什么内网穿透,但是钱也会多很多,不过云服务器有公网 IP 还有以后可以有很多利用的地方。大概的关系就是如下图,比较容易理解的吧还是,树莓派运行的客户端通过网络和云主机上的服务器进行通信,手机上的MQTT客户端同样如此。 + +![](http://begild-one.top/%E6%A0%91%E8%8E%93%E6%B4%BE-%E4%BA%91%E6%9C%8D%E5%8A%A1%E5%99%A8-EMQTT-%E7%8E%AF%E5%A2%83%E6%90%AD%E5%BB%BA/%E4%BA%91%E6%9C%8D%E5%8A%A1%E5%99%A8MQTT%E6%9C%8D%E5%8A%A1%E5%99%A8.jpg) + +MQTT 的服务器我选择使用的是开源的 EMQTT ,官方提供了很多系统的安装包,很容易搭建的,管理也很方便。官网见 [http://emqtt.com/](http://emqtt.com/).树莓派作为服务器的话安装使用需要采用源码的方式进行编译安装。 + +## 云主机作为MQTT服务器 +之前搞优惠活动的时候买的腾讯云的服务器,服务器的配置是 2G 内存 1Mbps 带宽 40GB 硬盘,跑这个绰绰有余。具体的购买流程就不说了,傻瓜式的,我选择的是 centos 7 作为系统,因为据说这个系统做服务器多?这个后续后悔了还可以免费改的。 +买了服务器之后要[设置安全组的规则](https://www.yuntunpuzi.com/qcloud/178/),我是把所有端口都打开了的(安全?不存在考虑的),最起码要把 22 端口开放,因为这个是 SSH 登录要用的端口。完成初步的配置就可以用了。搞到服务器的密码就可以用账户 root + 密码进行 SSH 访问了。之后的都是用 SSH 进行配置的。SSH 软件的使用可以看之前写的树莓派安装系统和配置下的->[使用SSH进行树莓派的连接](http://begild.top/article/fd8be0b3.html) +接下来的操作都是在 centos 7系统的终端里运行的。 +1. 通过 rpm 安装包进行安装。(使用简单快捷)教程可以看[这里](http://emqtt.com/docs/v2/install.html#rpm). +``` +yum install wget //安装下载工具这个应该都是预置了的 +yum install lksctp-tools //安装Erlang/OTP R19依赖库 +wget http://emqtt.com/downloads/latest/centos7-rpm -O emqttd-centos7-x86_64.rpm //下载安装包 +rpm -ivh emqttd-centos7-x86_64.rpm //安装 +``` + 安装完成之后呢就可以运行了,是不是超级简单。通过下面的命令可以启动、停止、重启、查看状态整个 EMQTT 服务。这个方式安装,配置文件存放在`/etc/emqttd/`下的。 +``` +systemctl start|stop|restart|status emqttd.service +``` +2. 通用包方式安装。(绿色解压版)。教程可以看[这里](http://emqtt.com/docs/v2/install.html#linux).绿色版嘛当然是要手动执行文件启动的啦。这个方式下的配置文件是存放在解压目录下的`etc`下,不在`/etc/emqttd/`下。 +``` +wget http://emqtt.com/downloads/latest/centos7 -O emqttd-centos7.zip //下载压缩包 +unzip emqttd-centos7.zip //解压安装 + +cd 解压目录/emqttd +./bin/emqttd console //运行控制台 ctrl+c退出 +./bin/emqttd start|stop|restart //后台守护进程方式 +``` + +3. 访问服务器控制界面 +Dashboard 插件可查询 EMQ 消息服务器基本信息、统计数据、度量数据,查询系统客户端(Client)、会话(Session)、主题(Topic)、订阅(Subscription)。EMQ 消息服务器默认加载 Dashboard 插件。 +安装完成之后访问在浏览器地址栏输入 服务器IP:18083/ 即可访问网页端的控制界面,如下图所示。会提示你输入登录账户和密码,默认的账户是`admin` 密码是 `public`。登录之后点击侧边 `USER` 栏,可以看到 `admin` 账户点击 `Edit` 即可更改密码。页面右上角可以切换主题配色,语言。 +![](http://begild-one.top/%E6%A0%91%E8%8E%93%E6%B4%BE-%E4%BA%91%E6%9C%8D%E5%8A%A1%E5%99%A8-EMQTT-%E7%8E%AF%E5%A2%83%E6%90%AD%E5%BB%BA/%E6%9C%8D%E5%8A%A1%E5%99%A8%E4%BB%AA%E8%A1%A8%E7%9B%98.png) +4. MQTT 服务器的配置。 +无论通过何种方式安装都需要修改服务器的一些插件和配置文件才能为你所用。这里呢主要是配置客户端的登录服务器验证方式和客户端的ID等信息。 +其认证方式如下,客户端接入服务器呢,需要进行用户名密码的认证,客户端ID的认证,如果你两个都不开(ignore)的话就是匿名认证。用户名的认证需要打开 `emq_auth_username` 插件。客户端ID的认证需要打开 `emq_auth_clientid` 插件。服务器默认打开匿名认证,我选择打开用户名密码认证,客户端ID认证。 +```bash + ---------------- ---------------- ------------ +Client --> | Username认证 | -ignore-> | ClientID认证 | -ignore-> | 匿名认证 | + ---------------- ---------------- ------------ + | | | + \|/ \|/ \|/ + allow | deny allow | deny allow | deny +``` + + - 添加配置列表-用户名/密码. + 既然使能了用户名密码验证,当然是需要添加用户名和密码的啦,配置文件为 `emq_auth_username.conf`,在各自存放配置文件的目录下的`plugins`目录下。软件安装版为`/etc/emqttd/plugins/emq_auth_username.conf`。解压绿色版为`解压目录/emqttd/etc/plugins/emq_auth_username.conf`。 使用下面命令打开文件(自行学习vim)。 + + ``` + vim /etc/emqttd/plugins/emq_auth_username.conf //软件安装版 + vim 解压目录/emqttd/etc/plugins/emq_auth_username.conf //解压绿色版 + ``` + + 打开文件可以看到给了示例的模板,按照模板增加即可。 贴一个示例如下。修改之后保存就好了。 + + ``` + ##-------------------------------------------------------------------- + ## Username Authentication Plugin + ##-------------------------------------------------------------------- + auth.user.1.username = BeGild_test + auth.user.1.password = 123456 + auth.user.2.username = BeGild_test_1 + auth.user.2.password = 123456 + ``` + + - 添加配置列表-客户端ID + 既然使能了用客户端ID 验证,当然是需要添加客户端ID列表和密码的啦,配置文件为 `emq_auth_clientid.conf `,在各自存放配置文件的目录下的`plugins`目录下。软件安装版为`/etc/emqttd/plugins/emq_auth_clientid.conf `。解压绿色版为`解压目录/emqttd/etc/plugins/emq_auth_clientid.conf `。 使用下面命令打开文件(自行学习vim)。 + + ``` + vim /etc/emqttd/plugins/emq_auth_clientid.conf //软件安装版 + vim 解压目录/emqttd/etc/plugins/emq_auth_clientid.conf //解压绿色版 + ``` + + 打开文件可以看到给了示例的模板,按照模板增加即可。 贴一个示例如下。修改之后保存就好了。看起来和用户名密码是差不多的,他俩之间的对应关系还不太清楚,之后搞懂了会再更新。 + + ``` + ##-------------------------------------------------------------------- + ## ClientId Authentication Plugin + ##-------------------------------------------------------------------- + auth.client.1.clientid = test1 + auth.client.1.password = test1_pwd + auth.client.2.clientid = test2 + auth.client.2.password = test2_pwd + ``` + + - 打开认证插件 + 插件打开可以点击网页的控制台侧边插件栏页面,可以看到很多插件第1,9个就是,点击右侧边启动按钮进行打开,打开成功就会变成绿色的运行中。 + 启用插件,配置完成之后即可投入使用啦。EMQ2.0支持的认证插件有可以看[这里](http://emqtt.com/docs/v2/guide.html#id1)这些. + +## 树莓派作为 MQTT 服务器 +树莓派作为 MQTT 服务器同样需要安装服务器的软件,不过只能通过源码编译安装的方式进行,编译源码依赖于 Erlang 工具,所以得走两步,安装编译工具,下载源码编译安装。 +1. 安装 erlang 编译环境.emmmm 这个工具编译完毕之后就可以卸磨杀驴! +``` +sudo apt-get install erlang //安装 erlang +sudo apt-get autoremove erlang //卸载 erlang +``` +2. 挑一个自己喜欢的目录执行下面指令进行源码克隆和编译. +``` +git clone https://github.com/emqtt/emq-relx.git +cd emq-relx +make +``` +3. 待编译成功后会生成`_rel`目录存放生成的一系列可执行文件和配置文件等,执行下面语句执行控制台方式启动. +``` +cd _rel/emqttd +./bin/emqttd console +``` + 可支持的指令和组合有如下. + ``` + Usage: emqttd {start|start_boot |foreground|stop|restart|reboot|pid|ping|console|console_clean|console_boot |attach|remote_console|upgrade|escript|rpc|rpcterms|eval} + ``` +4. 列一下常用指令正常的表现吧。 + +``` +//这是控制台方式启动 EMQTT 会输出一些启动,运行的信息。 +pi@BeGild_Raspi:~/Documents/MQtt/server/emq-relx/_rel/emqttd $ ./bin/emqttd console +Exec: /home/pi/Documents/MQtt/server/emq-relx/_rel/emqttd/erts-8.2.1/bin/erlexec -boot /home/pi/Documents/MQtt/server/emq-relx/_rel/emqttd/releases/2.3.11/emqttd -mode embedded -boot_var ERTS_LIB_DIR /home/pi/Documents/MQtt/server/emq-relx/_rel/emqttd/erts-8.2.1/../lib -mnesia dir "/home/pi/Documents/MQtt/server/emq-relx/_rel/emqttd/data/mnesia/emq@127.0.0.1" -config /home/pi/Documents/MQtt/server/emq-relx/_rel/emqttd/data/configs/app.2018.08.30.15.18.31.config -args_file /home/pi/Documents/MQtt/server/emq-relx/_rel/emqttd/data/configs/vm.2018.08.30.15.18.31.args -vm_args /home/pi/Documents/MQtt/server/emq-relx/_rel/emqttd/data/configs/vm.2018.08.30.15.18.31.args -- console +Root: /home/pi/Documents/MQtt/server/emq-relx/_rel/emqttd +/home/pi/Documents/MQtt/server/emq-relx/_rel/emqttd +Erlang/OTP 19 [erts-8.2.1] [source] [smp:4:4] [async-threads:32] [kernel-poll:true] + + +=INFO REPORT==== 30-Aug-2018::15:18:52 === + alarm_handler: {set,{system_memory_high_watermark,[]}} +starting emqttd on node 'emq@127.0.0.1' +emqttd ctl is starting...[ok] +emqttd hook is starting...[ok] +emqttd router is starting...[ok] +emqttd pubsub is starting...[ok] +emqttd stats is starting...[ok] +emqttd metrics is starting...[ok] +emqttd pooler is starting...[ok] +emqttd trace is starting...[ok] +emqttd client manager is starting...[ok] +emqttd session manager is starting...[ok] +emqttd session supervisor is starting...[ok] +emqttd wsclient supervisor is starting...[ok] +emqttd broker is starting...[ok] +emqttd alarm is starting...[ok] +emqttd mod supervisor is starting...[ok] +emqttd bridge supervisor is starting...[ok] +emqttd access control is starting...[ok] +emqttd system monitor is starting...[ok] +emqttd 2.3.11 is running now +Eshell V8.2.1 (abort with ^G) +(emq@127.0.0.1)1> Load emq_mod_presence module successfully. +dashboard:http listen on 0.0.0.0:18083 with 4 acceptors. +mqtt:tcp listen on 127.0.0.1:11883 with 4 acceptors. +mqtt:tcp listen on 0.0.0.0:1883 with 16 acceptors. +mqtt:ws listen on 0.0.0.0:8083 with 4 acceptors. +mqtt:ssl listen on 0.0.0.0:8883 with 16 acceptors. +mqtt:wss listen on 0.0.0.0:8084 with 4 acceptors. +mqtt:api listen on 0.0.0.0:8080 with 4 acceptors. + +(emq@127.0.0.1)1> +//这是后台守护进程方式启动 EMQTT 服务器 启动有点慢,稍等稍等。 +pi@BeGild_Raspi:~/Documents/MQtt/server/emq-relx/_rel/emqttd $ ./bin/emqttd start +emqttd 2.3.11 is started successfully! +//这是停止当前启动了的 EMQTT 服务器 +pi@BeGild_Raspi:~/Documents/MQtt/server/emq-relx/_rel/emqttd $ ./bin/emqttd stop +ok +//这是重启已经启动了的 EMQTT 服务器 +pi@BeGild_Raspi:~/Documents/MQtt/server/emq-relx/_rel/emqttd $ ./bin/emqttd restart +ok + +``` +如果运行的时候出现下面错误,那你一定是运行的目录不对,一定要是 `_rel/emqttd/`目录下才是编译生成的目录,才可以运行 EMQTT 服务器!!!。 +``` +pi@BeGild_Raspi:~/Documents/MQtt/server/emq-relx/bin $ ./emqttd restart +./emqttd: 20: ./emqttd: runner_log_dir: not found +``` +5. 访问服务器控制界面。 +在浏览器输入树莓派IP:18083,输入账号 admin 和默认密码 public 进入管理控制界面,其余操作和以云主机作为 MQTT 服务器上一样,打开两个认证插件即可。 +6. MQTT 服务器的配置。 +配置文件的修改参照上面以云主机为 MQTT 服务器的配置例子,只是配置文件在`_rel/emqttd/etc/`下面。 +7. 花生壳外网访问的配置。参照[树莓派-花生壳-内网穿透](http://begild.top/article/3ac023e7.html)中的添加端口映射1883到外网。 + +## 安装 MQTT 客户端依赖库 +安装好服务器可以使用了,就进入客户端代码的编写了呀,客户端在树莓派上运行一个,在手机上运行一个。 +1. 在树莓派上使用 MQTT 客户端当然是要安装 MQTT 客户端的库呀,首先运行下面几条命令做一些编译前的准备。 +``` +cd /home/pi/Documents && mkdir emqtt //创建一个mqtt的目录 +cd emqtt && git clone https://github.com/eclipse/paho.mqtt.c.git //克隆mqtt客户端源码 +sudo apt-get install build-essential gcc make cmake cmake-gui cmake-curses-gui //安装编译工具 +sudo apt-get install fakeroot fakeroot devscripts dh-make lsb-release //安装软件包构建工具 +sudo apt-get install libssl-dev //安装openssl +sudo apt-get install doxygen graphviz //安装文档生成工具 +``` + +2. 编译 MQTT 客户端源码。官方的教程看这里[paho.mqtt.c](https://github.com/eclipse/paho.mqtt.c) +``` +cd paho.mqtt.c && make //转到源码目录进行编译 +/***********等待漫长的时间没有报错就OK了*********************/ +sudo make html //编译生成文档 +sudo make install //安装到系统 +``` + 备注:需要编译生成文档不然安装时会提示如下错误的。 +``` +install -m 644 build/output/doc/MQTTClient/man/man3/MQTTClient.h.3 /usr/local/share/man/man3 +install: 无法获取'build/output/doc/MQTTClient/man/man3/MQTTClient.h.3' 的文件状态(stat): 没有那个文件或目录 +Makefile:273: recipe for target 'install' failed +make: [install] Error 1 (ignored) +install -m 644 build/output/doc/MQTTAsync/man/man3/MQTTAsync.h.3 /usr/local/share/man/man3 +install: 无法获取'build/output/doc/MQTTAsync/man/man3/MQTTAsync.h.3' 的文件状态(stat): 没有那个文件或目录 +Makefile:273: recipe for target 'install' failed +make: [install] Error 1 (ignored) +``` + 安装成功显示如下信息。 + ``` + pi@BeGild_Raspi:~/Documents/MQtt/paho.mqtt.c $ sudo make install + mkdir -p build/output/samples + mkdir -p build/output/test + echo OSTYPE is Linux + OSTYPE is Linux + mkdir -p /usr/local/include + install -m 644 build/output/libpaho-mqtt3c.so.1.0 /usr/local/lib + install -m 644 build/output/libpaho-mqtt3cs.so.1.0 /usr/local/lib + install -m 644 build/output/libpaho-mqtt3a.so.1.0 /usr/local/lib + install -m 644 build/output/libpaho-mqtt3as.so.1.0 /usr/local/lib + install build/output/paho_c_version /usr/local/bin + install build/output/samples/paho_c_pub /usr/local/bin + install build/output/samples/paho_c_sub /usr/local/bin + install build/output/samples/paho_cs_pub /usr/local/bin + install build/output/samples/paho_cs_sub /usr/local/bin + /sbin/ldconfig /usr/local/lib + ln -s libpaho-mqtt3c.so.1 /usr/local/lib/libpaho-mqtt3c.so + ln -s libpaho-mqtt3cs.so.1 /usr/local/lib/libpaho-mqtt3cs.so + ln -s libpaho-mqtt3a.so.1 /usr/local/lib/libpaho-mqtt3a.so + ln -s libpaho-mqtt3as.so.1 /usr/local/lib/libpaho-mqtt3as.so + install -m 644 src/MQTTAsync.h /usr/local/include + install -m 644 src/MQTTClient.h /usr/local/include + install -m 644 src/MQTTClientPersistence.h /usr/local/include + install -m 644 src/MQTTProperties.h /usr/local/include + install -m 644 src/MQTTReasonCodes.h /usr/local/include + install -m 644 src/MQTTSubscribeOpts.h /usr/local/include + install -m 644 doc/man/man1/paho_c_pub.1 /usr/local/share/man/man1 + install -m 644 doc/man/man1/paho_c_sub.1 /usr/local/share/man/man1 + install -m 644 doc/man/man1/paho_cs_pub.1 /usr/local/share/man/man1 + install -m 644 doc/man/man1/paho_cs_sub.1 /usr/local/share/man/man1 + install -m 644 build/output/doc/MQTTClient/man/man3/MQTTClient.h.3 /usr/local/share/man/man3 + install -m 644 build/output/doc/MQTTAsync/man/man3/MQTTAsync.h.3 /usr/local/share/man/man3 + ``` + +## 编写 MQTT 客户端代码 +1. 客户端代码。流程就是,根据服务器地址,用户名、密码、客户端ID登录到服务器,进行主题的订阅或者向某个主题进行消息的发布这样子。从网上抄了代码(只有ctrl+c ctrl+v才能够勉强维持生活这样子),魔改了一下贴上。这个程序在运行之后会创建一个发送线程`TestSend`,每隔 3s 发送一次信息,发送成功会通过回调函数`MQTTClient_deliveryToken`进行打印报告。收到信息会通过回调函数`MsgArrived_CallBack`进行信息的打印。 + +```c +#include +#include +#include +#include +#include "MQTTClient.h" +#include +/*类型兼容***********************************************/ +typedef unsigned long uint64_t; +typedef unsigned int uint32_t; +typedef unsigned short uint16_t; +typedef unsigned char uint8_t; +typedef unsigned long u64; +typedef unsigned int u32; +typedef unsigned short u16; +typedef unsigned char u8; +/***********************************************类型兼容*/ + +#define NUM_THREADS 2 //线程个数 +#define ADDRESS "tcp://*.*.*.*:1883" //云主机作为mqtt服务器地址 +//#define ADDRESS "tcp://localhost:1883" //树莓派作为mqtt服务器地址,直接通过内网访问。 +#define CLIENTID "test_1" //客户端ID +#define TOPIC_PUBLISH "Hello_1" //发送的主题 +#define TOPIC_SUBSCRIBE "Hello_2" //订阅的主题 +#define PAYLOAD "Hello! My Name is "CLIENTID //发送的信息 +#define QOS 1 //服务质量 <<0-最多发送一次 1-至少保证送达一次 2-保证只送达1次 +#define TIMEOUT 10000L //超时时间 +#define USERNAME "username" //登录用户名 +#define PASSWORD "password" //登录用户名对应密码 + +volatile MQTTClient_deliveryToken gDeliveredToken; +/** void deliveryComplete_CallBack(void *context, MQTTClient_deliveryToken deliveryToken) + * @brief MQTT发送信息成功回调函数 + * @note 客户端发送信息成功时将会调用该函数 + * @param[in] context 上下文指针 + * @param[in] deliveryToken 发送信息的Token值 + * @date 2018/08/25 17:20 + * @auth BeGild + * @email yucang_bao@126.com + */ +void deliveryComplete_CallBack(void *context, MQTTClient_deliveryToken deliveryToken) +{ + printf("\rMessage with token %5d Send Success\n", deliveryToken); + gDeliveredToken = deliveryToken; +} +/** int MsgArrived_CallBack(void *context, char *topicName, int topicLen, MQTTClient_message *message) + * @brief 接收到MQTT数据的回调函数 + * @param[in] context 上下文指针 + * @param[in] topicName 本次接收到信息的主题 + * @param[in] topicLen 本次接收到信息的主题长度 + * @param[in] message 本次接收到数据的存储结构体 + * 数据实体存放于 message->payload + * 数据长度为 message->payloadlen + * @date 2018/08/25 17:20 + * @auth BeGild + * @email yucang_bao@126.com + * return 返回值 + */ + int MsgArrived_CallBack(void *context, char *topicName, int topicLen, MQTTClient_message *message) + { + int i; + uint8_t *payloadptr; + printf("Recive Message\n"); + printf(" topic: %s\n", topicName); + printf(" message: \n>>\n"); + payloadptr = message->payload; + //打印接受到的数据 + for(i=0; ipayloadlen; i++) + { + putchar(*payloadptr++); + } + printf("\n<<\n"); + MQTTClient_freeMessage(&message); + MQTTClient_free(topicName); + return 1; + } +/** void ConnectLost_CallBack(void *context, char *cause) + * @brief 连接丢失回调函数 + * @note 可能原因: + * 1.被挤下线 + * 2.网络异常 + * @date 2018/08/25 16:18 + * @auth BeGild + * @email yucang_bao@126.com + */ +void ConnectLost_CallBack(void *context, char *cause) +{ + printf("\nConnection lost "); + printf("\t cause: %s\n", cause); +} +/** void PublishMessage(MQTTClient client,uint8_t* TopicName, uint8_t *DataBuf,uint32_t BufLen) + * @brief 推送信息 + * @param[in] client 发送的客户端ID + * @param[in] TopicName 发送的主题 + * @param[in] DataBuf 发送的数据缓冲区 + * @param[in] BufLen 发送的数据长度 + * @date 2018/08/25 17:49 + * @auth BeGild + * @email yucang_bao@126.com + */ +void PublishMessage(MQTTClient client,uint8_t* TopicName, uint8_t *DataBuf,uint32_t BufLen) +{ + MQTTClient_message Publishmsg = MQTTClient_message_initializer; + //声明消息token + MQTTClient_deliveryToken token; + Publishmsg.payload = DataBuf; + Publishmsg.payloadlen = BufLen; + Publishmsg.qos = QOS; + Publishmsg.retained = 0; + MQTTClient_publishMessage(client, TopicName, &Publishmsg, &token);//发送数据 + // rc = MQTTClient_waitForCompletion(client, token, TIMEOUT); + // printf("Message with delivery token %d delivered\n", token); +} +/** void *TestSend(void *arg) + * @brief 测试发送 + * @param[in] arg 传入参数指针 + * @return 返回值 + * @date 2018/08/25 18:58 + * @auth BeGild + * @email yucang_bao@126.com + */ +void *TestSend(void *arg) +{ + char MsgBuff [] = PAYLOAD; + MQTTClient *client = (MQTTClient *)arg;//客户端句柄 + while(1) + { + PublishMessage(*client,TOPIC_PUBLISH,MsgBuff,strlen(MsgBuff));//发送信息 + usleep(3000000L);//睡眠3s + } + pthread_exit(NULL);//退出线程 + return NULL; +} +/**int main(int argc, char* argv[]) + * @brief 主函数 + * @param[in] argc参数个数 + * @param[in] argv 参数列表 + */ +int main(int argc, char* argv[]) +{ + pthread_t threads[NUM_THREADS]; + char SubTopic[] = TOPIC_SUBSCRIBE; + char ClientID [] = CLIENTID; + long t; + MQTTClient client;//客户端句柄 + MQTTClient_connectOptions conn_opts = MQTTClient_connectOptions_initializer;//连接参数 + int rc; + int ch; + + MQTTClient_create(&client, ADDRESS, ClientID, + MQTTCLIENT_PERSISTENCE_NONE, NULL);//根据服务器地址客户端ID创建一个可用连接 + /*填写连接参数*/ + conn_opts.keepAliveInterval = 20; + conn_opts.cleansession = 1; + conn_opts.username = USERNAME; + conn_opts.password = PASSWORD; + /*设置回调函数*/ + MQTTClient_setCallbacks(client, NULL, + ConnectLost_CallBack,/*连接丢失*/ + MsgArrived_CallBack,/*收到信息*/ + deliveryComplete_CallBack);/*信息成功发出*/ + /*尝试连接服务器*/ + if ((rc = MQTTClient_connect(client, &conn_opts)) != MQTTCLIENT_SUCCESS) + { + printf("Failed to connect, return code %d\n", rc); + exit(EXIT_FAILURE);//连接失败退出 + } + printf("[-------------------------------"); + printf(" Connect to EMQTT server complete"); + printf("--------------------------------]\n\n"); + //订阅主题 + printf("Client [%s] ---- using QoS[%d] ---- Subscribing to topic [%s]\n\n", ClientID,QOS,SubTopic); + MQTTClient_subscribe(client, SubTopic, QOS); + + //创建测试发送线程 + pthread_create(&threads[0], NULL, TestSend,&client); + + /*主循环loop*/ + printf( "Press Q to quit\n\n"); + do + { + ch = getchar(); + } while(ch!='Q' && ch != 'q'); + pthread_exit(&threads[0]); + MQTTClient_unsubscribe(client, SubTopic);//取消订阅 + MQTTClient_disconnect(client, 10000);//断开连接 + MQTTClient_destroy(&client);//销毁当前clien + pthread_exit(NULL);//退出主线程main +} +``` + 点击上述代码段右上角拷贝保存为`mqtttest_1.c`,执行一面这条语句编译生成可执行文件`mqtttest_1`。 +``` +gcc -o mqtttest_1 mqtttest_1.c -lpaho-mqtt3c -lpthread +``` + +## MQTT 客户端通信测试 + +MQTT 的测试的话就是看两个客户端之间是否可以互相通信嘛。这里采用的方式是树莓派运行上面的客户端程序作为客户端1,用一个测试工具作为客户端2。客户端1订阅 `Hello_2` 主题 向 `Hello_1` 主题发送消息,客户端2订阅主题 `Hello_1` 向主题 `Hello_2` 发送消息。 +1. 执行`./mqtttest_1`运行树莓上的客户端1,成功运行会打印大致如下的信息。 +``` +pi@BeGild_Raspi:~/Documents/MQtt/mqtttest $ ./mqtttest_1 +[------------------------------- Connect to EMQTT server complete--------------------------------] + +Client [test_1] ---- using QoS[1] ---- Subscribing to topic [Hello_2] + +Press Q to quit + +Message with token 2 Send Success +``` + 如果连接失败返回错误码-1、4 检查 + - 是否运行了 EMQTT 服务器、服务器地址是否填写正确。 + - 服务器是否可达(ping 一下),如果是云主机查看端口(1883)是否打开允许访问。 + - 检查 EMQTT 服务器配置文件中是否添加了对应的`username`、`password` 以及`clientid`、`password`。 + +2. 运行 Mqtt 客户端测试工具 MQTT.fx 作为客户端2。 + - 点击[http://www.jensd.de/apps/mqttfx/](http://www.jensd.de/apps/mqttfx/)下载你想要的版本。 + - 点击安装程序。 + - 一个紫色的清秀小图标,打开 MQTT.fx 稍等片刻。 +![](http://begild-one.top/%E6%A0%91%E8%8E%93%E6%B4%BE-%E4%BA%91%E6%9C%8D%E5%8A%A1%E5%99%A8-EMQTT-%E7%8E%AF%E5%A2%83%E6%90%AD%E5%BB%BA/MQTT.fx.png) + + - 点击主界面小齿轮按钮进行相关服务器登录配置。如果是树莓派作为MQTT服务器的话这里的服务器地址就替换为在花生壳里添加映射的壳域名和分配的端口号(不是1883)。 +![](http://begild-one.top/%E6%A0%91%E8%8E%93%E6%B4%BE-%E4%BA%91%E6%9C%8D%E5%8A%A1%E5%99%A8-EMQTT-%E7%8E%AF%E5%A2%83%E6%90%AD%E5%BB%BA/MQTT.fx%E9%85%8D%E7%BD%AE.png) + - 点击小齿轮左边的连接列表,选择刚创建的连接。 + - 点击小齿轮右边的连接按钮进行连接服务器。连接成功后,下面的订阅和发布功能就都可以用了。 +3. 功能测试 + - MQTT.fx 点击切换到订阅(Subscribe)界面,在输入框输入需要订阅的主题,因为这里是作为客户端2当然是订阅`Hello_1`。订阅完成之后应该就可以在右下角的界面看到收到了客户端1每隔3s发过来的 `Hello! My Name is test_1` 。 + - MQTT.fx 切换到发布(Pubilsh)界面,在输入框输入需要推送消息的主题。因为树莓派运行客户端1订阅的是主题`Hello_2`所以这里输入`Hello_2`。在右侧选择消息通信的质量 Qos1 (保证至少一次送达),在下方输入框任意敲入字符。点击 Pubilsh 按钮进行发布。可以在树莓派端看到其接收到了来自`Hello_2`的消息。 + - 都能收发就测试成功了。 + +这里需要注意一下,如果订阅的主题就是发送的主题的话,自己也会收到自己发送的消息的。每个订阅了同一主题的客户端都能收到发布者的消息。 + +## 后记 +我发现记录过程可比实现还难,这我都断断续续写了一个星期了,记录了MQTT服务器的搭建、插件启动、配置文件修改、MQTT 客户端在树莓派上的安装和使用、两个客户端之间的通信。这一系列工作完成基本的远程通信功能就通了。 +后续再增加手机端 MQTT 客户端的开发(本来是打算用安卓 APP 的,后来想我做的 APP 界面惨不忍睹,已申请微信小程序明日开发)、通信协议制定、MCU 端的开发和硬件的制作,然后就可以远程控制了。我可真是个小机灵鬼。 diff --git a/_posts/树莓派—花生壳-内网穿透.md b/_posts/树莓派—花生壳-内网穿透.md new file mode 100644 index 0000000..facb12f --- /dev/null +++ b/_posts/树莓派—花生壳-内网穿透.md @@ -0,0 +1,103 @@ +--- +title: 树莓派-花生壳-内网穿透 +tags: + - 花生壳 + - 内网穿透 +categories: + - 树莓派 +password: 209445 +comments: true +abbrlink: 3ac023e7 +date: 2018-09-01 23:53:13 +images: http://begild-one.top/%E6%A0%91%E8%8E%93%E6%B4%BE-%E8%8A%B1%E7%94%9F%E5%A3%B3-%E5%86%85%E7%BD%91%E7%A9%BF%E9%80%8F/%E6%A0%91%E8%8E%93%E6%B4%BE+%E8%8A%B1%E7%94%9F%E5%A3%B3.png +--- +## 远程访问树莓派 +树莓派一般都是接在路由器下面的,当然是内网啦,在外面的时候是访问不了的,这时候就需要[内网穿透](http://service.oray.com/question/5571.html)才能实现外网依然能够访问到树莓派。内网穿透的软件网上有很多,这里选择花生壳,貌似挺有名的。 + +## 花生壳注册 +官网[https://hsk.oray.com/](https://hsk.oray.com/). +1. 打开之后在右上角有登录注册。 +2. 点击注册,同意隐私政策,填写账号密码手机号,按照正常流程走就OK了。貌似后续是会提示你进行实名制的,嫌麻烦可以不用实名制拍照上传啥的,不操作这一步。 +3. 注册成功会送你一个免费的花生壳域名用作以后使用,你也可以免费注册一个自定义的壳域名,不过后缀是指定的。 +![](http://begild-one.top/%E6%A0%91%E8%8E%93%E6%B4%BE-%E8%8A%B1%E7%94%9F%E5%A3%B3-%E5%86%85%E7%BD%91%E7%A9%BF%E9%80%8F/%E6%B3%A8%E5%86%8C%E6%88%90%E5%8A%9F.png) + +## 安装树莓派花生壳客户端 +下载最新安装包[https://hsk.oray.com/download](https://hsk.oray.com/download),选择树莓派下载。也可以通过SSH运行下面命令直接获得并安装。 +``` +cd /home/pi/Documents && mkdir hskoray && cd hskoray //创建下载目录 +wget https://hsk.oray.com/download/download?id=25 -O phddns_rapi.armhf.deb //下载 +sudo dpkg -i phddns_rapi.armhf.deb //安装 +``` +安装完毕会输出SN码和默认的登录密码,这个需要保存一下SN码,之后添加设备需要用到。 +``` +pi@BeGild_Raspi:~/Documents/hskoray $ sudo dpkg -i phddns_rapi_3.0.1.armhf.deb +正在选中未选择的软件包 phddns。 +(正在读取数据库 ... 系统当前共安装有 129540 个文件和目录。) +正准备解包 phddns_rapi_3.0.1.armhf.deb ... +正在解包 phddns (3.0.2) ... +正在设置 phddns (3.0.2) ... +2018-09-02 02:32:31 = Debug = [http_call] attempt to connect server: rapi.ephapi.oray.net/device/register +2018-09-02 02:32:31 = Debug = [http_call] create new stream because alive streams is empty. +2018-09-02 02:32:31 - Info - [http_call] connect server: rapi.ephapi.oray.net:443(121.40.234.27) + . Performing the SSL/TLS handshake... + ok + . Verifying peer X.509 certificate... + ok +2018-09-02 02:32:32 - Info - register ok +SN : RA***cac***4a4** +fastcode=2a868****b29e267****be05ee803a5 +SN : RA***cac***4a4** +2018-09-02 02:32:32 - Info - [Main] oraysl started as a daemon. +Phddns Service install success. + ++--------------------------------------------------+ +| Oray PeanutHull Linux 3.0 | ++--------------------------------------------------+ +| SN: RA***cac***4a4** Default password: admin | ++--------------------------------------------------+ +| Remote Management Address http://b.oray.com | ++--------------------------------------------------+ +正在处理用于 systemd (232-25+deb9u4) 的触发器 ... +pi@BeGild_Raspi:~/Documents/hskoray $ + +``` +其余的相关功能命令大致如下,可以通过输入`phddns` 获得。 +``` +sudo dpkg -r phddns //卸载花生壳 +phddns start(启动)| stop(停止)| restart(重启) +phddns status(状态)| version(版本)|reset(重置) +``` +日志保存在`/var/log/phddns`目录下。官方的教程见[花生壳 3.0 for 树莓派 安装使用攻略](http://service.oray.com/question/2680.html) + +## 绑定设备 +绑定需要先登录远程管理设备页面。点击[https://b.oray.com/](https://b.oray.com/),打开远程管理页面,输入刚生成的树莓派的SN码,输入默认密码admin进行登录。第一次登陆会让你完善信息填写手机号等信息。 +登录之后会提示你这个是内部的账号需要和你刚注册的账号进行”绑定”。点击`立即切换`即可切换到登录界面,输入你注册的账号和密码登录,设备自然就归属到你的名下了。 +[](http://begild-one.top/%E6%A0%91%E8%8E%93%E6%B4%BE-%E8%8A%B1%E7%94%9F%E5%A3%B3-%E5%86%85%E7%BD%91%E7%A9%BF%E9%80%8F/%E8%AE%BE%E5%A4%87%E7%BB%91%E5%AE%9A.png) + +## 开通内网穿透 +开通内网穿透体验版仅需6元,可以在绑定设备后在[设备管理界面](https://b.oray.com/forward/)点击左边侧栏的内网穿透进行开通. +![](http://upload-cdn.oray.com/upload/help/1806/201806251335371098.png) +也可以在[首页](https://hsk.oray.com/)左下角点击进入开通页面开通. +![](http://begild-one.top/%E6%A0%91%E8%8E%93%E6%B4%BE-%E8%8A%B1%E7%94%9F%E5%A3%B3-%E5%86%85%E7%BD%91%E7%A9%BF%E9%80%8F/%E5%BC%80%E9%80%9A%E5%86%85%E7%BD%91%E7%A9%BF%E9%80%8F.png) + +## ~~路由器打开DDNS~~ +emmm我看别人的教程都没说要设置DDNS了,但是我的不设置的话就不成功。所以这里有待考究[2018.10.04]这里找客服咨询过来,不需要设置路由器 DDNS ,不仅如此,如果设置了DDNS花生壳会提示账号重复登录的问题,之前不成功的原因是因为需要一定的刷新(映射?)时间。 +- 设置过程就是在浏览器输入路由器管理地址,一般就是`192.168.1.0`或者`192.168.1.1`,输入管理员密码登录,我的是TPLINK WR855N,是支持DDNS的。 +- 登录之后的页面里选择应用管理-> DDNS 进入,在服务提供者选择花生壳,输入自己的账号和密码勾选自动登录然后登录就OK了。 +- 对了这里建议使用路由器的IP和MAC地址绑定应用,将IP固定分配给树莓派,这样树莓派在内网的IP就固定了. +![](http://begild-one.top/%E6%A0%91%E8%8E%93%E6%B4%BE-%E8%8A%B1%E7%94%9F%E5%A3%B3-%E5%86%85%E7%BD%91%E7%A9%BF%E9%80%8F/TPLINK%E8%AE%BE%E7%BD%AEDDNS.png) + +## 添加端口映射 +开通了端口映射之后,在端口映射页面右边会出现一个增加端口映射的按钮。点击即可添加. +![](http://begild-one.top/%E6%A0%91%E8%8E%93%E6%B4%BE-%E8%8A%B1%E7%94%9F%E5%A3%B3-%E5%86%85%E7%BD%91%E7%A9%BF%E9%80%8F/%E6%B7%BB%E5%8A%A0%E7%AB%AF%E5%8F%A3%E6%98%A0%E5%B0%84.png) + +## 注册免费的自定义壳域 +注册了花生壳账号之后会给一个选一个自定义壳域名的机会。在设备管理页面点击侧边`我的域名`,左上角有个`注册壳域名`.点击之后进入注册界面,写一下自己喜欢的前缀在免费的后缀里选择一个,点击搜索,没有被别人注册的话就可以自注册了。 +用这个壳域名添加映射同样可以使用。 +## 验证访问 +打开SSH软件,新建一个连接填写主机地址(添加映射的壳域名),端口(花生壳为你分配的随机端口,在[设备管理页面](https://b.oray.com/)->内网穿透->映射列表->壳域名->后可以看到),输入登录账号pi和你的树莓派密码即可,双击新建的连接,能连接成功就是通了的。 +![](http://begild-one.top/%E6%A0%91%E8%8E%93%E6%B4%BE-%E8%8A%B1%E7%94%9F%E5%A3%B3-%E5%86%85%E7%BD%91%E7%A9%BF%E9%80%8F/%E5%85%AC%E7%BD%91SSH%E9%AA%8C%E8%AF%81.png) + +## 后记 +经过上面的一系列步骤树莓派已经可以在外网被访问了,这里端口映射添加的是SSH指定的22端口,当然你也可以根据需要指定其他的端口,不过免费版本的只支持两个端口映射。经过使用,这个为你分配的临时端口其实时间挺长的,不会几小时就变一次,两三天都不变一次的。 +可以下载官方的花生壳管理APP,[Android](https://hsk.oray.com/download/download?id=36)/[IOS](https://hsk.oray.com/download/download?id=37)进行管理和查看状态。 diff --git a/_posts/树莓派安装系统和配置.md b/_posts/树莓派安装系统和配置.md new file mode 100644 index 0000000..249d0a9 --- /dev/null +++ b/_posts/树莓派安装系统和配置.md @@ -0,0 +1,136 @@ +--- +title: 树莓派安装系统和配置 +tags: + - 树莓派安装系统 +categories: + - 树莓派 +password: 209445 +comments: true +abbrlink: fd8be0b3 +date: 2018-08-19 13:12:23 +images: http://begild-one.top/%E6%A0%91%E8%8E%93%E6%B4%BE%E7%B3%BB%E7%BB%9F%E5%AE%89%E8%A3%85%E5%92%8C%E9%85%8D%E7%BD%AE/%E6%A0%91%E8%8E%93%E6%B4%BE%E5%8A%A8%E5%9B%BE.gif +--- +最近打算玩一玩树莓派,感觉从毕业之后荒了蛮久没有新的东西注入了。其实有在考虑要不要记录这个安装的过程,因为其实教程已经漫天飞了,有重复造轮子之嫌。不过听说好记性不如烂笔头,记一下方便回顾也很有成就感不是吗?顺便说一下我的机器:树莓派3B+,因为穷,只买了裸板嘤嘤嘤。 + +## 下载树莓派系统 +1. 从官网的下载页面[https://www.raspberrypi.org/downloads/](https://www.raspberrypi.org/downloads/)可以看到树莓派支持的系统有好多种,这里下载官方的 RASPBIAN 系统,这个是基于 Debian 进行开发的。当然你也可以尝试一下 Ubuntu MATE 也蛮不错的。 +2. 点击大大的 PASPBIAN 图标可以进入选择下载 PASPBIAN DESKTOP 版还是 Mini 版。这里选择DESKTOP吧,安装好之后可以选择关闭视频输出用 VNC 远程桌面的。 +3. 点击 RASPBIAN STRETCH WITH DESKTOP 板块的[Download Zip](https://downloads.raspberrypi.org/raspbian_latest) 按钮即可开始下载。点击->[这里](https://downloads.raspberrypi.org/raspbian_latest)可以下载最新的桌面版 PASPIAN 系统。 +4. 下载完成之后就可以开始下一步了,不用解压,就保持为 zip 格式。 +## 安装烧录镜像的工具 Etcher +这个工具是linux macOS Windows都可以支持的,比起 Win32DiskImager来,长的还不错,界面也很简单(超级简单)。 +1. 去官网[https://etcher.io/](https://etcher.io/) 下载最新版本。 +2. 下载完毕之后安装,安装完毕打开就可以使用了。 +## 烧写系统镜像 +1. 选择你下载的系统镜像文件(.zip) +2. 选择你写的SD卡所在的盘符。 +3. 点击 Flash,等待进度的完成。 +![etcher使用](http://begild-one.top/%E6%A0%91%E8%8E%93%E6%B4%BE%E7%B3%BB%E7%BB%9F%E5%AE%89%E8%A3%85%E5%92%8C%E9%85%8D%E7%BD%AE/etcher%E4%BD%BF%E7%94%A8.gif) + +烧录完毕之后,SD卡会被分区为两个盘符,一个名字叫 boot(启动分区) 另一个叫 rootfs(根文件系统)。boot分区只有几十M,除去 rootfs 之外剩下的SD卡空间都是未被分配的状态所以 rootfs 只比系统大一点,等启动树莓派之后在树莓派的配置项里选择 SD 卡扩容把整个 SD 卡剩余空间合并到 rootfs 里。 +![](http://begild-one.top/%E6%A0%91%E8%8E%93%E6%B4%BE%E7%B3%BB%E7%BB%9F%E5%AE%89%E8%A3%85%E5%92%8C%E9%85%8D%E7%BD%AE/%E7%A9%BA%E9%97%B4%E6%9C%AA%E5%88%86%E9%85%8D.png) + +## 系统视频输出的配置 +这个配置是用于正确输出视频信号给显示器显示,树莓派会自动检测显示器属性自动调整的,当你的显示效果没有达到预期(HDMI->VGA)时可以通过手动配置一下。 +配置项在 /boot/config.txt文件里。打开该配置文件进行修改即可。 +关于配置的介绍可以在[这里](http://rpf.io/configtxt)看到。这里的配置需要贴合你显示器的属性,设置的教程可以参照->[自定义树莓派的显示分辨率](http://shumeipai.nxez.com/2013/08/31/custom-display-resolution-raspberry-pie.html) 进行显示器分辨率`hdmi_mode`的调整。我的显示器是2K屏,计算机显示器,配置项如下。 +``` +# uncomment if you get no picture on HDMI for a default "safe" mode +hdmi_safe=1 +# uncomment this if your display has a black border of unused pixels visible +# and your display can output without overscan +disable_overscan=1 +# uncomment if hdmi display is not detected and composite is being output +hdmi_force_hotplug=1 +# uncomment to force a specific HDMI mode (this will force VGA) +hdmi_group=2 +hdmi_mode=76 +hdmi_ignore_edid=0xa5000080 +# uncomment to force a HDMI mode rather than DVI. This can make audio work in +# DMT (computer monitor) modes +hdmi_drive=2 +# uncomment to increase signal to HDMI, if you have interference, blanking, or +# no display +config_hdmi_boost=4 +``` +配置完毕,插上SD卡、hdmi线、电源即可看到树莓派启动,如果使用的是HDMI转VGA为了保证视频的稳定这里最好使用单独电源供电的转换头。开机显示如下: +![](http://begild-one.top/%E6%A0%91%E8%8E%93%E6%B4%BE%E7%B3%BB%E7%BB%9F%E5%AE%89%E8%A3%85%E5%92%8C%E9%85%8D%E7%BD%AE/%E6%A0%91%E8%8E%93%E6%B4%BE%E5%BC%80%E6%9C%BA.jpg) + +## 系统选项配置 +插上鼠标键盘,启动系统之后打开终端,输入`sudo raspi-config`命令即可进行配置,界面如下。 +![](http://begild-one.top/%E6%A0%91%E8%8E%93%E6%B4%BE%E7%B3%BB%E7%BB%9F%E5%AE%89%E8%A3%85%E5%92%8C%E9%85%8D%E7%BD%AE/raspi-config.jpg) +配置界面的详细说明如下: +``` +1. 修改登录密码。 +2. 网络选项: + 1. 树莓派在网络上的名字(在路由器管理界面可以看到) + 2. WIFI名称和密码 + 3. 网络是否可以被探测。 +3. 启动选项: + 1. 启动选择桌面还是控制台,控制台就没有界面黑乎乎的。 + 1. 控制台不自动登录 + 2. 控制台自动登录 + 3. 桌面环境不自动登录 + 4. 桌面环境自动登录 + 2. 是否在启动是等待网络连接完成。 + 3. 是否启用画面过渡。用画面过渡开机过程,还是使用文本过渡(开机的时候刷刷刷的文本启动信息)。 +4. 本地化选项: + 1. 选择语言。在弹出的列表里上下移动直至找到 zh_CN.UTF-8 UTF-8。空格进行选择,回车进行确认。 + 2. 选择时区。Etc + 3. 选择键盘布局。国际标准105键。 + 4. 选择WIFI地区。CN-China +5. 接口选项:这里主要是树莓派对外的接口功能使能。 + 1. 摄像头。选择是否使用摄像头。根据需要选择使能。 + 2. SSH。选择是否启用SSH进行远程连接。选择使能。 + 3. VNC.选择是否启用VNC作为远程桌面连接。根据需要选择使能。 + 4. SPI。选择是否启用SPI接口。根据需要选择使能。 + 5. IIC。选择是否启用IIC接口。根据需要选择使能。 + 6. 串口Serial。选择是否启用串口。根据需要选择使能。 + 7. 1-Wire。选择是否启用单线接口。根据需要选择使能。 + 8. Remote GPIO。选择是否允许远程控制GPIO。根据需要选择使能。 +6. 超频选项:CPU超频。 +7. 高级选项: + 1. 扩展SD卡文件系统,也就是在刷入树莓派系统时候会有没分配的空闲空间,通过这个选项就可以将SD卡完全整合起来。 + 2. 过扫描选项。如果显示器显示有黑边可以开启这个选项。关于过扫描可以看http://bbs.a9vg.com/thread-2358167-1-1.html。 + 3. 修改显卡可用内存大小。默认值64 + 4. 声音选项。选择声音的输出方向。 + 1. 自动。根据有效的输出源输出。 + 2. 通过3.5耳机接口输出 + 3. 通过HDMI传输音频。 + 5. 分辨率选项。选择特定的分辨率作为输出视频的分辨率。根据显示器配置进行选择。 + 6. 像素点加倍选项。选择是否将像素进行2*2映射。我选择之后画面显示不全,很模糊。不知道干嘛用的感觉像是分辨率变低了。 + 7. Open GL驱动选项。选择是否启用open GL桌面驱动程序。这个是硬件加速的选项,如果使用桌面可以选择启用该功能。这个选项我其实并没有什么感觉,没有试过。可以看下https://www.jianshu.com/p/2438d2c76cdb。 + 1. Full KMS 这个效率更高全部通过内核直接输出,但是兼容性差一些,遇到一些远程桌面软件可能会出问题。 + 2. FAKE KMS 该选项兼容性好一些。 + 3. 使用软件渲染。不使用Open GL。 +8. 升级。检查升级系统。 +9. 关于树莓派配置工具的说明。 +``` +我用的系统2018-06-27-raspbian-stretch是可以通过桌面左上角的小树莓图标->首选项->树莓派配置进行配置的。 +配置完毕之后选择 Finish 按钮进行重启,生效更改。 +我的配置大致如下: + 修改登录密码、使用控制台自动登录、启用 SSH 和 VNC 、不超频、扩展SD卡、不进行像素点加倍、不使用Open GL(不好意思我只用SSH连接),另外GPU内存我就按照的默认64M来,之后需要再修改吧。 +## 安装中文输入法 +虽然之后都是使用SSH进行连接,但是!!!偶尔使用桌面时依然不能忍受没有中文的情况啦。运行下面的三条命令进行安装,最后使用reboot重启系统生效更改。通过 ctrl+space 可以切换。 +``` +sudo apt-get install fcitx #安装 fctix 输入法框架 +sudo apt-get install fcitx-pinyin # 安装fcitx拼音 +sudo apt-get install fcitx-googlepinyin # 安装google拼音 +``` +这样就完成了树莓派个性化的配置啦。 +## 使用SSH进行树莓派的连接 +这里推荐使用Finall shell这个远程连接软件。可以实时监控CPU、内存、磁盘等的使用,可以有命令历史,自动补全等。免费版本已经够使用了。 +1. Windows 点击[下载](http://www.hostbuf.com/downloads/finalshell_install.exe)Finall shell最新版本。官网:[http://www.hostbuf.com/](http://www.hostbuf.com/)。官网看起来毫无美感,胜在简单没有广告. +2. 下载之后运行安装。安装完毕打开软件。可以看到一个右边是一些图表栏,用于显示当前系统一些信息。右边是命令行窗口,下面是远程文件管理系统可以用来传输文件。 +3. 点击右上角文件夹样式的小图标打开连接管理器,点击左上角白色文件夹加号建立一个SSH连接。 + 1. 输入连接名称(标识,方便查看比如:树莓派)。 + 2. 主机,填入树莓派的IP地址。 + - 这里可以用树莓派运行 `ifconfig` 命令查看ip地址,应该是`192.168.1.*` + - 也可以通过浏览器输入`192.168.1.1��?92.168.1.0` 进入路由器管理界面查看树莓派的IP地址。 + 3. 端口默认22.方法使用密码,用户名为 pi (树莓派默认用户名),密码为你的登录密码。 + 4. 点击`确定`建立连接成功。 +4. 双击新建的连接进行连接,会在主窗口的右边命令行栏新建一个连接分页,连接成功就能看到大致如下的界面。 +![](http://begild-one.top/%E6%A0%91%E8%8E%93%E6%B4%BE%E7%B3%BB%E7%BB%9F%E5%AE%89%E8%A3%85%E5%92%8C%E9%85%8D%E7%BD%AE/SSH%E8%BF%9E%E6%8E%A5%E6%A0%91%E8%8E%93%E6%B4%BE.png) +5. 软件的其他个性化配置自行摸索,大致有命令行主题,颜色等的配置吧。点击软件右上角的三条横线图标->选项可以找到。 +## 后记 +这样就完成树莓派的基本配置和使用了,利用 SSH 整个树莓派只需要连接一根USB电源线就可以愉快的玩耍了,当然这里的电源适配器一定要稳定电流足量(2A以上),不要拿那种10块钱包邮的电源适配器。 diff --git a/_posts/测试编译器是否支持嵌套注释.md b/_posts/测试编译器是否支持嵌套注释.md new file mode 100644 index 0000000..f553f4b --- /dev/null +++ b/_posts/测试编译器是否支持嵌套注释.md @@ -0,0 +1,123 @@ +--- +title: 测试编译器是否支持嵌套注释 +date: 2017-10.1 00:16:47 +tags: + - 嵌套注释 +categories: + - c语言 +abbrlink: a56a64b5 +--- + +问题:某些C编译器允许嵌套注释。请写一个测试程序,要求:无论是对允许嵌套注释的编译器,还是对不允许嵌套注释的编译器,该程序都能正常通过编译(无错误消息出现), 但是这两种情况下程序执行的结果却不相同。 + +提示: 在用双引号括起的字符串中, 注释符 /* 属于字符串的一部分,而在注释中出现的双引号 " " 又属于注释的一部分。 + +出自——《C陷阱与缺陷》练习1-1 + + + +嵌套注释:顾名思义就是注释里嵌套着注释。比如 +```C +/*"/*"*/"*/ +``` +对于这段代码,不同的编译器识别的结果不同: + +![](https://s1.ax1x.com/2017/10/01/13Ezn.png) + + +我们如何通过代码的输出判定编译器是否支持嵌套注释呢,重点就是让同一段代码,支持嵌套注释的编译器和不支持嵌套注释的编译器注释掉不同的地方。根据题目的提示字符串中的 /\* 是属于字符串的一部分,比如 "/\*aa\*/" 这里面的注释标号编译器是不会理会的,而 /\*"aa\*"/ 这里面的 "aa" 是不会识别为字符串的。还有一点无论是 " " 还是 /\*\*/都是就近匹配的。 + + +- 1. 我们首先构建一个嵌套的注释,这个注释在**支持**嵌套注释的编译器里能编译通过,而在**不支持**的编译器里编译失败: +```C +/*"/*"*/"*/ +``` +不支持的系统中出现了"\*/"导致编译失败 + +![](https://s1.ax1x.com/2017/10/01/13Ezn.png) + + +- 2. 我们通过添加一个 " 使得不支持的系统编译成功 +```C +/*"/*"*/"*/" +``` +![](https://s1.ax1x.com/2017/10/01/13KdU.png) + + +- 3. 可以看出这样添加之后不支持的编译器已经能编译成功并且有输出一字符串,支持的系统由于多了一个 " 导致编译失败,根据题目提示我们构建一个字符串" "并且"/\*,\*/" 两两配对,所以我们添加一个 /\*形成"/\*" +```C +/*"/*"*/"*/"/*" +``` +![](https://s1.ax1x.com/2017/10/01/13MoF.png) + + +- 4. 这样操作之后支持/不支持的编译器输出不同的字符串(蓝色部分),但是不支持的编译器多了 /\* "编译失败,而它刚好又是多行注释的头,所以我们得加一个尾 \*/ 使得他们配对。 +```C +/*"/*"*/"*/"/*"*/ +``` +![](https://s1.ax1x.com/2017/10/01/13li4.png) + + +- 5. 我们从上图可以看出不支持嵌套注释的编译器已经能通过编译并且有区别去支持嵌套注释的编译器的输出。但是支持嵌套注释的编译器由于多了\*/导致编译失败,因为不支持嵌套注释的编译器的注释之间无论是什么都可以忽略,所以我们在最后的 \*/ 之前加一个 /\* 让支持嵌套注释的编译器能找到配对的注释对。 +```C +/*"/*"*/"*/"/*"/**/ +``` +![](https://s1.ax1x.com/2017/10/01/131JJ.png) + + +通过上述步骤我们找到了一个合适的语句使得在两种编译器中编译成功并且有不同的输出。 + +![](https://s1.ax1x.com/2017/10/01/133W9.png) + +通过一段简单的代码我们可以看下效果 + +```c +#include +int ISSupNestComment(void); +int main() +{ + printf("This compiler %s support nested comment \r\n", + ISSupNestComment()? "": "does not"); + return 0; +} + +int ISSupNestComment() +{ + char *Str=/*"/*"*/"*/"/*"/**/; + if(Str[0]=='*')//"*/"不支持嵌套注释 + return 0; + else //"/*"支持嵌套注释 + return 1; +} + +``` + + +自己做完这个感觉还是有点意思的,上网搜了一波,发现别人想的更是精妙。不禁发出一套赞赏三连,卧槽牛逼666。下面我们看下一大佬们是怎么做的。 + +# 1.Doug McIlroy +```C +/*/*/0*/**/1 +``` + 这个解法主要利用了编译器作词法分析时的“大嘴法”规则。编译器支持嵌套注释,则上式将被解释为**1**.编译器不支持嵌套注释,则上式将被解释为 **0\*1**. + +![](https://s1.ax1x.com/2017/10/01/135Wj.png) + +# 2.[TimWu](http://www.cppblog.com/Tim/archive/2011/03/25/142726.html) + +```c +#define A /* aaa /* a*/ a +#define B */ + +bool CanNesting() +{ +#ifdef B + return false; +#else + return true; +#endif +} +``` +他利用的多行注释和宏定义的特性,编译器支持嵌套注释宏定义B则会被注释掉导致没有宏定义B。编译器不支持嵌套注释,宏定义B则会定义为 \*/。通过预编译判断就可以输出结果。 + +![](https://s1.ax1x.com/2017/10/01/13OTU.png) diff --git a/about/@eaDir/index.md@SynoEAStream b/about/@eaDir/index.md@SynoEAStream new file mode 100644 index 0000000..3ca65d3 Binary files /dev/null and b/about/@eaDir/index.md@SynoEAStream differ diff --git a/about/index.md b/about/index.md new file mode 100644 index 0000000..41c6b5f --- /dev/null +++ b/about/index.md @@ -0,0 +1,5 @@ +--- +title: 关于博主 +date: 2017-09-13 16:30:45 +comments: true +--- \ No newline at end of file diff --git a/categories/@eaDir/index.md@SynoEAStream b/categories/@eaDir/index.md@SynoEAStream new file mode 100644 index 0000000..1bc9e7f Binary files /dev/null and b/categories/@eaDir/index.md@SynoEAStream differ diff --git a/categories/index.md b/categories/index.md new file mode 100644 index 0000000..66cbe92 --- /dev/null +++ b/categories/index.md @@ -0,0 +1,5 @@ +title: "分类页" +date: 2018-01-20 12:35:50 +type: "categories" +comments: false +--- \ No newline at end of file diff --git a/collection/@eaDir/index.md@SynoEAStream b/collection/@eaDir/index.md@SynoEAStream new file mode 100644 index 0000000..3949019 Binary files /dev/null and b/collection/@eaDir/index.md@SynoEAStream differ diff --git a/collection/index.md b/collection/index.md new file mode 100644 index 0000000..2e9dfde --- /dev/null +++ b/collection/index.md @@ -0,0 +1,11 @@ +--- +title: 收藏的一些网址和资源 +comments: true +date: 2018-03-05 20:40:50 +images: +--- + +### - Emoji表情网址(🐰😀👻😼❤️🚔): + [https://www.emojicopy.com/](https://www.emojicopy.com/) +### - fontawesome图标(): + [http://fontawesome.dashgame.com/](http://fontawesome.dashgame.com/) \ No newline at end of file diff --git a/img/ESP8266_Develop/@eaDir/ESP8266导入工程1.png@SynoEAStream b/img/ESP8266_Develop/@eaDir/ESP8266导入工程1.png@SynoEAStream new file mode 100644 index 0000000..642479b Binary files /dev/null and b/img/ESP8266_Develop/@eaDir/ESP8266导入工程1.png@SynoEAStream differ diff --git a/img/ESP8266_Develop/@eaDir/ESP8266导入工程2.png@SynoEAStream b/img/ESP8266_Develop/@eaDir/ESP8266导入工程2.png@SynoEAStream new file mode 100644 index 0000000..bc478a9 Binary files /dev/null and b/img/ESP8266_Develop/@eaDir/ESP8266导入工程2.png@SynoEAStream differ diff --git a/img/ESP8266_Develop/@eaDir/ESP8266导入工程3.png@SynoEAStream b/img/ESP8266_Develop/@eaDir/ESP8266导入工程3.png@SynoEAStream new file mode 100644 index 0000000..e4d5595 Binary files /dev/null and b/img/ESP8266_Develop/@eaDir/ESP8266导入工程3.png@SynoEAStream differ diff --git a/img/ESP8266_Develop/@eaDir/ESP8266导入工程4.png@SynoEAStream b/img/ESP8266_Develop/@eaDir/ESP8266导入工程4.png@SynoEAStream new file mode 100644 index 0000000..6d880de Binary files /dev/null and b/img/ESP8266_Develop/@eaDir/ESP8266导入工程4.png@SynoEAStream differ diff --git a/img/ESP8266_Develop/@eaDir/ESP8266工程裁剪和编译1.png@SynoEAStream b/img/ESP8266_Develop/@eaDir/ESP8266工程裁剪和编译1.png@SynoEAStream new file mode 100644 index 0000000..ce78562 Binary files /dev/null and b/img/ESP8266_Develop/@eaDir/ESP8266工程裁剪和编译1.png@SynoEAStream differ diff --git a/img/ESP8266_Develop/@eaDir/ESP8266工程裁剪和编译2.png@SynoEAStream b/img/ESP8266_Develop/@eaDir/ESP8266工程裁剪和编译2.png@SynoEAStream new file mode 100644 index 0000000..3574bf9 Binary files /dev/null and b/img/ESP8266_Develop/@eaDir/ESP8266工程裁剪和编译2.png@SynoEAStream differ diff --git a/img/ESP8266_Develop/@eaDir/ESP8266工程裁剪和编译3.png@SynoEAStream b/img/ESP8266_Develop/@eaDir/ESP8266工程裁剪和编译3.png@SynoEAStream new file mode 100644 index 0000000..b5c15f7 Binary files /dev/null and b/img/ESP8266_Develop/@eaDir/ESP8266工程裁剪和编译3.png@SynoEAStream differ diff --git a/img/ESP8266_Develop/@eaDir/ESP8266开发环境搭建过程1.png@SynoEAStream b/img/ESP8266_Develop/@eaDir/ESP8266开发环境搭建过程1.png@SynoEAStream new file mode 100644 index 0000000..0dc276e Binary files /dev/null and b/img/ESP8266_Develop/@eaDir/ESP8266开发环境搭建过程1.png@SynoEAStream differ diff --git a/img/ESP8266_Develop/@eaDir/ESP8266开发环境搭建过程2.png@SynoEAStream b/img/ESP8266_Develop/@eaDir/ESP8266开发环境搭建过程2.png@SynoEAStream new file mode 100644 index 0000000..e690757 Binary files /dev/null and b/img/ESP8266_Develop/@eaDir/ESP8266开发环境搭建过程2.png@SynoEAStream differ diff --git a/img/ESP8266_Develop/@eaDir/乐鑫SDK下载.png@SynoEAStream b/img/ESP8266_Develop/@eaDir/乐鑫SDK下载.png@SynoEAStream new file mode 100644 index 0000000..63bc983 Binary files /dev/null and b/img/ESP8266_Develop/@eaDir/乐鑫SDK下载.png@SynoEAStream differ diff --git a/img/ESP8266_Develop/ESP8266导入工程1.png b/img/ESP8266_Develop/ESP8266导入工程1.png new file mode 100644 index 0000000..011cd7f Binary files /dev/null and b/img/ESP8266_Develop/ESP8266导入工程1.png differ diff --git a/img/ESP8266_Develop/ESP8266导入工程2.png b/img/ESP8266_Develop/ESP8266导入工程2.png new file mode 100644 index 0000000..1acf95d Binary files /dev/null and b/img/ESP8266_Develop/ESP8266导入工程2.png differ diff --git a/img/ESP8266_Develop/ESP8266导入工程3.png b/img/ESP8266_Develop/ESP8266导入工程3.png new file mode 100644 index 0000000..7b5ef18 Binary files /dev/null and b/img/ESP8266_Develop/ESP8266导入工程3.png differ diff --git a/img/ESP8266_Develop/ESP8266导入工程4.png b/img/ESP8266_Develop/ESP8266导入工程4.png new file mode 100644 index 0000000..4e8bd69 Binary files /dev/null and b/img/ESP8266_Develop/ESP8266导入工程4.png differ diff --git a/img/ESP8266_Develop/ESP8266工程裁剪和编译1.png b/img/ESP8266_Develop/ESP8266工程裁剪和编译1.png new file mode 100644 index 0000000..554d33b Binary files /dev/null and b/img/ESP8266_Develop/ESP8266工程裁剪和编译1.png differ diff --git a/img/ESP8266_Develop/ESP8266工程裁剪和编译2.png b/img/ESP8266_Develop/ESP8266工程裁剪和编译2.png new file mode 100644 index 0000000..1fabfa4 Binary files /dev/null and b/img/ESP8266_Develop/ESP8266工程裁剪和编译2.png differ diff --git a/img/ESP8266_Develop/ESP8266工程裁剪和编译3.png b/img/ESP8266_Develop/ESP8266工程裁剪和编译3.png new file mode 100644 index 0000000..9c35f14 Binary files /dev/null and b/img/ESP8266_Develop/ESP8266工程裁剪和编译3.png differ diff --git a/img/ESP8266_Develop/ESP8266开发环境搭建过程1.png b/img/ESP8266_Develop/ESP8266开发环境搭建过程1.png new file mode 100644 index 0000000..1819f5b Binary files /dev/null and b/img/ESP8266_Develop/ESP8266开发环境搭建过程1.png differ diff --git a/img/ESP8266_Develop/ESP8266开发环境搭建过程2.png b/img/ESP8266_Develop/ESP8266开发环境搭建过程2.png new file mode 100644 index 0000000..6876235 Binary files /dev/null and b/img/ESP8266_Develop/ESP8266开发环境搭建过程2.png differ diff --git a/img/ESP8266_Develop/乐鑫SDK下载.png b/img/ESP8266_Develop/乐鑫SDK下载.png new file mode 100644 index 0000000..2a7e363 Binary files /dev/null and b/img/ESP8266_Develop/乐鑫SDK下载.png differ diff --git a/img/endian/@eaDir/查看存储内容.png@SynoEAStream b/img/endian/@eaDir/查看存储内容.png@SynoEAStream new file mode 100644 index 0000000..71a6c36 Binary files /dev/null and b/img/endian/@eaDir/查看存储内容.png@SynoEAStream differ diff --git a/img/endian/查看存储内容.png b/img/endian/查看存储内容.png new file mode 100644 index 0000000..f6a6a85 Binary files /dev/null and b/img/endian/查看存储内容.png differ diff --git a/img/favicon.ico b/img/favicon.ico new file mode 100644 index 0000000..0c3bab7 Binary files /dev/null and b/img/favicon.ico differ