这次,我考虑过将GPS追踪器藏在自行车中作为预防措施。 市场上有许多用于跟踪汽车,货物,自行车,行李,儿童和动物的自动装置。 他们中的绝大多数通过短信与用户互动。 更昂贵的选项提供“查找我的电话”功能,但与特定的在线服务相关。
理想情况下,我想完全控制跟踪器:在没有SMS和注册的便捷模式下使用它。 肤浅的Google给我带来了几个来自中国的模块,我订购了其中的一个模块(A9G布丁板)(〜15美元)。

本文是关于我如何使python在此模块上工作的。
如果A9G是ESP的类似物(顺便说一句,制造商是相同的),那么布丁板本身就是NodeMCU板的类似物,只是布丁板没有内置的USB-UART转换器。 但是还有许多其他有趣的事情。 制造商规格:
- 32位核心(RISC),最高312MHz
- 29个GPIO(均已焊接,所有接口均包含在此编号中)
- 手表和看门狗
- 1个USB 1.1接口(我在那里找不到,但是可以从异地复制)和microUSB供电
- 2个UART(+1服务)
- 2x SPI(未尝试)
- 3x I2C(未尝试)
- 1个SDMMC(带有物理插槽)
- 2个模拟输入(10位,锂电池控制器可能使用其中之一)
- 4Mb闪存
- 4Mb PSRAM
- ADC(麦克风,物理存在于板上)和DAC(扬声器,不存在)
- 电池充电控制器(本身没有电池)
- 实际上,带有SMS,语音和GPRS的GSM(800、900、1800、1900 MHz)
- GPS通过UART2连接(没有“ A9”模块)
- SIM卡插槽(nanoSIM)
- 两个按钮(一个复位,另一个-包含和可编程功能)
- 两个LED
工作电压为3.3V,输入电压为5-3.8V(取决于连接)。 通常,该模块具有所有必需的硬件,以便根据其组装简单的按钮式移动设备。 但是从这些例子中,似乎中国人正在从老虎机或老虎机或类似的东西上购买它来出售。 该模块的替代品是相当流行的SIM800模块,不幸的是,该模块在公共领域中没有SDK(即,这些模块作为AT调制解调器出售)。
开发包
该模块随附了令人满意的英语SDK 。 在Ubuntu下安装,但是Windows和容器是首选。 一切都可以通过在GUI中戳来完成:此模块的ESPtool尚未还原。 固件本身由Makefile构建。 存在调试器:冻结之前,模块将堆栈跟踪抛出到服务端口中。 但就我个人而言,我无法将地址转换为代码行(gdb报告该地址与任何内容都不对应)。 可能是由于对Linux这样的支持不佳所致。 因此,如果您想修改模块-尝试在Windows下进行(并在github上退订)。 否则,这是Linux的说明 。 安装后,您需要检查.bashrc中路径的正确性,并删除(重命名)所有CSDTK/lib/libQt*
:否则,由于可能与已安装的libQt发生冲突,刷新程序(即调试器)将无法启动。

闪光灯上有一条指示 。
连接方式
一切都比在NodeMCU上复杂。 这些模块看起来很相似,但是布丁板上没有USB-TTY芯片,microUSB仅用于供电。 因此,您将需要3.3V的USB-TTY。 两种比较好:一种用于调试端口,一种用于UART1:第一种用于上传固件,第二种可以用作常规终端。 为了不将所有这些鼻涕拖到计算机上,我还购买了带两米电缆和外部电源的4端口USB分配器(必需)。 该套件与模块本身的总成本为25-30美元(不带电源:可通过电话使用)。
韧体
该模块随附AT固件:您可以连接到3.3V arduino,并通过UART1将其用作调制解调器。 他们的固件使用C语言编写。make创建了两个固件文件:一个缝制了大约一分钟,另一个缝制得足够快。 只能缝制以下文件中的一个:第一次较大,以后较小。 总的来说,在开发过程中,我在桌面上打开了中文SDK( coolwatcher
),用于管理模块,miniterm(作为stdio和代码编辑器)。
API
API的内容反映了上面的列表,类似于ESP8266的早期版本:我花了大约3个小时来启动HelloWorld。 不幸的是,用户可用的功能集非常有限:例如,无法访问SIM卡上的电话簿,有关连接到蜂窝网络的低级信息等等。 API文档甚至还不够完善,因此您必须依靠示例(其中有两个打样)并包含文件。 不过,该模块可以完成许多工作,直至SSL连接:显然,制造商专注于最优先的功能。
但是,必须喜欢通过中文API进行中文微控制器的编程。 对于其他所有人,制造商开始将 micropython移植到此模块。 我决定尝试一个开源项目,并继续进行这项出色的工作(本文结尾处的链接)。
微型蟒蛇

Micropython是一个将cPython移植到微控制器的开源项目。 开发是从两个方向进行的。 首先是对所有微控制器通用的核心库的支持和开发,这些库描述了如何使用python中的主要数据类型:对象,函数,类,字符串,原子类型等。 第二个实际上是端口:对于每个微控制器,有必要“教”该库以使用UART进行输入输出,为虚拟机选择堆栈,指定一组优化。 可选地,描述了与硬件一起使用:GPIO,电源,无线,文件系统。
所有这些都是用带有宏的纯C语言编写的:micropython有一组建议的配方,从在ROM中声明字符串到编写模块。 除此之外,还完全支持python自写模块(主要是不要忘记内存大小)。 该项目的策展人将发布dzhanga (带有面包的图片)的机会作为他们的目标。 作为广告:该项目为pyboard学生出售自己的开发板,但ESP8266和ESP32模块的端口也很受欢迎。
准备好固件并上载后-您只需通过UART连接到微控制器,然后进入Python REPL。
$ miniterm.py /dev/ttyUSB1 115200 --raw MicroPython cd2f742 on 2017-11-29; unicorn with Cortex-M3 Type "help()" for more information. >>> print("hello") hello
之后,您可以开始使用几乎普通的python3编写代码,而不必担心内存限制。
A9G模块不受官方支持( micropython/ports
提供了官方支持的模块列表,其中大约有十二个)。 尽管如此,钢铁制造商分叉了micropython并为A9G端口创建了环境: micropython/ports/gprs_a9
,为此,他表示了很多谢意。 当我对这个问题感兴趣时,该端口已成功编译,微控制器向我致敬REPL。 但是,不幸的是,在第三方模块中,只能使用文件系统和GPIO:没有与无线网络和GPS相关的内容。 我决定修复此缺陷,并为自己设定了移植GPS跟踪器所需的所有功能的目标。 该案例的官方文档过于简洁:因此,我不得不在代码中四处张望。
从哪里开始
首先,转到micropython/ports
然后将micropython/ports/minimal
复制到端口将位于的新文件夹中。 然后,为您的平台编辑main.c
请记住,所有好吃的东西都在main
函数中,您需要在其中调用mp_init()
初始化器,之前已mp_init()
准备了微控制器和堆栈设置。 然后,对于事件驱动的API,您需要调用pyexec_event_repl_init()
并将通过UART输入的字符提供给pyexec_event_repl_process_char(char)
函数。 这将通过REPL提供互操作性。 第二个文件是micropython/ports/minimal/uart_core.c
描述了阻止UART中的输入和输出。 我为那些懒惰的人带来了STM32的原始代码。
main.c
int main(int argc, char **argv) { int stack_dummy; stack_top = (char*)&stack_dummy; #if MICROPY_ENABLE_GC gc_init(heap, heap + sizeof(heap)); #endif mp_init(); #if MICROPY_ENABLE_COMPILER #if MICROPY_REPL_EVENT_DRIVEN pyexec_event_repl_init(); for (;;) { int c = mp_hal_stdin_rx_chr(); if (pyexec_event_repl_process_char(c)) { break; } } #else pyexec_friendly_repl(); #endif
uart_core.c
之后,您需要使用制造商的建议/编译器重写Makefile:此处的所有操作都是单独的。 理想情况下,所有一切都应该足够:我们收集,填写固件,然后在UART中查看REPL。
恢复micropython
您需要照顾好它的健康:设置垃圾收集器,对Ctrl-D的正确反应(软复位)以及其他我不愿mpconfigport.h
其他事项:请参阅mpconfigport.h
文件。
创建一个模块
最有趣的是编写自己的模块。 因此,模块(不是必需的,但可取的)以其自己的mod[].c
文件开头,该文件由Makefile
添加(如果遵循约定, SRC_C
变量)。 空模块如下:
当然,端口本身无法识别mp_module_mymodule
常数:必须将其添加到mpconfigport.h
端口mpconfigport.h
的MICROPY_PORT_BUILTIN_MODULES
变量中。 顺便说一句 无聊的壁纸 芯片名称和端口名称也在此处更改。 完成所有这些更改后,您可以尝试编译模块并从REPL导入它。 只有一个具有模块名称的__name__
属性可用于该模块(这是通过Tab使用REPL检查自动完成的一种好方法)。
>>> import mymodule >>> mymodule.__name__ 'mymodule'
常数
复杂性的下一个阶段是添加常量。 设置通常需要常量( INPUT
, OUTPUT
, HIGH
, LOW
等)。这里的一切都很简单。 例如,这里的常数magic_number = 10
:
STATIC const mp_map_elem_t mymodule_globals_table[] = { { MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_mymodule) }, { MP_OBJ_NEW_QSTR(MP_QSTR_magic_number), MP_OBJ_NEW_SMALL_INT(10) }, };
测试:
>>> import mymodule >>> mymodule.magic_number 10
功能介绍
向模块添加功能遵循以下一般原则:声明,包装,添加(我给出的示例比文档中的示例稍微复杂一些)。
测试:
>>> import mymodule >>> mymodule.conditional_add_one(3) 4 >>> mymodule.conditional_add_one(9) >>>
类(类型)
使用类(类型),一切也都相对简单。 这是文档中的一个示例(差不多):
测试:
>>> mymodule.helloObj <type 'helloObj'>
可以继承,比较结果类型,但是它没有构造函数或任何关联数据。 数据被添加到构造函数的“旁边”:建议创建一个单独的结构,在该结构中Python类型将被单独存储,即一个任意数据集。
如何与这些数据进行交互? 最困难的方法之一是通过构造函数。
在其他领域中,还有.print
,我猜想Python3
的其他魔力。
但是获取一个对象的实例根本不需要make_new
:初始化可以在任意函数中完成。 这是来自micropython/ports/esp32/modsocket.c
一个好例子:
绑定方法
下一步是添加绑定方法。 但是,这与所有其他方法并没有太大区别。 我们从文档中返回示例:
仅此而已!
>>> x = mymodule.helloObj(12) >>> x.inc()
所有其他属性: getattr , setattr
如何使用@property
和通常使用自己的__getattr__
添加非功能? 请:通过绕过mymodule_hello_locals_dict_table
手动完成。
您说,简明扼要的attr结果出乎意料。 这些mp_raise_AttributeError
都在哪里( 注意 :这样的函数不存在)? 实际上,将自动调用AttributeError
。 秘密在于dest
是两个元素的数组。 第一个元素的含义是“输出”,仅写:如果需要写入该值,则取值MP_OBJ_NULL
如果需要读取,则MP_OBJ_NULL
。 因此,在函数退出时,在第一种情况下期望mp_obj_t
,在第二种情况下期望mp_obj_t
。 输入的第二个元素是只读的:如果需要写入该值,则取要写入的对象的值;如果需要读取该值,则取MP_OBJ_NULL
。 您不需要更改它。
仅此而已,您可以检查:
>>> x = mymodule.helloObj(12) >>> x.val = 3 >>> x.val 3
最有趣的是,REPL中的制表符.val
仍然可以使用并提供.val
! 老实说,我不是C语言方面的专家,所以我只能猜测这是怎么发生的(通过重新定义运算符'==')。
港口
回到A9G模块,我描述了对所有基本功能的支持,即SMS,GPRS(电子信号),GPS,电源管理。 现在,您可以将类似这样的内容上传到模块,并且可以正常工作:
import cellular as c import usocket as sock import time import gps import machine
该项目欢迎任何可行的帮助。 如果您喜欢该项目和/或本文,请不要忘记在github上留下一个赞 。