0

我非常不安。

我正在制作一台遥控机器,使用 pi pico 来驱动电机并读取一些传感器,并使用 raspberry pi 4 通过串行向 pi pico 发送命令并托管 Web 界面。

下面的代码似乎工作......但是......如果我用 uart_is_writable 编码和它的内容删除它不起作用。有谁知道为什么?

#include <stdlib.h>
#include <string.h>

#include "pico/stdlib.h"
#include "hardware/uart.h"
#include "hardware/irq.h"

//DEFINES
#define UART_ID uart0
#define BAUD_RATE 19200
#define DATA_BITS 8
#define STOP_BITS 1
#define PARITY    UART_PARITY_NONE
#define UART_TX_PIN 0
#define UART_RX_PIN 1
#define LED_PIN PICO_DEFAULT_LED_PIN

static int chars_rxed = 0;

volatile char uCommand[32] = {0, 0};

void on_uart_rx(void) {
   char tmp_string[] = {0, 0};
   new_command = true;
   while (uart_is_readable(UART_ID)) {
       uint8_t ch = uart_getc(UART_ID);
       tmp_string[0] = ch;
       strcat(uCommand, tmp_string);
       if(uart_is_writable(UART_ID)){
         uart_putc(UART_ID, '-');
         uart_puts(UART_ID, uCommand);
         uart_putc(UART_ID, '-');
       }
       chars_rxed++;
   }
}

int main(){

 uart_init(UART_ID, BAUD_RATE);

 gpio_set_function(UART_TX_PIN, GPIO_FUNC_UART);
 gpio_set_function(UART_RX_PIN, GPIO_FUNC_UART);

 uart_set_hw_flow(UART_ID, false, false);

 uart_set_format(UART_ID, DATA_BITS, STOP_BITS, PARITY);

 uart_set_fifo_enabled(UART_ID, false);

 int UART_IRQ = UART_ID == uart0 ? UART0_IRQ : UART1_IRQ;

 irq_set_exclusive_handler(UART_IRQ, on_uart_rx);
 irq_set_enabled(UART_IRQ, true);

 uart_set_irq_enables(UART_ID, true, false);

 uart_puts(UART_ID, "\nOK\n");

   while (1){
       tight_loop_contents();
       if(uCommand[0] != 0){
         uart_putc(UART_ID, '/');
         uart_puts(UART_ID, uCommand);
         memset(uCommand, 0, sizeof(uCommand));
       }
     }

}
4

1 回答 1

1

您链接到的示例代码用于简单的 tty/echo 实现。

您需要针对您的用例对其进行调整。

因为 Tx 中断被禁用,所以发送到发送器的所有输出都必须轮询 I/O。此外,UART 中的 FIFO 被禁用,因此仅使用单个字符 I/O。

因此,uart_is_writable检查是否可以传输字符。


链接代码...

在 Rx ISR 中回显接收到的字符。所以,它需要调用上面的函数。请注意,如果 Tx准备好(即已满),则字符不会回显并被丢弃

我不知道是否以这种uart_putc方式uart_puts检查准备传输。

所以,我假设他们没有。这意味着如果您调用uart_putc/uart_puts并且 Tx 已满,则 uart 中的当前/待处理字符可能会被破坏/损坏。

因此,uart_is_writable应该为要发送的任何/每个字符调用。

或者...uart_putc/uart_puts 检查并将阻塞,直到 uart Tx fifo 中有可用空间。对于您的用例,这种阻塞是不可取的。


你想要什么 ...

旁注:我在 RPi 上进行了类似的 [产品/商业级] 编程,用于通过 uart 进行电机控制,所以其中一些来自我自己的经验。

对于您的用例,您不想回显收到的字符。您想将其附加到接收缓冲区。

为了实现这一点,您可能想要使用环形队列:一个用于接收的字符,一个用于传输的字符。

我假设您已经 [或将会] 设计了某种简单的数据包协议来发送/接收命令。Rpi 发送的命令是(例如):

  1. 设置电机速度
  2. 获取当前传感器数据

对方应响应这些命令并执行所需的操作或返回所需的数据。

两个处理器可能都需要有类似的服务循环和 ISR。

Rx ISR 仅检查 Rx 环队列中的可用空间。如果空间可用,它会从 uart 获取一个字符并将其排入队列。如果 uart 中没有可用的 Rx 字符,则 ISR 可能会退出。

基础级代码服务循环应该:

  1. 检查 uart Tx 是否可以接受另一个字符(通过uart_is_writable),如果可以,它可以从 Tx 环队列 [如果可用] 中取出一个字符并发送它(通过uart_putc)。它可以在此循环以保持 uart 发送器忙碌。

  2. 检查是否收到足够的字符以形成来自另一端的数据包/消息。如果有这样的数据包,它可以为其中包含的“请求”提供服务[使字符出队以在 Rx 环队列中腾出更多空间]。

  3. 如果基础级别需要发送消息,它应该将它排入Tx 环队列。它将在上一步中 [最终] 发送。


一些额外的想法......

链接代码启用 Rx 中断并以轮询模式运行 Tx。这可能就足够了。但是,为了获得最大吞吐量和最低延迟,您可能还需要驱动 Tx 中断。

您可能还希望在 uart 中启用 FIFO,以便您可以排队多个字符。这可以减少对 ISR 的调用次数并提供更好的吞吐量/延迟,因为服务循环不必如此频繁地轮询。

于 2021-08-11T21:52:04.070 回答