amoBBS 阿莫电子论坛

 找回密码
 注册
搜索
bottom↓
查看: 6167|回复: 135

分享一份给小型项目使用的通用代码

  [复制链接]
发表于 2019-12-4 00:34:10 | 显示全部楼层 |阅读模式
本帖最后由 怂包BB 于 2019-12-4 00:35 编辑

BabyOS
        为小型项目而生,一个如孩童般需要集体喂养的弱操作系统。为什么称它为弱操作系统,因为相比已有的嵌入式操作系统,这个显得比较弱鸡。这里姑且称之为操作系统吧,其本质是一份代码集中营。


适用项目
        BOS: 当前项目是否需要使用像FreeRTOS等操作系统?
        U: 需要!
        BOS:不好意思,我可能不适合你。
        U: 开玩笑的,不需要用操作系统
        BOS: 那您可以尝试使用我哦!
             说一说写这么个东西的原因,大概就知道这份BOS有哪些功能。
             ................
        某天、一位猿说,现在对项目就只有两个要求,功耗和开发时间。99.874%产品是电池供电,功耗是重点考虑对象。其次产品的功能都不复杂,项目之间也有很多重复的部分,是否有套代码能够减少重复的工作,加速产品demo的开发。
             ................
        功耗,为减小功耗,对于外设的操作原则是,唤醒外设,操作完成后进入睡眠。这样的操作形式和文件的操作很类似,文件的操作步骤是打开到编辑到关闭。决定将外设的操作看作是对文件的操作进行。每个外设打开后返回一个描述符,后续代码中对外设的操作都是基于这个描述符进行。关闭外设后回收描述符。那么在外设的驱动中,打开和关闭操作可以执行对设备的唤醒和睡眠。利用描述符来操作外设还有一个好处是,当更换外设后,只需更换驱动接口,业务部分的代码不需要变动。
        快速开发,小型项目的开发中,有较多使用率高的功能模块,例如:UTC、错误管理、电池电量、存储数据、上位机通信、固件升级等等。将这些功能都做成独立的模块,不依赖于硬件。再配合一份配置文件,每次根据功能需求选择当前项目使用的功能模块。简单来说就是搭积木。
       BOS  0.0.1版本驱动只加入模拟串口和华邦flash。存在的功能模块如下表所示。
[td]
序号
功能模块
说明
1电量检测支持设置阈值用于判断电量状态,正常或者低电量
2校验计算支持CRC32,累加和,异或和校验
3错误管理支持两种等级的错误管理
4事件管理支持事件触发某个操作
5MODBUS协议支持MODBUS协议RTU传输组包和解析
6私有协议协议格式:[header|id|len|cmd|data|crc]
7固件升级支持固件升级(私有协议基础上完成新固件的接收与存储)
8数据存取支持三种数据存储方式(定时存储、单次存储、连续存储)
9发送管理管理发送数据的秩序,防止未发送完成时又有新数据请求发送
10UTC支持UTC的转换,UTC起始时间为2000-1-1 0:0:0
  电量检测 需要提供ADC转换的接口,设置阈值,判断当前电池的状态
  校验计算 提供几种校验方式,在需要时使用
  错误管理 提供两种等级的错误管理,低等级错误是只反馈一次异常,高等级错误是需要手动清除管理单元的异常信息,否则间隔时间到后就反馈异常。系统异常时,提交异常至管理单元并指定相同错误的最小间隔,防止同一个异常短时间多次被提交
  事件管理 支持注册一个功能函数,在需要时去触发执行
  MODBUS 支持RTU协议的组包发送和数据解析
  私有协议 支持私有协议,格式:  头(1字节)|ID(4字节)|Len(1字节)|Cmd(1字节)|数据|CRC(1字节)
  固件升级 支持基于私有协议接收和存储新固件
  数据存取 支持三种数据存取,定时存储(例如每小时存储一次、每天存储一次这样的场景),单次存储(加校验存储数据,例如存储配置数据),连续存储(flash上连续存储固定大小的数据,支持获取已存储数据的数量,例如存储异常日志以及获取已存储日志的数量)
  发送管理 支持管理数据的发送,保证数据发送完成后新的发送请求才能成功
  UTC  支持UTC和年月日时分秒的转换,UTC起始时间是2000-1-1 0:0:0
        部分功能模块需要使用具体外设,创建功能模块实例时需要指定具体设备。例如数据存取,创建功能模块时指定其对应的flash设备。
       如果某个产品的功能是每小时采集一次数据存储并上报,支持上位机取历史数据。物联网领域中有许多这样功能简单的终端设备,完成这个功能只需要添加2、6、8、9、10。如果需要监测设备异常状态则加入3,需要固件升级加入7,电池供电加入1。
      
使用方法1、添加文件
        bos/core/src目录文件全部添加至工程
        bos/driver/src选择需要的添加至工程
        bos/hal/ 添加至工程,根据具体平台进行修改
2、选择功能模块
        对于b_config.h进行配置,根据自己的需要选择功能模块。
3、列出需要使用的设备
     找到b_device_list.h,在里面添加使用的外设。例如当前项目只需要使用flash和模拟串口,那么添加如下代码:   
  1. //           设备        驱动接口      描述
  2. B_DEVICE_REG(W25QXX, bW25X_Driver, "flash")
  3. B_DEVICE_REG(SUART, SUART_Driver, "suart")
复制代码

4、使用设备
  1. bInit();    //初始化,外设的初始化会在此处调用
  2. //下面举例使用设备
  3. int fd;
  4. fd = bOpen(SUART, BCORE_FLAG_RW);    //其中SUART是在b_device_list.h中添加的设备
  5. if(fd >= 0)
  6. {
  7.      bWrite(fd, (uint8_t *)"hello world\r\n", strlen("hello world\r\n")); //发送字符串
  8.      bClose(fd);
  9. }
复制代码

   如果一个设备被打开正在使用,那么无法再次被打开。
5、使用功能模块
  1. int sdb_no;
  2. sdb_no = bSDB_Regist(0, 1, W25QXX);//创建B类数据存储实例,指定设备W25QXX,获的功能模块实例IDsdb_no
  3. //sdb_no大于等于0则有效
  4. int bSDB_Write(int no, uint8_t *pbuf);
  5. int bSDB_Read(int no, uint8_t *pbuf);
  6. //读写函数传入实例ID sdb_no
复制代码



喂养
       之所以称其为需要喂养的弱操作系统,因为驱动和功能模块都需要一点点加入进去,加入的越多,后续开发起来就越快。
https://github.com/notrynohigh/BabyOS
https://gitee.com/notrynohigh/BabyOS
纯属娱乐之作,高手勿喷!


 楼主| 发表于 前天 00:25 | 显示全部楼层
本帖最后由 怂包BB 于 2020-2-22 00:28 编辑

赶着2月份的尾巴再新增一项,FlexibleButton。也就是这份帖子:
回馈开源----史上最强按键驱动
https://www.amobbs.com/thread-5717909-1-1.html

具体的功能可以见上面帖子的介绍,我将这份开源代码加入进来,在它上面加了一层方便使用,具体使用方法如下:

FlexibleButton
  1. //填写按键ID
  2. typedef enum
  3. {
  4.     USER_BUTTON_1,
  5.     USER_BUTTON_2,
  6.     USER_BUTTON_3,
  7.     USER_BUTTON_WAKEUP,
  8.     USER_BUTTON_MAX
  9. }bBUTTON_ID_t;

  10. //b_button.c中配置每个按键被按下后的逻辑电平
  11. static flex_button_t bButtonList[USER_BUTTON_MAX] = {
  12.     [USER_BUTTON_1] = {
  13.         .pressed_logic_level = 0,
  14.     },
  15.     [USER_BUTTON_2] = {
  16.         .pressed_logic_level = 0,
  17.     },
  18.     [USER_BUTTON_3] = {
  19.        .pressed_logic_level = 0,
  20.     },
  21.     [USER_BUTTON_WAKEUP] = {
  22.        .pressed_logic_level = 0,
  23.     },     
  24. };


  25. int bButtonInit(void);   //初始化

  26. void bButtonCallback(void *p);   //重新实现回调,有按键事件触发后调用
  27. uint8_t bButtonRead(void *p);    //重新实现读取按键状态函数
复制代码




实验效果:




本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x
发表于 2019-12-4 03:16:47 来自手机 | 显示全部楼层
沙发,mark学习,谢谢lz
发表于 2019-12-4 03:46:44 来自手机 | 显示全部楼层
谢谢楼主。最近也打算弄一下操作系统。
发表于 2019-12-4 05:47:42 来自手机 | 显示全部楼层
谢谢楼主分享,学习一下
发表于 2019-12-4 06:23:36 | 显示全部楼层
不知占地面积如何
发表于 2019-12-4 07:51:38 | 显示全部楼层
学习一下,一直没有时间去学操作系统
发表于 2019-12-4 07:51:52 | 显示全部楼层
好想法》模块化,标准化,学习
发表于 2019-12-4 08:01:16 | 显示全部楼层
谢谢楼主分享,学习一下
发表于 2019-12-4 08:07:08 | 显示全部楼层
谢谢分享,学习学习
发表于 2019-12-4 08:11:48 | 显示全部楼层
谢谢分享!
发表于 2019-12-4 08:22:29 | 显示全部楼层
功耗两字深深地吸引了我
发表于 2019-12-4 08:30:08 | 显示全部楼层
mark学习,谢谢lz
发表于 2019-12-4 08:41:05 | 显示全部楼层
modbus协议是主从可配置?
发表于 2019-12-4 08:50:31 | 显示全部楼层
看操作有点linux在意思,不错
发表于 2019-12-4 08:58:04 | 显示全部楼层

谢谢分享!
发表于 2019-12-4 08:59:19 | 显示全部楼层
谢谢分享!
发表于 2019-12-4 09:02:21 | 显示全部楼层
关注  OS   小型项目使用的通用代码
发表于 2019-12-4 09:07:00 | 显示全部楼层
b_config.h   这个你是怎么做到的
发表于 2019-12-4 09:10:59 | 显示全部楼层
谢谢楼主分享,学习一下
发表于 2019-12-4 09:12:22 | 显示全部楼层
霸气侧漏 发表于 2019-12-4 09:07
b_config.h   这个你是怎么做到的

已经会了      
发表于 2019-12-4 09:13:28 | 显示全部楼层
霸气侧漏 发表于 2019-12-4 09:07
b_config.h   这个你是怎么做到的

戳这里看看吧:「Configuration Wizard」
发表于 2019-12-4 09:21:12 | 显示全部楼层
security 发表于 2019-12-4 09:13
戳这里看看吧:「Configuration Wizard」

谢谢  已经学会了
发表于 2019-12-4 09:27:59 | 显示全部楼层
谢谢分享
发表于 2019-12-4 09:35:18 | 显示全部楼层
感觉像是专门为了物联网传感器节点而生的,非常专业。
发表于 2019-12-4 09:35:24 | 显示全部楼层
security 发表于 2019-12-4 09:13
戳这里看看吧:「Configuration Wizard」

那个下拉列表没看懂怎么弄的

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x
发表于 2019-12-4 09:48:21 | 显示全部楼层
下载来看看,应该先贴一个完整的,然后我们再阉割
发表于 2019-12-4 09:52:40 | 显示全部楼层
设备树,设备符打开?
有点象LINUX,或是RTT,在单片机上实现这个,我真的是觉得好鸡肋啊。。

发表于 2019-12-4 09:56:14 | 显示全部楼层
security 发表于 2019-12-4 09:13
戳这里看看吧:「Configuration Wizard」


如何在 MDK  做 自己的 Wizard 配置界面


大神叼,我正想问这里,这个东西是个好东西,可以配置。。哈哈。。要学习一下来着。。不错不错。。

发表于 2019-12-4 10:01:25 | 显示全部楼层
霸气侧漏 发表于 2019-12-4 09:35
那个下拉列表没看懂怎么弄的

下面的 example 就是对应这个示例,我也没细究,你再认真看看,
这玩意,我已经快十年没用了。
发表于 2019-12-4 10:06:04 | 显示全部楼层
kinsno 发表于 2019-12-4 09:56
如何在 MDK  做 自己的 Wizard 配置界面

承让,刚好略懂一二。
发表于 2019-12-4 11:03:04 | 显示全部楼层
不错,支持
 楼主| 发表于 2019-12-4 11:09:33 | 显示全部楼层
ffbiao 发表于 2019-12-4 08:41
modbus协议是主从可配置?

没有,只是MODBUS RTU的小部分,提供给单片机调试485接口的传感器是够了的
发表于 2019-12-4 13:12:36 | 显示全部楼层
mark学习
发表于 2019-12-4 13:24:55 | 显示全部楼层
拿来主义,多谢多谢~
最近正在弄自己的通用框架,看了很多资料,现在有点糊了~
发表于 2019-12-4 13:46:08 | 显示全部楼层
谢谢分享,有空学习一下
发表于 2019-12-4 13:48:55 | 显示全部楼层
看着不错,有空学习一下
发表于 2019-12-4 13:52:00 | 显示全部楼层
拿了,谢谢,学习编写框架。
发表于 2019-12-4 14:27:56 | 显示全部楼层

mark学习,谢谢lz
发表于 2019-12-4 14:48:15 | 显示全部楼层
看起来不错
发表于 2019-12-4 14:59:25 | 显示全部楼层
值得学习
发表于 2019-12-4 15:04:16 | 显示全部楼层
mark一下
发表于 2019-12-4 20:44:20 | 显示全部楼层
不错,谢谢楼主分享~~
发表于 2019-12-4 22:27:34 来自手机 | 显示全部楼层
不错。多谢楼主分享
发表于 2019-12-4 23:06:20 | 显示全部楼层
已经在实际产品中验证过了么?
 楼主| 发表于 2019-12-5 01:25:51 | 显示全部楼层
genhao2 发表于 2019-12-4 23:06
已经在实际产品中验证过了么?

已经在实际产品中用过
发表于 2019-12-5 07:56:20 | 显示全部楼层
MARK 谢谢楼主分享
发表于 2019-12-5 08:13:37 | 显示全部楼层
楼主真牛,厉害,刚准备做个类似的应用,先看看
发表于 2019-12-5 08:14:48 | 显示全部楼层
很好的方法,也便于功能调整
发表于 2019-12-5 08:17:00 来自手机 | 显示全部楼层
mark谢谢分享
发表于 2019-12-5 08:26:48 | 显示全部楼层
看着不错,有空学习一下
发表于 2019-12-5 08:31:13 来自手机 | 显示全部楼层
不错不错
发表于 2019-12-6 09:37:59 来自手机 | 显示全部楼层
一直想模块化又便于管理和使用的框架。学习一下。感谢楼主分享
发表于 2019-12-6 10:19:18 | 显示全部楼层
好东西不错,楼主可以说一下,        发送管理 的实现思路么?另外发送的数据需要主机回复的这类消息,发送管理也适用么?
 楼主| 发表于 2019-12-6 10:45:27 | 显示全部楼层
wajlh 发表于 2019-12-6 10:19
好东西不错,楼主可以说一下,        发送管理 的实现思路么?另外发送的数据需要主机回复的这类消息,发送管理也 ...

发送管理目前是这样的:
只是管理数据的发送,保证当前数据没有发送完成前不会有新的数据插入。
针对两种类型的发送:
1. 类似串口,调用完发送函就可以认为发送结束
2. 类似通讯模组,数据丢给模组后还需要等待发送完成信号
应用中有需要发送数据的地方,实质是请求将数据copy进管理单元的一块buffer,如果当前正在执行发送(发送未完成)就会拒绝这次请求。

关于接收,接收一般都是中断。如果使用的是私有协议那一块,只需要将接收到的数据抛给私有协议处理,注册私有协议实例的时候会要求指定分发函数,所以如果是按照协议来通讯,最终会走到分发函数,根据不同的指令做对应的事情。
发表于 2019-12-6 10:50:12 | 显示全部楼层
怂包BB 发表于 2019-12-6 10:45
发送管理目前是这样的:
只是管理数据的发送,保证当前数据没有发送完成前不会有新的数据插入。
针对两种 ...

明白了。谢谢楼主
 楼主| 发表于 2020-1-2 19:14:18 | 显示全部楼层
本帖最后由 怂包BB 于 2020-1-2 19:26 编辑

2019_12_04~2020_01_02更新部分说明

FIFO

  1. int bFIFO_Regist(uint8_t *pbuf, uint16_t size);     //注册FIFO实例
  2. int bFIFO_Length(int no, uint16_t *plen);           //获取有效数据长度
  3. int bFIFO_Flush(int no);                                //FIFO读写复位
  4. int bFIFO_Write(int no, uint8_t *pbuf, uint16_t size);  //写入数据
  5. int bFIFO_Read(int no, uint8_t *pbuf, uint16_t size);   //读取数据
复制代码


AT

  1. typedef struct
  2. {
  3.     uint8_t *pResp;        //响应数据
  4.     uint16_t len;          //响应数据长度
  5.     uint32_t timeout;      //给定超时时间,调用bAT_Write之前给定超时时间
  6. }bAT_ExpectedResp_t;


  7. int bAT_Regist(pAT_TX ptx);     //注册AT使用实例,ptx是发送数据的接口
  8. int bAT_Write(int no, bAT_ExpectedResp_t *pe_resp, const char *pcmd, ...);
  9. //发送AT指令,   实例ID               结构体,如所述            不定长参数
  10. int bAT_Read(int no, uint8_t *pbuf, uint16_t size);
  11. //例如AT指令通过串口进行收发,串口接收到模块响应数据后将数据通过这个函数提交给AT单元


  12. //使用详情可见bos/drivers/src/b_f8l10d.c
复制代码




Nr_micro_shell

  1. int bShellStart(void);                      //shell 初始化
  2. int bShellParse(uint8_t *pbuf, uint16_t len);
  3. //例如用串口进行交互,串口收到数据后将数据通过此函数丢给shell进行解析
复制代码





本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x
发表于 2020-1-3 12:20:42 | 显示全部楼层
mark!   这是个好东西啊!
发表于 2020-1-5 13:05:09 来自手机 | 显示全部楼层
好东西,一直也是想搞这个的
发表于 2020-1-5 13:07:42 来自手机 | 显示全部楼层
可以移植mqtt模块
发表于 2020-1-5 15:40:31 来自手机 | 显示全部楼层
Mark,学习
 楼主| 发表于 2020-1-5 20:48:24 | 显示全部楼层
chinaboy25 发表于 2020-1-5 13:05
好东西,一直也是想搞这个的

来来来,欢迎一起堆代码哦
发表于 2020-1-5 21:20:49 | 显示全部楼层
谢谢分享         
发表于 2020-1-5 21:33:22 来自手机 | 显示全部楼层
有内部计时器拿来延时用吗?
 楼主| 发表于 2020-1-5 22:27:37 | 显示全部楼层
本帖最后由 怂包BB 于 2020-1-5 22:47 编辑
blueice1108 发表于 2020-1-5 21:33
有内部计时器拿来延时用吗?


bhal.c里面有一个函数void bHalIncSysTick(void);增加bSysTick这个变量的值。
配置文件里面有一个配置项 #define _TICK_FRQ_HZ                      1000

使用时,需要启动一个定时器,例如M3内核的MCU可以利用滴答定时器来做,定时调用bHalIncSysTick这个函数,然后根据定时器的周期配置_TICK_FRQ_HZ的值。


void bHalDelayMS(uint32_t xms);
这个延时函数根据bSysTick来实现。

微秒级别的延时使用 __nop();实现

代码:   https://gitee.com/notrynohigh/BabyOS/tree/master/bos/hal
发表于 2020-1-5 23:49:09 来自手机 | 显示全部楼层
牛逼,学习学习
发表于 2020-1-5 23:52:23 | 显示全部楼层
马克,备用研究下
发表于 2020-1-6 11:48:35 | 显示全部楼层
我非常佩服你们,但我真的不想再折腾了
发表于 2020-1-6 16:55:13 来自手机 | 显示全部楼层
谢谢分享,学习一下
发表于 2020-1-6 17:52:55 | 显示全部楼层
本帖最后由 zzz123456 于 2020-1-6 17:53 编辑

记号21楼的, 谢谢
发表于 2020-1-6 21:20:21 | 显示全部楼层
优秀的楼主
发表于 2020-1-7 08:58:08 | 显示全部楼层
Mark,3QQQQQ
发表于 2020-1-7 09:44:56 | 显示全部楼层
怂包BB 发表于 2020-1-5 22:27
bhal.c里面有一个函数void bHalIncSysTick(void);增加bSysTick这个变量的值。
配置文件里面有一个配置项  ...

谢谢
之后看能不能移植到M0系列
 楼主| 发表于 2020-1-7 09:49:16 | 显示全部楼层
blueice1108 发表于 2020-1-7 09:44
谢谢
之后看能不能移植到M0系列

应该是没问题的
发表于 2020-1-7 17:50:57 | 显示全部楼层
mark学习,谢谢lz
 楼主| 发表于 2020-1-10 22:50:10 | 显示全部楼层
本帖最后由 怂包BB 于 2020-1-10 22:52 编辑

BabyOS过年前最后更新一次。最近新增一项,大家帮忙看看是否有优化地方,在过年前将其改好。

新增:K/V键值对存取b_kv.c b_kv.h

基于SPI Flash存取,无文件系统。占用SPI Flash 4个最小擦除单位(4 * 4K),占用MCU内存 N * 12 Bytes (N表示最多存储多少个键值对,b_config.h配置)。

将4块最小擦除单位分为两组A,B每组两块分别存储数据索引和数据

A1  存储数据索引   
A2  存储数据


B1   存储数据索引
B2   存储数据

每次修改或者新增一条K/V键值对就将信息头和数据按照顺序写入A1 A2。当A1或者A2有一块存储满后将有效数据索引和数据抽取转移到B1 B2,将主要存储去转移到B组,B组存储满后按照同样的方法转移到A组。

每次新增或者修改不会对Flash进行擦除,保证了使用寿命。
一块最小擦除单位存满后抽取有效的部分转移到另一块区域,没有在内存定义大的buffer去处理,主要考虑到MCU的内存是稀缺资源不能随意占用。

使用例子:

如图所示,利用KV存储进行系统参数的存取、修改是比较方便的。结果如下:



欢迎大家指导!https://gitee.com/notrynohigh/BabyOS


本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x
发表于 2020-1-11 08:02:54 | 显示全部楼层
make 好优秀,好好学习
发表于 2020-1-11 08:18:03 | 显示全部楼层
make 好优秀,好好学习+1
发表于 2020-1-11 08:42:19 | 显示全部楼层
模块化 太棒  谢谢分享
发表于 2020-1-13 09:51:56 | 显示全部楼层
有点意思,很出奇的想法
发表于 2020-1-13 10:34:27 | 显示全部楼层
刚毕业那会都查寄存器写代码,后来有了库,再后来图形化添加组件,现在各种开源rtos,协议栈。。。眼花缭乱,措手不及,手足无措,何去何从
发表于 2020-1-13 10:37:58 | 显示全部楼层
厉害  谢谢分享
发表于 2020-1-13 16:17:05 | 显示全部楼层
学习一下。
发表于 2020-1-15 08:46:21 | 显示全部楼层
#define B_DEVICE_REG(dev, driver, desc)

#include "b_device_list.h"

typedef enum

{

#define B_DEVICE_REG(dev, driver, desc) dev,

#include "b_device_list.h"

bDEV_MAX_NUM

}bDeviceName_t;

这块看的不是很懂
 楼主| 发表于 2020-1-15 08:48:56 | 显示全部楼层
whatcanitbe 发表于 2020-1-15 08:46
#define B_DEVICE_REG(dev, driver, desc)

#include "b_device_list.h"

这个是将在b_device_list.h中定义的设备名 抽取到这里形成枚举
发表于 2020-1-15 09:12:47 | 显示全部楼层
怂包BB 发表于 2020-1-15 08:48
这个是将在b_device_list.h中定义的设备名 抽取到这里形成枚举

可以详细解释下怎么展开的吗,有点绕?
 楼主| 发表于 2020-1-15 09:40:18 | 显示全部楼层
whatcanitbe 发表于 2020-1-15 09:12
可以详细解释下怎么展开的吗,有点绕?
  1. B_DEVICE_REG(W25QXX, bW25X_Driver, "flash")
  2. B_DEVICE_REG(SUART, SUART_Driver, "suart")
  3. B_DEVICE_REG(F8L10D, bF8L10D_Driver, "lora")
复制代码


例如,我目前项目要用到三个设备,就在b_device_list.h写上三个如上所示的宏。


  1. typedef enum
  2. {
  3.     #define B_DEVICE_REG(dev, driver, desc)    dev,
  4.     #include "b_device_list.h"
  5.     bDEV_MAX_NUM
  6. }bDeviceName_t;
复制代码


这一个最终形成的是
  1. typedef enum
  2. {
  3.     W25QXX,
  4.     SUART,
  5.    F8L10D,
  6.   bDEV_MAX_NUM
  7. }DeviceName_t;
复制代码

如果在后面使用Flash就可以这么使用:
  1. int bKV_Init(int dev_no, uint32_t s_addr, uint32_t size, uint32_t e_size)
复制代码
  1. bKV_Init(W25QXX, 0xA000, 4096 * 4, 4096)
复制代码

应该明白了吧
发表于 2020-1-15 10:01:16 | 显示全部楼层
怂包BB 发表于 2020-1-15 09:40
例如,我目前项目要用到三个设备,就在b_device_list.h写上三个如上所示的宏。

好的,谢谢
 楼主| 发表于 2020-1-15 10:16:02 | 显示全部楼层

如果觉得好用,给个star支持一下
发表于 2020-1-15 11:43:20 | 显示全部楼层
这个fifo不太通用啊,内部维护一个静态数组持有相应结构体,还需要裁剪数组大小,然后暴露给用户索引,不如直接暴露指针.

给个我常用的,供参考, 可以fifo匹配任意类型
.
  1. /**
  2. * @file infra_ringbuffer.h
  3. * @brief 环型缓冲区模块
  4. * @author
  5. * @version  v1.2
  6. * @date
  7. * @attention
  8. */

  9. /*  用法  支持环形缓冲,支持先进先出,支持后进先出(也就是堆栈)
  10. *  首先定义一个ringBufferDummy_t实例mExampleQueue,
  11. *  其次定义一个任意类型缓冲区buffer(假设为uint32 类型),与缓冲区大小buffer_size,
  12. *  ringbuf_assign(&mExampleQueue, (uint8_t *)&buffer, sizeof(uint32_t), buffer_size);
  13. *  可以使用ringbuf_Pop,ringbuf_put,ringbuf_PutFront时,其中的data_element,要做强制转换
  14. */

  15. #ifndef _INFRA_RINGBUF_H_
  16. #define _INFRA_RINGBUF_H_

  17. #include <stdint.h>
  18. #include <stdbool.h>
  19. #include <stddef.h>

  20. #ifdef __cplusplus
  21. extern "C"
  22. {
  23. #endif

  24. /** @brief 结构体 */
  25. typedef struct {
  26.     void *dummy0;
  27.     int dummy1;
  28.     int dummy2;
  29.     int dummy3;
  30.     int dummy4;
  31.     int dummy5;
  32. } ringBufferDummy_t;

  33. /** @brief 句柄定义 */
  34. typedef void *ringBufferHandle_t;

  35. ringBufferHandle_t ringbuf_create(int element_size, int element_count);

  36. void ringbuf_destroy(ringBufferHandle_t b);

  37. ringBufferHandle_t ringbuf_assign(ringBufferDummy_t *b, uint8_t *buffer, int element_size, int element_count);

  38. void ringbuf_clear(ringBufferHandle_t b);

  39. int ringbuf_available(ringBufferHandle_t b);

  40. int ringbuf_count(ringBufferHandle_t b);

  41. bool ringbuf_full(ringBufferHandle_t b);

  42. bool ringbuf_empty(ringBufferHandle_t b);

  43. bool ringbuf_peek(ringBufferHandle_t b, uint8_t *data_element);

  44. bool ringbuf_pop(ringBufferHandle_t b, uint8_t *data_element);

  45. bool ringbuf_put(ringBufferHandle_t b, const uint8_t *data_element);

  46. bool ringbuf_putFront(ringBufferHandle_t b, const uint8_t *data_element);

  47. uint8_t *ringbuf_elementAlloc(ringBufferHandle_t b);

  48. #ifdef __cplusplus
  49. }
  50. #endif


  51. #endif
复制代码


  1. #include "infra_ringbuffer.h"
  2. #include "infra_wrapper.h"
  3. #include <string.h>

  4. typedef struct {
  5.     uint8_t *buffer;      //!< block of memory oBr array of data
  6.     int element_size;     //!< how many bytes for each chunk
  7.     int element_count;    //!< number of chunks of data
  8.     int head;             //!< where the reads come from
  9.     int tail;             //!< where the writes go
  10.     int count;            //!<  number of valid of data
  11. } ringBufferInner_t;


  12. /**
  13. * @brief Configures the ring buffer
  14. *
  15. * @param element_size 对象大小(以byte为准)
  16. * @param element_count 对象总个数
  17. * @return 句柄
  18. */
  19. ringBufferHandle_t ringbuf_create(int element_size, int element_count) {
  20.     ringBufferInner_t *inner = HAL_Malloc(sizeof(ringBufferInner_t) + element_size * element_count);

  21.     if (inner) {
  22.         inner->head = 0;
  23.         inner->tail = 0;
  24.         inner->count = 0;                      //!< 计数器
  25.         inner->buffer = (uint8_t *) inner + sizeof(ringBufferInner_t);
  26.         inner->element_size = element_size;    //!<  size of one element in the data block
  27.         inner->element_count = element_count;  //!<  number of elements in the data block
  28.     }

  29.     return (ringBufferHandle_t) inner;
  30. }

  31. void ringbuf_destroy(ringBufferHandle_t b) {
  32.     if (b) {
  33.         HAL_Free((void *) b);
  34.     }
  35. }

  36. /**
  37. * @brief Configures the ring buffer
  38. *
  39. * @param b 环形变量结构体指针
  40. * @param buffer 缓冲区指针
  41. * @param element_size 对象大小(以byte为准)
  42. * @param element_count 对象总个数
  43. * @return 句柄
  44. */
  45. ringBufferHandle_t ringbuf_assign(ringBufferDummy_t *b, uint8_t *buffer, int element_size, int element_count) {
  46.     ringBufferInner_t *inner = (ringBufferInner_t *) b;

  47.     inner->head = 0;
  48.     inner->tail = 0;
  49.     inner->count = 0;                      //!< 计数器
  50.     inner->buffer = buffer;
  51.     inner->element_size = element_size;    //!<  size of one element in the data block
  52.     inner->element_count = element_count;  //!<  number of elements in the data block

  53.     return (ringBufferHandle_t) inner;
  54. }

  55. /**
  56. * @brief clear the ring buffer
  57. *
  58. * @param b 句柄
  59. * @retval None
  60. */
  61. void ringbuf_clear(ringBufferHandle_t b) {
  62.     ringBufferInner_t *inner = (ringBufferInner_t *) b;

  63.     if (inner) {
  64.         inner->head = inner->tail = inner->count = 0;
  65.     }
  66. }


  67. /**
  68. * @brief got the number of elements available space in the ring buffer
  69. *
  70. * @param b 句柄
  71. * @retval Number of elements in the ring buffer
  72. */
  73. int ringbuf_available(ringBufferHandle_t b) {
  74.     return (b == NULL) ? 0 : (((ringBufferInner_t *) b)->element_count - ((ringBufferInner_t *) b)->count);
  75. }


  76. /**
  77. * @brief got the number of elements in the ring buffer
  78. *
  79. * @param b 句柄
  80. * @retval Number of elements in the ring buffer
  81. */
  82. int ringbuf_count(ringBufferHandle_t b) {
  83.     return (b == NULL) ? 0 : ((ringBufferInner_t *) b)->count;
  84. }

  85. /**
  86.   * @brief got the full status of the ring buffer
  87.   * @param b 句柄
  88.   * @retval true if the ring buffer is full, false if it is not.
  89.   */
  90. bool ringbuf_full(ringBufferHandle_t b) {
  91.     return (b == NULL) ? true : (bool) (((ringBufferInner_t *) b)->count == ((ringBufferInner_t *) b)->element_count);
  92. }

  93. /**
  94. * @brief got the empty status of the ring buffer
  95. *
  96. * @param b 句柄
  97. * @retval true if the ring buffer is empty
  98. * @retval false if it is not.
  99. */
  100. bool ringbuf_empty(ringBufferHandle_t b) {
  101.     return (b == NULL) ? false : (bool) (((ringBufferInner_t *) b)->count == 0);
  102. }

  103. /**
  104. * @brief Looks at the data from the head of the list without removing it
  105. *
  106. * @param b 句柄
  107.   * @retval true if data was got
  108.   * @retval false if list is empty
  109. */
  110. bool ringbuf_peek(ringBufferHandle_t b, uint8_t *data_element) {
  111.     uint8_t *ring_data = NULL;
  112.     ringBufferInner_t *inner = (ringBufferInner_t *) b;

  113.     if (ringbuf_empty(b) || data_element == NULL) {
  114.         return false;
  115.     }
  116.     ring_data = inner->buffer;
  117.     ring_data += inner->head * inner->element_size;
  118.     memcpy(data_element, ring_data, inner->element_size);

  119.     return true;
  120. }

  121. /**
  122.   * @brief Copy the data from the front of the list, and removes it
  123.   * @param b 句柄
  124.   * @param data_element 拷出数据的缓冲区指针
  125.   * @retval true if data was copied
  126.   * @retval false if list is empty
  127.   */
  128. bool ringbuf_pop(ringBufferHandle_t b, uint8_t *data_element) {
  129.     uint8_t *ring_data = NULL;
  130.     ringBufferInner_t *inner = (ringBufferInner_t *) b;

  131.     if (ringbuf_empty(b) || data_element == NULL) {
  132.         return false;
  133.     }

  134.     ring_data = inner->buffer;
  135.     ring_data += inner->head * inner->element_size;
  136.     memcpy(data_element, ring_data, inner->element_size);
  137.     if (++inner->head >= inner->element_count) {
  138.         inner->head = 0;
  139.     }
  140.     inner->count--;

  141.     return true;
  142. }

  143. /**
  144.   * @brief Adds an element of data to the ring buffer
  145.   * @param b 句柄
  146.   * @param data_element 拷入数据的缓冲区指针
  147.   * @retval true on succesful add
  148.   * @retval false if not added
  149.   */
  150. bool ringbuf_put(ringBufferHandle_t b, const uint8_t *data_element) {
  151.     uint8_t *ring_data = NULL;
  152.     ringBufferInner_t *inner = (ringBufferInner_t *) b;

  153.     /* limit the amount of elements that we accept */
  154.     if (ringbuf_full(b) || data_element == NULL) {
  155.         return false;
  156.     }

  157.     ring_data = inner->buffer;
  158.     ring_data += inner->tail * inner->element_size;//定义元素地址
  159.     memcpy(ring_data, data_element, inner->element_size);
  160.     if (++inner->tail >= inner->element_count) {
  161.         inner->tail = 0;
  162.     }
  163.     inner->count++;

  164.     return true;
  165. }

  166. /**
  167. * @brief Adds an element of data to the front of the ring buffer
  168. *
  169. * @param b 句柄
  170. * @param data_element 拷入数据的缓冲区指针
  171. * @retval true on succesful add
  172. * @retval false if not added
  173. */
  174. bool ringbuf_putFront(ringBufferHandle_t b, const uint8_t *data_element) {
  175.     uint8_t *ring_data = NULL;
  176.     ringBufferInner_t *inner = (ringBufferInner_t *) b;

  177.     /* limit the amount of elements that we accept */
  178.     if (ringbuf_full(b) || data_element == NULL) {
  179.         return false;
  180.     }

  181.     if (inner->head == 0) {
  182.         inner->head = inner->element_count - 1;
  183.     } else {
  184.         inner->head--;
  185.     }
  186.     ring_data = inner->buffer;
  187.     ring_data += inner->head * inner->element_size;
  188.     /* copy the data to the ring data element */
  189.     memcpy(ring_data, data_element, inner->element_size);
  190.     inner->count++;

  191.     return true;
  192. }

  193. /**
  194.   * @brief Reserves and gets the next data portion of the buffer.
  195.   * @param b 句柄
  196.   * @retval !NULL pointer to the data,
  197.   * @retval NULL if the list is full
  198.   */
  199. uint8_t *ringbuf_elementAlloc(ringBufferHandle_t b) {
  200.     uint8_t *ring_data = NULL; /* used to help point ring data */
  201.     ringBufferInner_t *inner = (ringBufferInner_t *) b;

  202.     /* limit the amount of elements that we accept */
  203.     if (ringbuf_full(b)) {
  204.         return NULL;
  205.     }

  206.     ring_data = inner->buffer;
  207.     ring_data += inner->tail * inner->element_size;
  208.     if (++inner->tail >= inner->element_count) {
  209.         inner->tail = 0;
  210.     }
  211.     inner->count++;

  212.     return ring_data;
  213. }

复制代码
 楼主| 发表于 2020-1-15 13:49:55 | 显示全部楼层
slzm40 发表于 2020-1-15 11:43
这个fifo不太通用啊,内部维护一个静态数组持有相应结构体,还需要裁剪数组大小,然后暴露给用户索引,不如直接 ...

嗯嗯,您这份代码很好,多谢分享。
您这个是每新增一个FIFO就malloc一段空间然后在这段空间中进行操作,返回给用户的是指针。我的是需要提前配置好FIFO的数量,并需要用户自己提供一块内存的地址,也就是由用户自己定义数组交到b_fifo使用,再返回FIFO的索引给用户。

在代码中我是刻意避免动态内存的使用,考虑的是,这份代码主要给裸机用户,他们的内存空间不是很多,增加不确定大小的堆空间,还不如使用过程中定义确定大小的数组。
发表于 2020-1-15 14:17:06 | 显示全部楼层
本帖最后由 slzm40 于 2020-1-15 14:20 编辑
怂包BB 发表于 2020-1-15 13:49
嗯嗯,您这份代码很好,多谢分享。
您这个是每新增一个FIFO就malloc一段空间然后在这段空间中进行操作, ...


我有个ringbuf_assign的API,这个就是专门给裸机匹配的,你可以屏蔽 create和destroy两个api.
 楼主| 发表于 2020-1-15 14:26:27 | 显示全部楼层
slzm40 发表于 2020-1-15 14:17
我有个ringbuf_assign的API,这个就是专门给裸机匹配的,你可以屏蔽 create和destroy两个api.  ...

嗯嗯,好的,谢谢
发表于 2020-1-15 14:43:47 | 显示全部楼层
Thank you !!!
发表于 2020-1-15 22:21:13 来自手机 | 显示全部楼层
没有ymodem?
 楼主| 发表于 2020-1-15 22:53:04 来自手机 | 显示全部楼层
inkfish321 发表于 2020-1-15 22:21
没有ymodem?

X Y Zmodem还都没加,有木有兴趣来一起开发,将这些加进去。会排上日程
发表于 2020-1-15 23:38:11 | 显示全部楼层

沙发,mark学习,谢谢lz
发表于 2020-1-16 11:57:13 | 显示全部楼层
感谢分享   好东西要学习
发表于 2020-1-16 14:15:58 | 显示全部楼层
谢谢分享~~~~
发表于 2020-1-16 17:40:04 | 显示全部楼层
谢谢分享
发表于 2020-1-17 11:06:24 | 显示全部楼层
学习了 谢谢分享
友情提示:标题不合格、重复发帖,将会被封锁ID。详情请参考:论坛通告:封锁ID、获得注册邀请码、恢复被封ID、投诉必读
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|阿莫电子论坛(原ourAVR/ourDEV) ( 公安备案:44190002001997(交互式论坛) 工信部备案:粤ICP备09047143号 )

GMT+8, 2020-2-24 18:50

阿莫电子论坛, 原"中国电子开发网"

© 2004-2018 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表