C/C++ | PICO-SDK | Raspberry Pi Pico 使用回调从 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)
,以便在有字符可供读取时收到通知。

我有以下代码用于测试目的。 现在,我不尝试仅读取字符串中的单个字符(作为整数),然后将整数回显给用户。当我无法读取字符时,我也无法读取字符串。

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

结束编辑

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.