电子说
送药小车代码仓库:https://gitee.com/lcsc/medical_car
既然使用了RTOS,就不能像以前裸机一样全局变量满天飞了(当然裸机也不能全局变量满天飞)。
在实时操作系统(RTOS)中,不推荐或不建议使用全局变量来传递信息的原因主要有以下几点:
竞争条件:在多任务环境下,全局变量会面临竞争条件的问题。当多个任务同时读写同一个全局变量时,会导致数据的不一致性和错误的结果。这是因为任务的执行是并发的,无法控制它们的执行顺序。
数据共享和保护:全局变量被所有任务共享,这意味着多个任务可以同时访问和修改该变量。如果没有正确的数据保护机制,可能会导致数据损坏或冲突。
可维护性和调试困难:使用全局变量传递信息可能导致代码的可维护性和调试的困难。由于全局变量可以被任何任务修改,追踪问题的根源和调试错误可能会变得更加困难。
为了避免上述问题,RTOS提供了一些机制来进行任务间的通信和数据传递,例如:
消息队列:任务可以通过消息队列来发送和接收消息。每个任务有自己的私有消息队列,通过发送和接收消息来进行通信,避免了全局变量的竞争条件和数据共享问题。
信号量:信号量可以用于同步任务的执行和共享资源的访问。任务可以通过申请和释放信号量来控制对共享资源的访问,并确保任务之间的互斥性和同步性。
事件标志组:事件标志组可以用于任务之间的通知和事件触发。一个任务可以等待一个或多个事件标志的状态变化,并在事件发生时被唤醒执行相应的操作。
通过使用这些RTOS提供的通信机制,可以更安全地在任务之间传递信息,避免竞争条件和数据共享问题,并提高代码的可维护性和调试效率。
在送药小车这个工程中采用RT-Thread软件包uMCN,uMCN (Micro Multi-Communication Node) 提供了一种基于发布/订阅模式的安全跨线程/进程的通信方式。在系统中,uMCN 被广泛应用于任务和模块间的数据通信。使用发布-订阅(Publish-Subscribe)机制可以提供更灵活和高效的任务间通信方式,支持一对一、一对多、多对一和多对多的通信模式。这种机制可以解决使用全局变量传递信息可能带来的竞争条件和数据共享问题。
发布-订阅机制基于事件驱动的思想,其中包含两个角色:发布者(Publisher)和订阅者(Subscriber)。发布者负责发布事件或消息,而订阅者则注册对感兴趣的事件或消息进行订阅。他提供了一种松散耦合的通信方式,允许任务或模块之间通过发布和订阅消息来进行通信,而不需要直接知道彼此的存在。
在使用发布-订阅模式获取数据时,通常涉及以下角色和操作:
发布者(Publisher):负责生成和发布数据或事件。发布者将数据发送到一个或多个特定的主题(Topic),而不关心具体的订阅者。
订阅者(Subscriber):订阅者对特定的主题感兴趣,并通过订阅该主题来接收与之相关的数据或事件。
主题(Topic):主题是数据或事件的分类或标识符,发布者根据主题将数据发送到相应的通道,而订阅者根据主题来选择订阅的数据源。
使用发布-订阅模式获取数据的好处在于,系统中的任务或模块之间解耦合,发布者和订阅者之间不直接依赖于彼此的存在,从而提高了系统的可扩展性和灵活性。此外,发布-订阅模式还能够支持多对多的通信,允许多个订阅者同时接收相同的数据或事件,实现了信息的分发和共享。
他的优势如下:
松耦合性:发布-订阅机制使任务之间的通信更加松耦合。发布者不需要直接知道订阅者的存在,也不需要关心具体的订阅者数量和位置。订阅者只需要订阅感兴趣的事件或消息,从而实现任务之间的解耦。
灵活性:发布-订阅机制支持多对多的通信模式,一个发布者可以有多个订阅者,一个订阅者也可以订阅多个发布者的事件或消息。这种灵活性使得任务之间可以方便地建立复杂的通信关系。
扩展性:通过发布-订阅机制,可以方便地扩展系统,添加新的发布者或订阅者,而不需要修改现有的任务逻辑。这种扩展性使得系统更具可维护性和可扩展性。
将各个数据发布,并对接上echo输出函数后,就可以在RT-Thread的Finsh控制台获取到数据信息了(下面是通过uMCN获取电机编码器1的数据):
具体使用参考uMCN的仓库:
为了添加新的主题 (topic),你需要先创建一个主题内容。例如:
typedef struct {
rt_uint32_t a;
float b;
int8_t c[4];
} data_content;
uMCN对主题内容的长度和类型没有限制,所以理论上可以用来传输任何类型的消息。
然后你需要使用宏
MCN_DEFINE(name, size)
来定义主题。一般在发布主题的源文件的顶部定义主题。例如:
MCN_DEFINE(my_topic, sizeof(data_content));
uMCN 支持一个主题拥有多个发布者和订阅者。注意同一个主题名字不同被重复定义,不然编译器会报错。
下一步就是使用
mcn_advertise()
来注册主题。例如:
mcn_advertise(MCN_ID(my_topic), my_topic_echo);
MCN_ID()
宏根据主题名获得枢纽节点。my_topic_echo
是一个回调函数,用来打印主题的数据。
static int my_topic_echo(void* param)
{
data_content data;
if(mcn_copy_from_hub((McnHub*)param, &data) == FMT_EOK){
printf("a:%d b:%f c:%c %c %c %cn", data.a, data.b, data.c[0], data.c[1], data.c[2], data.c[3]);
return 0;
}
return -1;
}
可以在系统的任意位置使用函数
mcn_publish()
来发布一个主题。例如:
data_content my_data = {50, -2.0, {1,2,3,4}};
mcn_publish(MCN_ID(my_topic), &my_data);
审核编辑 黄宇
全部0条评论
快来发表一下你的评论吧 !