我尝试使用
stdio
读取通过 USB 传输到 Raspberry Pi Pico 的字符串。
一旦字符可用,就应该在回调函数中读取字符串。我不想轮询界面是否有新字符或使用重复计时器。
因为
UART0
和 UART1
需要用于其他目的,并且所有 PIO 状态机都用于更多 UART 接口 USB 是唯一的选择。
void stdio_set_chars_available_callback(void(*)(void *) fn, void *param)
,以便在有字符可供读取时收到通知。
我有以下代码用于测试目的。 现在,我不尝试仅读取字符串中的单个字符(作为整数),然后将整数回显给用户。当我无法读取字符时,我也无法读取字符串。
编辑2023年6月19日
正如我在评论中所说,这不是实际的项目。真实的项目有 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
宏。
宏
PICO_ERROR_TIMEOUT
的值为 -1
。换句话说,我们超时了。
超时很奇怪,我们在回调方法中读取字符超时,通知我们可以读取字符。
选择
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)
编辑2023年6月19日
像这样的准系统 Echo 程序:
#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 poniter 不应该是易失性的,所以它会抛出警告(这是预期的)。 将
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,正如预期的那样。
结束编辑
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 的这一新功能的可用性(需要多一点代码)。