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

i5desfxk  于 2023-10-16  发布在  其他
关注(0)|答案(1)|浏览(117)

我尝试在字符可用时使用回调函数中的stdio读取通过USB传输到Raspberry Pi皮科的字符串。我不想轮询接口或使用重复计时器。由于UART0UART1需要用于其他目的,并且所有PIO状态机都用于更多的PCI接口,因此USB是唯一的选择。皮科_SDK提供void stdio_set_chars_available_callback(void(*)(void *) fn, void *param),以便在字符可用时获得通知。
我不尝试读取字符串,只是一个单一的字符(作为一个整数),然后回显整数。当我不能读一个字符时,我也不能读一个字符串。真实的项目超过3000行,完全基于中断和回调的概念。除了UART0UART1之外,我还使用PIO-Statemachines实现了UART2UART3UART4UART5getchar_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)。使ivolatile不会改变输出,因为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。

7ajki6be

7ajki6be1#

可能你需要使用CMakeLists.txt中的定义
https://www.opensourceagenda.com/projects/pico-sdk/versions
添加了stdio_set_chars_available_callback()函数,用于设置在输入可用时调用的回调。另请参阅新的PICO_STDIO_USB_SUPPORT_CHARS_AVAILABLE_CALLBACKPICO_STDIO_UART_SUPPORT_CHARS_AVAILABLE_CALLBACK定义,它们都默认为1,并分别控制USB和USB stdio的此新功能的可用性(以多一点代码为代价)。

相关问题