一旦字符可用,我就会尝试在回调函数中使用
stdio
读取通过 USB 传输到 Raspberry Pi Pico 的字符串。我不想轮询接口或使用重复计时器。由于 UART0
和 UART1
需要用于其他用途,并且所有 PIO 状态机都用于更多 UART 接口,因此 USB 是唯一的选择。 PICO_SDK 提供 void stdio_set_chars_available_callback(void(*)(void *) fn, void *param)
,以便在角色可用时收到通知。
我不尝试读取字符串,只是读取单个字符(作为整数),然后回显该整数。当我无法读取字符时,我也无法读取字符串。真实的项目有 3000 多行长,完全基于中断和回调的概念。除了
UART0
和 UART1
之外,我还使用 PIO 状态机实现了 UART2
、UART3
、UART4
和 UART5
。 getchar_timeout_us(0);
不是一个选项,它会使解析、检查字节间距(字节之间的时间)变得更加困难。
#include <stdio.h>
#include "pico/stdlib.h"
void callback(void *ptr){
int *i = (int*) ptr; // cast void pointer back to int pointer
// read the character which caused to callback (and in the future read the whole string)
*i = getchar_timeout_us(100); // length of timeout does not affect results
}
int main(){
stdio_usb_init(); // init usb only. uart0 and uart1 are needed elsewhere
while(!stdio_usb_connected()); // wait until USB connection
int i = 0;
stdio_set_chars_available_callback(callback, (void*) &i); //register callback
// main loop
while(1){
if(i!=0){
printf("%i\n",i); //print the integer value of the character we typed
i = 0; //reset the value
}
sleep_ms(1000);
}
return 0;
}
回调有效。我通过启用回调内的 LED 来测试它。当我在终端中输入内容时,LED 亮起。 void 指针的传递也有效。该值由回调更改。我认为问题是
*i = getchar_timeout_us(100);
。该函数返回 -1
,而不是我输入的字符的 ASCII(整数)值。当超时发生时,get_char_timeout_us()
返回PICO_ERROR_TIMEOUT
宏。我在回调中读取字符超时,通知字符可供读取。
选择
getchar_timeout_us(100);
中的100 μs是因为它并不比波特率115200时字节之间的最小时间长很多。最小时间将为86,805 μs。也许打字速度太快,但我会编写一个 Python 脚本将字符串发送到 Raspberry Pi Pico。
我希望在通知字符可用的回调中读取一个字符将返回发送字符,而不是
PICO_ERROR_TIMEOUT
。我的假设是 getchar_timeout_us(100);
中的 100 μs 超时太短,无法键入字符。尽管缓冲区中至少应该有一个字符,否则回调不应触发。我将超时增加到 1,000,000 μs,即 1 秒。还是PICO_ERROR_TIMEOUT
.
我尝试了多个终端,通常我在 Windows 上使用 PySerial
serial.tools.miniterm
。我还在 Fedora Linux 38(不同的计算机)上尝试了 Minicom 和 screen,没有不同的结果。使用 getchar();
消除超时会导致回调无限期阻塞。当我输入回调时,输入的字符似乎消失在空白中。我的假设是 getchar_timeout_us(100);
和 getchar();
是错误的函数。正确调用的函数是什么?或者如何使用现有的函数读取缓冲区中的字符?
CMakeList.txt:
# Generated Cmake Pico project file
cmake_minimum_required(VERSION 3.13)
set(CMAKE_C_STANDARD 11)
set(CMAKE_CXX_STANDARD 17)
# Initialise pico_sdk from installed location
# (note this can come from environment, CMake cache etc)
set(PICO_SDK_PATH "../../pico-sdk")
set(PICO_BOARD pico CACHE STRING "Board type")
# Pull in Raspberry Pi Pico SDK (must be before project)
include(pico_sdk_import.cmake)
if (PICO_SDK_VERSION_STRING VERSION_LESS "1.4.0")
message(FATAL_ERROR "Raspberry Pi Pico SDK version 1.4.0 (or later) required. Your version is ${PICO_SDK_VERSION_STRING}")
endif()
project(foo C CXX ASM)
# Initialise the Raspberry Pi Pico SDK
pico_sdk_init()
# Add executable. Default name is the project name, version 0.1
add_executable(foo src/foo.cpp )
target_include_directories(foo
PUBLIC
include/
)
pico_set_program_name(foo "foo")
pico_set_program_version(foo "0.1")
pico_enable_stdio_uart(foo 0) # disable stdio over UART we need it
pico_enable_stdio_usb(foo 1) # enable stdio over USB
# Add the standard library to the build
target_link_libraries(foo
pico_stdlib)
# Add the standard include files to the build
target_include_directories(foo PRIVATE
${CMAKE_CURRENT_LIST_DIR}
${CMAKE_CURRENT_LIST_DIR}/.. # for our common lwipopts or any other standard includes, if required
)
pico_add_extra_outputs(foo)
终端输出:
py -m serial.tools.miniterm COM14 115200
--- Miniterm on com14 115200,8,N,1 ---
--- Quit: Ctrl+] | Menu: Ctrl+T | Help: Ctrl+T followed by Ctrl+H ---
-1
-1
-1
-1
-1
--- exit ---
我输入了“Hello”
(72, 101, 108, 108, 111)
,但得到了“(-1, -1, -1, -1, -1)
”。这个:
#include <stdio.h>
#include "pico/stdlib.h"
int main()
{
//stdio_init_all();
stdio_usb_init(); // init usb only. uart0 and uart1 are needed elsewhere
while(!stdio_usb_connected()); // wait until USB connection
while(1){
int i = getchar_timeout_us(100);
if(i >= 0){
printf("%i", i);
}
}
return 0;
}
有效。当我输入
Hello
时,我会按预期得到 (72, 101, 108, 108, 111)
。制作 i
volatile
不会改变输出,并且因为 void 指针不应该是易失性的,所以它会引发警告。将 i
替换为全局 volatile int g = 0
(无示例)变量。
#include <stdio.h>
#include "pico/stdlib.h"
void callback(volatile void *ptr){
volatile int *i = (volatile int*) ptr; // cast void pointer back to int pointer
// read the character which caused to callback (and in the future read the whole string)
*i = getchar_timeout_us(100); // length of timeout does not affect results
}
int main(){
stdio_usb_init(); // init usb only. uart0 and uart1 are needed elsewhere
while(!stdio_usb_connected()); // wait until USB connection
volatile int i = 0;
stdio_set_chars_available_callback(callback, (volatile void*) &i); //register callback
// main loop
while(1){
if(i!=0){
printf("%i\n",i); //print the integer value of the character we typed
i = 0; //reset the value
}
sleep_ms(1000);
}
return 0;
}
在回调中将
gpio_put(PICO_DEFAULT_LED_PIN, 1)
放在 *i = getchar_timeout_us(100);
之后将打开 LED。在主循环中将 gpio_put(PICO_DEFAULT_LED_PIN, 0)
放在 sleep_ms(1000);
之后将不会 关闭 LED,正如预期的那样。
可能您需要使用 CMakeLists.txt 中的定义
https://www.opensourceagenda.com/projects/pico-sdk/versions
添加了
stdio_set_chars_available_callback()
函数来设置输入可用时调用的回调。另请参阅新的 PICO_STDIO_USB_SUPPORT_CHARS_AVAILABLE_CALLBACK
和 PICO_STDIO_UART_SUPPORT_CHARS_AVAILABLE_CALLBACK
定义,它们都默认为 1,并分别控制 USB 和 UART stdio 的这一新功能的可用性(需要多一点代码)。