从USB-CDC读取字符串;如何使用stdio_set_chars_available_callback()?

问题描述 投票:0回答:1

一旦字符可用,我就会尝试在回调函数中使用

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,正如预期的那样。

c usb microcontroller stdio raspberry-pi-pico
1个回答
0
投票

可能您需要使用 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 的这一新功能的可用性(需要多一点代码)。

© www.soinside.com 2019 - 2024. All rights reserved.