对于一个处女座的程序源来说,很反感那种全局变量乱飞,函数之间扯来扯去,乱入一团麻的感觉。
程序本可以是很优雅,很美观的一种享受。所以我自己试图定制一套适合于单片机的软件架构。
本来是想上一个专栏的,结果发布的博客不够数量。先一点点积攒吧
绪论
程序架构是一个很大很宽泛的东西,像建房子一样,需要一点点的来。
单片机程序如果需要做大,文件慢慢增多,你会慢慢发现程序间的变量开始乱飞了,很多地方都需要用到,需要去修改。但是很难控制。我一直都希望是模块化的编程方式,也正一步一步完善。
实现原理
我参考 PX4 开源代码的逻辑,开发了一个uORB简化版本的DB (data broker) 数据托管器
根据实际变量的空间需要动态分配内存,变量参数及相关属性通过链表存储。
只有在主题公布、订阅、删除、查找这几个操作会去查询和操作链表。
主题发布、更新检查、拷贝都不会操作链表,都是直接操作传入的句柄,竟可能保证执行效率。
注意:该模块会调用堆空间,通过malloc函数动态分配, 需要预留足够的堆空间
结构定义
typedef enum
{
DB_TRUE = 1,
DB_FALSE = 0,
DB_SUCCESS = 0, //大于等于0的返回值 说明该函数执行成功 成功类型 有上述定义
DB_ERR_SIZE = -1,
DB_ERR_NULL = -2, //对象为空
} db_result_t;
typedef void *db_advert_t;
函数结构
1、公布主题
/*公布主题
注意:不可多公布
topic_name 主题名 字符串 最大长度20 必须以\0结尾
size 主题大小
返回 0 内存分配失败 其他 成功
*/
db_advert_t db_advertise(char *topic_name, int size);
2、订阅主题
/*订阅主题
注意:可订阅未公布的主题
topic_name 主题名 字符串 最大长度20 必须以\0结尾
size 主题大小
订阅的主题原理上值允许获取主题,不建议用于发布
返回 0 内存分配失败 其他 成功
*/
db_advert_t db_subscribe(char *topic_name, int size);
3、释放主题
/*释放主题
释放主题所占用的堆空间
返回: db_result_t
*/
db_result_t db_unadvertise(db_advert_t handle);
4、发布主题
/*发布主题
handle 主题句柄
data 数据来源
size 数据大小 必须保证和公布的大小一致 否则报错
返回: db_result_t
*/
db_result_t db_publish(db_advert_t handle, void *data, int size);
5、检查主题更新
/*查询主题是否更新
返回: DB_TRUE / DB_FALSE / 其他失败
*/
db_result_t db_check(db_advert_t handle);
6、主题数据拷贝
/*数据拷贝
handle 主题句柄
data 数据存储位置
size 数据大小 必须保证和订阅的大小一致 否则报错
返回:
*/
db_result_t db_copy(db_advert_t handle, void *data, int size);
7、查看主题名是否存在
/*查看主题名是否存在
返回: DB_FALSE / DB_TRUE
*/
db_result_t db_exists(char *topic_name);
使用参考
int publish_task()
{
uint8_t vbat=0;
//公布
db_advert_t vbat_topic = db_advertise("vbat",1);
while(true)
{
//获取数据
vbat = 0x75;
//发布数据
db_publish(vbat_topic,&vbat,1);
/*......*/
}
}
int subscribe_task()
{
uint8_t vbat=0;
//订阅
db_advert_t vbat_topic = db_subscribe("vbat",1);
while(true)
{
if(db_check(vbat_topic)==true)
{
db_copy(vbat_topic,&vbat,1);
}
/*......*/
}
}