# Rasberry Pi Pico(RP2040板) C\_Cpp及Python微型机器学习

{% tabs %}
{% tab title="关键词" %}
Raspberry Pi Pico | RP2040 | C/C++ | MicroPython | Tensroflow Lite | TensorFlow | Arduino | 几何图形 | 微型机器学习 | GPU功能 | 月相 | 直流电机 | 温湿度 | 模数转换ADC | 定时器 | 音频采样 | ARM Mbed | 梅尔频率倒谱系数(MFCC) | 特征提取 | FOMO算法 | Edge Impulse | 传感器
{% endtab %}

{% tab title="关联链接" %}
{% embed url="https://viadean.notion.site/Rasberry-Pi-Pico-RP2040-C_Cpp-Python-6cf06f0b2efc49f296e8bb36e2aceae5?pvs=4" %}
{% endtab %}
{% endtabs %}

{% content-ref url="../zhi-dian-mi-jin-brief" %}
[zhi-dian-mi-jin-brief](../zhi-dian-mi-jin-brief)
{% endcontent-ref %}

### 要点

1. Raspberry Pi Pico使用C/C++和MicroPython开发环境设置,实现Python和C/C++两种微型机器学习几何图形检测
2. 自定义和使用第三方库更改Pi Pico 为GPU功能；Rpi Pico实现月相显示；Rpi Pico直流电机驱动；RP2040板微型机器学习音频分类
3. Rpi Pico 使用Arduino IDE ：温湿度检测;Rpi Pico声控 LED；Rpi Pico 使用数模转换和定时器采样音频；使用Rpi Pico和Arm Mbed OS手势识别
4. Rpi Pico 机器学习：Rpi Pico 梅尔频率倒谱系数（MFCC）特征提取分析音乐类型；使用FOMO算法图像分类

### Raspberry Pi Pico（RP2040板）

> **微控制器 vs 微处理器**
>
> \
> 您可能认为微控制器只是微处理器的较小版本。 虽然有些微控制器非常强大，但它们不是微处理器。 微处理器旨在最大限度地提高芯片上的计算能力，同时连接到总线（想想用于数字通信的并行高速公路）以利用 RAM 和输入等。

Raspberry Pi Pico（即 Pico）是一块小型绿色印刷电路板，大小如口香糖。 沿着任一长边是 GPIO 引脚，其中一个较短的一端有一个 micro-USB 连接器。 另一端是一组调试引脚，可用于高级诊断。 下图显示了 Pico 的俯视图，USB 端口位于右侧。

请注意顶部和底部边缘的 GPIO 接头座。 左边的三个引脚是调试引脚。 板上我们需要了解的唯一其他组件是位于图中右上角的 BOOTSEL（启动选择）开关。 此开关用于将 Pico 置于运行 MicroPython 平台的启动模式，或者，如果在 USB 电缆连接到计算机时按住该开关，它将作为可移动驱动器连接，允许您加载新文件或更改基础 平台文件。

下图显示了 Pico 的底面。 请注意，我们看到 GPIO 引脚带有标签，可以轻松找到特定引脚。 标有“TP”的位置是测试点，如果您需要对电路板执行任何高级诊断，则可以使用它们来测试电压。 同样，左侧的引脚用于串行线调试 (SWD) 接口。

Pico 的核心是位于主板顶部中央的大（相对于主板而言）黑色芯片。 这是 RP2040 微处理器，它提供了 Pico 的所有功能。

**RP2040 微处理器**

让我们从名字开始吧。 这个名字乍一看可能有点奇怪。 通常，我们认为该数字是某种修订或版本1，但 RP2040 的情况并非如此。 下图描述了名称的命名法。 正如您所看到的，它是一个编码短语，代表微处理器的四个特征。 将来我们很可能会看到该微处理器的变体，并且我们应该预期它的名称（编号）会根据该命名法而变化

RP2040 是一款结合了存储器、双核处理器、接口和支持电子器件的单芯片。 从很多方面来说，它都是一个独立的微控制器动力源。 该芯片旨在提供高性能和低功耗。 事实上，它还可以支持使用电池电源的扩展执行。 最重要的是，它能够运行 MicroPython，使编程变得非常容易学习，打破了微控制器常见的陡峭编程学习曲线。 换句话说，您不必拥有编程或电子学位就可以使用它。

您可能最感兴趣的功能包括 SPI 和 I2C 控制器（各 2 个）、16 个脉宽调制通道和 30 个 GPIO 引脚。 可以说，它几乎可以处理您的电子项目所需的任何内容。

有许多基于 RP2040 的微控制器板是围绕 RP2040 构建的。 有些提供 Pico 上没有的独特功能，而另一些则是对现有产品线的熟悉适应。 它们都从 RP2040 获得强大的基础，并且工作原理与 Pico 相同。

### MicroPyhon物理计算示例

**示例1：LED闪烁**

首先找到 LED：它是板顶部 micro-USB 端口左侧的小矩形组件（如 下图），标有“LED”标签。 这个小 LED 的工作原理与其他 LED 一样：通电时，它会发光；打开时，它会发光。 当它关闭时，它仍然是黑暗的。

板载 LED 连接到 RP2040 的通用输入/输出引脚之一 GP25。这是 RP2040 上存在的“缺失”GPIO 引脚之一，未分解为物理引脚 。 除了板载 LED 之外，您无法将任何外部硬件连接到该引脚，但它可以像程序中的任何其他 GPIO 引脚一样对待，并且它是向程序添加输出的好方法。

最后，让 LED 闪烁。 为此，您需要创建一个循环。 重写您的程序，使其与下面的程序匹配：

```python
 import machine
 import utime
 led_onboard = machine.Pin(25, machine.Pin.OUT)
 while True:
  led_onboard.value(1)
  utime.sleep(5)
  led_onboard.value(0)
  utime.sleep(5)
 ​
```

还有另一种方法可以处理相同的工作：使用切换，而不是明确地将 LED 的输出设置为 0 或 1。 删除程序的最后四行并替换它们，使其看起来像这样：

```python
 import machine
 import utime
 led_onboard = machine.Pin(25, machine.Pin.OUT)
 while True:
  led_onboard.toggle()
  utime.sleep(5)
```

再次运行您的程序。 您将看到与之前相同的活动：板载 LED 将亮起五秒钟，然后熄灭五秒钟，然后无限循环地再次亮起。 不过，这一次，您的程序缩短了两行：您已经对其进行了优化。 在所有数字输出引脚上可用，toggle() 只需在打开和关闭之间切换：如果引脚当前处于打开状态，toggle() 将其关闭； 如果它关闭，toggle() 将其打开。

**示例2：红黄蓝交通灯**

首先构建一个简单的交通灯系统，如下图所示。 将红色 LED 插入面包板，使其横跨中央分隔线。 如果您需要进行更长的连接，请使用一个 330 Ω 电阻器和跳线，将 LED 的较长引脚（阳极）连接到 Pico 左下角的引脚（从顶部看） 最上面的微型 USB 电缆，GP15。 如果您使用的是编号面包板并且将 Pico 插入到最顶部，则这将是面包板的第 20 行。

```python
 import machine
 import utime
 import _thread
 led_red = machine.Pin(15, machine.Pin.OUT)
 led_amber = machine.Pin(14, machine.Pin.OUT)
 led_green = machine.Pin(13, machine.Pin.OUT)
 button = machine.Pin(16, machine.Pin.IN, machine.Pin.PULL_DOWN)
 buzzer = machine.Pin(12, machine.Pin.OUT)
 global button_pressed
 button_pressed = False
 def button_reader_thread():
  global button_pressed
  while True:
     if button.value() == 1:
         button_pressed = True
 ​
 while True:
     if button_pressed == True:
         led_red.value(1)
         for i in range(10):
              buzzer.value(1)
              utime.sleep(0.2)
              buzzer.value(0)
              utime.sleep(0.2)
         global button_pressed
         button_pressed = False
      led_red.value(1)
      utime.sleep(5)
      led_amber.value(1)
      utime.sleep(2)
      led_red.value(0)
      led_amber.value(0)
      led_green.value(1)
      utime.sleep(5)
      led_green.value(0)
      led_amber.value(1)
      utime.sleep(5)
      led_amber.value(0)
```

单击运行图标。 首先，程序将正常运行：交通灯将按照通常的模式打开和关闭。 按下按钮开关：如果程序当前处于循环中间，则在到达末尾并再次循环之前不会发生任何事情

### C/C++

**示例3：闪烁LED**

当您为硬件编写软件时，打开、关闭 LED，然后再次打开，通常是在新编程环境中运行的第一个程序。 学习如何让 LED 闪烁可以让您成功一半。

此示例对 Raspberry Pi Pico 使用以下代码，使连接到 RP2040 引脚 25 的 LED 闪烁：

```c
 #include "pico/stdlib.h"
 ​
 int main() {
 #ifndef PICO_DEFAULT_LED_PIN
 #warning blink example requires a board with a regular LED
 #else
     const uint LED_PIN = PICO_DEFAULT_LED_PIN;
     gpio_init(LED_PIN);
     gpio_set_dir(LED_PIN, GPIO_OUT);
     while (true) {
         gpio_put(LED_PIN, 1);
         sleep_ms(250);
         gpio_put(LED_PIN, 0);
         sleep_ms(250);
     }
 #endif
 }
```

以下是 Raspberry Pi Pico W 的替代代码，它使连接到带有 WL\_GPIO0 的 Infineon 43439 无线芯片的 LED 闪烁：

```c
 #include "pico/stdlib.h"
 #include "pico/cyw43_arch.h"
 ​
 int main() {
     stdio_init_all();
     if (cyw43_arch_init()) {
         printf("Wi-Fi init failed");
         return -1;
     }
     while (true) {
         cyw43_arch_gpio_put(CYW43_WL_GPIO_LED_PIN, 1);
         sleep_ms(250);
         cyw43_arch_gpio_put(CYW43_WL_GPIO_LED_PIN, 0);
         sleep_ms(250);
     }
 }
```

**示例4：在低亮度和高亮度之间渐变 LEDf3**

```c
 #include "pico/stdlib.h"
 #include <stdio.h>
 #include "pico/time.h"
 #include "hardware/irq.h"
 #include "hardware/pwm.h"
 ​
 #ifdef PICO_DEFAULT_LED_PIN
 void on_pwm_wrap() {
     static int fade = 0;
     static bool going_up = true;
     // Clear the interrupt flag that brought us here
     pwm_clear_irq(pwm_gpio_to_slice_num(PICO_DEFAULT_LED_PIN));
 ​
     if (going_up) {
         ++fade;
         if (fade > 255) {
             fade = 255;
             going_up = false;
         }
     } else {
         --fade;
         if (fade < 0) {
             fade = 0;
             going_up = true;
         }
     }
     pwm_set_gpio_level(PICO_DEFAULT_LED_PIN, fade * fade);
 }
 #endif
 ​
 int main() {
 #ifndef PICO_DEFAULT_LED_PIN
 #warning pwm/led_fade example requires a board with a regular LED
 #else
     gpio_set_function(PICO_DEFAULT_LED_PIN, GPIO_FUNC_PWM);
     uint slice_num = pwm_gpio_to_slice_num(PICO_DEFAULT_LED_PIN);
 ​
     pwm_clear_irq(slice_num);
     pwm_set_irq_enabled(slice_num, true);
     irq_set_exclusive_handler(PWM_IRQ_WRAP, on_pwm_wrap);
     irq_set_enabled(PWM_IRQ_WRAP, true);
 ​
     pwm_config config = pwm_get_default_config();
     pwm_config_set_clkdiv(&config, 4.f);
     pwm_init(slice_num, &config, true);
 ​
     while (1)
         tight_loop_contents();
 #endif
 }
```

### 微型机器学习

我们将检测三种不同的几何图形：圆形、方形和三角形。模型构建的第一步是从传感器（在我们的例子中是加速度计）收集数据。 数据可以以不同的形式加载。 您可以使用内置 CLI 通过串行端口读取传感器数据。此外，您还可以导入 CSV 或 JSON 文件格式的数据。
