打印
[C语言]

我的代码简史:楼主从单片机coder到嵌入式programer的简单历程

[复制链接]
楼主: keer_zu
手机看帖
扫描二维码
随时随地手机跟帖
21
期待更新。。。呵呵 讲讲后面程序应该怎么写,我们该用什么语言来完成想要的功能。

使用特权

评论回复
22
yklstudent| | 2014-5-16 21:25 | 只看该作者
mark  期待楼主大作  别让小弟失望啊

使用特权

评论回复
23
dong_abc| | 2014-5-17 01:38 | 只看该作者
跟着学习,电子出身,代码功底实在太弱!
这么多年都难以突破!

使用特权

评论回复
24
keer_zu|  楼主 | 2014-5-17 08:06 | 只看该作者
本帖最后由 keer_zu 于 2014-5-17 08:59 编辑

从前面的分类看,C怎么也是3代以后的语言(1970-1980)。再看一下我前面的例子中我和我同事的代码,几乎就是第一代和第二代

早期语言写程序的特点(看16楼图):1.几乎很少使用参数传递,所有子程序几乎全部依靠共有全局变量来传递数据。2.共享全局变量带来的交叉耦合让这个代码调试起来非常费劲,因为每个函数都不是独立的,它依赖自身使用的大量全局变量。在MCU上,因为中断函数带来的并发性,如果有全局变量在中断内外都用到,那就会带来很多麻烦。这样的代码如果在多任务环境中将会更糟糕。3.再看看可读性,大量全局变量和全局标志位让代码的可读性非常差:首先是如此之多的变量和标志位所要表达的意图,再者他们分散得到处都是,即使不考虑并发性也让阅读的人摸不到头脑。4.看看扩展性和可维护性,如果有bug被测出,你定位问题将是极其困难的,因为这里的子程序没有内聚性,功能不独立,再加上可读性差,情况非常糟糕。如果要添加新功能,也是一件极其麻烦的事情,牵一发而动全身,要改的地方太多了。这样的编程方式也无法将项目做大。

你有这样的经历吗?刚开始做单片机的差不多都是这样的思维吧,除非之前有过其它领域的C开发经验。

使用特权

评论回复
25
keer_zu|  楼主 | 2014-5-17 08:26 | 只看该作者
本帖最后由 keer_zu 于 2014-5-17 09:00 编辑

为什么三代以后的语言写的程序出现了二代前期以前的特点?我们可以将它称作“语言的返祖现象”(这个将在后边专门讨论,这个概念可是咱首次提出的哦,哈哈,臭美一下),说明一个问题:每一代语言的开发者都是针对当时成熟而又先进的软件思想完成的,它里面支持他所要实现的那种编程思想所具备的大部分特征。但是如果使用者自己没有理解这种新的思想,而不使用这些新的特征,就会出现这种“返祖”现象,就像我身边很多人使用C++的时候,完全是用C的思维在编程,那些面向对象的特征完全成了他们的限制,这也算是“返祖现象”,哈哈。

既然你发现了它的缺陷,既然你已经知道它的‘错’在哪里,那问题可以得到解决了吧!问题怎么解决,如何改进?别着急!接下来我们将会看语言的下一次革新,还会附上下一阶段的代码做为实例。我简直就是一部活生生的发展史了,哈哈

使用特权

评论回复
26
cbaax| | 2014-5-17 08:30 | 只看该作者
先收藏 坐等楼主连载

使用特权

评论回复
27
reposemind| | 2014-5-17 08:40 | 只看该作者
不错,有实践,有思考

使用特权

评论回复
28
likezk| | 2014-5-17 09:35 | 只看该作者
  同样的感受啊,我的编程思路也是这么一步步升级过来的。从最初的全局变量满天飞,到后来的的功能划分,参数传递,再到后来的文件划分,接口驱动和应用部分分离。其中的一步步变化,都有着自己的所感所悟。不可否认,这种变化,也是伴随着器件的升级,也算是一种与时俱进吧。
  你不可能在89c51的片子上用那么多的参数传递,毕竟ram有限,参数传递会降低效率,浪费空间,直接用全局变量,省时省力。后来在avr上,上K的RAM空间,有了奢侈的感觉。再后来的ARM,ram已经不再是瓶颈了。随着MCU工作频率的提升,程序规模的扩大,我们的关注点从如何节省一个字节的ram,转移到了如何保证程序的可读性,易扩展性上了。

使用特权

评论回复
评分
参与人数 2威望 +7 收起 理由
jimiy123 + 1 很给力!
dong_abc + 6
29
yao1318| | 2014-5-17 09:46 | 只看该作者
收藏了,等着下会分解!

使用特权

评论回复
30
lh18753385| | 2014-5-17 09:46 | 只看该作者
mark

使用特权

评论回复
31
hwl1023| | 2014-5-17 11:17 | 只看该作者
期待楼主大作

使用特权

评论回复
32
keer_zu|  楼主 | 2014-5-17 11:24 | 只看该作者
likezk 发表于 2014-5-17 09:35
  同样的感受啊,我的编程思路也是这么一步步升级过来的。从最初的全局变量满天飞,到后来的的功能划分, ...

确实如此,大家是在与时俱进的。现在那种存储空间小的早期架构MCU成本上已经没有任何优势,而32位且存储空间一直才扩大的新架构价格一降再降,当年为了应对受限资源所做的特殊化处理今天越来越没有意义,为了应对这种有限资源所做的纯粹代码上的技巧已经越来越边缘化,条件已经允许我们回归正途了。。。

使用特权

评论回复
33
elec921| | 2014-5-17 12:22 | 只看该作者
只写MCU-C的同事,学过了C++,或者C#或者其他的一门语言,会尝试改变原先的思路

使用特权

评论回复
评论
xlsbz 2014-5-22 08:10 回复TA
然后学多了C++之后,又回到了C。很多大牛都是这个套路。面对对象次数多了,经常找不到北,所以最好得面对现实。推荐看 linus 说 C++是垃圾 
34
intermec| | 2014-5-17 18:43 | 只看该作者
坐等听课~~~要是多些例子就好了,,

使用特权

评论回复
35
keer_zu|  楼主 | 2014-5-17 19:32 | 只看该作者
插播【基础知识普及】
软件固有特性:复杂性等问题
【软件固有的复杂性】
* 问题域的复杂性 :
         —— 非功能性需求(可用性,健壮性,成本,性能等)的加入。
         —— 开发人员同用户之间沟通的困难。
         —— 设计过程中的需求变更。
* 管理开发过程的困难性
* 软件中随处可见的灵活性
         —— 这直接导致了软件开发领域不能像其他领域,可以对每个构件给出一个行业标
              准,比如机械制造行业,软件行业却很少能如此。这导致开发者需要打造大部分
              模块。
* 描述离散系统行为的问题
         —— 无法用连续系统建模的方式,本身也不受物理规律支配。

【复杂系统的5个属性】
* 层次性:可以逐级划分子系统。
* 相对本原:不同观察者对同系统组件的本原性认识不同。
* 分离关注:根据“组件”内部之间关联程度高于“组件”间外部关联程度来划分组件。
* 共同模式:如细胞,管脉系统在动物和植物中都有。
* 稳定的中间形式: 复杂系统是演化而来的,曾经的‘复杂系统’或其他‘复杂系统’变成基         
                   本组成。



【复杂系统的规范形式】
* 复杂系统的两种构成层次:1. 组成部分(Part of) 2. 是一种(Is a)


【控制复杂性的技巧】
控制复杂性的核心技巧:分而治之
* 算法分解 (自顶向下的结构化设计)强调了事件的顺序。
* 面向对象的分解 : 强调了一些代理。

使用特权

评论回复
36
xiaopingt| | 2014-5-18 09:38 | 只看该作者
在嵌入式系统设计中,要充分体现各个功能模块的独立性。如果功能模块已经成功运用,下次拿来用就是,基本不需要再调试。用预编译实现,#if  
#else  ,#endif.

使用特权

评论回复
37
xiaopingt| | 2014-5-18 09:42 | 只看该作者
在嵌入式系统编程中,一定要有编程的基本规范。多看看高手编程的习惯,你的水平才能提高!

使用特权

评论回复
38
loliweive| | 2014-5-18 09:50 | 只看该作者
长期关注楼主更新,,,过来人的经验对后来人是最有参考价值的。感谢!

使用特权

评论回复
39
keer_zu|  楼主 | 2014-5-18 18:29 | 只看该作者
如果把之前的代码比作旧石器时代,接下来就是新石器时代了。
在开始分析07年的代码之前,先科普一下:
【普及基础知识】
第二代和第三代前期程序设计语言的程序结构:



和图2-1相比有不同吗?对了。子程序不再那么单一,它有了嵌套的结构。看看这个时期引入了什么特点:
1.子函数调用支持嵌套。
2.支持各种参数传递。
3.程序拥有更丰富的控制结构。
4.声明的可见性范围多样化。如全局变量和函数内部的局部变量。
这个时候开始出现结构化程序设计。



使用特权

评论回复
40
keer_zu|  楼主 | 2014-5-18 18:33 | 只看该作者
这个是07年,我管这个时期叫做:
【新石器时代】
这是07年中的一个研发项目,是一个电力抄表终端,下面代码是他的液晶显示屏(128x64)的菜单部分。

代码有点长,先看头文件:
menu.h


#include"display_leaf.h"          //定义了显示叶子的函数
//字模数组
extern root_canshu[],root_shuju[],root_zhuangtai[],exit[],zhongduancanshu[],fukongcanshu[],celiangdian0[],
        celiangdian0canshu[],celiangdian1canshu[],
        celiangdian1[],celiangdian2[],celiangdian3[],zhongduanzhuangtai[],zhuzhantongxin[],fuhekongzhi[]
                ,tongxincanshu[],gaojingcanshu[],duankoucanshu[],biaoxieyi[],jibencanshu[],gongkongcanshu[]
                ,diankongcanshu[],dianzijishu[],biaojitongxin[],gongkongfangan[],diankongfangan[],diannengliang[],
                xuliang[],shunshiliang[],huanyingshiyong[],celiangdian0shuju[],celiangdian1shuju[],celiangdian2shuju[],celiangdian3shuju[];
//--------------------------------------------------------------------------
//-------------------------------------------
//  子界面编号数组
//-------------------------------------------
unsigned char Son0[1] ={1};              //对应界面0
unsigned char Son1[4] ={2,3,4,0};
unsigned char Son2[5] ={5,6,7,8,1};
unsigned char Son3[5] ={9,10,11,12,1};
unsigned char Son4[5] ={55,56,57,58,1};
unsigned char Son5[5] ={31,32,33,34,2};
unsigned char Son6[5] ={35,36,37,38,2};
unsigned char Son7[3] ={39,40,2};
unsigned char Son8[3] ={41,42,2};
unsigned char Son9[4] ={43,44,45,3};
unsigned char Son10[4] ={46,47,48,3};
unsigned char Son11[4] ={49,50,51,3};
unsigned char Son12[4] ={52,53,54,3};
//*****************
//以下是增加的叶子
//*****************

//-----------------------------------------------------------
//各个界面显示内容指针数组
//-----------------------------------------------------------
unsigned char *menu_char0[1]={huanyingshiyong};
unsigned char *menu_char1[4]={root_canshu,root_shuju,root_zhuangtai,exit};               //各元素枝指向对应行显示内容的字模数组
unsigned char *menu_char2[5]={zhongduancanshu,fukongcanshu,celiangdian0canshu,celiangdian1canshu,exit};
unsigned char *menu_char3[5]={celiangdian0shuju,celiangdian1shuju,celiangdian2shuju,celiangdian3shuju,exit};
unsigned char *menu_char4[5]={zhongduanzhuangtai,zhuzhantongxin,biaojitongxin,fuhekongzhi,exit};
unsigned char *menu_char5[5]={tongxincanshu,gaojingcanshu,duankoucanshu,biaoxieyi,exit};
unsigned char *menu_char6[5]={jibencanshu,gongkongcanshu,diankongcanshu,gongkongfangan,exit};
unsigned char *menu_char7[3]={jibencanshu,gaojingcanshu,exit};
unsigned char *menu_char8[3]={jibencanshu,gaojingcanshu,exit};
unsigned char *menu_char9[4]={diannengliang,xuliang,shunshiliang,exit};
unsigned char *menu_char10[4]={diannengliang,xuliang,shunshiliang,exit};
unsigned char *menu_char11[4]={diannengliang,xuliang,shunshiliang,exit};
unsigned char *menu_char12[4]={diannengliang,xuliang,shunshiliang,exit};

//-----------------------------------------------------------
// 各行文字数量
//-----------------------------------------------------------
unsigned char char_num0[1] = {4};
unsigned char char_num1[4] = {2,2,2,2};
unsigned char char_num2[5] = {4,4,6,6,2};
unsigned char char_num3[5] = {6,6,6,6,2};
unsigned char char_num4[5] = {4,4,4,4,2};
unsigned char char_num5[5] = {4,4,4,3,2};
unsigned char char_num6[5] = {4,4,4,4,2};
unsigned char char_num7[3] = {4,4,2};
unsigned char char_num8[3] = {4,4,2};
unsigned char char_num9[4] = {3,2,3,2};
unsigned char char_num10[4] = {3,2,3,2};
unsigned char char_num11[4] = {3,2,3,2};
unsigned char char_num12[4] = {3,2,3,2};

//-----------------------------------------------------------
struct INTERFACE
{
//当前行号对应子菜单编号,和反显行,对于不需要反显示的无意义
//行号在每次进入新的界面时清零
        unsigned char MAX_ROW_NUM;                  //该界面的最大行数
    unsigned char **MENU_char;                  //指向一指针数组,该数组元素为指向各行显示内容的指针
    unsigned char *Son_num;                     //指向当前界面子界面编号数组的指针
        unsigned char *Row_num;                     //指向当前界面各行文字数量数组的指针
};

struct INTERFACE Windows[13] =
{
  {1,menu_char0,Son0,char_num0},
  {4,menu_char1,Son1,char_num1},
  {5,menu_char2,Son2,char_num2},
  {5,menu_char3,Son3,char_num3},
  {5,menu_char4,Son4,char_num4},
  {5,menu_char5,Son5,char_num5},
  {5,menu_char6,Son6,char_num6},
  {3,menu_char7,Son7,char_num7},
  {3,menu_char8,Son8,char_num8},
  {4,menu_char9,Son9,char_num9},
  {4,menu_char10,Son10,char_num10},
  {4,menu_char11,Son11,char_num11},
  {4,menu_char12,Son12,char_num12}
};


//叶子节点的数据结构
struct LEAF
{
    unsigned char Father_num;          //该叶子要返回的父亲界面号
        void (*Display_leaf)();            //指向该叶子的显示函数的指针
};
struct LEAF leaf[28] =
{
    {5,display_tongxincanshu},         {5,display_gaojingcanshu},
        {5,display_duankoucanshu},         {5,display_biaoxieyi},
        {6,display_jibencanshu},           {6,display_gongkongcanshu},
        {6,display_diankongcanshu},        {6,display_gongkongfangan},
        {7,display_cljibencanshu},           {7,display_clgaojingcanshu},
        {8,display_cljibencanshu},           {8,display_clgaojingcanshu},
        {9,display_diannengliang},         {9,display_xuliang},
        {9,display_shunshiliang},          {10,display_diannengliang},
        {10,display_xuliang},              {10,display_shunshiliang},
        {11,display_diannengliang},        {11,display_xuliang},
        {11,display_shunshiliang},         {12,display_diannengliang},
        {12,display_xuliang},              {12,display_shunshiliang},
        {4,display_zhongduanzhuangtai},    {4,display_zhuzhantongxinzhuangtai},
        {4,display_biaojitongxinzhuangtai},{4,display_fuhekongzhizhuangtai}
};

//-----------------------------------------函数--------------------------------------------------
void Display_char(unsigned char,unsigned char ,unsigned char *,unsigned char);
void Display_row(unsigned char,unsigned char ,unsigned char ,unsigned char *,unsigned char);
void Display_window(unsigned char,unsigned char);                     
//

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则