我尝试在字符可用时使用回调函数中的stdio
读取通过USB传输到Raspberry Pi皮科的字符串。我不想轮询接口或使用重复计时器。由于UART0
和UART1
需要用于其他目的,并且所有PIO状态机都用于更多的PCI接口,因此USB是唯一的选择。皮科_SDK提供void stdio_set_chars_available_callback(void(*)(void *) fn, void *param)
,以便在字符可用时获得通知。
我不尝试读取字符串,只是一个单一的字符(作为一个整数),然后回显整数。当我不能读一个字符时,我也不能读一个字符串。真实的项目超过3000行,完全基于中断和回调的概念。除了UART0
和UART1
之外,我还使用PIO-Statemachines实现了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;
}
callback工作。我通过启用回调函数中的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_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和屏幕,没有不同的结果。通过使用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 ---
我输入你好(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指针不应该是volatile的,它会抛出一个警告。将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。
1条答案
按热度按时间7ajki6be1#
可能你需要使用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和USB stdio的此新功能的可用性(以多一点代码为代价)。