利用Matlab的simulink搭建模型生成C代码,通过stm32cubemx生成工程,最后在KEIL或者IAR等工具里面编译生成代码下载至MCU中执行。
本文以流水灯建立模型和简单使用定时器为例进行演示。
Matlab版本建议在2013B以上,本文使用Matlab 2016a。
下载地址(https://www.stmcu.org.cn/document/detail/index/id-216053)
安装完成后重启MATLAB。官网文档中提到,当前只支持F4和F3部分系列,F1系列生成代码后编译可能会报错,本文使用STM32-MAT版本V4.3.0。
用于配置单片机硬件资源,下载地址(https://www.stmcu.org.cn/document/detail/index/id-214984)
用于配置工程文件。
选择“access to MCU selector”
以STM32F103R6为例。如果搜索不到,那么可能需要下载安装库文件
下载对应的库文件即可。
搜索到芯片后,选中点击“Start Project”,进入配置界面。
这里选择HSE,使用外部晶振
选择PA1-5作为LED灯。引脚状态选择为输出。
再根据硬件设计,配置IO上拉还是下拉。
选择最大72MHz。
输入工程文件信息
选择生成的工程文件,如果是KEIL,那么选择“MDK-ARM V5”。
最后保存即可。
打开MATLAB,首先配置MATLAB搜索路径。
将STM32-MAT的安装路径添加进来。
添加完成后将MATLAB当前工作路径修改为第三步中IOC文件位置,默认是在Matlab安装位置,不修改的话后面生成代码的时候会报错。
最后建议重启一下MATLAB。
新建一个空白模型。
打开配置界面
选择stm32.tlc。
解算器(Solver)选项默认为固定步长,即“Fixed-step”,然后修改步长为1/10000,即0.1ms。也可以根据实际情况修改,默认为auto可能会导致程序运行时无法显示出效果。
添加代码注释
Simulink配置完成后就可以自己搭建模型。
选择MCU config,将右侧模块拖动至刚刚新建的空白模型。
双击刚刚拖出来的模块,进入配置界面,选择第三步生成的IOC文件。
同样拖动至SIMULINK,双击该模块配置IO引脚,可以看到我们在cubemx里面配置的IO,勾选要打开的IO,点击确认即可。
使用”Counter Free-Running”模块进行计数,参数配置如下
此配置的意思为每0.5秒计数一次,计数的最大值为2^Nbits – 1,其中Nbits为所填的2,所以这里最大值为3。
示波器显示和预期值一致。
然后通过一个关系比较符,当计数值分别等于0,1,2,3,时,相应的GPIO输出为1。
示波器仿真结果如图
最后模型如图所示
模型设计完成后,仿真结果无误,就可以进行代码生成。按“Ctrl+B”或者如图所示点击,进行代码生成。
最后生成工程目录如下
“stmDemo_stm32”目录为matlab生成的原始代码。
IOC文件为stm32cubemx工程文件。
Slx文件为simulink模型文件。
其他的为KEIL工程中的代码。
打开工程,代码编译完成后,下载程序到目标板。
这里使用proteus进行仿真,仿真中流水灯切换速度为5秒,比预定的时间0.5秒慢了10倍,仿真提示” Simulation is not running in real time due to excessive CPU load.”,说明仿真时单片机运行速度不是实时的。
为了进一步验证,再使用一个定时器进行让LED5以1Hz的频率闪烁。配置如下:
模型如下:
生成代码后编译报错,原因为F1系列的库函数中”__HAL_TIM_SetAutoreload”该函数未定义成” __HAL_TIM_SET_AUTORELOAD”。
而在F4系列的库函数中是有该定义的,编译不会报错。
因此生成的代码无法正常使用定时器,除非修改生成后的代码,这样并不是我们想要的。
最后以F429单片机为例,重新生成代码下载到单片机进行验证。IOC文件中,时钟配置为180MHz,其他步骤同第三~六步。
代码生成完成后对工程进行配置,设置程序下载完成后重置运行,下载器根据实际情况设置为”CMSIS-DAP-Debugger”。
编译完成下载至单片机中,看是否满足设计要求。
经过验证该代码无误。
生成代码后,由于使用了systick(系统定时器),但是生成的代码中没有对其进行调用,所以需要在stm32f4xx_it.C中手动添加一行代码,否则程序可能无法正常运行。添加的代码为:HAL_SYSTICK_IRQHandler();
该问题具体原因未知,可能和stm32cubemx配置或者版本有关。
!
建议生成代码之前,将matlab工作路径指定到IOC文件位置,同时将SLX文件也放在同一个文件夹下,这样方便工程管理。
在STM32-MAT安装路径下还有更多示例以及使用说明。
Invalid index. Component:Simulink | Category:Block diagram error
matlab2018b中生成代码时出现上述问题
解决方法如下:
在simulink设置选项“hardware implementation”中把设备STM改为“custom processor”
总的来说该方法生成底层代码较复杂,而且配置繁琐。当然优点是基本不需要修改生成的代码,但实际上未能节省太多时间。
MATLAB自动生成的代码是标准的C代码,支持所有的MCU。因此建议在实际开发中能在Simulink环境下仿真的部分,通过Simulink实现;对于单片机底层这类没法在Simulink下仿真的软件,不应该打包到Simulink环境下。
]]>如下图所示:
代码文件简介:
该文件中会调用 “模型名称_step();”函数,用于单步执行,可以根据实际情况放在定时器中断或者任务调度里面执行该函数。
除此之外,该文件中的main函数会初始化模型,调用“模型名称_initialize();”函数。该函数实际使用时也必须在模型执行前初始化。
在实际使用时该文件不必添加进工程。
该文件是根据模型生成的代码,包含“模型名称_step();”函数,“模型名称_initialize();”函数,“模型名称_terminate(void);”函数。
该文件包含模型中的模块数据结构定义。
该文件包含模型中的私有变量,主要是声明的全局变量。
该文件包含模型中的结构体定义。
该文件夹中的文件是一些乘除法的函数方法,需要添加至工程中。文件在./slprj/ert/_sharedutils目录中。
该文件夹中是在配置中的source files,如图所示。需要添加至工程中进行编译。
模型中使用C CALLER或者S-Function模块调用C文件中的函数时,需要将对应的文件添加至simulation target中。
这种情况生成的代码报告在下图所示中。
生成的代码在./slprj/ert目录下,对应的模型名称的文件夹中,生成代码后要在编译环境如KEIL中添加对应的搜索路径。
)
采用数据字典定义我们的数据结构便于管理,如要想使用全局变量,存储类型要选“importedExtern”,生成的代码会在.h文件中进行声明。
如果是定义全局变量,要选择“exportedGlobal”。
调用如下图所示
如下图所示,如果是数组,在dimensions中可以输入[1 8]。
调用如下图所示:
这里选中信号名称和模型信号对象绑定,生成的代码输出也将使用对应的信号对象名称。如果是全局变量可以方便在其他地方调用。
实际使用过程中,通常会对不同的模块按不同的间隔执行,也就是任务调度,比如taskA需要10ms间隔执行,taskB需要100ms时间间隔执行,所以这里我们利用“Function-Call Generator”模块配合状态机实现任务调度。分别实现10ms、100ms、200ms的任务调度。
Function-Call Generator”模块中的采样时间设为1,不使用小数,提高计算精度,实际调用的时候1ms执行一次本模块。
状态机的模型如下:
设置对应的输入输出事件,如下图。
实际测试结果无误。
在模型设计过程中,可能会出现这样的需求,比如ECU上电后,从EEPROM读出上次断电前保存的数据,而且只赋值一次,后续使用新计算的值。
如下图所示,上电后从EEPROM读取的值是SOC_From_EE,然后需要进行第一次累加,不然第一次的值是0,又要从0开始累加,并不是上次断电后的值。
这里首先想到的是使用IC模块赋值,如下图所示。
但是IC模块的参数不能是变量,所以放弃了这种操作,使用状态机来进行。
状态机如下图所示:使用一个IF-ELSE模块,上电init_i=0,初始化一次,然后init_i置1,不再执行SOC_From_EE赋值。
下图为状态机的数据和事件。
生成的代码如下:
使用data store memory进行局部变量的存储。
然后使用data store write将变量存储,data store read读出变量。
生成的代码如下:
最近在学习ESP8266,所以想用他来做个小玩意儿。
于是就有了这篇文章,其实最终实现的效果很简单。
就是当门铃按键按下,微信会收到消息提醒。
当然这只是初期,拓展的话可以进一步设计一套协议,添加更多设备,比如开关或者插座之类的电器设备。
添加用户绑定功能,实现数据双向通信。
下面介绍怎么完成他。
我选择的是nodemcu。因为他可以直接用micro usb烧录,下载程序方便。实质上他就是一块ESP8266.
本来准备外接一个按键的,结果发现nodemcu上面自带了两个按键,一个复位键,一个flash键。
因为是做门铃,所以暂时不需要杜邦线和按键了,一个安卓充电线当做下载线就可以了。
nodemcu原生是lua脚本来开发,但是我还是习惯用C来开发。
于是我的开发环境就是VS2015+visual micro
。
软件环境的搭建,可以见我博客的前几篇文章。
arduino IDE配置ESP8266开发环境
https://blog.rayuu.com/arduinoesp8266.html
使用VS2015 visual micro安装开发arduino
https://blog.rayuu.com/vs2015arduino.html
单片机部分:nodemcu采用C来编写;
后台:linux平台下使用python来写;
数据库:待定。
通信协议:基于MQTT+私有协议。
初期计划实现步骤大致如下:
用户在开机前3秒内按下flash key,系统进入flash模式。
在该模式下,esp8266是AP模式,会生成一个wifi热点。名称为smledart_xxxxx xxxxx为芯片ID。
用户连接该热点后,打开浏览器,输入192.168.4.1
打开配置wifi界面
输入正确的wifi热点和密码,即你家里的可以上网的wifi热点。
服务器地址和端口,后续不会对用户开放。这里仅供测试用。
另外后续可能采用通过smartconfig方式来连接wifi。即通过手机发送UDP报文出来,esp8266通过搜索报文自动建立连接。
配置完成后,重启esp8266即可。
热点名称,密码,服务器IP和端口,设备信息等信息 存在flash内,用文件系统spiffs来挂载读写。
网页同样用文件系统保存,用html,js,css来编写网页
开机,等5~6秒后,esp8266连上第一步配置的wifi后,同时也会连上服务器。
这时就可以正常使用了。
按下flashkey后,微信就会收到相应的消息了。这里按下flashkey不同于开机前三秒按下进入flash模式。
最后放上录的小视频。
]]>参考链接:http://www.52pojie.cn/forum.php?mod=viewthread&tid=460921 visual micro爆破
在安装目录下搜索
Visual.Micro.Processing.Sketch.dll
把它复制出来先备份。
然后 relfector 打开这个dll,
Visual.Micro.Utils.LicenseShared 下有一个 ProductActivated(String) : Boolean
选中,然后再打开“tools”,选中reflexil v2.1具体版本无所谓
插件链接分享
链接:http://pan.baidu.com/s/1cAjM5w 密码:v2hk
这是reflexil 2.1插件,点击工具tools addins就可以添加了。
添加完成后如下图;
右下角会加载出下图所示:
在上图空白处点右键,选中replace all with code,把activationmanager里面改为
return true
最后左下角点击compile编译,再点击ok.并保存
就会出现一个
Visual.Micro.Processing.Sketch.Patched.dll
把这个dll在原目录下替换为原来的就可以了。 名称需要和原来的一样。这样就不会提示注册了。
]]>安装arduino IDE for visual studio.
配置一下arduino ide的目录即可马上使用。
在菜单栏“文件”下面点“新建”,会出现一个arduino project选项。
然后输入工程名称即可新建工程。
选板子型号和串口。
如果不想下载程序后调试,就可以关闭automatic debugging.
具体操作如下图:
在菜单栏“工具”->“选项”,也可以配置visual micro
至于这个debugger调试不是很方便,只能在loop那里断点,查看变量参数。
编译生成的HEX文件在debug或者release下面。
这个visual micro的破解方法见另一篇文章。
]]>[TOC]
#include int main() { printf("Hello! This is our embedded world!\n"); return 0; }
在该阶段,对包含的头文件(#include
)和宏定义(#define
、#ifdef
等)进行处理。
可以通过gcc -E
选项进行查看。该选项的作用是让gcc 在预处理结束后停止编译过程。
gcc -E hello.c -o hello.i
-o
是指目标文件。 .i
文件为经预处理后的C程序。
gcc -S hello.i -o hello.s
上述命令只进行编译不进行汇编,结果生成汇编代码。
在编译阶段,gcc首先要检查代码的规范性、是否有语法错误。
汇编阶段把编译阶段生成的.s文件转成目标文件。
gcc -c hello.s -o hello.o
把汇编代码转为二进制目标代码。
链接时gcc会到系统默认的搜索路径/usr/lib
下进行查找动态库。
函数库用动态库和静态库两种。
静态库是指编译链接时,将库文件的代码全部加入到可执行文件中。生成文件比较大。在运行时也就不再需要库文件了。后缀名通常为.a
动态库与之相反,在编译链接时并没有将库文件的代码加入可执行文件中,而是在程序执行时加载库。这样可以减轻系统的开销。一般动态库的后缀名为.so
.
gcc编译时默认使用动态库。
完成了链接之后,gcc就可以生成可执行文件。
gcc hello.o -o hello
./hello
gcc编译选项分析
选 项 | 含 义 |
---|---|
-c | 只编译不链接,生成目标文件“ .o ” |
-S | 只编译不汇编,生成汇编代码 |
-E | 只进行预编译,不做其他处理 |
-g | 在可执行程序中包含标准调试信息 |
-o file | 将 file 文件指定为输出文件 |
-v | 打印出编译器内部编译各过程的命令行信息和编译器的版本 |
-I dir | 在头文件的搜索路径列表中添加 dir 目录 |
-I dir 选项可以在头问价的搜索路径列表中添加dir目录。 |
Linux中默认头文件都放到了“/usr/include/
”目录下。因此如果用户希望添加放置在其他位置的头文件时,就可以通过“-I dir”选项来指定。
gcc hello.c -I /home/rayu/cstudy/ -o hello
### gcc 库选项列表
选 项 | 含 义 |
---|---|
-static | 进行静态编译,即链接静态库,禁止使用动态库 |
-shared | 1.可以生成动态库文件 2.进行动态编译,尽可能地链接动态库,只有当没有动态库时才会链接同名的静态库(默认选项,即可省略) |
-L dir | 在库文件的搜索路径列表中添加 dir 目录-lname链接称为 libname.a(静态库)或者 libname.so(动态库)的库文件。若两个库都存在,则根据编译方式( -static 还是-shared)而进行链接 |
-fPIC(或-fpic) | 生成使用相对地址的位置无关的目标代码( Position Independent Code)。然后通常使用gcc 的-static 选项从该 PIC 目标文件生成动态库文件 |
/* unsgn_pow.c:库程序 */unsigned long long unsgn_pow(unsigned int x, unsigned int y){ unsigned long long res = 1; if (y == 0) { res = 1; } else if (y == 1) { res = x; } else { res = x * unsgn_pow(x, y - 1); } return res;}
#include#includeint main(int argc,char *argv[]){ unsigned int x,y; unsigned long long res; if((argc<3) || (sscanf(argv[1],"%u",&x)!=1) || (sscanf(argv[2],"%u",&y))!=1) { printf("Usage: pow base exponent\n"); exit(1); } res = unsgn_pow(x,y); printf("%u ^ %u = %u\n",x,y,res); exit(0);}
gcc -c unsgn_pow.car rcsv libpow.a unsgn_pow.ogcc -o pow_test pow_test.c -L. -lpow./pow_test 2 10
首先使用 gcc -fPIC
选项为动态库构造一个目标文件
gcc -fPIC -Wall -c unsgn_pow.c
接下来,使用-shared
选项和已创建的位置无关目标代码,生成一个动态库libpow.so
gcc -shared -o libpow.so unsgn_pow.o
下面编译主程序,它将会链接到刚刚生成的动态库libpow.so
gcc -o pow_test pow_test.c -L. -lpow
在运行可执行程序之前,需要注册动态库的路径名。其方法有几种:修改/etc/ld.so.conf
文件,或者修改LD_LIBRARY_PATH
环境变量,或者将库文件直接复制到/lib
或者/usr/lib
目录下(这两个目录为同的默认的库路径名)
cp libpow.so /lib./pow_test 2 10
gcc 的告警和出错选项。
gcc 警告和出错选项选项列表
选 项 | 含 义 |
---|---|
-ansi | 支持符合 ANSI 标准的 C 程序 |
-pedantic | 允许发出 ANSI C 标准所列的全部警告信息 |
-pedantic -error | 允许发出 ANSI C 标准所列的全部错误信息 |
-w | 关闭所有告警 |
-Wall | 允许发出 gcc 提供的所有有用的报警信息 |
-Werror | 把所有的告警信息转化为错误信息,并在告警发生时终止编译过程 |
gcc –Wall –O -g –c kang.c -o kang.o
-Wall
是打开警告开关,-O
代表默认优化,可选:-O0不优化,-O1低级优化,-O2中级优化,-O3高级优化,-Os代码空间优化。-g
是生成调试信息,生成的可执行文件具有和源代码关联的可调试的信息。
http://hao.qquu8.com/ 然后跳转到hao123。
心想还是要支持正版系统啊!
我首先是改浏览器的配置,把chrome的首页设置为打开新的标签页,结果操作无效。
紧接着我分别删除了桌面和任务栏chrome的快捷方式,属性快捷方式目标后面跟的http://hao.qquu8.com/?m=yx&r=j这个链接。
"C:\Program Files (x86)\Google\Chrome\Application\chrome.exe"
只保留这个,还有任务栏的地址在
C:\Users\rayu\AppData\Roaming\Microsoft\Internet Explorer\Quick LaunchC:\Users\rayu\AppData\Roaming\Microsoft\Internet Explorer\Quick Launch\User Pinned\TaskBar
这两个地方的http://hao.qquu8.com/也删除了。
这时候打开浏览器不会跳转到hao123了,我以为战斗结束了,也就没去管他了。
过了几个小时,我把浏览器关掉重新打开,发现又出现了hao123首页。
这我就不淡定了,强迫症又犯了。
开始网上找解决方案。
参考文章:http://xinghao.me/2016/03/01/2016-03-01-kill-hao123/
我其实就是按照上面链接里的方法来做的。
不过还是要自己记录一下是怎么做的。
双击ActiveScriptEventConsumer.Name=”VBScriptKids_consumer”,弹出属性页面:
在 ScriptText里面看见了hao.qquu8.com/?m=yx&r=j这一串代码。
然后把它删掉,或者直接在WMI event viewer中将“_EventFilter:Name=”unown_filter””项目右键删除!
这样问题就解决了。
]]>感觉自己萌萌哒!!!!
]]>之前用Python做了一个通道号查找的小程序,只不过没有做界面。
最近的一个项目要用到帧校验(CS),为了方便,写了一个计算的小程序。
该程序用了QT4来做界面,也算是我的第一个QT小程序。
现在来分享一下编写过程中的心得体会,以及遇到的坑。
Python的环境是2.7。
CS校验和的C代码如下:
/****************************************************************** *校验码 将所有相加MOD 256 *******************************************************************/ unsigned char Get_csckNum( unsigned char *Ptr, unsigned char Len ) { register unsigned char Num; Num = 0; while( Len > 0 ) { Num += *Ptr; printf("%d--%d\n",Len,Num); Ptr++; Len--; } return Num; }
转为Python代码
def CalCS(self,inputstr): input = inputstr.replace(" ", "") content = [] for i in range(0, len(input), 2): content.append(input[i:i + 2]) print content int_list = [int(i, 16) for i in content] print int_list num = 0 for i in range(0, len(int_list)): num = num + int(int_list[i]) return hex(num % 256)
我用的是QT Designer来进行界面的绘制,第一次用。但是感觉直接写代码来绘制图形界面提升的会更快。
首先打开QT designer,添加需要用到的小组件。
最终我的设计界面如下:
界面绘制完成后,保存会生成一个后缀名为.ui的文件。
界面完成后,进行框架的导入。
开始编写程序。
from __future__ import division import sys from PyQt4 import QtCore, QtGui,uic from uicode import * qtCreatorFile = "calc.ui" # Enter file here. Ui_MainWindow, QtBaseClass = uic.loadUiType(qtCreatorFile) class MyApp(QtGui.QMainWindow, Ui_MainWindow): def __init__(self): QtGui.QMainWindow.__init__(self) Ui_MainWindow.__init__(self) self.setupUi(self) self.calc_button.clicked.connect(self.CalculateTax) def CalculateTax(self): content = str(self.content_box.toPlainText()) total = self.CalCS(content) total_string = "" + str(total) self.results_window.setText(total_string) def CalCS(self,inputstr): input = inputstr.replace(" ", "") content = [] for i in range(0, len(input), 2): content.append(input[i:i + 2]) # print content int_list = [int(i, 16) for i in content] # print int_list num = 0 for i in range(0, len(int_list)): num = num + int(int_list[i]) return hex(num % 256) if __name__ == "__main__": app = QtGui.QApplication(sys.argv) window = MyApp() window.show() sys.exit(app.exec_())
至此,最简单的程序就编写完成了。
利用pyinstaller直接生成。
命令代码:
pyinstaller -w -F main.py
具体见下面链接
http://blog.rayuu.com/pyinstaller_py2exe_exe.html
但是在生成的过程中会报错,原因是.ui的界面代码没有打包到exe文件里面去。
所以不得不另辟蹊径。
在网上找了好久资料。最后的解决方法如下:
1、首先尝试在QT Designer下直接生成代码。
在菜单栏,窗体,查看代码下。
结果运行报错。
可能实在安装过程中出了错误,安装位置好像不能有中文和空格。
接着尝试第二种方式。
2、利用uic路径下的pyuic.py生成代码
在生成ui文件后,利用\Python27\Lib\site-packages\PyQt4\uic下面的pyuic.py进行生成代码。
pyuic4 -o ui_xxx.py xxx.ui
也可以用pycharm进行转换。
也可以写一个批处理文件进行快速转换,把下面的批处理文件放置在UIC目录下。
接着把需要转换的ui文件拖入到批处理文件打开,就可以转换成功了。
我的是在D盘目录下,所以里面的代码自行修改。
@echo off@cd /d "%~dp0"pyuic4 %1 > %~n1.py
这样代码就转换成功了。
本次生成的界面代码文件名称为 uicode.py
下面修改代码
from __future__ import division import sys from PyQt4 import QtCore, QtGui,uic # 从uicode.py里面导入界面代码 from uicode import * class MyApp(QtGui.QMainWindow): def __init__(self,parent=None): QtGui.QWidget.__init__(self,parent) # 重载 self.ui=Ui_MainWindow() self.ui.setupUi(self) self.ui.calc_button.clicked.connect(self.CalculateTax) def CalculateTax(self): content = str(self.ui.content_box.toPlainText()) total = self.CalCS(content) total_string = "" + str(total) self.ui.results_window.setText(total_string) def CalCS(self,inputstr): input = inputstr.replace(" ", "") content = [] for i in range(0, len(input), 2): content.append(input[i:i + 2]) # print content int_list = [int(i, 16) for i in content] # print int_list num = 0 for i in range(0, len(int_list)): num = num + int(int_list[i]) return hex(num % 256) if __name__ == "__main__": app = QtGui.QApplication(sys.argv) window = MyApp() window.show() sys.exit(app.exec_())
最后重新打包生成exe文件就可以直接运行了。
只是打包的库比较多,所以最后的程序大小有10几兆。
最后:
另外,如果界面需要加载资源文件的话,还要进行另外的操作,把资源文件转为.qrc后缀的文件。
http://www.cnblogs.com/dcb3688/p/4237121.html
转换资源文件用的是Pyqt
的pyrcc4
命令
pyrcc4 qrcfile.qrc -o pyfile.py
1.Pycharm集成pyrcc4
我们使用Pycharm来集成pyrcc4,这样更利于我们高效开发
首先在菜单里面找到 File => settings => Tools => External Tools
(外边工具设置)
选择添加Add
Name 填写: Rcc2Py
Group: 自已任意填写,我填写的是PyQt4
下面的Options默认
在Tools settings 里面这样填写:
Program 就是你安装Pyqt4的路径
Parameters 是指转换的参数 $FileName$ -o $FileNameWithoutExtension$.py
Working directory 表示输出在当前的工作目录 $FileDir$
2.转换qrc为py
选择要转换的qrc文件,右键,找到group 为(PyQt4) 目录下的Rcc2Py
转换完成后,同级目录下就多出一个与qrc文件同命名的py文件。
3、引用资源py文件
py文件生成好了如何来引用使用呢?
说对了,引用就这么简单
import uicode
使用的时候 冒号 “ : ” 加 图片的路径, 如:
:/img/firefox.png
运行试试,发现图片不显示,为什么呢,因为qrc文件添加过程中,我加了一个 “前缀” prefix。
所以,如果在qrc文件中不添加前缀 使用 :/img/firefox.png
是可以的,但添加了前缀生成的qrc文件 qresource标签会多一个属性
qresource prefix="picture"
在这里,正确的使用是:
:picture/img/firefox.png
附:uicode.py
# -*- coding: utf-8 -*- # Form implementation generated from reading ui file 'C:\Users\jx007\Desktop\PyQt_first-master\calc.ui' # # Created by: PyQt4 UI code generator 4.11.4 # # WARNING! All changes made in this file will be lost! from PyQt4 import QtCore, QtGui # 导入资源 import sources try: _fromUtf8 = QtCore.QString.fromUtf8 except AttributeError: def _fromUtf8(s): return s try: _encoding = QtGui.QApplication.UnicodeUTF8 def _translate(context, text, disambig): return QtGui.QApplication.translate(context, text, disambig, _encoding) except AttributeError: def _translate(context, text, disambig): return QtGui.QApplication.translate(context, text, disambig) class Ui_MainWindow(object): def setupUi(self, MainWindow): MainWindow.setObjectName(_fromUtf8("MainWindow")) MainWindow.resize(700, 240) icon = QtGui.QIcon() # icon.addPixmap(QtGui.QPixmap(_fromUtf8("ico.png")), QtGui.QIcon.Normal, QtGui.QIcon.Off) icon.addPixmap(QtGui.QPixmap(_fromUtf8(":ico/ico.png")), QtGui.QIcon.Normal, QtGui.QIcon.Off) MainWindow.setWindowIcon(icon) self.centralwidget = QtGui.QWidget(MainWindow) self.centralwidget.setObjectName(_fromUtf8("centralwidget")) self.gridLayout = QtGui.QGridLayout(self.centralwidget) self.gridLayout.setObjectName(_fromUtf8("gridLayout")) self.label_3 = QtGui.QLabel(self.centralwidget) font = QtGui.QFont() font.setPointSize(20) font.setBold(True) font.setWeight(75) self.label_3.setFont(font) self.label_3.setObjectName(_fromUtf8("label_3")) self.gridLayout.addWidget(self.label_3, 0, 1, 1, 1) self.label = QtGui.QLabel(self.centralwidget) font = QtGui.QFont() font.setPointSize(10) font.setBold(True) font.setWeight(75) self.label.setFont(font) self.label.setObjectName(_fromUtf8("label")) self.gridLayout.addWidget(self.label, 1, 0, 1, 1) self.content_box = QtGui.QTextEdit(self.centralwidget) font = QtGui.QFont() font.setFamily(_fromUtf8("Times New Roman")) font.setPointSize(10) font.setBold(False) font.setWeight(50) self.content_box.setFont(font) self.content_box.setObjectName(_fromUtf8("content_box")) self.gridLayout.addWidget(self.content_box, 1, 1, 1, 1) self.calc_button = QtGui.QPushButton(self.centralwidget) self.calc_button.setObjectName(_fromUtf8("calc_button")) self.gridLayout.addWidget(self.calc_button, 1, 2, 1, 1) self.label_2 = QtGui.QLabel(self.centralwidget) font = QtGui.QFont() font.setPointSize(10) font.setBold(True) font.setWeight(75) self.label_2.setFont(font) self.label_2.setObjectName(_fromUtf8("label_2")) self.gridLayout.addWidget(self.label_2, 2, 0, 1, 1) self.results_window = QtGui.QTextEdit(self.centralwidget) font = QtGui.QFont() font.setFamily(_fromUtf8("Times New Roman")) font.setPointSize(14) font.setBold(False) font.setWeight(50) self.results_window.setFont(font) self.results_window.setObjectName(_fromUtf8("results_window")) self.gridLayout.addWidget(self.results_window, 2, 1, 1, 1) MainWindow.setCentralWidget(self.centralwidget) self.menubar = QtGui.QMenuBar(MainWindow) self.menubar.setGeometry(QtCore.QRect(0, 0, 700, 23)) self.menubar.setObjectName(_fromUtf8("menubar")) MainWindow.setMenuBar(self.menubar) self.statusbar = QtGui.QStatusBar(MainWindow) self.statusbar.setObjectName(_fromUtf8("statusbar")) MainWindow.setStatusBar(self.statusbar) self.retranslateUi(MainWindow) QtCore.QMetaObject.connectSlotsByName(MainWindow) def retranslateUi(self, MainWindow): MainWindow.setWindowTitle(_translate("MainWindow", "CS Calculator By:Rayu 2016-11-24", None)) self.label_3.setText(_translate("MainWindow", "CS Calculator", None)) self.label.setText(_translate("MainWindow", "Text", None)) self.calc_button.setText(_translate("MainWindow", "Calculate", None)) self.label_2.setText(_translate("MainWindow", "Result", None)) self.results_window.setHtml(_translate("MainWindow", "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0//EN\" \"http://www.w3.org/TR/REC-html40/strict.dtd\">\n" "<html><head><meta name=\"qrichtext\" content=\"1\" /><style type=\"text/css\">\n" "p, li { white-space: pre-wrap; }\n" "</style></head><body style=\" font-family:\'Times New Roman\'; font-size:14pt; font-weight:400; font-style:normal;\">\n" "<p style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\"><span style=\" font-family:\'SimSun\'; font-size:9pt;\">/******************************************************************</span></p>\n" "<p style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\"><span style=\" font-family:\'SimSun\'; font-size:9pt;\">*校验码 将所有相加MOD 256 </span></p>\n" "<p style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\"><span style=\" font-family:\'SimSun\'; font-size:9pt;\">*******************************************************************/</span></p>\n" "<p style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\"><span style=\" font-family:\'SimSun\'; font-size:9pt;\">unsigned char Get_csckNum( unsigned char *Ptr, unsigned char Len )</span></p>\n" "<p style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\"><span style=\" font-family:\'SimSun\'; font-size:9pt;\">{</span></p>\n" "<p style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\"><span style=\" font-family:\'SimSun\'; font-size:9pt;\"> register unsigned char Num;</span></p>\n" "<p style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\"><span style=\" font-family:\'SimSun\'; font-size:9pt;\"> </span></p>\n" "<p style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\"><span style=\" font-family:\'SimSun\'; font-size:9pt;\"> Num = 0;</span></p>\n" "<p style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\"><span style=\" font-family:\'SimSun\'; font-size:9pt;\"> while( Len > 0 )</span></p>\n" "<p style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\"><span style=\" font-family:\'SimSun\'; font-size:9pt;\"> {</span></p>\n" "<p style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\"><span style=\" font-family:\'SimSun\'; font-size:9pt;\"> Num += *Ptr;</span></p>\n" "<p style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\"><span style=\" font-family:\'SimSun\'; font-size:9pt;\"> printf("%d--%d\\n",Len,Num);</span></p>\n" "<p style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\"><span style=\" font-family:\'SimSun\'; font-size:9pt;\"> Ptr++;</span></p>\n" "<p style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\"><span style=\" font-family:\'SimSun\'; font-size:9pt;\"> Len--;</span></p>\n" "<p style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\"><span style=\" font-family:\'SimSun\'; font-size:9pt;\"> }</span></p>\n" "<p style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\"><span style=\" font-family:\'SimSun\'; font-size:9pt;\"> return Num;</span></p>\n" "<p style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\"><span style=\" font-family:\'SimSun\'; font-size:9pt;\">}</span></p></body></html>", None))
]]>串口直通线和交叉线的区别
串口线两头都一样都相同。都是公对公或者母对母串口线,这种线必须是交叉线。
一端的第二针与另一端的第三针是通路的,说明此线是交叉线。
以下是判断方法:
如果用户串口设备与串口服务器连接使用公对母串口线,那必须使用公对母直通线。
一端公头的2对应,另一端母头的2,一端母头的3对应另一端公头的3.
公头:
母头:
使用WiFi网络串口服务器,或者DTU,我们配套的串口线都是标配的,如果我们的串口服务器的公头的,那我们配套的串口线应该是母对母的交叉线,如果客户的设备的公头,可以直接用我们配套的线,前提是客户的串口母头符合标准母头串口定义。如果客户买的我们的串口服务器是母头,那我们配套的串口线应该是公对母的直通线,如果客户的设备是公头,那使用我们的公对母的直通线应该是可以通信的。前提是客户的公头串口是标准的串口,符合公头串口引脚定义。
摘自:http://www.usr.cn/Faq/117.html
对接方法
相信很多人都对单片机与计算机或者芯片通信时,RXD与TXD如何连接比较困惑。因为在一些电路图中,有的是直连接法,有的是交叉接法,让人有点摸不着头脑。
首先需要明白两个概念,就是DTE和DCE。DTE是指数据终端设备,典型的DTE就是计算机和单片机。DCE是指数据通信设备,典型的DCE就是MODEM。RS232串口标准中的RXD和TXD都是站在DTE立场上的,而不是DCE。明白了这一点,再讲下面的接线方法,就很好理解了。
单片机与计算机进行串口通信时,单片机的RXD接计算机的TXD,单片机的TXD接计算机的RXD。
(1)使用串口直通线。设计电路时,单片机的RXD连接电路板DB9的TXD,单片机的TXD连接电路板DB9的RXD,具体实现可在232电平转换芯片处反接。
(2)使用串口交叉线。设计电路时,因为串口线已做交叉,单片机的RXD连接电路板DB9的RXD,单片机的TXD连接电路板DB9的TXD,均直连即可。
这就可以解释为什么有的电路中使用直连接法,有的电路中使用交叉接法,就是因为使用的串口线不同。
单片机与串口设备(如GPRS模块、载波芯片等)通信时,一律将RXD与TXD反接,即单片机的RXD接设备的TXD,单片机的TXD接设备的RXD。
摘自: http://blog.csdn.net/sdwuyulunbi/article/details/6632382
]]>最近在玩micropython
,下载了micropython
的源码后想进行编译玩一玩。
https://github.com/micropython/micropython
查看readme.md
发现编译stm32的固件需要安装arm-linux-gcc
等gnu arm toolchain
交叉编译工具.
说干就干,还好电脑装了双系统,打开ubuntu16.04
。
开始安装。
https://launchpad.net/gcc-arm-embedded
右面有对应的版本下载,
下载完成后就是安装,查看readme.txt。
但是我的网速用浏览器下载太慢了。所以,我准备用apt-get 来安装。
https://launchpadlibrarian.net/287100883/readme.txt
参考这篇文章 http://jingpin.jikexueyuan.com/article/56406.html
sudo add-apt-repository ppa:terry.guo/gcc-arm-embeddedsudo apt-get updatesudo apt-get install gcc-arm-none-eabi
这样就安装好了,工具链路径在/usr/bin/目录下,具体可以用 ls | grep arm查看;
然后搞个链接,像这样
cd /usr/binsudo ln arm-none-eabi-gcc arm-linux-gccsudo ln arm-none-eabi-ar arm-linux-ar.....
最后就安装完成了这个编译工具。
git clone https://github.com/micropython/micropython.gitcd stmhal/make
还以为要编译好久,结果一会儿就编译完了。
在stmhal/build-PYBV10
目录下的firmware.hex
和firmware.dfu
的就是编译出来的固件咯!
接下来继续研究源码!!!
]]>1.在sqlite官网 http://www.sqlite.org/download.html 上下载sqlite-amalgamation-3071000.zip
和sqlite-dll-win32-x86-3071000.zip
。
2.分别解压上述两个文件到各自文件夹下(sqlite3.def、sqlite3.dll
在同一文件夹sqlite-dll
下)。
3.从VS2010的安装目录下Microsoft Visual Studio 10.0\VC\bin
找到lib.exe
和link.exe
,从VS2010的安装目录下\Microsoft Visual Studio 10.0\Common7\IDE
找到mspdb100.dll
。将lib.exe`` link.exe ``mspdb100.dll
放到步骤2中的sqlite-dll
文件夹下。
4.打开cmd窗口,转到上述sqlite-dll文件夹下,在Windows右键添加cmd菜单可以快速到达,详见http://blog.rayuu.com/cmdhere.html
5.输入命令:
LIB /DEF:sqlite3.def /machine:ix86
这时,在sqlite-dll文件夹下会出现sqlite3.lib。
VS2010静态编译生成的.exe可执行文件,可以免安装在其他电脑直接运行
静态编译:就是在编译可执行文件的时候,将可执行文件需要调用的对应动态链接库(.so)中的部分提取出来,链接到可执行文件中去,使可执行文件在运行的时候不依赖动态链接库。
编译方式:
第1种:
设置:
1、项目->配置属性->常规->MFC的使用:在静态库中使用MFC
2、项目 -> 配置属性->C/C++->代码生成->运行库 :选择 多线程调试(/MTd)。
编译时,选择的是debug,win32
然后执行编译生成方案,在该工程目录下的debug文件中,找到该.exe文件,即可在其他电脑运行。
第2种:
一般可以配置一下两项:
1.项目 -> 配置属性->常规->MFC的使用 :在静态库中使用MFC。
2.项目 -> 配置属性->C/C++->代码生成->运行库 :选择 多线程调试(/MT)。
编译时,选择的是release,win32(这个选择项在工具栏的debug选框中,一般我们使用debug方式)
debug方式产生的文件会比较大,听说它包含了一些调试用的信息,release方式生成的只是该软件所需要的所有功能而已(这个我也不懂,反正大小差不多2:1)。
#include<iostream>#include<sstream>#include"lib/sqlite3.h"#include<string>using namespace std;//定义课表结构struct content{ string context;};/********************************** 数据库操作***********************************/bool Connect();//连接数据库并创建表bool Select(int day);//查询单条记录bool Delete(int day);//删除单条记录bool SelectAll();//查询全部bool DeleteAll();//删除全部bool Add(int day,const string& no1,const string& no2,const string& no3,const string& no4,const string& no5);//添加单条记录int AddDay(content *p);//添加某一天记录bool exist_in_db(int pathstr);//判断要添加的数据是否存在/********************************** 其他操作***********************************/string IntToString (int a);//数字转字符void Menu();//菜单void show(content *m);//显示输入的课表内容void Find();//查找void DelDay();//删除某一天的数据//SQLITE_OK 是零sqlite3 *db=NULL;// 回调sqlstatic int callback(void *NotUsed, int argc, char **argv, char **azColName){ int i; for(i=0; i<argc; i++){ printf("%s = %s\n", azColName[i], argv[i] ? argv[i] : "NULL"); } printf("\n"); return 0;}static int feedback(void *NotUsed, int argc, char **argv, char **azColName){ int i; cout<<"星期 "<<argv[1]<<" 的课表为:\n"; for(i=2; i<argc; i++){ cout<<"第 "<<i-1<<" 节课: "; printf("%s\n", argv[i] ? argv[i] : "NULL"); } printf("\n"); return 0;}int main(){ int SetDay;//星期 int MenuChoice;//菜单选择 char *errmsg = 0; content *p = new content[5]; Connect(); Menu(); while(cin>>MenuChoice) { cin.sync(); cin.clear(); switch(MenuChoice) { case 1:{ SetDay = AddDay(p); show(p); Add(SetDay,p[0].context,p[1].context,p[2].context,p[3].context,p[4].context); }break; case 2:{Find();}break; case 3:{DelDay();}break; case 0:{exit(0);}break; default :Menu();break; } cout << "按回车键返回主菜单......"; cin.get(); system("cls"); Menu(); } sqlite3_close(db); system("pause"); return 0;}//connect & create tablebool Connect(){ int con; con = sqlite3_open("schedule.db",&db); if(con) { fprintf(stderr, "Can't open database: %s\n",sqlite3_errmsg(db)); exit(0); } else { fprintf(stdout,"连接数据库成功\n"); } char *sql; char * errmsg=0; // 新建表 schedule sql = "CREATE TABLE IF NOT EXISTS schedule("\ "ID INTEGER PRIMARY KEY AUTOINCREMENT,"\ "WEEKLY INT NOT NULL,"\ "NO1 TEXT NOT NULL,"\ "NO2 TEXT NOT NULL,"\ "NO3 TEXT NOT NULL,"\ "NO4 TEXT NOT NULL,"\ "NO5 TEXT NOT NULL"\ ");"; con = sqlite3_exec(db,sql,callback, 0, &errmsg); if(con != SQLITE_OK) { cout << "add fail: "<<errmsg<<endl; return false; } return true;}//添加bool Add(int day,const string& no1,const string& no2,const string& no3,const string& no4,const string& no5){ char *errmsg=0; int res=1; int week; week = day; string strsql = ""; strsql += "insert into schedule(WEEKLY,NO1,NO2,NO3,NO4,NO5)"; strsql += " values("; strsql += "'"; strsql += IntToString(day); strsql += "','"; strsql += no1; strsql += "','"; strsql += no2; strsql += "','"; strsql += no3; strsql += "','"; strsql += no4; strsql += "','"; strsql += no5; strsql += "');"; //启动一个事务处理 //cout <<strsql<<endl; if(!exist_in_db(week)) { res = sqlite3_exec(db,strsql.c_str(),0,0, &errmsg); } else { return false; } if(res != SQLITE_OK) { cout << "add fail: "<<errmsg<<endl; return false; } else { cout << "add success"<<endl; } return true;}//查找某一天的课表bool Select(int day){ stringstream strsql; char *errmsg = 0; //启动一个事务处理 int res; strsql << "SELECT * FROM schedule WHERE WEEKLY="; strsql << day; string str = strsql.str(); res=sqlite3_exec(db,str.c_str(),feedback, 0, &errmsg); if(res!=SQLITE_OK) { cout << "查找失败"<<endl; return false; } return true;}// 查找全部bool SelectAll(){ stringstream strsql; char *errmsg = 0; //启动一个事务处理 int res; strsql << "SELECT * FROM schedule"; string str = strsql.str(); res=sqlite3_exec(db,str.c_str(),feedback, 0, &errmsg); if(res!=SQLITE_OK) { cout << "查找失败"<<endl; return false; } return true;}// 删除bool Delete(int day){ stringstream strsql; char *errmsg = 0; //启动一个事务处理 int res; strsql << "DELETE FROM schedule WHERE WEEKLY="; strsql << day; string str = strsql.str(); res=sqlite3_exec(db,str.c_str(),feedback, 0, &errmsg); if(res!=SQLITE_OK) { cout << "删除失败"<<endl; return false; } return true;}// 删除全部bool DeleteAll(){ stringstream strsql; char *errmsg = 0; //启动一个事务处理 int res; strsql << "DELETE FROM schedule"; string str = strsql.str(); res=sqlite3_exec(db,str.c_str(),feedback, 0, &errmsg); if(res!=SQLITE_OK) { cout << "删除全部失败"<<endl; return false; } return true;}//判断星期是否存在bool exist_in_db(int pathstr){ char sql_query[128]={0}; sprintf(sql_query,"select count(*) from schedule where WEEKLY='%d'",pathstr);// sprintf(sql_query,"select count(*) from schedule where ID='%d'",day); //cout << sql_query<<endl; sqlite3_stmt *pstmt; sqlite3_prepare(db, sql_query, strlen(sql_query), &pstmt, NULL); sqlite3_step(pstmt); int count=sqlite3_column_int(pstmt,0); sqlite3_finalize(pstmt); //cout << count<<endl; if(count > 0) { cout<<"星期 "<<pathstr<<" 的课表已添加,\n请删除后重新添加."<<endl; return true; } return false;}// 输入课表int AddDay(content *p){ int day; cout <<"请输入星期数: "<<endl; cin >> day; cin.get(); int i=0; for(i=0;i<5;i++) { cin.clear(); cin.sync(); cout << "第 "<<i+1<<" 节课"<<endl; getline(cin,p[i].context); } return day;}// 删除void DelDay(){ int day; cout <<"Please enter the day(1~7)"<<endl; cin>>day; //while(cin>>day) { cin.sync(); cin.clear(); switch(day) { case 1:Delete(day);break; case 2:Delete(day);break; case 3:Delete(day);break; case 4:Delete(day);break; case 5:Delete(day);break; case 6:Delete(day);break; case 7:Delete(day);break; default:DeleteAll();break; } } if(!cin) { cout << "请输入数字......"<<endl; }}// 显示输入的内容void show(content *m){ cout <<"你输入的内容是:"<<endl; int i=0; for(i=0;i<5;i++) { cout << "第 "<<i+1<<" 节课 "<< m[i].context << endl; } cout << endl;}// 菜单void Menu(){ cout<<"+++++++++++++++++++++++++++++++++++++++++\n"; cout<<"+ 课 表 +\n"; cout<<"+ V1.0 +\n"; cout<<"+ by:Rayu +\n"; cout<<"+ 2016.10.18 +\n"; cout<<"+++++++++++++++++++++++++++++++++++++++++\n"; cout<<"\n"; cout<<"【1】添加课表\t"; cout<<"【2】查询课表\n"; cout<<"【3】删除课表\t"; cout<<"【0】退出系统\n"; cout<<"输入对应的数字进入菜单: \n";}void Find(){ int day; cout <<"Please enter the day(1~7)"<<endl; cin>>day; //while(cin>>day) { cin.sync(); cin.clear(); switch(day) { case 1:Select(day);break; case 2:Select(day);break; case 3:Select(day);break; case 4:Select(day);break; case 5:Select(day);break; case 6:Select(day);break; case 7:Select(day);break; default:SelectAll();break; } } if(!cin) { cout << "请输入数字......"<<endl; }}// int to stringstring IntToString (int a){ ostringstream temp; temp<<a; return temp.str();}
]]>写了一个查找产品通道号的小程序,目前还没进行异常处理。
以下是程序源码。
另外一个地址
http://blog.rayuu.com/pyinstaller_py2exe_exe.html
# -*- coding:UTF-8 -*- import serial import time # import argparse import serial.tools.list_ports from time import sleep # 串口 class Serial(object): def __init__(self): print u"+++++++++++++++++++++++++++++++++++++++++" print u"+ 通道号查找程序 +" print u"+ V1.0 +" print u"+ by:Rayu +" print u"+ 2016.09.27 +" print u"+++++++++++++++++++++++++++++++++++++++++" # 查找串口 def serial_find(self): plist = list(serial.tools.list_ports.comports()) if len(plist) <= 0: print u"串口未发现!" else: print u"找到的串口如下:" for i in range(0, len(plist)): print [i+1], plist[i] print u"请输入对应的数字选择你想要使用的串口:<默认为1>" number = raw_input() if not number: number = 1 number = int(number) while number > len(plist): print u"串口未找到,请重新输入。" print u"请输入对应的数字选择你想要使用的串口:" number = raw_input() number = int(number) if number <= len(plist): uart_choose = plist[number-1][0] return uart_choose # 串口波特率 def serial_baudrate(self): print u"请输入串口波特率:<默认115200>" baudrate = raw_input() if not baudrate: baudrate = 115200 baudrate = int(baudrate) return baudrate # 获取设备地址 def input_dev_addr(self): print u'请输入设备地址:<如:dc00000233>' data_dev = raw_input() # print data_dev, type(data_dev) return data_dev # 打开串口 def serial_open(self, com, baud): try: ser = serial.Serial(com, baud, timeout=0.1) except Exception, e: print u"打开串口失败,请检查串口是否被占用。\n5秒后自动退出程序" time.sleep(5) exit(1) print u"串口", com, u"打开成功......波特率为:", baud sleep(0.5) return ser # 更改通道号 def serial_send_channel(self, com, baud, dev, sta): # data_comm = "AB" data_sum = "01" # 通道号修改 ser = self.serial_open(com, baud) start = time.clock() for data_channel in range(0, 256): # 转换为十六进制字符串 dev_channel = hex(data_channel) # 把0x删掉 dev_channel = dev_channel[2:4] if len(dev_channel) == 1: dev_channel = '0' + dev_channel # 连接字符串 content_addr = data_comm+dev_channel+data_sum # print content_addr,"content_addr",type(content_addr) # 十六进制发送 content_addr = content_addr.decode("hex") # print content_addr # print u"开始发送数据..." ser.write(content_addr) lowerpower = int(sta) # sta = self.serial_send_order(ser,DEV) re_str = [] cou = 0 find_time = data_channel + 1 print u"进行第 %s" % find_time, u"次查找....." i = 1 while i <= 10: i += 1 for c in ser.read(): # re_str += c re_str.append(c) cou += 1 if cou == 10: # print re_str,"re_str" re_str = [] break content_order = self.serial_send_order(dev) if lowerpower == 1: print u"低功耗设备,6秒发一次" ser.write(content_order) time.sleep(6) else: # time.sleep(0) ser.write(content_order) line = [] cnt = 0 j = 1 while j <= 10: j += 1 for d in ser.read(): line.append(d) cnt += 1 if cnt == 10: # print "line",line # line = [] # print data_channel print u"查找结束......" end = time.clock() print u"用时: %f s" % (end-start) line[8] = ord(line[8]) # print ord(line[8]) ser.close() return line[8] end = time.clock() print u"用时: %f s" % (end - start) print u"未找到通道号,请确定设备地址和工装是否正常......" ser.close() return -1 # 发送通信命令 def serial_send_order(self, dev): # 发送通信测试命令 data_head = "F01" data_dev = dev data_tail = "E3" # print data_dev data_addr = data_head + data_dev + data_tail # data_addr = "F0" data_addr = data_addr.decode("hex") return data_addr if __name__ == '__main__': comm = Serial() # 获取COM口 COMM = comm.serial_find() # print COMM BAUD = comm.serial_baudrate() while True: DEV = comm.input_dev_addr() if DEV == 'q': exit() print u"低功耗设备请输入1,否则请直接按回车......\n输入q结束程序......" sta = raw_input() if not sta: sta = 0 channel = comm.serial_send_channel(COMM, BAUD, DEV, sta) if channel == -1: print u"查找失败......请重新尝试......" else: channel = hex(channel) print u"通道号为: ", channel # comm.serial_send_order(DEV) # print BAUD # comm.serial_open(COMM, BAUD) # parser = argparse.ArgumentParser(description="通道号查找程序") # parser.add_argument('--port', action='store', dest='port', type=int, required=True) # given_args = parser.parse_args() # port = given_args.port
1).新建setup.py
# -*- coding: utf-8 -*- __author__ = 'Rayu' from distutils.core import setup import py2exe includes = ["encodings", "encodings.*"] options = {"py2exe": {"compressed": 1, "optimize": 2, "includes": includes, "bundle_files": 1}} setup( version = "0.1.0", description = u"[利用工装查找设备通道号]", name = "FindChannel", options = options, zipfile = None, # 生成有指定图标的exe console = [{"script": "main.py", "icon_resources": [(1, u"833.ico")] }] # 生成无图标exe # windows = [{"script": "[源码文件名].py"}] ) # from distutils.core import setup # import py2exe # # setup(console=['main.py'])
然后运行程序 python setup.py py2exe
在64位系统下运行会报错: bundle_files:1
在64位操作系统下无效。 这句话的意思就是生成单文件程序。
所以64位操作系统下想生成单文件程序的可以改用pyinstaller
.
2).利用
pip install PyInstaller
或者去官网下载安装包。
我安装的PyInstaller3.2
版本。
安装完成后,在命令窗口下执行:
pyinstaller main.py
会在当前文件夹的dist
目录下生成main
文件夹,里面的main.exe
就是生成的可执行文件。
把main
文件夹整个复制出来就可以在其他地方运行了。
如果想为程序添加自定义图标和版本信息,那么在main.py
的目录下,会有一个main.spec
文件,使用notepad++
打开进行编辑。
# -*- mode: python -*- block_cipher = None a = Analysis(['main.py'], pathex=['C:\\Users\\jx007\\Desktop\\commserial'], binaries=None, datas=None, hiddenimports=[], hookspath=[], runtime_hooks=[], excludes=[], win_no_prefer_redirects=False, win_private_assemblies=False, cipher=block_cipher) pyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher) exe = EXE(pyz, a.scripts, a.binaries, a.zipfiles, a.datas, name='FindChannel', version='version.txt', debug=False, strip=False, upx=True, console=True , icon='833.ico')
在a.datas
, 下面添加
version='version.txt', icon='833.ico',
然后保存。
先不要执行,然后把你心仪的ico
图标放到和main.py
同一目录下,version
是版本信息路径。
名称为version.txt
这时候我们需要编写version.txt
下面是一个例子:
# UTF-8 # VSVersionInfo( ffi=FixedFileInfo( # filevers and prodvers should be always a tuple with four items: (1, 2, 3, 4) # Set not needed items to zero 0. filevers=(6, 1, 7600, 16385), prodvers=(6, 1, 7600, 16385), # Contains a bitmask that specifies the valid bits 'flags'r mask=0x3f, # Contains a bitmask that specifies the Boolean attributes of the file. flags=0x0, # The operating system for which this file was designed. # 0x4 - NT and there is no need to change it. OS=0x40004, # The general type of file. # 0x1 - the file is an application. fileType=0x1, # The function of the file. # 0x0 - the function is not defined for this fileType subtype=0x0, # Creation date and time stamp. date=(0, 0) ), kids=[ StringFileInfo( [ StringTable( u'040904B0', [StringStruct(u'CompanyName', u'Microsoft Corporation'), StringStruct(u'FileDescription', u'Windows Command Processor'), StringStruct(u'FileVersion', u'6.1.7600.16385 (win7_rtm.090713-1255)'), StringStruct(u'InternalName', u'cmd'), StringStruct(u'LegalCopyright', u'© Microsoft Corporation. All rights reserved.'), StringStruct(u'OriginalFilename', u'Cmd.Exe'), StringStruct(u'ProductName', u'Microsoft® Windows® Operating System'), StringStruct(u'ProductVersion', u'6.1.7600.16385')]) ]), VarFileInfo([VarStruct(u'Translation', [1033, 1200])]) ] )
如果你想要自己找这个文件的话,可以参考pyinstaller3
的文档,里面写的很详细。
下面简单介绍一下如何获取这个文件。
首先在文档里面写到了,利用 pyi-grab_version executable_with_version_resource
这个命令来获取命令的版本信息。
我们运行 pyi-grab_version c:/windows/system32/cmd.exe
然后会把一个file_version_info.txt
记事本文件保存在你cmd命令运行时候的路径下面。
找到并打开它,就是上面所列出的内容了。
然后根据自己的需要进行修改就可以了。
最后在main.py
的路径下执行
pyinstaller main.spec
在dist
文件夹下就产生了一个exe
文件,图标也是我们想要的那个图标了,至于程序的详细信息可以通过右键查看详细信息进行查看了。
这和要求的功耗设计都不在一个数量级,要求的功耗是在微安级别的。所以需要一个方法降低系统的功耗。
单片机系统的功耗是由MCU和其他外围电路的功耗共同决定。所以首先要对单片机系统的工作特点非常熟悉。
查阅手册发现,现在用的瑞萨单片机,有STOP,HALT,SNOOZE三种模式可以降低功耗。
以下是用户手册的说明
(1) HALT 模式
通过执行 HALT 指令进入 HALT 模式。 HALT 模式是停止 CPU 运行时钟的模式。在设定 HALT 模式前,如果高速系统时钟振荡电路、高速内部振荡器或者副系统时钟振荡电路正在振荡,各时钟就继续振荡。虽然此模式无法让工作电流降到 STOP 模式的程度,但是在想要通过中断请求立即重新开始处理或者想要频繁地进行间歇运行时是一种有效的模式。
(2) STOP 模式
通过执行 STOP 指令进入 STOP 模式。 STOP 模式是停止高速系统时钟振荡电路和高速内部振荡器的振荡并且停止整个系统的模式。能大幅度地降低 CPU 的工作电流。
因为 STOP 模式能通过中断请求来解除,所以也能进行间歇运行。但是,在 X1 时钟的情况下,因为在解除STOP 模式时需要确保振荡稳定的等待时间,所以如果一定要通过中断请求立即开始处理,就必须选择 HALT 模式。
(3) SNOOZE 模式
通过 CSIp 或者 UARTq 的数据接收以及由定时器触发信号 (中断请求信号 ( INTRTC/INTIT))产生的 A/D转换请求,解除 STOP 模式,不需要 CPU 运行而进行 CSIp 或者 UARTq 的数据接收,或者进行 A/D 转换。只有在选择高速内部振荡器作为 CPU/ 外围硬件时钟 ( fCLK)时才能设定 SNOOZE 模式。
在任何一种模式中,寄存器、标志和数据存储器全部保持设定为待机模式前的内容,并且还保持输入 / 输出端口的输出锁存器和输出缓冲器的状态。
最后决定使用STOP模式来进行功耗设计,使功耗尽可能降低到最低。
以单片机为核心构成的系统,其系统的总能耗是由单片机能耗及其外围电路能耗共同构成。
所以为了降低整个系统的功耗,除了要降低单片机自身的运行恭号外,还要降低外围电路的功耗。
如果要在STOP模式下工作,首先要把单片机外围的IO设备最大程度上禁用。
在本系统中,除了单片机,还有无线模块,蜂鸣器和一个LED灯耗电。
下面进行分步描述
Si24R1芯片内部有状态机,控制着芯片在不同工作模式的切换。
Si24R1可配置为Shutdown,Standby,Idle-TX,TX,Rx五种工作模式。
为了降低无线模块的功耗,也要让无线模块在Shutdown模式下工作。
在Shutdown工作模式下,Si24R1所有收发功能模块关闭,芯片停止工作,消耗电流最小,
但所有内部寄存器值和FIFO值保持不变,仍可通过SPI实现对寄存器的读写。
设置CONFIG寄存器的PWR_UP位的值为0,芯片立即返回到Shutdown工作模式。
查看CONFIG寄存器的配置如下:
PWR_UP在CONFIG寄存器的第一位,所以把该位拉低即可。
编写子函数如下:
/****************************************************************** SPI Shutdown 关断模式 把config 配置寄存器的第一位PWR_up拉低 ********************************************************************/ void SI24R1_Shutdown(void ) { SI24R1_CEL; SPI_Write_Reg(NRF_WRITE_REG + CONFIG, 0x00); SI24R1_Delay_ms(2); SI24R1_CEH; }
然后在必要的时候需要对无线模块进行唤醒。所以编写无线开启子函数。
/******************************************************************SPI 上电模式 ********************************************************************/void SI24R1_PowerOn(void ){ SI24R1_CEL; SPI_Write_Reg(NRF_WRITE_REG + CONFIG, 0x71);//发射模式 SI24R1_Delay_us(120); SPI_Write_Reg(NRF_WRITE_REG + CONFIG, 0x3F); // Set PWR_UP bit, enable CRC(2 bytes) SI24R1_Delay_ms(2); SI24R1_CEH; RX_Mode(WireComm.Addr,WireComm.CommChannel);}
至此无线低功耗设计完成。
该系统对单片机I/O的利用有A/D转换,蜂鸣器,LED灯,EEPROM等。所以在进入STOP模式时,要把这些引脚给拉高。
蜂鸣器的话要根据硬件情况拉低或拉高。
进入STOP模式很简单,一条STOP();就可以进入,所以在进入STOP模式之前要把单片机系统外围的I/O进行处理。没有用到的I/O最好也要设为输出拉高。
但是没有用到I/O对电流影响不大。
对于唤醒stop模式,打开单片机的内部定时器,周期为200ms。根据用户手册进行时序设计。它可以用来唤醒STOP模式。
内部定时器是一个12位间隔定时器。我们按事先设定的任意时间间隔产生中断 ( INTIT),能用于从 STOP 模式的唤醒以及 A/D 转换器的 SNOOZE模式的触发。
在定时器里面设定无线为休眠状态,主函数里面调用STOP模式。
无线的状态为每5s唤醒一次,工作50ms,然后重新进入休眠。
定时器中断和STOP模式部分程序如下:
/************************************************************************************************************************ Function Name: r_it_interrupt* Description : This function is INTIT interrupt service routine.* Arguments : None* Return Value : None***********************************************************************************************************************/__interrupt static void r_it_interrupt( void){ /* Start user code. Do not edit comment generated here */ if(Envent.Si24R1Sleep< 0xF0) Envent.Si24R1Sleep++; if(Envent.DoorSleep< 0xF0) Envent.DoorSleep++; //按键扫描 KeyScan(); .................................... /* End user code. Do not edit comment generated here */}
/********************************************************************************** Function Name : Stop_mode(void) Description : 睡眠模式 Parameters : none Return value : none ***********************************************************************************/ void Stop_mode(void ) { if((Envent.Si24R1Work> 0) || (WIRREC !=WireComm.WorkSta) ) return ; SI24R1_Shutdown(); R_ADC_Set_OperationOff(); P6.0 =1; P6.1 =1; BELLOFF; P2.2 =1; P7.0 =1; Envent.Si24R1Sleep =1; while(Envent.Si24R1Sleep) { STOP(); NOP(); NOP(); NOP(); NOP(); .................... ............... if(Envent.DoorSleep>= 5) { Envent.DoorSleep =0; //状态改变上报一次 if(ReedSwitch!= Envent.DoorSta) { Envent.DoorSta =ReedSwitch; if(WirPro.ParaMode== 1 && ReedSwitchOn ==ReedSwitch) { BELLON; delay_ms(200); delay_ms(100); BELLOFF; TimeDelayUp=0; } Envent.DeviceUp =0; Envent.CtrlUpSend =VALID_FLAG; Envent.Si24R1Sleep =25; } } else if (Envent.Si24R1Sleep>=25) //5s { Envent.Si24R1Sleep =0; Envent.Si24R1Work =50;//50ms } R_WDT_Restart(); } SI24R1_PowerOn(); ............... }
最后对系统的功能进行整体调试,得到的待机模式下工作电流为6微安左右。无线发射和接收时有15mA,蜂鸣器工作时,最高有37mA。
基本满足要求设计。不过还需要继续完善。
]]>1、安装git
2、在本地创建ssh key
ssh-keygen -t rsa -C "your_email@youremail.com"
比如 ssh-keygen -t rsa -C "rayu@engineer.com"
邮箱就是你的github邮箱。
之后会要求确认路径和输入密码,我们这使用默认的一路回车就行。
成功的话会在~/下生成.ssh文件夹,进去,打开id_rsa.pub,复制里面的key。
回到github,进入Account Settings,左边选择SSH Keys,Add SSH Key,title随便填,粘贴key。
添加完成。
3、连接到github
ssh -T git@github.com
输入一个yes,会看到:You’ve successfully authenticated, but GitHub does not provide shell access
。这就表示已成功连上github。
4、设置常用的用户名和密码
git config --global user.name "your name"git config --global user.email "your_email@youremail.com"
这里的用户名和邮箱分别是github的用户名和邮箱。
5、进入仓库
git remote add origin git@github.com:yourName/yourRepo.git
后面的yourName和yourRepo表示你再github的用户名和刚才新建的仓库,加完之后进入.git目录,打开config,这里会多出一个remote “origin”内容,这就是刚才添加的远程地址,也可以直接修改config来配置远程地址。
6、提交上传
接下来在本地仓库里添加一些文件,比如README,
git add README #git add . touch git.md git commit -m "first commit"
上传到github:
git push origin master
git push
命令会将本地仓库推送到远程服务器。
git pull
命令则相反。
使用git status
可以查看文件的差别,
使用git add
添加要commit的文件,
之后git commit
提交本次修改,git push
上传到github。
或者git push origin master
7、克隆仓库
找到想要克隆的仓库。
git clone git@github.com:AloneMonkey/weekly.git
提交上传的命令见第六步。
hexo new "git"
会自带md后缀,哈哈,然后hexo d -g
Please, commit your changes or stash them before you can merge.Aborting
git pull
时出现上述情况,解决方法如下:
这是因为如果系统中有一些配置文件在服务器上做了配置修改,然后后续开发又新添加一些配置项的时候,
在发布这个配置文件的时候,会发生代码冲突:
如果希望保留生产服务器上所做的改动,仅仅并入新配置项, 处理方法如下:
git stash git pull git stash pop
然后可以使用git diff -w +文件名
来确认代码自动合并的情况.
反过来,如果希望用代码库中的文件完全覆盖本地工作版本. 方法如下:
git reset --hard git pull
其中git reset是针对版本,如果想针对文件回退本地修改,使用
git checkout HEAD file/to/restore
进阶:
git stash save "work in progress for foo feature"
当你多次使用’git stash’命令后,你的栈里将充满了未提交的代码,这时候你会对将哪个版本应用回来有些困惑,
’git stash list
’ 命令可以将当前的Git栈信息打印出来,
你只需要将找到对应的版本号,
例如使用’git stash apply stash@{1}’
就可以将你指定版本号为stash@{1}的工作取出来,
当你将所有的栈都应用回来的时候,可以使用’git stash clear
’来将栈清空。
在windows右键添加cmd菜单,如下图。
原文地址:http://blog.rayuu.com/cmdhere.html
这样使用cmd进入某个路径就方便多了!!!!
Windows Registry Editor Version 5.00 [HKEY_CLASSES_ROOT\*\shell\cmdhere] @="Cmd&Here"[HKEY_CLASSES_ROOT\*\shell\cmdhere\command] @="cmd.exe /c start cmd.exe /k pushd \"%l \\..\" "[HKEY_CLASSES_ROOT\Folder\shell\cmdhere] @="Cmd&Here"[HKEY_CLASSES_ROOT\Folder\shell\cmdhere\command] @="cmd.exe /c start cmd.exe /k pushd \"%l\" "
点进去就是命令行了。
]]>发现百度的sitemap.xml抓取不到github上面的,所以今天又弄了一个coding。
在个人设置里面添加好公钥后,本地git登录
然后在站点配置文件_config.yml
里面配置如下:
# Deployment## Docs: https://hexo.io/docs/deployment.htmldeploy: type: git #repository: https://github.com/Rayuu/Rayuu.github.io.git #branch: master repo: github: git@github.com:Rayuu/Rayuu.github.io.git,master coding: git@git.coding.net:chay/chay.git,coding-pages
接下来git bash
到站点目录
最后
hexo d -g
没有报错说明完成,添加密钥后也不用每次输入密码了。
这样就完美了哦!
今天重装了系统,感觉整个人都好多了。哈哈哈(#滑稽)
重新部署hexo
先安装hexo
,
再安装nodejs,git
接着安装npm install -g cnpm --registry=https://registry.npm.taobao.org
cnpm install -g hexo
找个文件夹打开 git bash here
hexo initcnpm install hexo-deployer-git --savecnpm install hexo-generator-sitemap --savecnpm install hexo-generator-baidu-sitemap --savecnpm install hexo-generator-search --save
把备份的公钥文件夹放到C:\Users\用户名\.ssh
下面
ssh -T git@git.coding.netssh -T git@github.com
让服务器使用ssh
协议。
成功的话就一切正常。
hexo d -g
上传!!!搞定。。。
]]>github
上搭起了博客,虽然搬瓦工也买了一年的服务器。centos6.4系统自带的python版本是2.6,用起来不是很方便。
于是今天我又开始折腾了。
首先看一下系统的版本
发现是centos6.4
再查看python版本
Python 2.6.6
下面开始升级,下载源码自己编译。。。。。
操作步骤如下:
1)安装devtoolset
yum groupinstall “Development tools”
2)安装编译Python需要的包包
yum install zlib-devel
yum install bzip2-devel
yum install openssl-devel
yum install ncurses-devel
yum install sqlite-devel
3)下载并解压Python 2.7.9的源代码
cd /opt
wget –no-check-certificate https://www.python.org/ftp/python/2.7.9/Python-2.7.9.tar.xz
tar xf Python-2.7.9.tar.xz
cd Python-2.7.9
4)编译与安装Python 2.7.9
./configure –prefix=/usr/local
make && make altinstall
5)将python命令指向Python 2.7.9
ln -s /usr/local/bin/python2.7 /usr/local/bin/python //这句好像没什么用。。。
#mv /usr/bin/python /usr/bin/python2.6
#ln -s /usr/local/bin/python2.7 /usr/bin/python
6)重新检验Python 版本
#python -V
7)解决系统 Python 软链接指向 Python2.7 版本后,因为yum是不兼容 Python 2.7的,所以yum不能正常工作,我们需要指定 yum 的Python版本
#vi /usr/bin/yum
将文件头部的
#!/usr/bin/python
改成
#!/usr/bin/python2.6
保存并退出大功告成。。。。
先是搭硬件,小车,电机驱动,稳压,电池什么的。
此处略去很多字。
既然是wifi小车,首先要让车跑起来。
让车跑,首先要控制I/O口。
用的是python的GPIO口的库。
sudo apt-get install python-dev # 下载 $ wget http://raspberry-gpio-python.googlecode.com/files/RPi.GPIO-0.5.3a.tar.gz # 解压缩 $ tar xvzf RPi.GPIO-0.5.3a.tar.gz # 进入解压之后的目录 $ cd RPi.GPIO-0.5.3a # 启动安装 $ sudo python setup.py install
然后进入python界面
import RPi.GPIO as GPIO
没有报错则说明安装成功。
下面就是用I/O口控制小车了。
import RPi.GPIO as GPIO import time GPIO.setmode(GPIO.BOARD) GPIO.setup(11, GPIO.OUT) GPIO.setup(12, GPIO.OUT) GPIO.setup(15, GPIO.OUT) GPIO.setup(16, GPIO.OUT) in11 = GPIO.PWM(11, 50) in12 = GPIO.PWM(12, 50) in21 = GPIO.PWM(15, 50) in22 = GPIO.PWM(16, 50) shudu=30 def yanshi(t): while t>0: t=t-1 def houtui(): in11.start(30) in12.start(0) in21.start(30) in22.start(0) def tingzhi(): in11.stop() in12.stop() in21.stop() in22.stop() def zhizou1(): in11.start(0) in12.start(30) in21.start(0) in22.start(30) def zhizou(): in11.start(0) in12.start(shudu) in21.start(0) in22.start(shudu) def youzhuan(): in11.start(0) in12.start(30) in21.start(30) in22.start(0) def zuozhuan(): in11.start(30) in12.start(0) in21.start(0) in22.start(30) while True: fangxiang=raw_input() if fangxiang=='q': shudu=shudu+10 zhizou() elif fangxiang=='e': shudu=shudu-10 zhizou() elif fangxiang=='w': zhizou1() elif fangxiang=='a': t=30000 while t>0: t=t-1 zuozhuan() tingzhi() elif fangxiang=='s': houtui() elif fangxiang=='d': t=30000 while t>0: t=t-1 youzhuan() tingzhi() else : tingzhi()
]]>######我是参考的这个帖子做的
http://www.shumeipai.net/forum.php?mod=viewthread&tid=18882
插上摄像头可以看见usbvideo0.
接下来安装
sudo apt-get install subversionsudo apt-get install libv4l-devsudo apt-get install libjpeg8-devsudo apt-get install imagemagick
到上面这些步骤都没有错。
下面下载的是mipg-steamer
软件,编译并安装。
那个帖子里面的下载地址都过期了,所以我就重新百度 google找啊找。
在网上搜mjpg-streamer
搜出一个mjpg-streamer-r63,这个包始终编译不成功,有郁闷了很久。
终于在github上面有一个和帖子说的一样的。
还有在这里也有一个链接http://pan.baidu.com/share/link?shareid=507341537&uk=84253138
于是希望重新燃起,
开始编译,建立软连接:sudo ln -s /usr/include/libv4l1-videodev.h /usr/include/linux/videodev.h
进入目录并编译:
cd mjpg-streamermake USE_LIBV4L2=true clean all
编译好像是成功了,因为没有报错。
然后执行 sudo ./start.sh
打开浏览器访问,树莓派ip地址:8080
发现并没有成功,摄像头并没有出来,多么痛的领悟啊。
很忧桑有木有。
于是又开始找问题,
分析得出以下结论:
摄像头没有打开,但是这不科学啊,设备可以检查到usbvideo0。
摄像头驱动问题,我把摄像头放到windows下发现可以使用。
就是环境问题咯。
所以我一个一个尝试,首先看用摄像头拍照可以不。
结果发现摄像头没有问题。
就是拍出来的照片有点失真。图片如下:
然后又各种找资料。
找到一个用motion软件做的摄像头识别。好像是专门的网络摄像头监控软件。
嘿嘿,希望还是有的。
sudo apt-get install motion
配置motion,编辑motion.conf文件
sudo vi /etc/motion/motion.conf
找到”control_localhost on “和”webcam_localhost on“这两行,改为以下两行后,保存退出
control_localhost off
webcam_localhost off
运行motion软件,输入motion -n
在pc上用浏览器打开 树莓派ip地址:8080
经过我的测试 ie11 和chrome 不可以实现,火狐浏览器可以哦
画面就是上面的这样子咯。
昨天弄了一天效果还可以,感觉很满意。
总结一下吧:
树莓派和以前玩过全志A20差不多,都是烧入操作系统。
直接上操作系统,因为有过这方面的经验,所以折腾起来也就不费事了。
摄像头监控还做的不好,有时间再玩一玩,可能是因为昨天折腾了一天,头很晕,所以后面摄像头的思路不是很清晰。
等暑假再做个wifi小车玩一玩。嘿嘿~~!
还有就是最近的微信公众号效果不错,800多粉丝了。
这几天查成绩功能不可用,还是很不爽的,所以就传了2个游戏让大家玩。
嘿嘿,另外发现小米路由器还是很坑的。
星期五服务器莫名其妙的无法访问,使用的云监控没有报警,原因很奇怪,后来发现是小米路由器不知道什么时候自己把硬盘自动休眠给开启了。害的我找了半天,还以为是网络问题呢。结果把小米路由器的硬盘休眠功能一关闭,服务器就不挂了,正常运行了一天。等查成绩功能教务系统开放了再看一看效果。实在不行就用树莓派当web服务器了。刷个openwrt玩一玩。
]]>首先开始烧系统到内存卡。用win32disk imager
官网下载地址 http://sourceforge.net/projects/win32diskimager/
然后就到上图所示的界面了。
点击write
就开始烧写到内存卡了。
我开始还很二逼的点了read
,苦苦的等了十几分钟发现内存卡还是空的,我的内心几乎是崩溃的。
记得一定要点write
哦!
烧写完成,把内存卡插到树莓派上面。
插上网线,通电。
通过路由器查看raspberry设备的ip地址,然后ssh登上raspberry。
因为树莓派默认开启了ssh,所以可以直接连上哦!
默认账号和密码分别是:pi
和raspberry
接着可以把root权限打开
sudo passwd root
输入2次密码就行了。
然后进入如下界面:
第一次用 root 登录,会自动弹出树莓派的高级设置面板(以后也可以通过 raspi-config
命令进入):
选择第一项 Expand Filesystem
扩展 SD 卡上可用的空间,不然以后会有很多大软件,不能安装(提示空间不足,例如 mysql)。
扩展之后可以通过 df -h
命令看到效果~
第二项是修改密码。
第五项是开启摄像头。可以自己都试一试。
然后最好更改一下软件源,因为在国内毕竟要快一些。
树莓派官方有提供一个镜像列表:http://www.raspbian.org/RaspbianMirrors 里面有很多中国的镜像。
然后 vi /etc/apt/sources.list
改为
deb http://mirrors.ustc.edu.cn/raspbian/raspbian/ wheezy main contrib non-free rpideb-src http://mirrors.ustc.edu.cn/raspbian/raspbian/ wheezy main contrib non-free rpi
按下ESC键,再按下wq 回车,就保存退出了。
下面apt-get update
一下吧。
然后我觉得网线连着不方便,所以就配置了无线网卡。
vi /etc/network/interfaces
修改下面的代码,自行配制连上你的路由器。
iface wlan0 inet staticwpa-ssid Your_Wifi_SSIDwpa-psk Your_Wifi_Passwordaddress 192.168.1.200 # 设定的静态IP地址netmask 255.255.255.0 # 网络掩码gateway 192.168.1.1 # 网关network 192.168.1.1 # 网络地址#wpa-roam /etc/wpa_supplicant/wpa_supplicant.conf
然后拔掉网线,重启restart,开机就是无线上网了。很高兴是吧。
后面我又安装了lamp
步骤如下:
搭建lamp环境,apt-get install apache2 mysql-server php5
修改apache2权限,chmod 777 /var/www/
安装phpmyadmin,apt-get intstall phpmyadmin
选apache2
链接到apache2目录,ln -s /usr/share/phpmyadmin /var/www/
在浏览器访问树莓派ip地址检查是否成功。并检查phpmyadmin可以进否。
下面我开始研究GPIO口的配置。说出来又是一把心酸一把泪。
上面是GPIO口的分布。
我在网上找了一下python的程序。
先要安装RPi.GPIO
http://sourceforge.net/projects/raspberry-gpio-python/
从这上面下载
然后我是通过winscp把文件复制到板子里面去的。
后来发现sudo apt-get install python-rpi.gpio
这个命令也可以安装
安装成功以后运行python
输入
import RPi.GPIO as GPIO
注意RPi i是小写的,白天就找了半天的错误。
没有错误的话就说明安装成功了。
然后就可以写个简单的程序。点亮一个流水灯。
开始在网上找的程序都不能用,我也恨郁闷啊。
因为
GPIO.setmode(GPIO.BOARD)
这句话报错。
后来想一想还是靠自己,于是我用python help 对RPi.GPIO的用法进行查看,发现这个函数都没有了。可能是因为硬件的更新吧。
于是我就注释了这条代码。
发现下面还有几条不能用。
这是多么的纠结啊。
所以我又继续改。
最后
GPIO.setup(11, GPIO.OUT) while True: GPIO.output(11, 1) time.sleep(1) GPIO.output(11, 0) time.sleep(1)
这样写就没问题了,接在板子上的led灯也一秒一秒的闪烁了。
真是喜大普奔啊。啊哈哈~!
好吧就先写到这里。
其实我下午还弄了摄像头监控。
但是效果不太好。晚上如果还有时间的话我就继续写。
先吃个饭洗个澡去啦。
啦啦啦!!~
]]>sudo apt-get update
su passwd root
su xcy
然后是安装ssh
sudo apt-get install openssh-server openssh -client
安装完成服务端和客户端后,用电脑进行ssh远程登录。
连接成功。
回忆起来了一些命令。
chmod 777 filename
groupadd testgroup
useradd test1 -g testgroup
adduser test2 -g testgroup
其中useradd新建用户在home目录下面没有文件夹,而adduser则有。
ps -e 查看进程
kill 3400杀死3400进程
kill -9 pid process
mkdir 目录名 => 创建一个目录
rmdir 空目录名 => 删除一个空目录
rm 文件名 文件名 => 删除一个文件或多个文件
rm –rf 非空目录名 => 删除一个非空目录下的一切
touch 文件名 => 创建一个空文件
重命名文件(夹) / 移动文件(夹)到指定文件夹
执行格式: mv source destination
mv file1 file2 => 将文件 file1,更改文件名为 file2。
mv file1 dir1 => 将文件 file1,移到目录 dir1下,文件名仍为 file1。
mv dir1 dir2 => 若目录 dir2 存在,则将目录 dir1,及其所有文件和子目录,移到
目录 dir2 下,新目录名称为 dir1。若目录 dir2 不存在,则将dir1,及其所有文件和
子目录,更改为目录 dir2。
今天就练到这里。明天继续!加油!