Grove 接口
Grove 是一种规范的嵌入式开发套件连接接口定义。
什么是 Grove 系统
Grove 是一个模块化的标准连接器原型系统。Grove 采用积木式组装电子技术。与基于跳线或焊接的系统相比,连接、试验和构建更容易,并简化了学习系统。Grove 系统允许你构建真正的系统。因而它需要一些学习和专业知识才能正确地将物件联接起来。
Grove 系统由基本处理单元(树干)和具有标准化连接器的各种模块(树枝)组成。基本单元(通常为微处理器)允许从 Grove 模块轻松连接任何输入或输出。每个 Grove 模块通常都可以处理单个功能,例如简单的按钮或更复杂的心率传感器。
如果您使用的处理单元没有 Grove 接口。您可以使用 Grove 转 Pin Header 转接线,从 Raspberry Pi 或 Arduino 的针脚连接到 Grove 模块。
当然,ODYSSEY-STM32MP157C 提供了两个 Grove 接口,一个是数字 Grove 接口,一个是 I2C Grove 接口。用户可以通过这两个 Grove 接口快速搭建项目原型。我整理了一些 Grove 模块资料,有需要的小伙伴可以点击购买。
厂家 | 型号 | 接口 |
Seeed | 多合一 Grove 传感器套件 | - |
Seeed | 1.12寸 OLED 显示屏模块 | I2C |
Seeed | 0.96寸 12864 OLED 显示屏模块 | I2C |
Seeed | 绿色 LED Grove 模块 | GPIO |
Seeed | 白色 LED Grove 模块 | GPIO |
Seeed | 可变色 LED Grove 模块 | GPIO |
Seeed | 可编程 RGB 全彩 LED 模块 |
快速测试 Grove 模块
想要在 ODYSSEY-STM32MP157C 开发板上测试 Grove 模块非常简单,因为 Seeed Studio 已经为我们提供了一个基于 Python 的 Grove 库(https://github.com/Seeed-Studio/grove.py)。里面有许多测试程序,包括按钮、LED、显示屏、电机等模块。
但是在使用这些库之前,我们还需要做一些工作!如果你已经完成了上一节《【ODYSSEY-STM32MP157C】环境搭建与系统运行》的环境搭建,那么接下来,我们就可以直接来测试 GPIO 了。
首先,安装 Grove.py
sudo pip3 install
然后,下载 grove.py 库源代码
git
进入 grove 目录,运行示例
cd grove.py/grove
sudo
此时,如果你插上了 Grove Kit 扩展板,并在 5 号 Grove 接口上接入 IO 模块(比如 LED 灯、继电器),将会看到 LED 灯闪烁或继电器开合动作。
使用 Libgpiod 库
本着勤俭节约的精神,我没有入手 Grove 模块,而是用白嫖的 ODYSSEY-STM32MP157C 开发板 + 现有的 LED 模块来完成实验。没有的小伙伴赶紧上车啦~
- ODYSSEY-STM32MP157C
- LED 模块
那不用 Grove 库,应该怎么操作 GPIO 呢?答案是 —— libgpiod 库!
从 Linux 4.8 开始,不再推荐使用 sysfs 接口(/sys/class/gpio)操作 GPIO,而是建议在用户空间使用字符设备进行操作,libgpiod 就是一个用于操作 GPIO 字符设备的库,同时提供了一些工具,方便开发者进行调试。
-
gpiodetect
—— 列出系统上存在的所有 gpiochip,以及它们的名称、标签和 GPIO lines。 -
gpioinfo
—— 列出指定 gpiochip 的所有 line,以及它们的名称、使用者、方向、活动状态和其他标志。 -
gpioget
—— 读取指定 GPIO line 的值。 -
gpioset
—— 设置指定的 GPIO line 的值。 -
gpiofind
—— 通过名称找到对应的 gpiochip 及行内偏移量。 -
gpiomon
—— 等待指定 GPIO 线上的事件,或指定要监视的事件。
例如:
# gpiodetect
gpiochip0 [GPIOA] (16 lines)
gpiochip1 [GPIOB] (16 lines)
gpiochip2 [GPIOC] (16 lines)
gpiochip3 [GPIOD] (16 lines)
gpiochip4 [GPIOE] (16 lines)
gpiochip5 [GPIOF] (16 lines)
gpiochip6 [GPIOG] (16 lines)
gpiochip7 [GPIOH] (16 lines)
gpiochip8 [GPIOI] (16 lines)
gpiochip9 [GPIOZ] (16 lines)
控制 LED 闪烁
我在 40 pin 扩展接口的 GPIO_A14(7号管脚)接了一个 LED 模块,而 GPIO_A14 对应 gpiochip0 的 line 14,因此,通过如下命令即可控制 LED 的亮灭。
gpioset gpiochip0 14=1 # 高电平
gpioset gpiochip0 14=0 # 低电平
因此,我们可以通过这种方式写个 shell 脚本来实现 LED 灯闪烁的效果。
#!/bin/bash
while :
do
gpioset gpiochip0 14=0
sleep 0.5
gpioset gpiochip0 14=1
sleep 0.5
done
运行该 shell 脚本,效果如下:
实现呼吸灯效果
要实现呼吸灯效果,通常采用 DAC 数模转换 和 PWM 控制 两种方式,当然软件 PWM 也能实现,但从运行效率来讲并不是很好的方法。同时,由于 STM32MP157C 中包含一个 Cortex-M4 核,因此,我们可以在 M4 侧实现呼吸灯,完全采用 STM32 MCU 的编程方法即可。
还是那个 LED 模块,这次选择 GPIO_A3(29号管脚),因为 PA3 有定时器功能,因此可以设置为 PWM 控制输出模式。
- 打开 STM32CubeIDE,创建新工程,选择 STM32MP157C 芯片。
- 将 PA3 引脚分配给 Cortex-M4 核,配置 PA3 为 TIM2_CH4 模式,配置 Timer2,使能 Channel 4,如下图所示。
- 接着配置 TIM2 参数。由于 Timer 的频率为 64 MHz,因此预分频系数设置为 64-1,自动重载值设置为 1000-1。所以 PWM 频率为 64,000,000 / 64 / 1000 = 1000 Hz。
- 接着,我们在一个周期内(比如 1ms)调节 PWM 的占空比(dutyCycle)即可实现呼吸灯效果,main 函数代码如下。
int main(void)
{
/* USER CODE BEGIN 1 */
uint16_t dutyCycle = 0;
/* USER CODE END 1 */
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
if(IS_ENGINEERING_BOOT_MODE())
{
/* Configure the system clock */
SystemClock_Config();
}
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_TIM2_Init();
/* USER CODE BEGIN 2 */
HAL_TIM_PWM_Start(&htim2,TIM_CHANNEL_4);
/* USER CODE END 2 */
/* USER CODE BEGIN WHILE */
while (1)
{
while (dutyCycle < 1000)
{
dutyCycle++;
__HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_4, dutyCycle);
HAL_Delay(1);
}
HAL_Delay(200);
while (dutyCycle > 10) /* 为了效果好一点,我故意不让LED全灭 */
{
dutyCycle--;
__HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_4, dutyCycle);
HAL_Delay(1);
}
HAL_Delay(400);
}
}
- 点击 STM32CubeIDE 工具栏的“锤子”编译工程,将在 /CM4/Debug/ 目录下生成 elf 文件(比如 led_CM4.elf)。
- 将刚生成的 led_CM4.elf 文件放到 ODYSSEY-STM32MP157C 的
/lib/firmware
目录,并执行如下操作。
echo led_CM4.elf > /sys/class/remoteproc/remoteproc0/firmware
echo start >
此时,Cortex-M4 侧的固件已经运行起来了!呼吸灯效果如下:
附录