gpt4 book ai didi

c - UART ISR Tx Rx 架构

转载 作者:太空狗 更新时间:2023-10-29 17:24:26 24 4
gpt4 key购买 nike

我是不是把事情复杂化了?

我正在设计我的代码以通过 UART 从 8051 微型计算机与外围设备通信。外设响应主机的命令,一次只能响应一个命令。这是一个简单的发送和接收协议(protocol)。 (tx1, rx1, tx2, rx2, tx3, rx3) 每个 TX 消息以 CR 结束,每个响应以 > 结束。在收到对上一条消息的回复之前,我无法发送新消息。如果我启用该选项,响应也可以在开始时回显打印原始 TX 消息(但这会导致更多流量)

示例消息是:

  • TX:你好
  • RX:世界!>

或者使用 echo 选项...

  • TX:你好
  • RX:你好\rWorld!>

选项 A诸如 getHello 之类的函数将包含发送和接收。并行 ISR 例程将收集传入字节并在收到“>”字符时抛出一个标志。

char* getHello(char * buf){
sendMsg("Hello\r");
delay(10ms); //wait a little bit

//wait for receive to come in or timeout to occur
while(!receiveFlag || !timeoutFlag); //thrown by ISR
receiveMsg(buf);
//parse the message and do some other stuff
return buf;
}

优点:

  • 一切都包含在一个函数中。
  • 更容易调试

缺点:

  • 此函数是阻塞的,如果外设从不响应则可能会挂起,因此必须实现超时。
  • 消息不能乱序接收,必须是连续的(即tx1, rx1, tx2, rx2, tx3, rx3)

选项 B采用并行方法。将创建两个单独的函数。一个用于发送消息,一个在收到 ISR 的响应后会转向。

void sendHello(){
sendMsg("Hello\r");
//do some other stuff if needed
}

char* receiveMsg(char * buf){
//figure out from echo print what the tx message was
//use a switch statement to decide which response parser to call
switch(txMessage){ //pseudo code
case "Hello":
receiveMsg(buf);
//parse the message and do some other stuff
break;
}
return buf;
}

优点:

  • 可以处理乱序返回的并行消息,因为它依赖于 tx 消息的回显打印来确定如何解析它。 (即 tx1、tx2、tx3、rx1、rx2、rx3)

缺点:

  • 很难调试
  • 产生多个线程
  • 大量额外代码
  • 不值得,因为消息肯定会按顺序返回

现在,我正在做选项 B,但随着我继续这个项目,我开始觉得这变得过于复杂了。我很好奇你们的想法。

谢谢!

最佳答案

不过,我倾向于做这类事情,我倾向于有一个单独的串行端口“类”(结构 + 函数)和一个位于串行端口之上的协议(protocol)类。我一直在我的嵌入式系统中使用这些。这为您提供了两全其美的方法,一个阻塞的同步调用和一个异步调用,这样您就可以进行伪多任务处理。

typedef struct serial_port_s serial_port;
typedef void (*serial_on_recived_proc)(serial_port* p);
typedef struct serial_port_s{
bool timeoutFlag;
bool receiveFlag;
void* context;
serial_on_recived_proc response_handler;
};

void send_serial(serial_port* p, char* message)
{
//SendMsg?
}
void receive_serial(serial_port* p, char* response)
{
//receiveMsg?
}

bool has_data(serial_port* p)
{
return p->receiveFlag;
}

bool has_timed_out(serial_port* p)
{
return p->timeoutFlag;
}
bool is_serial_finished(serial_port* p)
{
return has_data(p) || has_timed_out(p);
}

bool serial_check(serial_port* p)
{
if(is_serial_finished(p) && p->response_handler != NULL)
{
p->response_handler(p)
p-> response_handler = NULL;
return true;
}
return false;
}

void send(serial_port* p, char* message, char* response)
{
p->response_handler=NULL;
send_serial(p, message);
while(!is_serial_finished(p));
receive_serial(p, response);
}

void sendAsync(serial_port* p, char* message, serial_on_recived_proc handler, void* context)
{
p->response_handler = handler;
p->context = context;
send_serial(p, message);
}

void pow_response(serial_port* p)
{
// could pass a pointer to a struct, or anything depending on what you want to do
char* r = (char*)p->context;
receive_serial(p, r);
// do stuff with the pow response
}

typedef struct
{
char text[100];
int x;
bool has_result;
} bang_t;

void bang_parse(bang_t* bang)
{
bang->x = atoi(bang->text);
}

void bang_response(serial_port* p)
{
bang_t* bang = (bang_t*)p->context;
receive_serial(p, bang->text);
bang_parse(bang);
bang->has_result=true;
}

void myFunc();
{
char response[100];
char pow[100];
bang_t bang1;
bang_t bang2;
serial_port p; //
int state = 1;
// whatever you need to do to set the serial port

// sends and blocks till a response/timeout
send(&p, "Hello", response);
// do what you like with the response

// alternately, lets do an async send...
sendAsync(&p, "Pow", pow_response, pow);

while(true)
{
// non block check, will process the response when it arrives
if(serial_check(p))
{
// it has responded to something, we can send something else...

// using a very simple state machine, work out what to send next.
// in practice I'd use enum for states, and functions for managing state
// transitions, but for this example I'm just using an int which
// I just increment to move to the next state
switch(state)
{
case 1:
// bang1 is the context, and will receive the data
sendAsync(&p, "Bang1", bang_response, &bang1);
state++;
break;
case 2:
// now bang2 is the context and will get the data...
sendAsync(&p, "Bang2", bang_response, &bang2);
state++;
break;
default:
//nothing more to send....
break;
}
}
// do other stuff you want to do in parallel
}
};

关于c - UART ISR Tx Rx 架构,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13520272/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com