esp32 完整开发指南_前端也能玩硬件:在ESP32上运行JavaScript

0. 写在前面

本文的主要目的是描述如何让 ESP32 芯片运行 JavaScript,并且让 web 前端开发人员也能玩转硬件。 作者之前是 web 前端开发工程师,所以文章会尽量站在 web 前端开发工程师的角度,抛开底层的硬件知识,去掉一些目前不需要关心的,将重点放在软件上。 尽管这样,我们接下来所要做的是 硬件+软件 的一个整体,所以一些基础的 C 语言和硬件知识会让你更好的阅读此文章。没有也不要紧,因为高深的我也不会阿!

文章会分为 2 个篇幅进行讲解。其中基础篇会先介绍基础知识,有以下几个部分:

  1. ESP32 硬件介绍
  2. JerryScript 简单介绍
  3. FreeRTOS 简单介绍

实战篇将会介绍如何在 ESP32 芯片上面运行 JerryScript,有以下几个部分:

  1. 让 JerryScript 运行并接受串口输入
  2. 使用片上存储芯片:flash
  3. 实现 JS 文件模块

1. ESP32 硬件介绍

首先先介绍一下 ESP32 是个什么东西,简单来说,它就是一块集成了 WiFi、蓝牙、天线、功率放大器、电源管理模块、CPU、存储器、传感器的单片机微控制器,说人话就是:它能存储并运行我们的代码,还具有 WiFi 和蓝牙功能。先来看一张图吧:

884bf449610be5c7f751e703458d2363.png
ESP32 开发板

左边一块比较大的就是 ESP32 模组,上面提到的所有硬件配置都集成在这片模组上。下面的板子和其它元件是为了方便开发以及芯片启动必要的电路连接,而做成的一个开发板。这个开发板加了电源转换芯片,使得支持 3.3 - 5V 电压,右边小的方块型的是 cp2102 USB转串口芯片,使得我们可以使用 USB 线连接电脑。这个板子把引脚都引出来了,方便使用杜邦线连接各种外围器件。下面我们说的 ESP32 都表示这整块开发板,而不是 ESP32 模组本身。

ESP32 采用两个哈佛结构 Xtensa LX6 CPU 构成双核系统,时钟频率在 80MHz - 240MHz 范围内可调。片上集成了 520KB SRAM, 448KB ROM。拥有 41 个外设模块,包含常见的 IIC, SPI, UART, PWM, IR, I2S, SDIO 等。常见的协议基本都有了,这使得我们可以更方便的和大部分电子模块或外设进行通信,而不需要像 51 单片机一样,使用软件模拟实现。比如常见的 SSD12864 oled 屏幕,同时具有 IIC 和 SPI 的接口。BLOX-NEO-6M GPS 模块是使用的 UART 接口。直流电机和伺服机可以使用 PWM 驱动。电风扇、空调等用的是 IR 红外线传输信号。

除此之外,ESP32 还集成了片上传感器和模拟信号处理器。比如电容式触摸传感器,霍尔传感器,ADC,DAC 等。如果我们设计了有电池的产品,有了 ADC,我们就可以方便的测量电池的电量,虽然这样测量的值不一定准。

以上是单片机系统中很常见的外设,ESP32 将它们都集成在一个片上系统中了。但 ESP32 最让人激动的是,它集成了 WIFI 和 蓝牙。有了 WIFI 和 蓝牙,再配合各种外设,GPIO,我们就能拿它做很多事情,比如温度湿度传感器的值直接上传到服务器。远程下发执行指令开关灯等,尽可以发挥你的想象。

但硬件编程对于软件工程师来说却实门槛有点高,尤其像我们 web前端开发工程师,C 语言就是第一道门槛。我一直想将 JavaScript 带到硬件编程中去,这样我们就可以使用熟悉的 JavaScript 发挥我们的创意。所以才有了本篇文章。

2. JerryScript 简单介绍

Node.js 很强大,但它是建立在 V8 和 libuv 之上的, ESP32 片上 SRAM 只有 520KB,别说 v8 了,libuv 都跑不起来。所以我们需要一个轻量的,为嵌入式设计的 JavaScript 引擎,幸运的是,我们有 JerryScript。

JerryScript 是一个轻量级的 JavaScript 引擎,它可以运行在受限制的设备上,例如微控制器,它能在 RAM < 64 KB, ROM < 200 KB 的设备上运行。而且它还提供了完整的 ES5.1 语法支持,以及部分 ES6 语法支持,比如 箭头函数,Symbol, Promise 等。在编程体验上虽然没有 v8 这么爽,但有这些就已经很好了啊(相对于其它的嵌入式 JavaScript 引擎来说)!

还有一个重要的点是 JerryScript 的 api 更符合我们的编程习惯,对于已经习惯编写 Node.js addon 的人来说会更容易接受。所以以上2点,是我们选择 JerryScript 的理由。为了让大家更直观的理解,下面我们对比2个目前在嵌入式比较流行的 JavaScript 引擎。

duktape

duktape 目前在 github 上面是 3.7K 个 Star,下面是官网的 hello world!

#include <stdio.h>
#include "duktape.h"

/* Adder: add argument values. */
static duk_ret_t native_adder(duk_context *ctx) {
    
  int i;
  int n = duk_get_top(ctx);  /* #args */
  double res = 0.0;

  for (i = 0; i < n; i++) {
    
    res += duk_to_number(ctx, i);
  }

  duk_push_number(ctx, res);
  return 1;  /* one return value */
}

int main(int argc, char *argv[]) {
    
  duk_context *ctx = duk_create_heap_default();

  duk_push_c_function(ctx, native_adder, DUK_VARARGS);
  duk_put_global_string(ctx, "adder");

  duk_eval_string(ctx, "adder(1+2);");
  printf("1+2=%dn", (int) duk_get_int(ctx, -1));

  duk_destroy_heap(ctx);
  return 0;
}

JerryScript

#include "jerryscript.h"
#include "jerryscript-ext/handler.h"

static jerry_value_t adder_handler(const jerry_value_t func_value, /**< function object */
                                   const jerry_value_t this_value, /**< this arg */
                                   const jerry_value_t args[],    /**< function arguments */
                                   const jerry_length_t args_cnt)  /**< number of function arguments */
{
    
  double total = 0;
  uint32_t argIndex = 0;

  while (argIndex < args_cnt)
  {
    
    double = double + jerry_get_number_value(args[argIndex]);
    argIndex++;
  }
  return jerry_create_number(total);
}

int main (void)
{
    
  const jerry_char_t script[] = "print(adder(1, 2));";

  /* Initialize engine */
  jerry_init (JERRY_INIT_EMPTY);

  /* Register 'print' function from the extensions */
  jerryx_handler_register_global ((const jerry_char_t *) "print", jerryx_handler_print);

  /* Register 'adder' function from the extensions */
  jerryx_handler_register_global ((const jerry_char_t *) "adder", adder_handler);

  /* Setup Global scope code */
  jerry_value_t parsed_code = jerry_parse (NULL, 0, script, sizeof (script) - 1, JERRY_PARSE_NO_OPTS);

  if (!jerry_value_is_error (parsed_code))
  {
    
    /* Execute the parsed source code in the Global scope */
    jerry_value_t ret_value = jerry_run (parsed_code);

    /* Returned value must be freed */
    jerry_release_value (ret_value);
  }

  /* Parsed source code must be freed */
  jerry_release_value (parsed_code);

  /* Cleanup engine */
  jerry_cleanup ();

  return 0;
}

3. FreeRTOS 简单介绍

FreeRTOS 是一个热门的嵌入式设备用即时操作系统核心,它设计小巧且简易,大部分的代码由 C 语言编写。它提供多任务,互斥锁,信号量,和软件定时器等功能,让用户可以快速的进行应用程序设计。

以上是维基百科的介绍,简单来说主要就是为设计多任务的应用程序提供基本的工具库,让应用开发者可以专注于逻辑的实现,而没必要自己实现任务管理和调度。因为在单片机上编程是没有像 Linux 一样的多进程,多线程的概念的,单片机上电启动后就从指定地址加载指令,按照顺序执行完。

单片机一般来说只有一个处理器,同一时间只能处理一个任务,假如你想让 2 个 LED 交替闪烁,那么你必须在 while(true){...} 循环内手动控制 2 个 LED 逻辑代码的执行时间,假如后续有 3 个,4 个,N 个呢?那么所有的逻辑都得写在里面,会非常庞大。

FreeRTOS 的任务能让各个逻辑跑在单独的 Task 中互不干扰,各 Task 以优先级抢占 CPU 时间。值得注意的是,即使使用了 FreeRTOS,整个应用仍然是单线程的,高优先级任务执行完后,必须要让出 CPU 时间才能让其它低优先级任务执行。记住,单片机只有一个处理器,同一时间只能处理一个任务。

整个 FreeRTOS 的任务是一个链表,从任务列表中取出最高优先级的任务执行,执行完后再取出下一优先级任务,一直循环。不过有几点不同,F

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值