Raspberry Pi Pico的GPIO端口SIO类结构体不好使
本帖最后由 量子隧道 于 2025-2-1 12:17 编辑Raspberry Pi Pico的SIO是一系列与其它设备统一进行地址编址的寄存器。通过对SIO寄存器的直接访问,可以便捷地对IO进行批量赋值和读取。我在熟悉它的过程中,发现其中的sio_hw->gpio_oe_set和sio_hw->gpio_oe等寄存器操作不好使。非要调用arduino IDE框架下的pinMode,才能设置管脚为输出。如下是示例程序。其中的四句pinMode函数是不可缺少的。有玩树莓派pico的坛友遇到过和我一样的问题吗?
#include <Arduino.h>
#include "pico/stdlib.h"
#include "hardware/gpio.h"
#define LED_PIN_1 25
#define LED_PIN_2 2
#define LED_PIN_3 3
#define LED_PIN_4 4
void setup() {
// 设置 GPIO 为输出模式
pinMode(LED_PIN_1,OUTPUT);
pinMode(LED_PIN_2,OUTPUT);
pinMode(LED_PIN_3,OUTPUT);
pinMode(LED_PIN_4,OUTPUT);
sio_hw->gpio_oe_set = 0x3fffffff;
Serial.begin(115200);
}
void loop() {
//轮流点亮LED
sio_hw->gpio_out = 1<<LED_PIN_1 ;
delay(500);
sio_hw->gpio_out = 1<<LED_PIN_2 ;
delay(500);
sio_hw->gpio_out = 1<<LED_PIN_3 ;
delay(500);
sio_hw->gpio_out = 1<<LED_PIN_4 ;
delay(500);
//同时点亮所有 LED
sio_hw->gpio_set = (1 << LED_PIN_1) | (1 << LED_PIN_2) | (1 << LED_PIN_3) | (1 << LED_PIN_4);
delay(500);
// 同时关闭所有 LED
sio_hw->gpio_clr = (1 << LED_PIN_1) | (1 << LED_PIN_2) | (1 << LED_PIN_3) | (1 << LED_PIN_4);
delay(500);
Serial.println("***************");
} 本帖最后由 girlexplorer 于 2025-2-1 12:37 编辑
老衲不懂编程,问了一下AI:
其中的四句pinMode函数是不可缺少的吗?
AI回答:
在上述代码中,`pinMode(LED_PIN_1, OUTPUT);`、`pinMode(LED_PIN_2, OUTPUT);`、`pinMode(LED_PIN_3, OUTPUT);`和`pinMode(LED_PIN_4, OUTPUT);`是必不可少的。这些函数用于将指定的GPIO引脚设置为输出模式,以便能够控制LED灯的状态。
具体来说:
1. **初始化阶段**:
- `sio_hw->gpio_oe_set = 0x3fffffff;` 将所有GPIO引脚设置为输出状态。
- 这一步是必要的,因为如果没有将这些引脚设置为输出模式,后续的写操作(如`sio_hw->gpio_out`、`sio_hw->gpio_set`和`sio_hw->gpio_clr`)将会导致未定义的行为。
2. **主循环**:
- 在每次循环中,通过调用 `pinMode(LED_PIN_1, OUTPUT);` 等函数来确保LED引脚仍然处于输出模式。虽然在每个循环的开头已经设置了所有GPIO为输出状态,但为了明确表示这一点,并且避免潜在的问题,这些函数通常会在每一步操作之前再次被调用。
因此,在实际应用中,即使在初始化阶段将所有GPIO设置为输出状态,`pinMode(LED_PIN_1, OUTPUT);`等函数仍然需要在每次写操作前进行调用。
(感觉这次AI回答的不靠谱。主循环里好像没有再次调用pinmode)
本帖最后由 scoopydoo 于 2025-2-1 12:45 编辑
看了下数据手册,你这个 pinMode 函数应该是对应 GPIO 控制寄存器的 0..4 bit 的,必须要设置啊!
你看数据手册的 2.19.2. Function Select 就清楚了。
(AI编出了类似程序,不知这个AI编的程序是否可行。这个程序里,AI也用了pinmode)
您:(提出要求)
使用Arduino和Pico微控制器控制四个LED灯的亮灭。逐个点亮每个LED,每次点亮一个LED后等待500毫秒。同时点亮所有四个LED,然后等待500毫秒。同时关闭所有四个LED,然后等待500毫秒。每次循环结束后,打印一行“***************”。请编出程序。
AI回答:
以下是一个使用Arduino和Pico微控制器控制四个LED灯的示例程序。这个程序逐个点亮每个LED,然后同时点亮所有四个LED,关闭所有四个LED,并在每次循环结束后打印一行“***************”。
```cpp
#include <Arduino.h>
// 定义LED引脚
const int led1 = 2; // Pico上的GPIO2连接到第一个LED
const int led2 = 3; // Pico上的GPIO3连接到第二个LED
const int led3 = 4; // Pico上的GPIO4连接到第三个LED
const int led4 = 5; // Pico上的GPIO5连接到第四个LED
void setup() {
// 初始化所有LED为输出模式
pinMode(led1, OUTPUT);
pinMode(led2, OUTPUT);
pinMode(led3, OUTPUT);
pinMode(led4, OUTPUT);
Serial.begin(9600); // 启动串口通信,用于调试和打印信息
}
void loop() {
// 逐个点亮每个LED
digitalWrite(led1, HIGH);
delay(500);
digitalWrite(led2, HIGH);
delay(500);
digitalWrite(led3, HIGH);
delay(500);
digitalWrite(led4, HIGH);
delay(500);
// 同时点亮所有四个LED
digitalWrite(led1, LOW);
digitalWrite(led2, LOW);
digitalWrite(led3, LOW);
digitalWrite(led4, LOW);
delay(500);
// 关闭所有四个LED
digitalWrite(led1, HIGH);
digitalWrite(led2, HIGH);
digitalWrite(led3, HIGH);
digitalWrite(led4, HIGH);
delay(500);
// 打印一行“***************”
Serial.println("*****************");
}
```
### 解释:
- **引脚定义**:`const int led1 = 2;` 到 `const int led4 = 5;` 定义了四个LED的GPIO引脚。
- **初始化**:在 `setup()` 函数中,使用 `pinMode()` 将所有LED设置为输出模式,并启动串口通信以进行调试和打印信息。
- **循环体**:
- 首先逐个点亮每个LED,每次点亮后等待500毫秒。
- 然后同时关闭所有四个LED,再次等待500毫秒。
- 最后,打印一行“***************”以表示一次完整的循环结束。
这个程序可以在Arduino IDE或Pico SDK中运行。确保你的开发环境已经正确配置,并且连接了正确的硬件设备(如Arduino板和Pico微控制器)。
scoopydoo 发表于 2025-2-1 12:44
看了下数据手册,你这个 pinMode 函数应该是对应 GPIO 控制寄存器的 0..4 bit 的,必须要设置啊!
你看 ...
你说的是指2.19.2里的“ The SIO function (F5) must be selected for the processors to drive a GPIO”,而pinMode()函数就是用来设置管脚为“F5”功能的?那就清楚了。
只不过,我以为,这个“设置为F5”功能在SIO结构体里已经定义了呢,而且我以为它就是sio_hw->gpio_oe_set寄存器呢。看来不是。
这个编程框架有点不伦不类。按理说,应该在sio结构体里定义这个设置,而不应该一会儿pico sdk,一会儿arduino ide,显得这个程序框架像个大杂烩。 量子隧道 发表于 2025-2-1 12:57
你说的是指2.19.2里的“ The SIO function (F5) must be selected for the processors to drive a GPIO” ...
俺没实验,但是俺觉得应该是这样的,一般来说单片机的 IO 引脚在使用前都要先选择功能的,毕竟都是多功能复用的。
俺对 Arduino 框架不熟悉,手里有两块 Nano 系列的 Arduino 小板子(33 IOT 和 Matter),但是基本只是拿来验证网上找到的一些 Arduino 代码 ... 本帖最后由 量子隧道 于 2025-2-1 13:08 编辑
girlexplorer 发表于 2025-2-1 12:46
(AI编出了类似程序,不知这个AI编的程序是否可行。这个程序里,AI也用了pinmode)
程序应该没问题,但是很可惜,它没有使用SIO类结构体和寄存器,而是调用了arduino的管脚控制函数(digitalwrite)来实现的。
--读了一下,看来AI还是个智障,程序是有基本逻辑错误的。不过框架应该没问题。 找到了pinMode()函数的定义,看起来若定义为output的话,库函数是啥都没做。这下子彻底风中凌乱了。。。;P
先别凌乱,为啥俺看到的代码和你的不一样呢? :o
scoopydoo 发表于 2025-2-1 14:20
先别凌乱,为啥俺看到的代码和你的不一样呢?
我的wiring_digital.cpp文件的头两行注释是这样式儿的,你看看你的是不是:
pinMode and digitalRead/Write for the Raspberry Pi Pico RP2040
Copyright (c) 2021 Earle F. Philhower, III <earlephilhower@yahoo.com> 量子隧道 发表于 2025-2-1 14:47
我的wiring_digital.cpp文件的头两行注释是这样式儿的,你看看你的是不是:
pinMode and digitalRead/ ...
俺看到的头两行是这样婶儿的,估计你那个是对的 :L
wiring_digital.cpp - digital input and output functions
Part of Arduino - http://www.arduino.cc/
scoopydoo 发表于 2025-2-1 14:50
俺看到的头两行是这样婶儿的,估计你那个是对的
我这是装了:
https://github.com/earlephilhower/arduino-pico/releases/download/global/package_rp2040_index.json
这个RP2040支持库的结果。 量子隧道 发表于 2025-2-1 14:52
我这是装了:
https://github.com/earlephilhower/arduino-pico/releases/download/global/package_rp20 ...
哈哈,刚好俺也搜到这个,之前用的是 mBed 那个。
俺装上这个看看 ....... 本帖最后由 scoopydoo 于 2025-2-1 15:37 编辑
应该是找到答案了,在 pico-sdk 的 gpio.c 文件的 gpio_init 函数里面:
void gpio_init(uint gpio) {
gpio_set_dir(gpio, GPIO_IN);
gpio_put(gpio, 0);
gpio_set_function(gpio, GPIO_FUNC_SIO);
}
具体的实现是这样婶儿的:
/// \tag::gpio_set_function[]
// Select function for this GPIO, and ensure input/output are enabled at the pad.
// This also clears the input/output/irq override bits.
void gpio_set_function(uint gpio, gpio_function_t fn) {
check_gpio_param(gpio);
invalid_params_if(HARDWARE_GPIO, ((uint32_t)fn << IO_BANK0_GPIO0_CTRL_FUNCSEL_LSB) & ~IO_BANK0_GPIO0_CTRL_FUNCSEL_BITS);
// Set input enable on, output disable off
hw_write_masked(&pads_bank0_hw->io,
PADS_BANK0_GPIO0_IE_BITS,
PADS_BANK0_GPIO0_IE_BITS | PADS_BANK0_GPIO0_OD_BITS
);
// Zero all fields apart from fsel; we want this IO to do what the peripheral tells it.
// This doesn't affect e.g. pullup/pulldown, as these are in pad controls.
io_bank0_hw->io.ctrl = fn << IO_BANK0_GPIO0_CTRL_FUNCSEL_LSB;
#if !PICO_RP2040
// Remove pad isolation now that the correct peripheral is in control of the pad
hw_clear_bits(&pads_bank0_hw->io, PADS_BANK0_GPIO0_ISO_BITS);
#endif
}
/// \end::gpio_set_function[] 本帖最后由 量子隧道 于 2025-2-1 17:00 编辑
scoopydoo 发表于 2025-2-1 15:24
应该是找到答案了,在 pico-sdk 的 gpio.c 文件的 gpio_init 函数里面:
问题在于,如果pinmode()函数里设置管脚为OUTPUT,那么gpio_init()函数得不到执行的机会啊
----啥也没干,就让管脚变成了function5(SIO)模式了?:Q
页:
[1]
2