[讨论] 一点一点搭建起程序框架,实现方便移植,异于管理的一个通用模版

辛昕   2012-6-18 00:15 楼主
这个帖子,实际上可以认为是先前我发的那个帖子

让我们一起来搭建一个 单片机通用程序模版 的 后续篇章。
那一章里,主要阐述了我自己的观点和想法,最后觉得比较空,毕竟这个模版要在实际操作中,针对遇到的新情况重新分析,增删修改,才能真正实现的。

于是,我打算开始换一种方式,我将以自己的stm8s为例子,从最基本的gpio timer开始,一点一点地搭建起这个框架。

这些内容本身都不难,并且似乎没有太新奇的地方,它唯一的意义就是,使其不再只是一个针对stm8s105c6t6,甚至是不再只是针对stm8s,st这个系列的MCU单片机的项目文件,它是一个通用模版。

闲话少说,下面的贴子里,将一点一点 补充 我的进展。


强者为尊,弱者,死无葬身之地

回复评论 (20)

第一步:基本gpio外设操作

首先是 框架图
框架图 120617.jpg

一些说明:

Hardware.h作为公用头文件,它的作用主要是:

1.(一处)设置所选用的MCU,用以选择对应的 外设函数实现——因为它们含有一组统一的调用接口;

2.一些对应相应MCU下,一些共用的设置,比如说,基本数据类型的字长等——使得其上不再直接使用基本数据类型,如char,short等,而是U8,U16等,避免不同机器字长之间的区别,妨碍了程序的通用性和方便移植性。

 

外设头文件及其源文件(框架图中没有体现出 对应源文件)

以具体的gpio外设为例——注:此处的“外设”的定义用以区别“模块”。

仍以例子说明,比方说,对gpio的基本设置和读写操作,被认为是属于gpio外设的操作;

而使用gpio显示LED,读取按键,这种使用gpio完成的操作则认为是 使用了gpio外设的某某模块的操作;如此区分,是因为,gpio的读写和设置是对于任何在其之上的使用都需要的基本,更底层的操作。

 

首先,我们需要 重定义 一些数据类型。

因为stm8s采用了一套自己的 数据类型,比如gpio portgpio  pin的都有一个重定义的数据类型,而我们,如果要保证gpio对外有一套通用的数据接口,首先就保证一组通用的 数据类型。

 

文件中的 gpio.h,Line 20 ~ Line 25

 

类似的,还有,当然这是针对gpio这一个外设本身所独有的——也就是说,在我们做这些通用框架程序之前,我们一定要首先尽可能考虑(或者说在不断深入了解之后,不断完善)这个外设本身,有一些什么共性的内容,然后使它们对外保持一种通用的接口,或者宏定义。

 

比方说,gpio这个外设。

我们对它的基本操作无非是 设置方向(除了传统51,基本上任何一款MCU都有IO口读写方向的区分); 然后是,读io口状态;写io口状态;

 

于是,我们对应的需要 一组宏,表示不同的io口模式(方向包含在其中)——当然,你还可以有别的方式实现,比如stm的架构,直接用enum枚举结构体实现——但要注意的是,这次,stm架构是enum,那下次,如果换了430呢?如果是51呢?所以,在不甚明了的情况下,并且区别不大的情况下,我会选择宏定义。

 

又比如,目前,据我所知道,有两种给gpio/IO口编号的方法:

一种是 P0,P1,P2

一种是PA PB PC(或者GPIOA GPIOB,应该是类似的。当然,跟其具体硬件的实现或者底层固件库的实现方法有关系。比如stm8s的,GPIOA GPIOB就是 结构体,但PICPA PB如何,我则不知道了。)

 

为了统一,我采取的办法是,PA(或者GPIOA)就对应P0,其他依次对应这个顺序——当然,后来我觉得,这种对应实际上,从我的实现方式来看,对应不对应并没太大关系,只看我怎么处理——但我保留这种方式,也许有一天我会想到更好的一一对应方便实现的办法,即使这种方法现在看不出非常明显的必要,但至少——逻辑上是更好的选择。

 

有了这个,我们还要考虑,如何定义一个引脚,因为它实际上,包含了两个信息,一个是port口,一个是pin口,从最一般的情况来看,我们在安排IO口时,它们可能是都不相同。

这里暂时没有想到更加好的办法,采用的办法仍然是先前提到的。

 

以带参宏 把一个GPIO口的port数和pin脚按照 8位一个port的组织方式换算出一个编号,再在调用时,反算出其所属的port口和pin脚。

具体代码 详见

gpio.h Line 45 ~ Line 48

 

 

在这里,我实际上没有想到更好地实现方法,目前采用的办法是switch开关切换选择对不同port口操作,因为stm8s这个GPIOA的结构体指针,实现起来真不如这个简单,而且速度指不定更优于结构体指针寻址方式。

 

实现方法,请参考 代码:

gpio.cSetGpioMode()函数,或者WriteGpioPin()函数

gpio.c Line 70 ~ Line 133

 

目前做的工作只有这么多。

因为还不涉及具体模块,故而,直接在main.c中直接调用这些函数,以观察这种封装是否真的如愿实现。

main.c的内容作为试验代码。(Application Layer往往就只是一个main.c以及其他与其并行的中断函数而已。)

 

然后是我今天保存的 程序备份版本。
General Framework 120617.rar (57.69 KB)
(下载次数: 68, 2012-6-18 00:18 上传)

密码:xinxin
并非给各位做任何限制,只不过,工作的习惯造成——这是防止有时电脑中毒之类的意外篡改项目文件某些设置,环境,甚至是修改源代码。


[ 本帖最后由 辛昕 于 2012-6-18 00:18 编辑 ]
强者为尊,弱者,死无葬身之地
点赞  2012-6-18 00:15
谢谢版主分享,刚转到开发部门,软件架构以及如何编写比较茫然!有待进一步学习,另外一个帖子看到版主下载了《代码大全》如果版主方便的话,能否发一份给我,最好是第二版中文的。在此先谢过了!留下邮箱:37682279@qq.com
点赞  2012-6-20 17:11

回复 板凳 hb1012 的帖子

难道我忘了上传上去?
行,我现在就传,你到那个帖子去下载吧
强者为尊,弱者,死无葬身之地
点赞  2012-6-20 21:08

0701版本

这个版本在上一个版本变化不大。只是补充了gpio的读函数。

主要是完成了 用SI 使用pc-lint检查代码

GeneralFramework 120701.rar (205.76 KB)
(下载次数: 23, 2012-7-2 00:17 上传)

强者为尊,弱者,死无葬身之地
点赞  2012-7-2 00:16
其实这个版本搞了这么久,大多数时间都花在配置pc-lint
关于这个过程将要单独花时间写一个配置的贴,但愿你们看了以后能否顺利地进行这一步,不需要绕这么多弯路。

但是我是没有想到 stm8s的这个固件库居然检查出这么多问题——因为我的代码本身好像还没写多少。

另外是。我自己在封装这些函数时也遇到一些奇怪的问题。

比如我在这个版本中 主程序中演示  gpio读写——读键控制灯亮灭 的那个地方。发现了一个非常奇怪的地方:

SET居然没有如我所理解的和想象的起到 该有的作用——
我试过拿回原来的固件库函数依然如此。可见我的封装本身并没有问题。这个问题是固有的。

周末折腾了些杂七杂八的事情。这个东东也没怎么整理好。发上来纯属留个版本。希望什么时候有时间再进一步把这些现有的问题想明白。
强者为尊,弱者,死无葬身之地
点赞  2012-7-2 00:25

关于上一个贴,提到的 问题。

这是详细的链接帖。
我发到了stm8版块里。
https://bbs.eeworld.com.cn/viewth ... =page%3D1&frombbs=1
强者为尊,弱者,死无葬身之地
点赞  2012-7-3 00:36
昨晚把完成的 数码管 显示模块(只是针对我的硬件的一种显示方式,未经IO扩展,单纯的IO控制动态显示)
的几个担心的疑虑基本搞清楚了:
1.我采用的那种新的gpio操作模式 对执行时间并没有影响——从昨晚粗略测试的结果来看几乎是一样的。
2.先前发现的有重影,纯属硬件焊接不良所致。

不过昨晚有点累,今晚再整理一下文档,然后发上来。
强者为尊,弱者,死无葬身之地
点赞  2012-7-13 10:10

07.28最新更新:已使用定时器中断+数码管显示+按键

呵呵,这个版本释出的有点晚。
因为这阵子比较忙,同时也碰到一些问题,昨晚才刚解决,今天稍微整理了整理,才发上来。

本来想好好整理才上传,但想到整理思路还没完全定好,所以只好先释出先。
至于,如何整理,这是个很重要的部分,现在我的一个思路是:
整理应该从一开始,在项目编写过程中就一点一点跟着做。

因为,边整理不仅可以减少后期的整理工作——事实上,如果不是在编码时整理,有很多细节和内容等到项目收尾时才整理会忘记许多细节。
另外,整理本身就是一件可以理清思路 的事情,而在项目的进行过程中,本身就需要对系统的结构设计和规划不断调整——因为这个时候,你对于项目有更深的理解,这个时候无可避免地要对最初做的规划进行调整,使得整个系统架构更加完善。

正好的,我决定在我发的贴子
【暑假酷学】写一个程序(工程项目)该怎么一步步去做?
https://home.eeworld.com.cn/my/li ... %253D1%23pid1351458
中采用这个项目作为一个实践的例子。

[ 本帖最后由 辛昕 于 2012-7-28 21:28 编辑 ]
强者为尊,弱者,死无葬身之地
点赞  2012-7-28 21:27
好的
点赞  2012-8-31 13:10

回复 9楼 辛昕 的帖子

不错,支持楼主,程序框架确实很关键。现在毕业半年了,在做公司的一个单片机项目,在51上实现了一个以任务队列为核心的系统架构。。。
点赞  2012-12-30 11:54
我还没弄过实时操作系统,但我看了一些介绍,感觉只是一个任务调度。

不知道这种想法是否过于肤浅,还是麻烦你给介绍介绍?
点赞  2012-12-30 11:59
标记下  值得回味的辛哥的作品
点赞  2012-12-30 13:31
   欲言又止,提笔不知所言
分享铸就美好未来。。。
点赞  2015-8-6 17:15
楼主,3年过去了,技术进步到什么地步了啊?看好你!
点赞  2015-8-6 20:56
引用: samos2011 发表于 2015-8-6 20:56
楼主,3年过去了,技术进步到什么地步了啊?看好你!

呵呵,这种没办法量化的说的。
我只能说,我还坚持在开发第一线。
关于这个话题,过去我写的几个帖子都太长太罗嗦,而且因为当时连自己都不太清楚自己在面对的想确定的是一个问题,所以自然也就让人看了云里雾里。
好吧,最近关于这个,也常有人问起,比如 你LS那个家伙。
我想想,怎么整理一下这个思路,然后写成一个简洁点的帖子把这事情了结了。

这里先简单说一下我的思路:
这里其实应该把问题分成两种:

1.类似LED这种简单的gpio而已的使用。
其实现在很多东西,比如Arduino底层,比如很多基于stm32 msp430等的库,或者说跟什么单片机无关,而是目前非常流行的一个就是用一组宏去匹配一个外设的寄存器操作。
比如

  1. #define PORT_GPIO0          5
  2. #define PIN_GPIO0          11
  3. #define MODE_GPIO0          0x01
  4. #define SPEED_GPIO0          2
  5. #define OTYPE_GPIO0          0
  6. #define PUPD_GPIO0          0
  7. #define STATE_GPIO0         0  

  8. 比如这个
  9. 这其实是一个io口的设置
  10. 它是 PF11,设置成普通IO模式 速度25,输出方向,上拉,初始低


我不知道你怎么看待这个方案,但我觉得特别傻,也特别复杂。

所以我的思路更多的是不以宏,具体操心到哪个寄存器的位去设置,而是直接以与实际底层结构。数据完全无关的普通函数接口来封装。
在此之上,调用者只知道led_on led_off这类,而在函数里面,直接操作寄存器,根本不需要顾忌什么,不同的单片机当然是不一样的一套,不一样的板子配置自然又是另一套,这是一个类似BSP的写法。但并没有什么太大的关系。

2.对于LCD这类复杂的接口,同样地,我还是采用这种 无关具体接口的函数接口来 封装底层具体的操作。
但是,这类复杂接口比起普通的LED又有了一些新情况。
那就是,LCD不仅仅只是操作寄存器而已,它还有不同的读写命令,分不一样的接口模式(并口串口,还分6800或者8060等)

这些不同的情况又会导致不一样的接口,所以,这个地方我也折腾了很久,最后我采取了类似bsd的bus的思路。
其实想起来这也算是业界一种通用的思路把,只是我以前不知道,或者没意识到。

那就是不管底层如何,我只把这个留给上层应用的接口做成 基于 读写总线 的接口。
就是应用可以通过它直接读写寄存器或者FIFO之类的,至于什么接口之类的,它完全不关心,最多只是通过ioctl函数来设置即可。
所有这些实现的细节由底层封装者完成提供。
强者为尊,弱者,死无葬身之地
点赞  2015-8-7 11:17
刚扯了一通,也许你要的并不是这个问题方面的 “进展”。
我想一般点地说就是。这几年的进步主要体现在

我开始知道并渐渐理解学习一些业界现有的更加成熟优良的方案。
有时它们可能不仅仅是我们熟悉的“狭隘”的单片机,但是,同样地可以被学习和借鉴,我从干这行开始,就一直抱这种想法,希望把PC上的那一套搬到我的单片机上用。
但限于我当时的眼界和能力,我实际上是做不到的,我在这上面做了很多乱七八糟的尝试和阅读思考之类的,现在已经证明基本没有什么直接效果的东西。
但是,慢慢地随着做的事情越来越多,能力逐渐增长。
那些东西中有一些我渐渐能用上了,我的眼界也逐渐开阔,了解到一些我以前不了解的东西。

所以我想,我这三年的进步就是,不断把过去那些我只是听说知道的东西,一点点落到实处去用在我的单片机上。

好了不扯了,今天请假了,去附近一个城市散散心,旅游旅游,刚起床看到你的问题所以胡乱写了两个回答,见谅!
回头我整理好了一些相关的博客,发表了一定还请你多多指教。
强者为尊,弱者,死无葬身之地
点赞  2015-8-7 11:21
引用: 574433742 发表于 2015-8-6 17:15
欲言又止,提笔不知所言

别太介意这种东西。
你和我一样,问题不在于说的少,而是说的太多
强者为尊,弱者,死无葬身之地
点赞  2015-8-7 11:22
引用: 辛昕 发表于 2015-8-7 11:21
刚扯了一通,也许你要的并不是这个问题方面的 “进展”。
我想一般点地说就是。这几年的进步主要体现在
...

楼主的热心肠令人敬佩!
其实PC机的那些程序设计思想是完全可以用在嵌入式开发的
结合楼主的爱好,我强烈建议您研究研究<设计模式>,您就会顿悟!
欢迎楼主来看看我的这篇博文:
https://bbs.eeworld.com.cn/thread-470692-1-1.html
点赞  2015-8-7 11:55
引用: hb1012 发表于 2012-6-20 17:11
谢谢版主分享,刚转到开发部门,软件架构以及如何编写比较茫然!有待进一步学习,另外一个帖子看到版主下载 ...

对了,这书,请记得一定看网络电子版。
纸质版,我只见过第二版,简直狗屎。
强者为尊,弱者,死无葬身之地
点赞  2017-11-1 11:39
12下一页
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 京公网安备 11010802033920号
    写回复