t3486784401 发表于 2018-12-11 02:47:55

【分享】在 Arduino 当中看到了 C++流式接口

本帖最后由 t3486784401 于 2018-12-11 02:44 编辑

【背景】
想必接触过 AVR 的各位都或多或少接触过 Arduino,简单说就是一个积木式平台,有着众多的代码库。
用着很高层的语法(C++)干着很底层(单片机)的工作,不求代码效率,但求效果晃瞎眼。

之前一直对于 Arduino 不屑,认为除了官方的核心板外,其他的系统/电路很难做到兼容。
事实证明太小瞧这平台了,基本上给定个能力较AVR差不多的处理器,就可以找到对应的内核,
再接下来你连的外设(传感器、驱动器、IO总线)找到对应的库就可以直接编译出结果了。


【Arduino 的呼吸灯】
闲来无事,想看看呼吸灯这样的操作有没有现成的库,结果真找着了(JLed),效果不多讲,但调用的代码着实晃瞎眼。
(至此各位可以回忆下标准 C 怎么写个呼吸灯、怎么封装个库):

#include <jled.h>

// breathe LED for 5 times, LED is connected to pin 9 (PWM capable) gpio
JLed led = JLed(9).Breathe(2000).Repeat(5).DelayAfter(2000);

void setup()
{
}

void loop()
{
led.Update();
}

这里解释下(Arduino大神请移步下一节):
Arduino 程序有两个入口点(区别于C的main):setup 和 loop,分别执行一次/永久循环。这结构我总觉得类似 Verilog 当中的 initial 和 always...
由于是 C++,故全局实例化了一个 Jled 类,然后类实例直接操作板载 LED,由后台 Update 实现呼吸灯效果。


【Fluent Interface】
本来用这个库的时候,想着无非就是调用几个类成员函数,设定速度、电平、效果就完事了,结果被那行实例定义晃瞎了。

JLed led = JLed(9).Breathe(2000).Repeat(5).DelayAfter(2000);

这行代码信息量略大,实现的功能大致为:
在虚拟引脚9上定义 JLed 类,设定一个2000ms的呼吸灯,重复呼吸5次,每次呼吸间隔熄灭2000ms

仔细想来,如果这些函数返回了类的引用,在 C++ 语法里这么写没毛病,当然你分开一行行调用设定也可以。
另外由于设定的都是属性,这些调用的先后顺序无所谓,例如把 Repeat 和 DelayAfter 换一换,不影响最终效果。这可读性真不是盖的。

在 .md 文件当中看到了这种代码风给的名称:“Fluent Interface”,直译过来就是 :“流式接口”。
搜索了下这种接口风格,是为提升代码可读性而设计的,典型的例子如 C++::iostream,那一堆 << << >> >> 符号就是重载的流式接口。
一个单片机的编译器(GNU这个组织真心不说啥了),居然标准地支持 C++ 到如此地步,说实在的让人不寒而栗。


【后记】
说到呼吸灯,哪怕是汇编也能在 M64 上码出一模一样的运行结果。但封装这个灯光库的歪果仁,恐怕不单单是为了晃瞎观众那么简单。
总之搬运过来给大家分享,如有不当之处还请各位前辈指教。

P.S.    我用了第三方的处理器 + 第四方的内核库 + 第五方的灯光库,在 Arduino 平台上居然合成了可以正确运行的 HEX 文件,真心佩服这兼容性。
P.S.2. 以下是库源文件地址,有兴趣各位可移步瞻仰:https://github.com/jandelgado/jled

dukelec 发表于 2018-12-11 04:10:06

本帖最后由 dukelec 于 2018-12-11 04:25 编辑

前两年打算为 Arduino 写一个库,看了下官方对代码组织结构的要求太操蛋了,连子目录都不给用。
自己的项目文件多了想搞一个子目录也不行,必须要安装到插件目录当作库来调用。

另外,我觉得这个例子的可读性不见得有多友好,感觉直接把这些参数传给一个 init 函数更直观,N 多个接口化简为 1 个接口。

leiyitan 发表于 2018-12-11 04:25:52

一天做项目就是凑个功能…很少去思考这些有点深度的问题…注定累死累活,事业也走不远

wye11083 发表于 2018-12-11 07:01:24

gcc其实后端是直接支持avr的。所以可以直接编译c++等。只是生成代码量可能稍大。avr,avr32,arm,mips,riscv,这几个都是支持较好的。openrisc就不行。开gc-sections就不出bin了。

jcrorxp 发表于 2018-12-11 08:47:07

刚毕业的时候就想去学C++ , 面向对象还好理解,就是有时候很郁闷,
对象.对象.对象.函数
这些函数树,说明去哪找?
找不到了..不学了丢~

t3486784401 发表于 2018-12-11 14:02:14

dukelec 发表于 2018-12-11 04:10
前两年打算为 Arduino 写一个库,看了下官方对代码组织结构的要求太操蛋了,连子目录都不给用。
自己的项目 ...

容易上手的玩意,往往深挖就麻烦

t3486784401 发表于 2018-12-11 14:04:09

leiyitan 发表于 2018-12-11 04:25
一天做项目就是凑个功能…很少去思考这些有点深度的问题…注定累死累活,事业也走不远 ...

国内这行情,想深入研究的不如会倒腾关系的

t3486784401 发表于 2018-12-11 14:05:30

wye11083 发表于 2018-12-11 07:01
gcc其实后端是直接支持avr的。所以可以直接编译c++等。只是生成代码量可能稍大。avr,avr32,arm,mips, ...

Atmel 官方的 AvrStudio 内嵌就是 GCC,看样子是找对了大后台

t3486784401 发表于 2018-12-11 14:07:32

jcrorxp 发表于 2018-12-11 08:47
刚毕业的时候就想去学C++ , 面向对象还好理解,就是有时候很郁闷,
对象.对象.对象.函数
这些函数树,说明去 ...



以前 VS 的时候用 MSDN,现在 Arduino 直接翻源码去了
页: [1]
查看完整版本: 【分享】在 Arduino 当中看到了 C++流式接口