独闷闷网

 找回密码
 立即注册
搜索
楼主: jianhong_wu
打印 上一主题 下一主题
收起左侧

[原创] 从业十年,教你单片机入门基础。(连载)

[复制链接]
52#
 楼主| 发表于 2015-5-22 05:45:55 | 只看该作者
本帖最后由 jianhong_wu 于 2015-5-22 05:48 编辑

第十九节:加法运算中,神秘中间变量的类型以及解决“掺杂多种变量类型”的办法。
       在开始本节内容之前,先告诉大家前面第十一节内容有一处笔误,unsigned long的数据长度应该是4个字节,而不是3个字节。
上一节提到了一个“隐藏中间变量”的概念,两个加数相加,其结果先保存在一个“隐藏中间变量”里,然后再把这个“隐藏中间变量”赋值给左边的“保存变量”。这里的“隐藏中间变量”到底是unsigned int类型还是unsigned long类型?为了研究它的规律,在keil自带的C51编译环境下,我专门编写了好几个测试程序来观察实际运行的结果。
       “保存变量”=“加数1+“加数2;
       我测试的程序如下:
    (1)“保存变量”为 unsigned int类型,“加数1”为unsigned char类型,“加数2”为unsigned char 类型。
  1. unsigned int a;
  2. unsigned char x=0x12;
  3. unsigned char y=0xfe;
  4. a=x+y;
复制代码

运行结果:a等于0x0110
分析过程:两个char类型的数相加,当运算结果大于char本身时,并没有发生溢出现象,int型的“保存变量”a最终得到了完整的结果。
初步结论:这种情况,“隐藏中间变量”应该为unsigned int 类型。
    (2)“保存变量”为 unsigned long类型,“加数1”为unsigned int类型,“加数2”为unsigned char 类型。
  1. unsigned long a;
  2. unsigned int x=0xfffe;
  3. unsigned char y=0x12;
  4. a=x+y;
复制代码

运行结果:a等于十六进制的0x0010
分析过程:一个int类型的数与一个char类型的数相加,当运算结果大于其中最大加数int类型本身时,本来以为运算结果应该是long类型的0x00010010,结果是int类型的0x0010,发生了溢出现象。
初步结论:这种情况,“隐藏中间变量”应该为unsigned int 类型。
     (3)“保存变量”为 unsigned long类型,“加数1”与“加数2”都为常量。
  1. unsigned long a;
  2. a=50000+50000;
复制代码

运行结果:a等于100000
分析过程:int的最大数据范围是65535,而两个常量相加,其结果超过了65535还能完整保存下来。
初步结论:这种情况,“隐藏中间变量”等于左边的“保存变量”类型。
     (4)“保存变量”为 unsigned long类型,“加数1”为unsigned int类型,“加数2”为常量。
  1. unsigned long a;
  2. unsigned long b;
  3. unsigned  int x=50000;
  4. a=x+30000;
  5. b=x+50000;
复制代码


运行结果:a等于14464,b等于100000
分析过程:本来以为a应该等于80000的,结果是14464发生了溢出。而b100000没有发生溢出。
初步结论:这是一种很怪异的现象,为什么同样的类型,因为常量的不同,一个发生了溢出,另外一个没有发生溢出?这时的“隐藏中间变量”到底是int类型还是long类型我无法下结论。
       经过上述简单的测试,我发现规律是模糊的,模糊的规律就不能成为规律。如果真要按这种思路研究下去,那真是没完没了,因为还有很多情况要研究,当超过3个以上加数相加,同时存在long,int,char,常量这4种类型时又是什么规律?在不同的C编译器里又会是什么现象?即使把所有情况的规律摸清楚了又能怎么样,因为那么繁杂很容易忘记导致出错。有什么解决的办法吗?现在跟大家分享一种很简单的解决办法。
       当遇到有争议的问题时,还有一种解决思路是:与其参与争议越陷越深,还不如想办法及时抽身绕开争议。在上述运算中,只要经过简单的变换,让它们遵循“所有参与运算的变量,左边的变量类型必须跟右边的保存变量类型一致”这个原则,那么就不会存在这些争议了。
     (5)比如上述第(4)个例子,其转换方法如下:
  1. unsigned long a;
  2. unsigned long b;
  3. unsigned  int x=50000;
  4. Unsigned  long t;  //多增加一个long类型的变量,用来变换类型
  5. t=0;  //把变量的高位和低位全部清零。
  6. t=x;   //把x的数值先放到一个long类型的变量里,让”加数”跟”保存变量”类型一致。
  7. a=t+30000;
  8. b=t+50000;
复制代码

运行结果:a等于80000,b等于100000。都没有发生溢出。
      (6)比如上述第(2)个例子,其转换方法如下:
  1. unsigned long a;
  2. unsigned int x=0xfffe;
  3. unsigned char y=0x12;
  4. unsigned  long t;  //多增加一个long类型的变量,用来变换类型。
  5. unsigned  long r;  //多增加一个long类型的变量,用来变换类型。
  6. t=0;//把变量的高位和低位全部清零。
  7. t=x;   //把x的数值先放到一个long类型的变量里,让”加数”跟”保存变量”类型一致。
  8. r=0;  //把变量的高位和低位全部清零。
  9. r=y   //把y的数值先放到一个long类型的变量里,让”加数”跟”保存变量”类型一致。
  10. a=t+r;
复制代码

运行结果:a等于十六进制的0x00010010,没有发生溢出现象。

        下节预告:减法运算的常见格式。
(未完待续)



乐于分享,勇于质疑!
51#
 楼主| 发表于 2015-5-16 23:41:15 | 只看该作者
本帖最后由 jianhong_wu 于 2015-6-3 18:29 编辑

第十八节:加法运算的溢出。
       我前面介绍的三种数据类型unsigned char ,unsigned int ,unsigned long,都是有最大范围限制的,它们最大范围分别是255,65535,4294967295,如果加法运算的结果超过了参与运算的变量本身,会出现什么结果,有什么规律,这就是本节要讲解的溢出问题。
    (1)何谓溢出?比如以下例子:
unsigned char a;
a=0x8536;
分析:
因为aunsigned char变量,位数是8位,也就是1个字节,而0x853616位,2个字节,这种情况下,把0x8536赋值给单字节变量a,变量a只能接收到最低位的一个字节0x36,而高位字节的0x85就被丢失了,这个就是本节所说的“溢出”了。
    (2)再看一个例子如下:
unsigned char b=0xff;
b=b+1;
分析:
b默认值是0xff,再加1后,变成了0x0100保存在一个隐藏的中间变量,然后再把这个中间变量赋值给单字节变量bb只能接收到低位字节0x00,所以运算后b的数值由于溢出变成了0x00
    (3)再看一个例子如下:
unsigned char c=0xff;
c=c+2;
分析:
c默认值是0xff,再加2后,变成了0x0101保存在一个隐藏中间变量,然后再把这个中间变量赋值给单字节变量cc只能接收到低位字节0x01,所以运算后c的数值由于溢出变成了0x01
    (4)再看一个例子如下:
Unsigned int d=0xfffe;
d=d+5;
分析:
d默认值是0xfffe,再加5后,变成了0x10003保存在一个隐藏中间变量,由于这个隐藏的中间变量是unsigned int类型,只能保存2个字节的数据,所以在中间变量这个环节就溢出了,实际上隐藏的中间变量只保存了0x0003,然后再把这个中间变量赋值给双字节变量dd理所当然也是0x0003
    (5)再看一个例子如下:
unsigned long e=0xfffffffe;
e=e+5;
分析:
e默认值是0xfffffffe,再加5后,变成了0x100000003保存在一个隐藏中间变量,由于这个隐藏的中间变量是unsigned long类型,只能保存4个字节的数据,所以在中间变量这个环节就溢出了,实际上隐藏的中间变量只保存了0x00000003,然后再把这个中间变量赋值给4字节变量ee理所当然也是0x00000003
       现在编写一个程序来练习上述前面4个例子,最后把程序编译后下载到坚鸿51学习板观察结果。请直接复制第十节模板程序,修改的main程序代码如下:

  1. void main() //主程序
  2. {
  3. /*---C语言学习区域的开始---------------------------------------------------------------------------*/
  4.         
  5.    unsigned char a;
  6.          unsigned char b=0xff;
  7.          unsigned char c=0xff;
  8.           unsigned int  d=0xfffe;

  9.         
  10.    a=0x8536;
  11.    b=b+1;
  12.    c=c+2;
  13.    d=d+5;




  14.    GuiWdData0=a;   //把变量a这个数值放到窗口变量0里面显示
  15.    GuiWdData1=b;   //把变量b这个数值放到窗口变量1里面显示
  16.    GuiWdData2=c;   //把变量c这个数值放到窗口变量2里面显示
  17.    GuiWdData3=d;   //把变量d这个数值放到窗口变量3里面显示





  18.         
  19. /*---C语言学习区域的结束---------------------------------------------------------------------------*/
  20.    while(1)  
  21.    {
  22.       initial();
  23.       key_service();
  24.       display_service();
  25.    }

  26. }
复制代码

        如何在坚鸿51学习板上观察a,b,c,d4个变量的十六进制?按下S1或者S5按键即可切换显示不同的窗口,从而显示不同的变量,只要按住S9按键不放,此时显示的就是该变量的十六进制。上坚鸿51学习板观察程序执行的结果如下:

变量a为0x36。
变量b为0x00。
变量c为0x01。
变量d为0x0003。

        这一节提到了一个“隐藏中间变量”的概念,这个神秘的“隐藏中间变量”到底是unsigned int类型还是unsigned long类型?有什么规律?如果运算中存在多种不同变量类型该怎么办,实际应用中有解决的办法吗?预知详情,请看一节内容。
       下节预告:加法运算中,神秘中间变量的类型以及解决“掺杂多种变量类型”的办法。
(未完待续)




乐于分享,勇于质疑!
50#
 楼主| 发表于 2015-5-10 07:53:28 | 只看该作者
本帖最后由 jianhong_wu 于 2015-6-3 18:29 编辑

第十七节:连加以及自加运算的简写。
       上一节我列举的加法例子中,右边的加数个数都是两个。实际上,C语言规则没有限制加数的个数,它的通用格式如下:
       “保存变量”=“加数1+“加数2+...+“加数N”;
       当右边的加数个数超过两个的时候,这种情况就是我所说的“连加”,每个加数的属性没有限定,可以是常量,也可以是变量。比如:
a=1+69+102;     //加数全部是常量。
b=q+x+y+k+r;    //加数全部是变量。
c=3+x+y+5+k;   //加数有的是常量,有的是变量。
        连加的运行顺序是,赋值符号“=”右边的加数挨个相加,把每一次的运算结果放在一个临时的隐蔽变量里,这个隐蔽的变量我们看不到,是单片机系统内部参与运算时的专用寄存器,等右边所有的加数连加的计算结果出来后,再把这个隐蔽变量所保存的计算结果赋值给左边的“保存变量”。
        讲完了连加的格式,接着讲自加的简写。何谓自加?当右边的加数只要其中有一个是“保存变量”本身时,这种情况就是我所说的“自加”。比如:
“保存变量”=“保存变量”+“加数1”;
“保存变量”=“保存变量”+“加数1+“加数2+...+“加数N”;
        当这类自加计算式中,右边的加数有且仅有一个是“保存变量”本身时,那么上述自加计算式可以简写成如下格式:
“保存变量”+=“加数1”;
“保存变量”+=“加数1+“加数2+...+“加数N”;
        这种格式就是我所说的自加简写。现在举几个例子如下:
d+=6;  //相当于d=d+6;
e+=x;  //相当于e=e+x;
f+=18+y+k; //相当于f=f+18+y+k;
        这些例子都是很常规的自加简写,再跟大家讲一种很常用的特殊简写。当右边只有2个加数,当一个加数是“保存变量”,另一个是常数1时,格式如下:
“保存变量”=“保存变量”+1
        这时候,可以把上述格式简写成如下两种格式:
“保存变量”++;
++“保存变量”;
        这两种格式也是俗称的“自加1”操作。比如:
g++;  //相当于g=g+1或者g+=1;
++h;  //相当于h=h+1或者h+=1;
        也就是说自加1符号“++”可以在变量的左边,也可以在变量的右边,它们在这里本质是一样的,没有差别。当然,如果是在循环条件语句中,这时自加1符号“++”在左边还是在右边是有一点点微弱的差别,这方面的内容以后再讲。

        现在编写一个程序来练习刚才讲到的内容,最后把程序编译后下载到坚鸿51学习板观察结果。请直接复制第十节模板程序,修改的main程序代码如下:


  1. void main() //主程序
  2. {
  3. /*---C语言学习区域的开始---------------------------------------------------------------------------*/
  4.         
  5.   unsigned char a;       //定义一个变量a,并且分配了1个字节的RAM空间。
  6.   unsigned char b;       //定义一个变量b,并且分配了1个字节的RAM空间。
  7.   unsigned char c;       //定义一个变量c,并且分配了1个字节的RAM空间。
  8.   unsigned char d=5;       //定义一个变量d,并且分配了1个字节的RAM空间。初始化默认为5.
  9.   unsigned char e=5;       //定义一个变量e,并且分配了1个字节的RAM空间。初始化默认为5.
  10.   unsigned char f=5;       //定义一个变量f,并且分配了1个字节的RAM空间。初始化默认为5.
  11.         unsigned char g=5;       //定义一个变量g,并且分配了1个字节的RAM空间。初始化默认为5.        
  12.   unsigned char h=5;       //定义一个变量h,并且分配了1个字节的RAM空间。初始化默认为5.

  13.         
  14.   unsigned char q=1;    //定义一个变量q,并且分配了1个字节的RAM空间。初始化默认为1.
  15.   unsigned char x=3;    //定义一个变量x,并且分配了1个字节的RAM空间。初始化默认为3.
  16.   unsigned char y=6;     //定义一个变量y,并且分配了1个字节的RAM空间。初始化默认为6.        
  17.   unsigned char k=2;     //定义一个变量k,并且分配了1个字节的RAM空间。初始化默认为2.
  18.   unsigned char r=8;     //定义一个变量r,并且分配了1个字节的RAM空间。初始化默认为8.
  19.         
  20.         
  21.          //第1个知识点:连加。
  22.    a=1+69+102;     //加数全部是常量。a的结果为:172。
  23.    b=q+x+y+k+r;    //加数全部是变量。b的结果为:20。
  24.    c=3+x+y+5+k;   //加数有的是常量,有的是变量。c的结果为:19。

  25.          //第2个知识点:自加的常规格式。
  26.    d+=6;  //相当于d=d+6;  d的结果为:11。
  27.    e+=x;  //相当于e=e+x;  e的结果为:8。
  28.    f+=18+y+k; //相当于f=f+18+y+k;  f的结果为:31。
  29.          
  30.          
  31.          //第3个知识点:自加的特殊格式。
  32.    g++;  //相当于g=g+1或者g+=1;  g的结果为:6。
  33.    ++h;  //相当于h=h+1或者h+=1;  h的结果为:6。




  34.    GuiWdData0=a;   //把变量a这个数值放到窗口变量0里面显示
  35.    GuiWdData1=b;   //把变量b这个数值放到窗口变量1里面显示
  36.    GuiWdData2=c;   //把变量c这个数值放到窗口变量2里面显示
  37.    GuiWdData3=d;   //把变量d这个数值放到窗口变量3里面显示
  38.    GuiWdData4=e;   //把变量e这个数值放到窗口变量4里面显示
  39.    GuiWdData5=f;   //把变量f这个数值放到窗口变量5里面显示
  40.    GuiWdData6=g;   //把变量g这个数值放到窗口变量6里面显示
  41.    GuiWdData7=h;   //把变量h这个数值放到窗口变量7里面显示



  42.         
  43. /*---C语言学习区域的结束---------------------------------------------------------------------------*/
  44.    while(1)  
  45.    {
  46.       initial();
  47.       key_service();
  48.       display_service();
  49.    }

  50. }
复制代码

        如何在坚鸿51学习板上观察a,b,c,d,e,f,g,h8个变量?按下S1或者S5按键即可切换显示不同的窗口,从而显示不同的变量。上坚鸿51学习板观察程序执行的结果如下:

变量a为172
变量b为20
变量c为19
变量d为11
变量e为8
变量f为31
变量g为6
变量h为6
     下节预告:加法的溢出和优先级
(未完待续)




乐于分享,勇于质疑!
49#
发表于 2015-5-4 13:02:02 | 只看该作者
学习了,赞一个
乐于分享,勇于质疑!
48#
 楼主| 发表于 2015-5-2 10:42:46 | 只看该作者
本帖最后由 jianhong_wu 于 2015-6-3 18:28 编辑

第十六节:加法运算的5种常用格式。
       根据上一节的预告,本来这节应该讲判断语句的,但是考虑到后续章节的连贯性,决定先讲运算语法。
       在讲运算语法之前,先讲一个我在前面忘了讲的知识点,那就是注释语句。何谓注释语句?在我前面一些章节的main函数中,经观察,发现一个规律,凡是中文解说的文字,要么前面有符号”//”,要么就是被包含在“/*”和”*/”之间。符号“//”和“/*  */”都是注释语句。注释语句是用来添加文字备忘,方便程序员阅读记忆的。在注释语句里的文字是不会被编译器翻译成机器码的,也就是说即使注释里面的文字再多,也不会增加单片机的程序容量,它是被编译器过滤忽略的,仅仅方便程序员做备注文字而已。
符号“//”和“/*  */”都是注释语句,但应用方面有点小差异。符号“//”是用来注释一行文字。而“/*  */”往往是用来注释一段文字,当然“/*  */”也可以注释一行文字。但是符号“//”仅仅能注释一行文字,却不能注释一段文字。
       讲完注释语句,继续回到本节正题。单片机本身具备了简单的加减乘除运算能力,我们只需要通过C语言调用相关的运算语法,即可指示单片机按我们的要求进行简单的运算。至于内部具体的运算细节我们可以不管,除非是涉及到大数据的运算才需要我们额外编写算法。请先看以下的加法语法格式:
       “保存变量”=“加数1+“加数2+...+“加数N”;
        含义是:右边的“加数”与“加数”相加,并且把最终的运算结果赋值给左边的“保存变量”。注意,这里的符号“=”不是等于号的意思,而是赋值的意思。左边的“保存变量”必须是变量,不能是常量,否则编译时会报错。而右边的“加数”既可以是变量,也可以是常量,也可以是“保存变量”本身自己。多说一句,何谓变量和常量?变量就是可以在程序中被更改的,是分配的一个RAM空间。而常量往往就是数字,或者是被分配在ROM空间的一个具体数值。下面根据右边“被加数”与“加数”的不同组合,列出了加法运算的5种常用格式。
      第1种:“加数1”是常量,“加数2”是常量。比如:
unsigned char a;
a=3+15;
数字“3”和“15”都是常量。执行上述语句后,保存变量a变成了18

      第2种:“加数1”是变量,“加数2”是常量。比如:
unsigned char b;
unsigned char x=10;
b=x+15;
x是变量,“15”是常量。由于原来x变量里面的数值是10,执行上述语句后,保存变量b变成了25。而变量x则保持不变,x还是10

      第3种:“加数1”是变量,“加数2”是变量。比如:
unsigned char c;
unsigned char x=10;
unsigned char y=6;
c=x+y;
x是变量,y也是变量。由于原来x变量里面的数值是10y变量里面的数值是6,执行上述语句后,保存变量c变成了16。而变量xy则保持不变,x还是10y还是6

      第4种:“加数1”是保存变量本身,“加数2”是常量。比如:
unsigned char d=2;
d=d+18;
d=d+7;
d是保存变量,“18”是常量。这类语句有一个特点,具备了自加功能,可以更改自己本身自己的数值。比如原来保存变量d的数值是2,执行“d=d+18;”语句后,d变成了20,接着再执行完“d=d+7;”语句后,d最后变成了27

      第5种:“加数1”是保存变量本身,“加数2”是变量。比如:
unsigned char e=2;
unsigned char x=10;
unsigned char y=6;
e=e+x;
e=e+y;
e是保存变量,xy都是变量。这类语句有一个特点,具备了自加功能,可以更改自己本身自己的数值。比如原来保存变量e的数值是2,执行“e=e+x;”语句后,e变成了12,接着再执行完“e=e+y;”语句后,e最后变成了18

       现在编写一个程序来练习上述5种格式的加法语句,最后把程序编译后下载到坚鸿51学习板观察结果。请直接复制第十节模板程序,修改的main程序代码如下:


  1. void main() //主程序
  2. {
  3. /*---C语言学习区域的开始---------------------------------------------------------------------------*/
  4.         
  5.   unsigned char a;       //定义一个变量a,并且分配了1个字节的RAM空间。
  6.   unsigned char b;       //定义一个变量b,并且分配了1个字节的RAM空间。
  7.   unsigned char c;       //定义一个变量c,并且分配了1个字节的RAM空间。
  8.   unsigned char d=2;       //定义一个变量d,并且分配了1个字节的RAM空间。初始化默认为2.
  9.   unsigned char e=2;       //定义一个变量e,并且分配了1个字节的RAM空间。初始化默认为2.
  10.         
  11.   unsigned char x=10;    //定义一个变量x,并且分配了1个字节的RAM空间。初始化默认为10.
  12.   unsigned char y=6;     //定义一个变量y,并且分配了1个字节的RAM空间。初始化默认为6.        

  13.   //第1种:“加数1”是常量,“加数2”是常量。
  14.         a=3+15;
  15.         
  16.         
  17.         //第2种:“加数1”是变量,“加数2”是常量。
  18.         b=x+15;
  19.         
  20.         
  21.         //第3种:“加数1”是变量,“加数2”是变量。
  22.   c=x+y;
  23.         
  24.         
  25.   //第4种:“加数1”是保存变量本身,“加数2”是常量。
  26.   d=d+18;
  27.   d=d+7;
  28.         
  29.         
  30.         //第5种:“加数1”是保存变量本身,“加数2”是变量。
  31.         e=e+x;
  32.   e=e+y;


  33.   GuiWdData0=a;   //把变量a这个数值放到窗口变量0里面显示
  34.   GuiWdData1=b;   //把变量b这个数值放到窗口变量1里面显示
  35.   GuiWdData2=c;   //把变量c这个数值放到窗口变量2里面显示
  36.   GuiWdData3=d;   //把变量d这个数值放到窗口变量3里面显示
  37.   GuiWdData4=e;   //把变量e这个数值放到窗口变量4里面显示

  38.         
  39. /*---C语言学习区域的结束---------------------------------------------------------------------------*/
  40.    while(1)  
  41.    {
  42.       initial();
  43.       key_service();
  44.       display_service();
  45.    }

  46. }
复制代码

        如何在坚鸿51学习板上观察a,b,c,d,e5个变量?按下S1或者S5按键即可切换显示不同的窗口,从而显示不同的变量。上坚鸿51学习板观察程序执行的结果如下:
变量a为18
变量b为25
变量c为16
变量d为27
变量e为18

     下节预告:加法的连写和自加运算的简写。
(未完待续)



乐于分享,勇于质疑!
47#
 楼主| 发表于 2015-4-23 23:10:41 | 只看该作者
本帖最后由 jianhong_wu 于 2015-6-3 18:27 编辑

第十五节:十进制与十六进制。
       十六进制是二进制的缩写形式,而C语言程序里只用了十进制和十六进制这两种书写格式。它们各有什么应用特点?十六进制方便人理解机器,通常应用在配置寄存器,底层通讯驱动,底层IO口驱动,以及数据的移位,转换和合并等场合。而十进制方便人理解值的大小,在应用层经常用总之,进制数据的表现形式而已。
    十进制与十六进制如何相互转换?其实很多教科书上有介绍它们之间如何通过手工计算进行转换的方法。但是实际应用中,我从来没有用过这种手工计算方法,我用的方法是最简单直接的,就是借助电脑自带的计算器进行转换即可。现在把这种方法介绍给大家。
    第一步:点击电脑左下角“开始”菜单,在下拉菜单中把鼠标移动到“所有程序”,在下拉菜单中把鼠标移动到“附件”,在下拉菜单中点击“计算器”,此时会弹出“计算器” 的窗口。
    第二步:点击计算器窗口上面的“查看”菜单,在下拉菜单中点击“科学型”,此时“计算器” 的窗口会变长。按键上方出现“十六进制”,“十进制”,“八进制”,“二进制”等单选项。
    第三步:在按键上方“十六进制”,“十进制”,“八进制”,“二进制”等单选项中,单击所要切换到的进制,然后按数字按键输入数据。输完数据后,再单击切换到所要转换的进制中,即可完成各进制的数据切换。注意,在切换到“十六进制”的时候,在右边“四字”,“双字”,“单字”,“字节”中选中“四字”。
    第四步:把十进制转换到十六进制的方法如下:单击切换到“十进制”,然后按数字按键输入数据。输完数据后,再单击切换到“十六进制”,即可完成进制的转换。比如输入十进制的“230”,切换到十六进制就变成了“E6”。
    第五步:把十六进制转换到十进制的方法如下:单击切换到“十六进制”,然后按数字按键输入数据。输完数据后,再单击切换到“十进制”,即可完成进制的转换。比如输入十六进制的“AC”,切换到十进制就变成了“172”。
现在我们编写一个程序来观察十进制和十六进制的关系,最后把程序编译后下载到坚鸿51学习板观察结果。请直接复制第十节模板程序,修改的main程序代码如下:

  1. void main() //主程序
  2. {
  3. /*---C语言学习区域的开始---------------------------------------------------------------------------*/
  4.         
  5.   unsigned char a;    //定义一个变量a,并且分配了1个字节的RAM空间。
  6.   unsigned char b;    //定义一个变量b,并且分配了1个字节的RAM空间。

  7.   a=230;    //把十进制的230赋值给变量a,在坚鸿51学习板上观察一下它的十六进制是不是E6。
  8.   b=0xAC;   //把十六进制的AC赋值给变量b,在坚鸿51学习板上观察一下它的十进制是不是172。
  9.          
  10.   GuiWdData0=a;   //把变量a这个数值放到窗口变量0里面显示
  11.   GuiWdData1=b;   //把变量b这个数值放到窗口变量1里面显示

  12.         
  13. /*---C语言学习区域的结束---------------------------------------------------------------------------*/
  14.    while(1)  
  15.    {
  16.       initial();
  17.       key_service();
  18.       display_service();
  19.    }

  20. }
复制代码


如何在坚鸿51学习板上观察十进制和十六进制?S1S5按键是切换窗口按键。按住S9按键不松手,就可以观察当前窗口数据的十六进制格式了。松开S9按键就是当前窗口的十进制数据格式。而坚鸿51学习板右上角的16LED灯就代表了当前窗口的二进制,亮的代表1,灭的代表0
上坚鸿51学习板观察程序执行的结果如下:
                      十六进制        十进制     
unsigned char变量a      E6            230
unsigned char变量b      AC            172

     下节预告:判断语句“if”和等于关系符“==”。
(未完待续)





乐于分享,勇于质疑!
46#
 楼主| 发表于 2015-4-19 11:28:12 | 只看该作者
本帖最后由 jianhong_wu 于 2015-6-3 18:26 编辑

第十四节:二进制与十六进制。
       C51编译器并不支持二进制的书写格式,即使添加某个头文件后能支持二进制的书写格式,二进制的书写还是有个弊端,就是数字太多太长了,写起来非常费劲不方便,怎么办?解决办法就是用十六进制。十六进制是二进制的缩写,之所以称它为二进制的缩写,是因为它们的转换关系非常简单直观,不需要借助计算器即可相互转换。
      何谓十六进制?欲搞清楚这个问题,还得先从十进制说起。所谓十进制,就是用一位字符可以表示从09这十个数字。所谓二进制,就是用一位字符可以表示从01这二个数字。所谓十六进制,当然也就是用一位字符可以表示从015这十六个数字。但是马上就会面临一个问题,十六进制的10156个数其实是有两位字符组成的,并不是一位呀?于是C语言用一个字符A,B,C,D,E,F分别替代10,11,12,13,14,156个数,10前面的09还是跟十进制的字符一致。A,B,C,D,E,F也可以用小写a,b,c,d,e,f来替代,不区分大小写。
     前面提到了十六进制是二进制的缩写,它们的转换关系非常简单直观,每1位十六进制的字符,对应4位二进制的字符。关系如下:
十进制       二进制      十六进制
0               0000        0
1               0001        1
2               0010        2
3               0011        3
4               0100        4
5               0101        5
6               0110        6
7               0111        7
8              1000        8
9              1001        9
10            1010        A
11            1011        B
12            1100        C
13            1101        D
14            1110        E
15            1111        F

        二进制转换成十六进制的时候,如果不是4位的倍数,则最左边高位默认补上0凑合成4位的倍数。比如二进制101001,可以在左边补上20变成00101001,然后把每4位字符转成1个十六进制的字符。左边高40010对应十六进制的2,右边低41001对应十六进制的9,所以合起来最终的十六进制是29
        十六进制的标准书写格式。刚才提到的十六进制29,在C语言里不能直接写29,否则就跟十进制的写法混淆了。为了把十六进制和十进制的书写格式进行区分,C语言规定凡是十六进制必须加一个数字0和一个字母x作为前缀,也就是十六进制必须以0x作为前缀,刚才的十六进制29就应该写成0x29。凡是不加前缀的就默认为十进制。
       现在我们编写一个程序来观察十六进制和二进制的关系,最后把程序编译后下载到坚鸿51学习板观察结果。请直接复制第十节模板程序,修改的main程序代码如下:


  1. void main() //主程序
  2. {
  3. /*---C语言学习区域的开始---------------------------------------------------------------------------*/
  4.         
  5.   unsigned char a;    //定义一个变量a,并且分配了1个字节的RAM空间。
  6.   unsigned char b;    //定义一个变量b,并且分配了1个字节的RAM空间。
  7.   unsigned char c;    //定义一个变量c,并且分配了1个字节的RAM空间。
  8.   unsigned char d;    //定义一个变量d,并且分配了1个字节的RAM空间。

  9.   a=0x06;   //十六进制前记得加0x前缀,超过9部分的字母不分大小写。
  10.   b=0x0A;   //十六进制前记得加0x前缀,超过9部分的字母不分大小写。
  11.   c=0x0e;   //十六进制前记得加0x前缀,超过9部分的字母不分大小写。
  12.   d=0x2C;   //十六进制前记得加0x前缀,超过9部分的字母不分大小写。
  13.         
  14.         
  15.   GuiWdData0=a;   //把变量a这个数值放到窗口变量0里面显示
  16.   GuiWdData1=b;   //把变量b这个数值放到窗口变量1里面显示
  17.   GuiWdData2=c;   //把变量c这个数值放到窗口变量2里面显示
  18.   GuiWdData3=d;   //把变量d这个数值放到窗口变量3里面显示

  19.         
  20. /*---C语言学习区域的结束---------------------------------------------------------------------------*/
  21.    while(1)  
  22.    {
  23.       initial();
  24.       key_service();
  25.       display_service();
  26.    }

  27. }
复制代码


        如何在坚鸿51学习板上观察十六进制和二进制?S1S5按键是切换窗口按键。按住S9按键不松手,就可以观察当前窗口数据的十六进制格式了。松开S9按键就是当前窗口的十进制数据格式。而坚鸿51学习板右上角的16LED灯就代表了当前窗口的二进制,亮的代表1,灭的代表0
       上坚鸿51学习板观察程序执行的结果如下:
                                   十六进制         二进制         十进制     
unsigned char变量a      6                   0000 0110       6
unsigned char变量b      A                   0000 1010       10
unsigned char变量c      E                   0000 1110       14
unsigned char变量d      2C                 0010 1100       44

        多说一句,在程序里,可以用十六进制,也可以用十进制,比如:
d=0x2Cd=44的含义是一样的。十六进制的0x2C和十进制的44最终都会被C51编译器翻译成二进制00101100
       下节预告:十进制与十六进制。
(未完待续)





乐于分享,勇于质疑!
45#
 楼主| 发表于 2015-4-19 01:39:34 | 只看该作者
大耳怪 发表于 2015-4-18 13:49
鸿哥基础篇,写程序模块化教学可以吗。谢谢

暂时不会讲这些。以后再看情况。
乐于分享,勇于质疑!
44#
发表于 2015-4-18 19:47:00 | 只看该作者
继续学习   
乐于分享,勇于质疑!
43#
发表于 2015-4-18 13:49:34 | 只看该作者
鸿哥基础篇,写程序模块化教学可以吗。谢谢
乐于分享,勇于质疑!
42#
 楼主| 发表于 2015-4-16 19:49:35 | 只看该作者
本帖最后由 jianhong_wu 于 2015-6-3 18:24 编辑

第十三节:二进制与字节单位,以及各种定义变量的取值范围。
      为什么是二进制?人类日常生活明明是十进制的,为何数字电子领域偏要选择二进制?这是由数字硬件电路决定的。人有十个手指头,人可以发出十种不同声音来命名0,1,2,3...9这些数字,人可以肉眼识别十种不同状态的信息,但是数字电路要直接处理十进制却很难,相对来说,二进制就轻松多了。一颗LED灯的亮与灭,一根IO口的输出是高电平和低电平,读取某一个点的电压是高于2V还是低于0.8V,只需要用三极管等元器件就可把处理电路搭建起来,二进制广泛应用在数字电路的存储,通讯和运算等领域,想学好单片机就必须掌握它。
     二进制如何表示成千上万的数值?现在用LED灯的亮和灭来跟大家讲解。
  (11LED灯:
灭   第0种状态
亮   第1种状态
合计:共2种状态。
  (22LED灯挨着:
灭灭   第0种状态
灭亮   第1种状态
亮灭   第2种状态
亮亮   第3种状态
合计:共4种状态。
  (33LED灯挨着:
灭灭灭   第0种状态
灭灭亮   第1种状态
灭亮灭   第2种状态
灭亮亮   第3种状态
亮灭灭   第4种状态
亮灭亮   第5种状态
亮亮灭   第6种状态
亮亮亮   第7种状态
合计:共8种状态。
  (48LED灯挨着:
灭灭灭灭灭灭灭灭   第0种状态
灭灭灭灭灭灭灭亮   第1种状态
......
亮亮亮亮亮亮亮灭   第254种状态
亮亮亮亮亮亮亮亮   第255种状态
合计:共256种状态。
  (516LED灯挨着:
灭灭灭灭灭灭灭灭灭灭灭灭灭灭灭灭   第0种状态
灭灭灭灭灭灭灭灭灭灭灭灭灭灭灭亮   第1种状态
......
亮亮亮亮亮亮亮亮亮亮亮亮亮亮亮灭   第65534种状态
亮亮亮亮亮亮亮亮亮亮亮亮亮亮亮亮   第65535种状态
合计:共65536种状态。
  (632LED灯挨着:
灭灭灭灭灭灭灭灭灭灭灭灭灭灭灭灭灭灭灭灭灭灭灭灭灭灭灭灭灭灭灭灭   
0种状态
灭灭灭灭灭灭灭灭灭灭灭灭灭灭灭灭灭灭灭灭灭灭灭灭灭灭灭灭灭灭灭亮   
1种状态
......
亮亮亮亮亮亮亮亮亮亮亮亮亮亮亮亮亮亮亮亮亮亮亮亮亮亮亮亮亮亮亮灭   
4294967294种状态
亮亮亮亮亮亮亮亮亮亮亮亮亮亮亮亮亮亮亮亮亮亮亮亮亮亮亮亮亮亮亮亮   
4294967295种状态
合计:共4294967296种状态。

       什么是位?以上一个LED灯就代表一位,8LED灯就代表8位。一个变量的位数越大就意味着这个变量的取值范围越大。一个单片机的位数越多大,就说明这个单片机一次处理的数据范围就越大,意味着运算和处理速度就越快。我们日常所说的8位单片机,32位单片机,就是这个位的概念。为什么32位的单片机比8位单片机的处理和运算能力强,就是这个原因。位的英文名是用bit来表示。
什么是字节?字节是计算机很重要的一个基本单位,一个字节有8位。8LED灯挨着能代表多少种状态,就意味着一个字节的数据范围有多大。从上面举的例子中,我们知道8LED灯挨着,能表示从0255种状态,所以一个字节的取值范围就是从0255
       各种定义变量的取值范围。前面第十一节讲了常用变量的定义有3种,unsigned charunsigned int ,unsigned long。但是没有讲到它们的取值范围,现在讲到二进制和字节了,可以回过头来跟大家讲讲这3种变量的取值范围,而且很重要。
unsigned char的变量占用1个字节RAM,共8位,根据前面LED灯的例子,取值范围是从0255
Unsigned int的变量占用2个字节RAM,共16位,根据前面LED灯的例子,取值范围是从065535
Unsigned long的变量占用4个字节RAM,共32位,根据前面LED灯的例子,取值范围是从04294967295
       现在我们编写一个程序来验证unsigned charunsigned int的取值范围。定义两个unsigned char变量aba赋值255b赋值256255256恰好处于unsigned char的取值边界。另外再定义两个unsigned int变量cdc赋值65535d赋值655366553565536恰好处于unsigned int的取值边界。最后把程序编译后下载到坚鸿51学习板观察结果。请直接复制第十节模板程序,修改的main程序代码如下:

  1. void main() //主程序
  2. {
  3. /*---C语言学习区域的开始---------------------------------------------------------------------------*/
  4.         
  5.   unsigned char a;   //定义一个变量a,并且分配了1个字节的RAM空间。
  6.   unsigned char b;   //定义一个变量b,并且分配了1个字节的RAM空间。
  7.   unsigned int c;    //定义一个变量c,并且分配了2个字节的RAM空间。
  8.   unsigned int d;    //定义一个变量d,并且分配了2个字节的RAM空间。

  9.         a=255;//把255赋值给变量a,a此时会是什么数?会超范围溢出吗?
  10.         b=256;//把256赋值给变量b,b此时会是什么数?会超范围溢出吗?
  11.         c=65535;//把65535赋值给变量c,c此时会是什么数?会超范围溢出吗?
  12.         d=65536;//把65536赋值给变量d,d此时会是什么数?会超范围溢出吗?
  13.         
  14.         
  15.   GuiWdData0=a;   //把变量a这个数值放到窗口变量0里面显示
  16.   GuiWdData1=b;   //把变量b这个数值放到窗口变量1里面显示
  17.   GuiWdData2=c;   //把变量c这个数值放到窗口变量2里面显示
  18.   GuiWdData3=d;   //把变量d这个数值放到窗口变量3里面显示

  19.         
  20. /*---C语言学习区域的结束---------------------------------------------------------------------------*/
  21.    while(1)  
  22.    {
  23.       initial();
  24.       key_service();
  25.       display_service();
  26.    }

  27. }
复制代码

    上坚鸿51学习板观察程序执行的结果如下:
    unsigned char变量a的数值是255。
     unsigned char变量b的数值是0。
    unsigned int  变量c的数值是65535。
     unsigned int  变量d的数值是0。
     通过以上现象分析,我们知道unsigned char变量最大能取值到255,如果非要赋值256就会超出范围溢出后变成了0。而unsigned int变量最大能取值到65535,如果非要赋值65536就会超出范围溢出后变成了0。
    多说一句,至于unsigned long的取值范围,大家暂时不用尝试,因为我现在给大家用的模板程序能观察的最大变量是16位的unsigned int类型,暂时不支持32位的unsigned long类型。
       下节预告:二进制与十六进制。
(未完待续)



乐于分享,勇于质疑!
41#
 楼主| 发表于 2015-4-10 12:09:36 | 只看该作者
第十二节:两个变量的数据交换。
为了加深理解赋值语句的一个重要特性“覆盖性”,本节利用赋值语句“=”做一个实验。要求把变量a与b的两个数据进行交换,假设a原来的数据是1,b原来的数据是5,交换数据后,a的数据应该变为5,b的数据应该变为1。
很多初学者刚看到这么简单的题目,会想当然的根据我们日常生活的思路,你把你的东西给我,我把我的东西给你,就两个步骤,so easy!请直接复制第十节的模板程序,仅修改main函数后,main函数源代码如下:
  1. void main() //主程序
  2. {
  3. /*---C语言学习区域的开始---------------------------------------------------------------------------*/
  4.         
  5.   unsigned char a=1;   //定义一个变量a,并且分配了一个字节的RAM空间,里面保存的数据被初始化成1.
  6.   unsigned char b=5;   //定义一个变量b,并且分配了一个字节的RAM空间,里面保存的数据被初始化成5.

  7.         b=a; //第一步:为了交换,先把a的数赋值给b。
  8.         a=b; //第二步:为了交换,再把b的数赋值给a。

  9.   GuiWdData0=a;   //把变量a这个数值放到窗口变量0里面显示
  10.   GuiWdData1=b;   //把变量b这个数值放到窗口变量1里面显示

  11.         
  12. /*---C语言学习区域的结束---------------------------------------------------------------------------*/
  13.    while(1)  
  14.    {
  15.       initial();
  16.       key_service();
  17.       display_service();
  18.    }

  19. }
复制代码

       上坚鸿51学习板观察程序执行的结果:
       变量a的数值是1。
       变量b的数值是1。
     上述实验结果并没有达到交换数据的目的,为什么?因为赋值语句有一个重要的特性,就是覆盖性。分析如下:
         b=a; //第一步
     分析点评:执行第一步后,此时虽然b得到了a的数据1,但是b原来自己的数据5已经被覆盖丢失了!
         a=b; //第二步
     分析点评:由于b的数据在执行第一步后变成了1,执行第二步后,此时相当于把1赋值给a,并没有5!所以a和b的数据都是1,不能达到交换后“a为5,b为1”的目的。
     上述交换数据的程序宣告失败!怎么办?既然赋值语句具有覆盖性,那么两变量想交换数据,就必须借助第三方寄存,此时只需要多定义一个第三方变量t。main函数源代码如下:
  1. void main() //主程序
  2. {
  3. /*---C语言学习区域的开始---------------------------------------------------------------------------*/
  4.         
  5.   unsigned char a=1;   //定义一个变量a,并且分配了一个字节的RAM空间,里面保存的数据被初始化成1.
  6.   unsigned char b=5;   //定义一个变量b,并且分配了一个字节的RAM空间,里面保存的数据被初始化成5.
  7.   unsigned char t;     //定义一个变量t,并且分配了一个字节的RAM空间,里面默认是什么数据不重要。
  8.        
  9.         t=b; //第一步:为了避免b的数据在执行第二步后被覆盖丢失,先把b的数据寄存在第三方变量t那里。
  10.         b=a; //第二步:把a的数赋值给b,b原来的数据虽然被覆盖丢失,但是b在t变量那里有备份,再也不用担心了。
  11.         a=t; //第三步:由于此时b已经获得了a的数据,如果想交换,此时只能把b在t变量里的备份赋值给a,而不能用b。

  12.   GuiWdData0=a;   //把变量a这个数值放到窗口变量0里面显示
  13.   GuiWdData1=b;   //把变量b这个数值放到窗口变量1里面显示

  14.         
  15. /*---C语言学习区域的结束---------------------------------------------------------------------------*/
  16.    while(1)  
  17.    {
  18.       initial();
  19.       key_service();
  20.       display_service();
  21.    }

  22. }
复制代码

       上坚鸿51学习板观察程序执行的结果:
       变量a的数值是5。
       变量b的数值是1。
      交换成功!
     
       下节预告:二进制与字节单位。
(未完待续)

乐于分享,勇于质疑!
40#
发表于 2015-4-7 17:53:00 | 只看该作者
jianhong_wu 发表于 2015-4-2 13:10
第十节:一个用来学习C语言的模板程序。目前,几乎所有的初学者在学习和上机练习C语言的时候,都是在电脑上 ...

没有注释啊,
乐于分享,勇于质疑!
39#
 楼主| 发表于 2015-4-7 09:31:11 | 只看该作者
本帖最后由 jianhong_wu 于 2015-6-3 18:23 编辑

第十一节:变量的定义与赋值语句。
      写程序到底是写什么?我用七个字概括是:对象之间的行为。假设以下a,b,c,d,e.这些都是对象,那么程序往往是对象之间的以下这些行为:
    (1)把某个数值赋值给对象a
    (2)把对象b赋值给对象a
    (3)把对象b与对象c运算的结果赋值给对象a
    (4)如果对象d等于某个数值,则把某个数值赋值给对象a
    (5)如果对象d等于某个数值,则把对象b赋值给对象a
    (6)如果对象d等于某个数值,则把对象b与对象c运算的结果赋值给对象a
    (7)如果对象d等于对象e,则把某个数值赋值给对象a
    (8)如果对象d等于对象e,则把对象b赋值给对象a
    (9)如果对象d等于对象e,则把对象b与对象c运算的结果赋值给对象a
    (10)...等等,不一一列举。
      从上述可以看出,程序的两个要素是:对象和行为。如果把对象看作是单片机的RAM数据存储器,那么行为就是单片机的ROM程序存储器。如果把对象看作是变量,那么行为就是指令语句。本节标题“变量的定义与赋值语句”,其中“变量的定义”就是对象,“赋值语句”就是行为。
      变量的定义。一个程序最大允许有多少个对象,是由数据存储器RAM的字节数决定的(字节是一种单位,后面章节会讲到)stc89c52rc这个单片机有几百个字节的RAM,但是并不意味着程序就一定要全部占用这些RAM。程序需要占用多少RAM,完全是根据程序的实际情况来决定,需要多少就申请多少。这里的“对象”就是变量。这里的“申请”就是变量的定义。
       定义变量的关键字。常用有3种容量的变量,每种变量的取值范围不一样。第一种是”unsigned char”变量,取值范围从0255,占用RAM一个字节,比喻成一房一厅。第二种是”unsigned int”变量,取值范围从065535,占用RAM两个字节,比喻成两房一厅。第三种是“unsigned long”变量,取值范围从04294967295,占用RAM三个字节,比喻成三房一厅。unsigned char,unsigned intunsigned long都是定义变量的关键字。
       定义变量的语法格式。定义变量的语法格式由3部分组成:关键字,变量名,分号。比如:
       unsigned char a;
      其中unsigned char就是关键字,a就是变量名,分号”;”就是一条语句的结束符号。
      变量名的命名规则。变量名的第一个字符不能是数字,必须是字母或者下划线,字母或者下划线后面可以带数字,一个变量名之间的字符不能带空格。变量名不能跟编译器的关键字重名,不能跟函数名重名。比如:
      unsigned char 3a; //不合法,第一个字符不能是数字。
      unsigned char char; //不合法,char是编译器的关键字。
      unsigned char a b; //不合法,ab是一个变量名,ab的中间不能有空格。
      unsigned char a; //合法。
      unsigned char abc; //合法。
      unsigned char _ab; //合法。
      unsigned char _3ab; //合法。
      unsigned char a123; //合法。
      unsigned char a12ced; //合法。
      定义变量与RAM的内在关系。当我们定义一个变量时,相当于向单片机申请了一个RAM空间。C编译器会自动为这个变量名分配一个RAM空间,每个字节的RAM空间都有一个固定的地址。把每个字节的RAM空间比喻成 房间,这个地址就是房号。地址是纯数字编号,不利于我们记忆,C语言编译器为了降低我们的工作难度,不用我们记每个变量的地址,只需要记住这个变量的名称就可以了。操作某个变量名,就相当于操作到对应地址的RAM空间。变量名与对应地址RAM空间的映射关系是C编译器暗中帮我们做好了。比如:
      unsigned char a;  //a占用一个字节的RAM空间,这个空间的地址由C编译自动分配。
      unsigned char b;  //b占用一个字节的RAM空间,这个空间的地址由C编译自动分配。
      unsigned char c;  //c占用一个字节的RAM空间,这个空间的地址由C编译自动分配。  
      上述a,b,c三个变量名占用一个字节的RAM空间,同时被C编译器分配了3个不同的RAM空间地址。
      赋值语句的含义。赋值语句是行为。把右边对象的内容复制一份给左边对象。 赋值语句有一个很重要的特性,就是覆盖性,左边对象原来的内容会被右边对象复制过来的新内容所覆盖。比如,左边对象是变量a,原来a里面存的数据是3,右边对象是立即数6,执行赋值语句后,把6赋值给了对象a,那么a原来的数据3就被覆盖丢失了,变成了6.
赋值语句的格式。赋值语句的语法格式由4部分组成:左边对象,关键字,右边对象,分号。比如:
      a=b;
      其中a就是左边对象。
      其中“=”就是关键字。写法跟我们平时用的等于号是一样,但是在C语言里不是等于的意思,而是代表赋值的意思。跟等于号是两码事。
      其中b就是右边对象。
      其中分号“;”代表一条语句的结束符。
      赋值语句与ROM的内在关系。赋值语句是行为,凡是程序的行为指令都存储在单片机的ROM区。C编译器会把一条赋值语句翻译成对应的一条或者几条机器码,机器码指令也是以字节为单位的。下载程序的时候,这些机器码就会被下载进单片机的ROM区。比如以下这行赋值语句:
      a=b;
      经过C编译器编译后会生成以字节为单位的机器码。这些机器码记录着这些信息:变量aRAM地址,变量bRAM地址,以及把b变量RAM地址里面的内容赋值到a变量地址里面的RAM空间。
      变量定义的初始化。讲了赋值语句之后,再回过头来讲变量定义的初始化。变量定义之后,等于被C编译器分配了一个RAM空间,那么这个空间里面存储的数据是什么?如果没有刻意给它初始化,那么RAM空间里面存储的数据是不太确定的,是默认的。有些场合,需要在给变量分配RAM空间时就给它一个固定的初始值,这就是变量定义的初始化。变量初始化的语法格式由3部分组成:关键字,变量名赋值,分号。比如:
      unsigned char a=9;
     其中unsigned char就是关键字。
     其中a=9就是变量名赋值。a从被C编译器分配RAM空间那一刻起,就默认是存了9这个数据。
     分号”;”就是一条语句的结束符号。
     接下来练习一个程序实例。直接复制前面章节中第十节的模板程序,只需要在main函数里编写练习代码,编译后,把程序下载进坚鸿51学习板,通过按S1或者S5按键即可在数码管上观察不同的变量数值。其它部分的模板程序代码就不贴出来了,详细的main函数源代码讲解如下:
  1. void main() //主程序
  2. {
  3. /*---C语言学习区域的开始---------------------------------------------------------------------------*/
  4.         
  5.   unsigned char a;   //定义一个变量a,并且分配了一个字节的RAM空间,里面保存的数据是默认值0.
  6.   unsigned char b;   //定义一个变量b,并且分配了一个字节的RAM空间,里面保存的数据是默认值0.
  7.   unsigned char c;   //定义一个变量c,并且分配了一个字节的RAM空间,里面保存的数据是默认值0.  
  8.   unsigned char d=9; //定义一个变量d,并且分配了一个字节的RAM空间,里面保存的数据被初始化成9.

  9.   b=3;  //把3赋值给变量b,b原来的默认数据是0被覆盖了,此时变量b保存的数值是3
  10.   c=b;  //把右边变量b的内容复制一份赋值给左边的变量c,c原来的默认数据0被覆盖了,此时,c保存的数值跟b的数值一样,都是3.

  11.         
  12.         
  13.   GuiWdData0=a;   //把变量a这个数值放到窗口变量0里面显示
  14.   GuiWdData1=b;   //把变量b这个数值放到窗口变量1里面显示
  15.   GuiWdData2=c;   //把变量c这个数值放到窗口变量2里面显示
  16.   GuiWdData3=d;   //把变量d这个数值放到窗口变量3里面显示

  17.         
  18. /*---C语言学习区域的结束---------------------------------------------------------------------------*/
  19.    while(1)  
  20.    {
  21.                   initial();
  22.       key_service();
  23.       display_service();
  24.    }

  25. }
复制代码

       上坚鸿51学习板观察程序执行的结果:
       变量a的数值是0
       变量b的数值是3
       变量c的数值是3
       变量d的数值是9



       下节预告:两个变量的数据交换。
(未完待续)



乐于分享,勇于质疑!
38#
发表于 2015-4-3 22:18:15 | 只看该作者
非常精彩,期待后续。。。
乐于分享,勇于质疑!
37#
发表于 2015-4-3 22:16:59 | 只看该作者
这个帖子的一楼就有坚鸿51学习板原理图(第三版)。
乐于分享,勇于质疑!
36#
 楼主| 发表于 2015-4-3 15:20:29 | 只看该作者
西北狼 发表于 2015-4-2 21:58
如果能附上坚鸿51学习板相关电路图,对照学习,会更好

你这个建议很好。我马上附上原理图。
乐于分享,勇于质疑!
35#
发表于 2015-4-2 21:58:08 | 只看该作者
如果能附上坚鸿51学习板相关电路图,对照学习,会更好
乐于分享,勇于质疑!
34#
 楼主| 发表于 2015-4-2 13:10:45 | 只看该作者
本帖最后由 jianhong_wu 于 2015-4-2 13:19 编辑

第十节:一个用来学习C语言的模板程序。
目前,几乎所有的初学者在学习和上机练习C语言的时候,都是在电脑上安装VC这个调试软件,在源代码里只要调用打印语句printf就可以观察到不同的变量结果,挺方便的。但是现在我要提出另外一种方法,学习单片机的C语言,不一定非要用VC调试软件,也可以直接在坚鸿51学习板上学习和上机练习的。我可以做一个调试模板程序给初学者使用,利用8位数码管和16个LED灯来显示不同的变量结果,利用3个按键来切换显示不同的变量,这样就能达到类似在VC平台下用printf语句来观察变量的效果。甚至我个人认为这样比用VC调试的效果还更加直观。现在重点介绍这个模板程序的使用。
在模板程序里,初学者只需要在主程序的初始化区域填入自己练习的C语言代码,最后把需要观察的变量赋值给窗口变量就可以了,其它部分的代码属于模板的监控调试代码,大家暂时不用读懂它,直接复制过来就可以了。上述所谓的“赋值”,就是“=”这个语句,它表面上像我们平时用的等于号,实际上不是等于号,而是代表“给”的意思,把“=”符号右边的数复制一份给左边的变量,比如“a=36;”就是代表把36这个数值复制一份给变量a,执行这条指令后,a就等于36了。这里的分号“;”代表一条程序指令的结束。窗口变量有几个?有哪些?一共有10个,分别是GuiWdData0,GuiWdData1,GuiWdData2,GuiWdData3,GuiWdData4,GuiWdData5,GuiWdData6,GuiWdData7,GuiWdData8,GuiWdData9。这10个窗口变量是给大家调试专用的,8位数码管可以切换显示10个窗口变量,最左边2位数码管代表窗口变量号,剩下6位数码管显示十进制的窗口变量数值,另外16个LED实时显示此数据的二进制格式。最左边2位数码管从“0-”到“9-”代表从第0个窗口变量到第9个窗口变量,也就是GuiWdData0依次到GuiWdData9。用S1和S5按键可以切换显示不同的窗口变量,按住S9不放可以观察到当前窗口变量的十六进制格式数据,松开S9按键后,又自动返回显示当前窗口变量的十进制数据。
该模板程序是基于坚鸿51学习板,现在跟大家分享这个程序,要让这10个窗口变量分别显示10,11,12,13,14,15,16,17,18,19这10个数,用S1按键可以切换显示从小往大的窗口变量号,用S5按键可以切换显示从大往小的窗口变量号。再强调一次,大家只需要关注主程序main函数的初始化区域就可以了,其它的代码请直接复制过来,不用理解。比如:
void main()  //主程序   
{
   //...初始化区域
   while(1)                     
   {
      
   }
}
   详细的源代码如下:
  1. #include "REG52.H"
  2. #define const_voice_short  40  
  3. #define const_key_time1  20  
  4. #define const_key_time2  20  
  5. #define const_key_time3  20   
  6. void initial(void);
  7. void delay_short(unsigned int uiDelayShort);
  8. void dig_hc595_drive(unsigned char ucDigStatusTemp16_09,unsigned char ucDigStatusTemp08_01);  
  9. void display_drive(void);
  10. void display_service(void);
  11. void hc595_drive(unsigned char ucLedStatusTemp16_09,unsigned char ucLedStatusTemp08_01);
  12. void T0_time(void);
  13. void key_service(void);
  14. void key_scan(void);
  15. sbit beep_dr=P2^7;
  16. sbit key_sr1=P0^0;
  17. sbit key_sr2=P0^1;
  18. sbit key_sr3=P0^2;
  19. sbit key_gnd_dr=P0^4;
  20. sbit led_dr=P3^5;  
  21. sbit dig_hc595_sh_dr=P2^0;     
  22. sbit dig_hc595_st_dr=P2^1;  
  23. sbit dig_hc595_ds_dr=P2^2;  
  24. sbit hc595_sh_dr=P2^3;   
  25. sbit hc595_st_dr=P2^4;  
  26. sbit hc595_ds_dr=P2^5;  
  27. unsigned char GucKeySec=0;   
  28. unsigned char GucKey3Sr=1;
  29. unsigned int  GuiVoiceCnt=0;
  30. unsigned char GucVoiceStart=0;
  31. unsigned char GucDigShow8;
  32. unsigned char GucDigShow7;  
  33. unsigned char GucDigShow6;  
  34. unsigned char GucDigShow5;
  35. unsigned char GucDigShow4;
  36. unsigned char GucDigShow3;
  37. unsigned char GucDigShow2;
  38. unsigned char GucDigShow1;
  39. unsigned char GucDisplayUpdate=1;
  40. unsigned char GucWd=0;
  41. unsigned int GuiWdData0=0;
  42. unsigned int GuiWdData1=0;
  43. unsigned int GuiWdData2=0;
  44. unsigned int GuiWdData3=0;
  45. unsigned int GuiWdData4=0;
  46. unsigned int GuiWdData5=0;
  47. unsigned int GuiWdData6=0;
  48. unsigned int GuiWdData7=0;
  49. unsigned int GuiWdData8=0;
  50. unsigned int GuiWdData9=0;
  51. code unsigned char dig_table[]=
  52. {
  53.   0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71,0x00,0x40,
  54. };



  55. void main() //主程序
  56. {
  57. /*---C语言学习区域的开始---------------------------------------------------------------------------*/
  58.        

  59.        
  60.   GuiWdData0=10;   //把10这个数值放到窗口变量0里面显示
  61.   GuiWdData1=11;   //把11这个数值放到窗口变量1里面显示
  62.   GuiWdData2=12;   //把12这个数值放到窗口变量2里面显示
  63.   GuiWdData3=13;   //把13这个数值放到窗口变量3里面显示
  64.   GuiWdData4=14;   //把14这个数值放到窗口变量4里面显示
  65.   GuiWdData5=15;   //把15这个数值放到窗口变量5里面显示
  66.   GuiWdData6=16;   //把16这个数值放到窗口变量6里面显示
  67.   GuiWdData7=17;   //把17这个数值放到窗口变量7里面显示
  68.   GuiWdData8=18;   //把18这个数值放到窗口变量8里面显示
  69.   GuiWdData9=19;   //把19这个数值放到窗口变量9里面显示
  70.        
  71. /*---C语言学习区域的结束---------------------------------------------------------------------------*/
  72.    while(1)  
  73.    {
  74.                   initial();
  75.       key_service();
  76.       display_service();
  77.    }

  78. }


  79. void display_service(void)
  80. {
  81.     static unsigned char SucLedStatus16_09=0;  
  82.     static unsigned char SucLedStatus08_01=0;   
  83.     static unsigned int  SinWdDataTemp=0;

  84.     if(1==GucDisplayUpdate)
  85.     {
  86.         GucDisplayUpdate=0;
  87.                
  88.                           switch(GucWd)
  89.                           {
  90.            case 0:
  91.                 GucDigShow8=0;
  92.                                               SinWdDataTemp=GuiWdData0;
  93.                                               break;
  94.            case 1:
  95.                 GucDigShow8=1;
  96.                                               SinWdDataTemp=GuiWdData1;
  97.                                               break;
  98.            case 2:
  99.                 GucDigShow8=2;
  100.                                               SinWdDataTemp=GuiWdData2;
  101.                                               break;
  102.            case 3:
  103.                 GucDigShow8=3;  
  104.                                               SinWdDataTemp=GuiWdData3;
  105.                                               break;
  106.            case 4:
  107.                 GucDigShow8=4;
  108.                                               SinWdDataTemp=GuiWdData4;
  109.                                               break;
  110.            case 5:
  111.                 GucDigShow8=5;
  112.                                               SinWdDataTemp=GuiWdData5;
  113.                                               break;
  114.            case 6:
  115.                 GucDigShow8=6;
  116.                                               SinWdDataTemp=GuiWdData6;
  117.                                               break;
  118.            case 7:
  119.                 GucDigShow8=7;
  120.                                               SinWdDataTemp=GuiWdData7;
  121.                                               break;
  122.            case 8:
  123.                 GucDigShow8=8;
  124.                                               SinWdDataTemp=GuiWdData8;
  125.                                               break;
  126.            case 9:
  127.                 GucDigShow8=9;
  128.                                               SinWdDataTemp=GuiWdData9;
  129.                                               break;                 
  130.         }
  131.                                
  132.         GucDigShow7=17;
  133.         GucDigShow6=16;         
  134.                                
  135.                                 if(1==GucKey3Sr)
  136.                                 {
  137.                                    if(SinWdDataTemp>=10000)
  138.                              {
  139.               GucDigShow5=SinWdDataTemp/10000;
  140.            }
  141.                              else
  142.                                    {
  143.               GucDigShow5=16;
  144.            }
  145.                                
  146.                                    if(SinWdDataTemp>=1000)
  147.                                    {
  148.               GucDigShow4=SinWdDataTemp%10000/1000;
  149.            }
  150.                                     else
  151.                                    {
  152.               GucDigShow4=16;
  153.            }
  154.                                
  155.                                    if(SinWdDataTemp>=100)
  156.                                    {
  157.               GucDigShow3=SinWdDataTemp%1000/100;
  158.            }
  159.                                     else
  160.                                    {
  161.               GucDigShow3=16;
  162.            }       
  163.                                
  164.                                    if(SinWdDataTemp>=10)
  165.                                    {
  166.               GucDigShow2=SinWdDataTemp%100/10;
  167.            }
  168.                                     else
  169.                                    {
  170.               GucDigShow2=16;
  171.            }       
  172.                                
  173.            GucDigShow1=SinWdDataTemp%10;
  174.                           }
  175.                                 else
  176.                                 {
  177.                                          GucDigShow5=16;
  178.                                
  179.                                    if(SinWdDataTemp>=0x1000)
  180.                                    {
  181.               GucDigShow4=SinWdDataTemp/0x1000;
  182.            }
  183.                                     else
  184.                                    {
  185.               GucDigShow4=16;
  186.            }
  187.                                
  188.                                    if(SinWdDataTemp>=0x0100)
  189.                                    {
  190.               GucDigShow3=SinWdDataTemp%0x1000/0x0100;
  191.            }
  192.                                     else
  193.                                    {
  194.               GucDigShow3=16;
  195.            }       
  196.                                
  197.                                    if(SinWdDataTemp>=0x0010)
  198.                                    {
  199.               GucDigShow2=SinWdDataTemp%0x0100/0x0010;
  200.            }
  201.                                     else
  202.                                    {
  203.               GucDigShow2=16;
  204.            }       
  205.                                
  206.            GucDigShow1=SinWdDataTemp%0x0010;
  207.         }
  208.                                
  209.                                
  210.                                 SucLedStatus16_09=SinWdDataTemp>>8;  
  211.         SucLedStatus08_01=SinWdDataTemp;
  212.         hc595_drive(SucLedStatus16_09,SucLedStatus08_01);
  213.     }

  214. }


  215. void key_scan(void)
  216. {  
  217.        
  218.   static unsigned int  SuiKeyTimeCnt1=0;
  219.   static unsigned char SucKeyLock1=0;

  220.   static unsigned int  SuiKeyTimeCnt2=0;
  221.   static unsigned char SucKeyLock2=0;

  222.   static unsigned int  SuiKey3Cnt1=0;
  223.   static unsigned int  SuiKey3Cnt2=0;
  224.        
  225.        
  226.   if(1==key_sr1)
  227.   {
  228.      SucKeyLock1=0;
  229.      SuiKeyTimeCnt1=0;
  230.   }
  231.   else if(0==SucKeyLock1)
  232.   {
  233.      SuiKeyTimeCnt1++;
  234.      if(SuiKeyTimeCnt1>const_key_time1)
  235.      {
  236.         SuiKeyTimeCnt1=0;
  237.         SucKeyLock1=1;  
  238.         GucKeySec=1;   
  239.      }
  240.   }

  241.   if(1==key_sr2)
  242.   {
  243.      SucKeyLock2=0;
  244.      SuiKeyTimeCnt2=0;
  245.   }
  246.   else if(0==SucKeyLock2)
  247.   {
  248.      SuiKeyTimeCnt2++;
  249.      if(SuiKeyTimeCnt2>const_key_time2)
  250.      {
  251.         SuiKeyTimeCnt2=0;
  252.         SucKeyLock2=1;  
  253.         GucKeySec=2;  
  254.      }
  255.   }

  256.        
  257.   if(1==key_sr3)
  258.   {
  259.        SuiKey3Cnt1=0;
  260.        SuiKey3Cnt2++;
  261.        if(SuiKey3Cnt2>const_key_time3)
  262.        {
  263.            SuiKey3Cnt2=0;
  264.            GucKey3Sr=1;  
  265.        }
  266.    }
  267.    else   
  268.    {
  269.        SuiKey3Cnt2=0;
  270.        SuiKey3Cnt1++;
  271.        if(SuiKey3Cnt1>const_key_time3)
  272.        {
  273.           SuiKey3Cnt1=0;
  274.           GucKey3Sr=0;
  275.        }
  276.    }


  277. }


  278. void key_service(void)
  279. {
  280.         static unsigned char SucKey3SrRecord=1;
  281.        
  282.   if(GucKey3Sr!=SucKey3SrRecord)
  283.   {
  284.      SucKey3SrRecord=GucKey3Sr;
  285.                  GucDisplayUpdate=1;
  286.                
  287.   }
  288.        
  289.   switch(GucKeySec)
  290.   {
  291.     case 1:
  292.           GucWd++;
  293.                       if(GucWd>9)
  294.                                         {
  295.              GucWd=9;
  296.           }
  297.                       GucDisplayUpdate=1;
  298.                                        
  299.                                        
  300.           GuiVoiceCnt=const_voice_short;
  301.           GucVoiceStart=1;
  302.           GucKeySec=0;  
  303.           break;   
  304.    
  305.     case 2:
  306.           GucWd--;
  307.                       if(GucWd>9)
  308.                                         {
  309.              GucWd=0;
  310.           }
  311.                       GucDisplayUpdate=1;
  312.                
  313.           GuiVoiceCnt=const_voice_short;
  314.           GucVoiceStart=1;
  315.           GucKeySec=0;  
  316.           break;  
  317.   }     



  318.        
  319. }

  320. void display_drive()  
  321. {
  322.    static unsigned char SucDigShowTemp=0;
  323.    static unsigned char SucDisplayDriveStep=1;
  324.        
  325.    switch(SucDisplayDriveStep)
  326.    {
  327.       case 1:
  328.            SucDigShowTemp=dig_table[GucDigShow1];
  329.            dig_hc595_drive(SucDigShowTemp,0xfe);
  330.            break;
  331.       case 2:  
  332.            SucDigShowTemp=dig_table[GucDigShow2];
  333.            dig_hc595_drive(SucDigShowTemp,0xfd);
  334.            break;
  335.       case 3:
  336.            SucDigShowTemp=dig_table[GucDigShow3];
  337.            dig_hc595_drive(SucDigShowTemp,0xfb);
  338.            break;
  339.       case 4:  
  340.            SucDigShowTemp=dig_table[GucDigShow4];
  341.            dig_hc595_drive(SucDigShowTemp,0xf7);
  342.            break;
  343.       case 5:
  344.            SucDigShowTemp=dig_table[GucDigShow5];
  345.            dig_hc595_drive(SucDigShowTemp,0xef);
  346.            break;
  347.       case 6:  
  348.            SucDigShowTemp=dig_table[GucDigShow6];
  349.            dig_hc595_drive(SucDigShowTemp,0xdf);
  350.            break;
  351.       case 7:  
  352.            SucDigShowTemp=dig_table[GucDigShow7];
  353.            dig_hc595_drive(SucDigShowTemp,0xbf);
  354.            break;
  355.       case 8:
  356.            SucDigShowTemp=dig_table[GucDigShow8];
  357.            dig_hc595_drive(SucDigShowTemp,0x7f);
  358.            break;
  359.    }

  360.    SucDisplayDriveStep++;
  361.    if(SucDisplayDriveStep>8)  
  362.    {
  363.      SucDisplayDriveStep=1;
  364.    }



  365. }



  366. void dig_hc595_drive(unsigned char ucDigStatusTemp16_09,unsigned char ucDigStatusTemp08_01)
  367. {
  368.    unsigned char i;
  369.    unsigned char ucTempData;
  370.    dig_hc595_sh_dr=0;
  371.    dig_hc595_st_dr=0;

  372.    ucTempData=ucDigStatusTemp16_09;  
  373.    for(i=0;i<8;i++)
  374.    {
  375.          if(ucTempData>=0x80)dig_hc595_ds_dr=1;
  376.          else dig_hc595_ds_dr=0;

  377.          dig_hc595_sh_dr=0;   
  378.          delay_short(1);
  379.          dig_hc595_sh_dr=1;
  380.          delay_short(1);

  381.          ucTempData=ucTempData<<1;
  382.    }

  383.    ucTempData=ucDigStatusTemp08_01;  
  384.    for(i=0;i<8;i++)
  385.    {
  386.          if(ucTempData>=0x80)dig_hc595_ds_dr=1;
  387.          else dig_hc595_ds_dr=0;

  388.          dig_hc595_sh_dr=0;     
  389.          delay_short(1);
  390.          dig_hc595_sh_dr=1;
  391.          delay_short(1);

  392.          ucTempData=ucTempData<<1;
  393.    }

  394.    dig_hc595_st_dr=0;
  395.    delay_short(1);
  396.    dig_hc595_st_dr=1;
  397.    delay_short(1);

  398.    dig_hc595_sh_dr=0;
  399.    dig_hc595_st_dr=0;
  400.    dig_hc595_ds_dr=0;

  401. }

  402. void hc595_drive(unsigned char ucLedStatusTemp16_09,unsigned char ucLedStatusTemp08_01)
  403. {
  404.    unsigned char i;
  405.    unsigned char ucTempData;
  406.    hc595_sh_dr=0;
  407.    hc595_st_dr=0;

  408.    ucTempData=ucLedStatusTemp16_09;  
  409.    for(i=0;i<8;i++)
  410.    {
  411.          if(ucTempData>=0x80)hc595_ds_dr=1;
  412.          else hc595_ds_dr=0;

  413.          hc595_sh_dr=0;   
  414.          delay_short(1);
  415.          hc595_sh_dr=1;
  416.          delay_short(1);

  417.          ucTempData=ucTempData<<1;
  418.    }

  419.    ucTempData=ucLedStatusTemp08_01;  
  420.    for(i=0;i<8;i++)
  421.    {
  422.          if(ucTempData>=0x80)hc595_ds_dr=1;
  423.          else hc595_ds_dr=0;

  424.          hc595_sh_dr=0;     
  425.          delay_short(1);
  426.          hc595_sh_dr=1;
  427.          delay_short(1);

  428.          ucTempData=ucTempData<<1;
  429.    }

  430.    hc595_st_dr=0;  
  431.    delay_short(1);
  432.    hc595_st_dr=1;
  433.    delay_short(1);

  434.    hc595_sh_dr=0;   
  435.    hc595_st_dr=0;
  436.    hc595_ds_dr=0;

  437. }


  438. void T0_time(void) interrupt 1
  439. {
  440.   TF0=0;
  441.   TR0=0;

  442.   if(1==GucVoiceStart)
  443.         {

  444.                  if(GuiVoiceCnt!=0)
  445.                  {
  446.                           GuiVoiceCnt--;
  447.                           beep_dr=0;
  448.      }
  449.                  else
  450.                  {
  451.                           beep_dr=1;
  452.                           GucVoiceStart=0;
  453.      }
  454.   }

  455.   key_scan();
  456.   display_drive();  


  457.   TH0=0xfe;  
  458.   TL0=0x0b;
  459.   TR0=1;
  460. }


  461. void delay_short(unsigned int uiDelayShort)
  462. {
  463.    static unsigned int i;  
  464.    for(i=0;i<uiDelayShort;i++);
  465. }



  466. void initial(void)
  467. {
  468.          static unsigned char SucInitialLock=0;
  469.        
  470.          if(0==SucInitialLock)
  471.          {
  472.        SucInitialLock=1;
  473.                  
  474.              key_gnd_dr=0;
  475.        led_dr=0;  
  476.        beep_dr=1;
  477.        TMOD=0x01;
  478.        TH0=0xfe;  
  479.        TL0=0x0b;          
  480.                  
  481.        EA=1;     
  482.        ET0=1;   
  483.        TR0=1;   

  484.    }


  485. }

复制代码

下节预告:三种类型变量的定义与赋值语句。
(未完待续)
乐于分享,勇于质疑!
33#
 楼主| 发表于 2015-3-31 17:58:09 | 只看该作者
本帖最后由 jianhong_wu 于 2015-6-3 18:21 编辑

第九节:程序从哪里开始,要到哪里去?
程序从哪里开始,要到哪里去?为了让初学者了解C语言程序的执行顺序,我把程序分成三个区域:进入主程序前的区域,主程序的初始化区域,主程序的循环区域。
进入主程序前的区域。这是上电后,在单片机执行主程序代码之前就已经完成了的工作。包括头文件的包含,宏定义,内存分配这些工作。这部分的内容可以暂时不用去了解,我会在后面的一些章节中陆续深入讲解。
主程序的初始化区域。这是上电后,单片机进入主程序后马上就要执行的程序代码,这部分区域的代码有一个特点,大家也必须记住的,就是单片机只执行一次。只要单片机不重启,不复位,那么上电后这部分的代码只被执行一次。
主程序的循环区域。单片机在主程序中执行完了初始化区域的代码,紧接着就进入这片循环区域的代码。单片机一直在循环执行这段代码,这就是上电后单片机的最终归宿,一直处在循环的状态。
下面我跟大家分析一个程序源代码的三个区域和执行顺序,大家先看中文解释部分的内容,暂时不用理解每行指令的语法。该源代码实现的功能是:上电后,蜂鸣器鸣叫一声就停止,然后看到一个LED灯一直在闪烁。本程序是基于坚鸿51单片机学习板。

  1. #include "REG52.H"  //进入主程序前的区域:头文件包含

  2. sbit beep_dr=P2^7;  //进入主程序前的区域:宏定义
  3. sbit led_dr=P3^5;   //进入主程序前的区域:宏定义

  4. unsigned long i;    //进入主程序前的区域:内存分配

  5. void main()                    //主程序入口,即将进入初始化区域
  6. {
  7.          beep_dr=0;                  //第一步:初始化区域:蜂鸣器开始鸣叫。
  8.    for(i=0;i<6250;i++);       //第二步:初始化区域:延时0.5秒左右。也就是蜂鸣器鸣叫的持续时间。
  9.          beep_dr=1;                  //第三步:初始化区域:蜂鸣器停止鸣叫。
  10.    while(1)                    //执行完上面的初始化区域,即将进入循环区域
  11.    {
  12.        led_dr=1;               //第四步:循环区域:LED开始点亮。
  13.        for(i=0;i<6250;i++);   //第五步:循环区域:延时0.5秒左右。也就是LED点亮的持续时间。
  14.        led_dr=0;  //LED灭      //第六步:循环区域:LED开始熄灭。
  15.        for(i=0;i<6250;i++);   //第七步:循环区域:延时0.5秒左右。也就是LED熄灭的持续时间。马上返回上面第四步继续循环往下执行。
  16.    }
  17. }

  18. //解释:
  19. //单片机进入主程序后,第一步到第三步是属于初始化区域,只被执行一次。然后进入循环区域,从第四步执行到第七步,
  20. //执行完第七步之后,马上返回上面第四步继续循环往下执行,单片机一直处于第四步到第七步的循环区域中。
复制代码


经过以上的分析,可以看出这三个区域的大概分布如下:


//...进入主程序前的区域
void main()               
    {
   //...初始化区域
   while(1)                     
   {
       //...循环区域
   }
}


下节预告:一个用来学习C语言的模板程序。
(未完待续)



乐于分享,勇于质疑!
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|Archiver|手机版|独闷闷网 ( 粤ICP备12007667号-2 )

GMT+8, 2024-5-17 18:06 , Processed in 0.224132 second(s), 15 queries .

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