独闷闷网

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

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

[复制链接]
41#
 楼主| 发表于 2015-8-23 16:21:14 | 显示全部楼层
本帖最后由 jianhong_wu 于 2015-8-23 16:25 编辑

第三十二节:逻辑运算符的“异或”运算。
       “异或”运算是以位为单位进行运算的。位是指二进制中的某一位,位只能是0或者1。两个数的“异或”运算就是转换成二进制后每一位的“异或”运算。
       “异或”运算的符号是“^”。运算规律是:两个位的“异或”运算,如果两个位都相同,那么运算结果就是0;如果两个位不同(相异),则运算结果是1。比如:
0^0等于0。(两个位相同)
0^1等于1。(两个位相异)
1^0等于1。(两个位相异)
1^1等于0。(两个位相同)
       现在举一个完整的例子来分析“^”运算的规律。有两个unsigned char类型的十进制数分别是12和9,求12^9的结果是多少?分析步骤如下:
       第一步:先把参与运算的两个数都转换成二进制的格式。十进制转二进制的方法请参考前面第13,14,15节的内容。
十进制12的二进制格式是:00001100。
十进制9的二进制格式是:00001001。
       第二步:二进制数右对齐,按每一位进行“异或”运算。
            00001100
         ^00001001
结果是 00000101。
        第三步:把二进制的 00000101转换成十六进制是:0x05。转换成十进制是5。所以12^9的结果是5。
       “异或”在哪些项目上经常应用?以我个人的项目经验,平时很少用“异或”,我唯一用过一次“异或”,是在制定串口通讯协议时,通过“异或”算法,增加一个校验字节,此校验字节是一串数据依次相“异或”的总结果,目的是为了增加数据传送时的抗干扰能力。

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

  1. void main() //主程序
  2. {
  3. /*---C语言学习区域的开始---------------------------------------------------------------------------*/
  4.         
  5.   unsigned char a;


  6.   a=12^9;


  7.   GuiWdData0=a;   //把a这个变量放到窗口变量0里面显示

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

  16. }
复制代码


         查看运算结果的方法。如何在坚鸿51学习板上观察变量?按下S1或者S5按键即可切换显示不同的窗口,从而显示不同的变量。按下S9按键不松手就可以切换到十六进制的显示界面,松开手后会自动切换到十进制的界面。16个LED灯显示的就是当前变量的二进制数,亮代表1,灭代表0上坚鸿51学习板观察程序执行的结果如下:
        变量a为5(十六进制是0x05,二进制是00000101)。

        下节预告:逻辑运算符的“按位取反”运算。
(未完待续)

乐于分享,勇于质疑!
42#
 楼主| 发表于 2015-8-30 07:05:49 | 显示全部楼层
本帖最后由 jianhong_wu 于 2015-8-30 10:46 编辑

第三十三节:逻辑运算符的“按位取反”和“非”。
       “按位取反”运算的符号是波浪符号“~”。运算规律是:针对某个数的“按位取反”,先将其展开成二进制的格式,然后每个位取反,所谓取反就是1的变成0,0的变成1。
         现在举一个完整的例子来分析“按位取反”运算的规律。有一个unsigned char类型的十进制数分别是5和0,求~5和~0的结果是多少?分析步骤如下:
         第一步:先把参与运算的数转换成二进制的格式。十进制转二进制的方法请参考前面第13,14,15节的内容。
十进制5的二进制格式是:00000101。
十进制0的二进制格式是:00000000。
         第二步:
(1)将5的二进制数每一位取反,1的变成0,0的变成1。
        ~00000101
结果是11111010。
把二进制的11111010转换成十六进制是:0xFA。转换成十进制是250。所以~5的结果是250。
(2)将0的二进制数每一位取反,1的变成0,0的变成1。
        ~00000000
结果是11111111。
把二进制的11111111转换成十六进制是:0xFF。转换成十进制是255。所以~0的结果是255。
       讲完“按位取反”,现在接着讲“非”。 “非”跟“按位取反”有点相似,但是区别也明显。“按位取反”针对的是一个数的某一位,侧重在局部。而“非”是针对一个数的整体,侧重在全局。“非”只有两种状态“假”和“真”。0代表假,大于0的数值代表真,也可以说“非”假即真,“非”真即假。不是假的就是真的,不是真的就是假的。强调的是两种状态的切换。在数值表示上,用0代表假的状态,用1代表真的状态。
      “非”运算的符号是感叹号“!”。运算规律是:针对某个数的“非”,不管此数有多大,只要它大于0,那么被“非”后就一定是0。也不管此数是什么变量类型,只要它数值等于0,那么被“非”后就一定是1。
        现在举一个完整的例子来分析“非”运算的规律。有一个unsigned char类型的十进制数分别是5和0,求!5和!0的结果是多少?分析步骤如下:
        第一步:5大于0,是一个整体,被“非”后为0.
        第二步:0就是0,是一个整体,被“非”后为1.

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

  1. void main() //主程序
  2. {
  3. /*---C语言学习区域的开始---------------------------------------------------------------------------*/
  4.         

  5.   unsigned char a=5;
  6.   unsigned char b=5;
  7.   unsigned char c=0;
  8.   unsigned char d=0;

  9.   a=~a;
  10.   b=!b;


  11.   c=~c;
  12.   d=!d;

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


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

  24. }
复制代码


       查看运算结果的方法。如何在坚鸿51学习板上观察变量?按下S1或者S5按键即可切换显示不同的窗口,从而显示不同的变量。按下S9按键不松手就可以切换到十六进制的显示界面,松开手后会自动切换到十进制的界面。16个LED灯显示的就是当前变量的二进制数,亮代表1,灭代表0。上坚鸿51学习板观察程序执行的结果如下:
       变量a为250(十六进制是0xFA,二进制是11111010)。
       变量b为0 (十六进制是0x00,二进制是00000000)。
       变量c为255(十六进制是0xFF,二进制是11111111)。
       变量d为1 (十六进制是0x01,二进制是00000001)。
       下节预告:移位运算的左移。
(未完待续)

乐于分享,勇于质疑!
43#
 楼主| 发表于 2015-9-5 13:07:05 | 显示全部楼层
本帖最后由 jianhong_wu 于 2015-9-6 06:55 编辑

第三十四节:移位运算的左移。
        前面讲的“与,或,异或”运算,漏讲了它们的简写格式的内容,在本节开始之前先把这部分内容补上。在“与,或,异或”这些运算中,当赋值语句左边的“保存变量”是参与运算的变量本身时,也存在简写的语法格式,比如:
      a&=0x01;  //相当于a=a&0x01;
      a|=0x01;  //相当于a=a|0x01;
      a^=0x01;  //相当于a=a^0x01;

     现在正式开始本节内容“移位运算的左移”。左移的运算符号是“<<”,语法格式如下:
     保存变量=被移数<<n;
     其中n代表“被移数”需要左移的位数。
     整句语法的含义是:“被移数”的二进制格式数据被整体往左边移动了n位,原来高n位数据被直接覆盖,新空出的低n位数据填入0。最后把移位结果存入“保存变量”。
     现在举一个完整的例子来分析“左移”运算的规律。有2个unsigned char类型的变量a和b,a的初始值是十进制数5,a=a<<1的结果是多少?b的初始值也是十进制数5,b=b<<2的结果是多少?
     分析步骤如下:
     第一步:先把参与运算的数转换成二进制的格式。十进制转二进制的方法请参考前面第13,14,15节的内容。
十进制5的二进制格式是:00000101。
     第二步:
(1) 将5的二进制数整体往左边移动1位:
                                   原来是:00000101
        整体往左移动1位后变成:00001010
        把二进制的00001010转换成十六进制是:0x0A。转换成十进制是10。所以a初始值是5,左移1位后的结果是10.
(2) 将5的二进制数整体往左边移动2位:
                                  原来是:00000101
        整体往左移动2位后变成:00010100
        把二进制的00010100转换成十六进制是:0x14。转换成十进制是20。所以b初始值是5,左移2位后的结果是20.
        仔细观察上述两个例子,发现了一个重要的规律:某数左移1位相当于此数乘以2,左移多少位相当于乘以多少个2.比如上述例子中5左移1位相当于5乘以2,结果等于10。而5左移2位相当于5乘以2再乘以2,5*2*2的结果等于20。既然左移1位相当于某个数乘以2,那么为什么不直接用乘法来替代左移呢?原因是一条左移语句的运算速度比一条乘法语句的运算速度要快很多倍。
        左移是在单片机项目中很常用的语法,也经常应用在一些数据类型之间的合并中。比如有两个unsigned char单字节的类型数据H和L,H的初始值是十六进制的0x12,L的初始值是十六进制的0x34,要将两个单字节的H和L合并成一个unsigned int双字节的数据c,其中H是高8位字节,L是低八位字节,合并成c后,c的值应该是十六进制的0x1234,此程序如何写?就需要用到左移。程序分析如下:
unsigned char H=0x12;  //单字节
unsigned char L=0x34;  //单字节
unsigned int c; //双字节
c=H;//c的低8位被H覆盖,也就是c的低8位得到了H的各位值。
c=c<<8; //及时把c的低8位移动到高8位,同时c原来的低8位被填入0
c=c+L;//此时c再加L,c的低8位就L的值。
程序运行结果:c就等于十六进制的0x1234,十进制是4660。
       再多讲一下知识点,左移也存在简写格式,比如:
d<<=1; //就相当于d=d<<1;
e<<=2; //就相当于e=e<<2;
       现在编写一个程序来练习刚才讲到的主要内容,最后把程序编译后下载到坚鸿51学习板观察结果。请直接复制第十节模板程序,修改的main程序代码如下:



  1. void main() //主程序
  2. {
  3. /*---C语言学习区域的开始---------------------------------------------------------------------------*/


  4. unsigned char a=5;
  5. unsigned char b=5;

  6. unsigned char H=0x12; //单字节
  7. unsigned char L=0x34; //单字节
  8. unsigned int c; //双字节

  9. a=a<<1; //a左移1位,从原来的5变成了10.
  10. b=b<<2; //b左移2位,从原来的5变成了20.


  11. c=H; //c的低8位被H覆盖,也就是此时c的低8位得到了H的各位值。
  12. c=c<<8; //及时把c的低8位移动到高8位,同时c原来的低8位被填入0
  13. c=c+L; //此时c再加L,c的低8位就L的值。此时c得到了H和L合并而来的值。


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



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

  24. }

复制代码

        查看运算结果的方法。如何在坚鸿51学习板上观察变量?按下S1或者S5按键即可切换显示不同的窗口,从而显示不同的变量。按下S9按键不松手就可以切换到十六进制的显示界面,松开手后会自动切换到十进制的界面。16个LED灯显示的就是当前变量的二进制数,亮代表1,灭代表0。上坚鸿51学习板观察程序执行的结果如下:
        变量a为10 (十六进制是0x0A,二进制是00001010)。
        变量b为20(十六进制是0x14,二进制是00010100)。
        变量c为4660(十六进制是0x1234,二进制是0001 0010 0011 0100)。
        下节预告:移位运算的右移。
(未完待续)



乐于分享,勇于质疑!
44#
 楼主| 发表于 2015-9-6 06:56:56 | 显示全部楼层
本帖最后由 jianhong_wu 于 2015-9-6 06:59 编辑

第三十五节:移位运算的右移。
        右移的运算符号是“>>”,语法格式如下:
        保存变量=被移数>>n;
        其中n代表“被移数”需要右移的位数。
        整句语法的含义是:“被移数”的二进制格式数据被整体往右边移动了n位,原来低n位数据被直接覆盖,新空出的高n位数据填入0。最后把移位结果存入“保存变量”。
        现在举一个完整的例子来分析“右移”运算的规律。有2个unsigned char类型的变量a和b,a的初始值是十进制数5,a=a>>1的结果是多少?b的初始值也是十进制数5,b=b>>2的结果是多少?
分析步骤如下:
        第一步:先把参与运算的数转换成二进制的格式。十进制转二进制的方法请参考前面第13,14,15节的内容。
十进制5的二进制格式是:00000101。
       第二步:
(1) 将5的二进制数整体往右边移动1位:
                                   原来是:00000101
        整体往右移动1位后变成:00000010
        把二进制的00000010转换成十六进制是:0x02。转换成十进制是2。所以a初始值是5, 右移1位后的结果是2.
(2) 将5的二进制数整体往右边移动2位:
                                   原来是:00000101
        整体往右移动2位后变成:00000001
        把二进制的00000001转换成十六进制是:0x01。转换成十进制是1。所以b初始值是5, 右移2位后的结果是1。
       上一节讲的“左移”1位有乘以2的规律,相反,这节讲的“右移”也存在整除的规律:某数右移1位相当于此数整除2,右移多少位相当于整除多少个2.比如上述例子中5右移1位相当于5整除2,结果等于2。而5右移2位相当于5整除2再整除2,5/2/2的结果等于1。既然右移1位相当于某个数整除2,那么为什么不直接用整除来替代右移呢?原因是一条右移语句的运算速度比一条整除语句的运算速度要快很多倍。
        右移是在单片机项目中很常用的语法,也经常应用在一些数据类型之间的拆分中。比如有一个双字节unsigned int类型的变量c,它的初始值是0x1234,要把它拆分成两个unsigned char单字节的类型数据H和L,其中H是高8位字节,L是低八位字节,拆分后H应该等于0x12,L应该等于0x34,此程序如何写?就需要用到右移。程序分析如下:
unsigned char H;  //单字节
unsigned char L;  //单字节
unsigned int c=0x1234; //双字节
L=c;  //c的低8位直接赋值给单字节的L
H=c>>8;  //c先把高8位右移到低8位,然后再把这8位数据赋值给H
        程序运行结果:H就等于十六进制的0x12,十进制是18。L就等于十六进制的0x34,十进制是52.提一个问题,请问执行完上述最后一条语句H=c>>8后,此时c的值是多少?答案是0x1234,因为只要它没有赋值给它自己,执行完语句后就不会改变它自己本身。
       再多讲一下知识点,右移也存在简写格式,比如:
e>>=1; //就相当于e=e>>1;
f>>=2; //就相当于f=f>>2;
       现在编写一个程序来练习刚才讲到的主要内容,最后把程序编译后下载到坚鸿51学习板观察结果。请直接复制第十节模板程序,修改的main程序代码如下:


  1. void main() //主程序
  2. {
  3. /*---C语言学习区域的开始---------------------------------------------------------------------------*/

  4. unsigned char a=5;
  5. unsigned char b=5;


  6. unsigned char H; //单字节
  7. unsigned char L; //单字节
  8. unsigned int c=0x1234; //双字节

  9. unsigned int d;

  10. a=a>>1;
  11. b=b>>2;

  12. L=c; //c的低8位直接赋值给单字节的L
  13. H=c>>8; //c先把高8位右移到低8位,然后再把这8位数据赋值给H

  14. //执行上述语句后,此时的c变量的数值是多少呢?
  15. //答案是0x1234,因为只要没有赋值给它自己,就不会改变它自己.

  16. d=c; //此时d就等于c,是十六进制的0x1234.十进制是4660

  17. GuiWdData0=a; //把a这个变量放到窗口变量0里面显示
  18. GuiWdData1=b; //把b这个变量放到窗口变量1里面显示
  19. GuiWdData2=H; //把H这个变量放到窗口变量2里面显示
  20. GuiWdData3=L; //把L这个变量放到窗口变量3里面显示
  21. GuiWdData4=d; //把d这个变量放到窗口变量4里面显示

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

  29. }

复制代码

        查看运算结果的方法。如何在坚鸿51学习板上观察变量?按下S1或者S5按键即可切换显示不同的窗口,从而显示不同的变量。按下S9按键不松手就可以切换到十六进制的显示界面,松开手后会自动切换到十进制的界面。16个LED灯显示的就是当前变量的二进制数,亮代表1,灭代表0。上坚鸿51学习板观察程序执行的结果如下:
       变量a为2 (十六进制是0x02,二进制是00000010)。
       变量b为1(十六进制是0x01,二进制是00000001)。
       变量H为18(十六进制是0x12,二进制是00010010)。
       变量L为52(十六进制是0x34,二进制是00110100)。
       变量d为4660(十六进制是0x1234,二进制是0001 0010 0011 0100)。

     下节预告:括号改变优先级。
(未完待续)



乐于分享,勇于质疑!
45#
 楼主| 发表于 2015-9-13 08:47:46 | 显示全部楼层
本帖最后由 jianhong_wu 于 2015-9-13 08:48 编辑

第三十六节:括号改变优先级。
        C语言的加减乘除,与或取反,左移右移等运算符是有严格优先级顺序的,但是我本人记忆力有限,做项目哪能记住这么多优先级的前后顺序,只是大概明白乘除的优先级比加减的优先级高,其它方面真的记不住那么多,怎么办?为了确保万一,我用到了括号。
       括号的用法跟我们日常的数据运算公式的用法一直,先运行括号里面的运算,再执行其它运算。比如:
a=a<<2+5;
       到底是先把变量a左移2位后再加5,还是先2加5等于7再让变量a左移7位?对于像我这样不能熟记C语言运算优先级顺序的人,这条语句很容易让我搞混。但是加上括号就明了:
a=(a<<2)+5;
a=a<<(2+5);
      不用多说,加上括号后,上述两行代码传递了清晰的优先级顺序。再看一个例子:
c=1+3*c;
      到底是1加3的结果再乘以变量c,还是3乘以变量c的结果再加1?因为我记得乘除法的优先级比加减法的优先级高,所以答案是3乘以变量c的结果再加1。对于初学者,为了避免出错,可以加上括号就更加清晰了,比如:
c=(1+3)*c;
c=1+(3*c);
      加括号后,优先级顺序一目了然。

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

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

  7.   unsigned char c=0x02;
  8.   unsigned char d=0x02;


  9.   a=(a<<2)+5;  //a左移2位后变成4,再加5等于9
  10.   b=b<<(2+5);  //2加5等于7,b再左移动7位等于128

  11.   c=(1+3)*c;  //1加3等于4,再乘以变量c等于8
  12.   d=1+(3*d);  //3乘以d等于6,再加1等于7

  13.         
  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学习板上观察变量?按下S1或者S5按键即可切换显示不同的窗口,从而显示不同的变量。按下S9按键不松手就可以切换到十六进制的显示界面,松开手后会自动切换到十进制的界面。16个LED灯显示的就是当前变量的二进制数,亮代表1,灭代表0。上坚鸿51学习板观察程序执行的结果如下:
       变量a为9。
       变量b为128。
       变量c为8。
       变量d为7。
      下节预告:if判断语句和等于关系符“==”。
     (未完待续)

乐于分享,勇于质疑!
46#
 楼主| 发表于 2015-9-20 06:06:46 | 显示全部楼层
本帖最后由 jianhong_wu 于 2015-9-20 06:11 编辑

第三十七节:if判断语句以及常量变量真假的判断。
        “if”是C语言的判断语句关键词,意思是如果if小括号里面的条件满足,就执行条件后面大括号里的语句;如果条件不满足,则直接跳过条件后面大括号里的语句。“if”语句的常见格式如下:
if(条件)
{
    语句1;
    语句2;
    语句3;
……
}
        还有一种省略大括号的书写格式,但是要注意,当if条件语句后面省略了大括号时,如果if小括号里面的条件满足,仅仅执行条件后面第一条语句,如果条件不满足,则跳过条件后面第一条语句。比如:
if(条件)
    语句1;
    语句2;
    语句3;
……
       上述格式省略了大括号,实际上默认相当于:
if(条件)
{
    语句1;
}
    语句2;
    语句3;
……
       上述语句分析:当条件满足时,就执行语句1,如果不满足,就跳过语句1,直接从语句2处开始往后执行。在实际项目中,为了阅读清晰,建议大家不要省略大括号。
        接着讲另一个新的知识点,对于if(条件),if语句的条件包含两种,一种是常量或者变量真假的判断,另一种是关系判断。本节内容先举例讲常量或变量的判断。比如:
if(常量或者变量)
{
    语句1;
    语句2;
}
    语句3;
    语句4;
……
        当小括号里面的常量或者变量大于0时,就代表小括号里面的条件满足;当小括号里面的常量或者变量等于0时,就代表小括号里面的条件不满足。还有一种专业的说法,条件满足称之为“真”,条件不满足称之为“假”。在这里,常量或者变量大于0称之为“真”,等于0称之为“假”。还可以换一种思路来记忆,常量或者变量不等于0称之为“真”,等于0称之为“假”。比如刚才的例子:
if(常量或者变量)
{
    语句1;
    语句2;
}
    语句3;
    语句4;
……
        若条件为真,则从语句1处开始执行,若条件为假,则跳过语句1和语句2,直接从语句3开始执行。
        现在编写一个程序,有5条if判断语句,如果条件为真,累加统计变量就会自动加1,最后看看条件为真的语句有几条。最后把程序编译后下载到坚鸿51学习板观察结果。请直接复制第十节模板程序,修改的main程序代码如下:

  1. void main() //主程序
  2. {
  3. /*---C语言学习区域的开始---------------------------------------------------------------------------*/
  4.         
  5.   unsigned char x=2;
  6.   unsigned char y=0;
  7.   unsigned char a=0;  //此变量统计有多少条语句是真的

  8.   if(1)      //常量大于0,因此为真
  9.   {
  10.      a=a+1;  //a由0自加1后变成1。
  11.   }


  12.   if(0)   //常量等于0,因此为假
  13.   {
  14.      a=a+1;  //由于条件为假,这条语句没有被执行,因此此时a仍然是1
  15.   }


  16.   if(15)     //常量大于0,因此为真
  17.   {
  18.      a=a+1;  //a由1自加1后变成2。
  19.   }



  20.   if(x)     //变量x为2,大于0,因此为真
  21.   {
  22.      a=a+1;  //a由,2自加1后变成3。
  23.   }


  24.   if(y)     //变量y为0,等于0,因此为假
  25.   {
  26.      a=a+1;  //由于条件为假,这条语句没有被执行,因此此时a仍然是3
  27.   }
  28.         
  29.   GuiWdData0=a;   //把a这个变量放到窗口变量0里面显示

  30.         
  31. /*---C语言学习区域的结束---------------------------------------------------------------------------*/
  32.    while(1)  
  33.    {
  34.       initial();
  35.       key_service();
  36.       display_service();
  37.    }

  38. }
复制代码


         查看运算结果的方法。如何在坚鸿51学习板上观察变量?按下S1或者S5按键即可切换显示不同的窗口,从而显示不同的变量。按下S9按键不松手就可以切换到十六进制的显示界面,松开手后会自动切换到十进制的界面。16个LED灯显示的就是当前变量的二进制数,亮代表1,灭代表0。上坚鸿51学习板观察程序执行的结果如下:
         变量a为3。
         下节预告:等于关系符“==”和不等于关系符“!=”。
(未完待续)

乐于分享,勇于质疑!
47#
 楼主| 发表于 2015-9-26 09:47:46 | 显示全部楼层
本帖最后由 jianhong_wu 于 2015-9-26 09:49 编辑

第三十八节:等于关系符“==”和不等于关系符“!=”。
       上一节讲了if(条件)语句中当条件是纯常量或者变量的情况,这节开始讲if语句的关系判断。要进行关系判断,就涉及到关系符语句。本节先讲等于关系符“==”和不等于关系符“!=”。
        一. 等于关系符“==”语句。
      (1)等于关系符“==”语句的常见格式如下:
if(常量或变量==常量或变量)
{
    语句1;
    语句2;
}
语句3;
……
语句N;
        上述格式的含义是:如果等于号”==”左边的数确实等于右边的数,就执行大括号里的语句1和语句2;如果左右的数不相等,直接跳过大括号里的语句1和语句2,从语句3开始继续往下执行。
if语句省略大括号时的执行顺序上一节已经讲过了,本节和以后的章节就不再重复讲这方面的内容。
        (2)被判断的左右两个数中,如果有一个数是常量,另外一个是变量,针对这种情况建议大家尽量把常量放在等于号“==”的左边,原因是:万一程序员不小心把等于号“==”误写成赋值符号“=”时,编译器在编译时,能及时报错,因为常量在左边是无法赋值的,编译器能及时发现错误。但是如果变量在左边,因为变量是允许赋值的,所以有一些C语言编译器未必会报错,就会留下不易察觉的程序隐患。比如:
    if(a==5)
{
    语句1;
}
建议改成
    if(5==a)
{
    语句1;
}
         二. 不等于关系符“!=”语句。
        (1)不等于关系符“!=”语句的常见格式如下:
if(常量或变量!=常量或变量)
{
    语句1;
    语句2;
}
语句3;
……
语句N;
        上述格式的含义是:如果不等于号”!=”左边的数确实不等于右边的数,就执行大括号里的语句1和语句2;如果左右的数恰好相等,就直接跳过大括号里的语句1和语句2,从语句3开始继续往下执行。
       (2)被判断的左右两个数中,如果有一个数是常量,另外一个是变量,针对这种情况建议大家尽量把常量放在不等于号“!=”的左边,原因是:万一程序员不小心把不等于号“!=”误写成赋值符号“=”时,编译器在编译时,能及时报错,因为常量在左边是无法赋值的,编译器能及时发现错误。但是如果变量在左边,因为变量是允许赋值的,所以有一些C语言编译器未必会报错,就会留下不易察觉的程序隐患。比如:
    if(a!=5)
{
    语句1;
}
建议改成
    if(5!=a)
{
    语句1;
}

        现在编写一个实验程序,一共有8个给定的数,要统计其中数值等于85的数有几个,统计其中数值不等于75的数有几个。最后把程序编译后下载到坚鸿51学习板观察结果。请直接复制第十节模板程序,修改的main程序代码如下:

  1. void main() //主程序
  2. {
  3. /*---C语言学习区域的开始---------------------------------------------------------------------------*/
  4.   unsigned char x1=90; //给定的第1个数     
  5.   unsigned char x2=65; //给定的第2个数   
  6.   unsigned char x3=85; //给定的第3个数   
  7.   unsigned char x4=79; //给定的第4个数   
  8.   unsigned char x5=95; //给定的第5个数   
  9.   unsigned char x6=65; //给定的第6个数   
  10.   unsigned char x7=75; //给定的第7个数   
  11.   unsigned char x8=85; //给定的第8个数  

  12.   unsigned char a=0; //统计等于85的变量总数
  13.   unsigned char b=0; //统计不等于75的变量总数

  14.   if(85==x1)  //把常量85放在等于号的左边
  15.   {
  16.      a++;   //相当于a=a+1,用来统计等于85的总数
  17.   }

  18.   if(85==x2)  //把常量85放在等于号的左边
  19.   {
  20.      a++;   //相当于a=a+1,用来统计等于85的总数
  21.   }


  22.   if(85==x3)  //把常量85放在等于号的左边
  23.   {
  24.      a++;   //相当于a=a+1,用来统计等于85的总数
  25.   }


  26.   if(85==x4)  //把常量85放在等于号的左边
  27.   {
  28.      a++;   //相当于a=a+1,用来统计等于85的总数
  29.   }


  30.   if(85==x5)  //把常量85放在等于号的左边
  31.   {
  32.      a++;   //相当于a=a+1,用来统计等于85的总数
  33.   }


  34.   if(85==x6)  //把常量85放在等于号的左边
  35.   {
  36.      a++;   //相当于a=a+1,用来统计等于85的总数
  37.   }


  38.   if(85==x7)  //把常量85放在等于号的左边
  39.   {
  40.      a++;   //相当于a=a+1,用来统计等于85的总数
  41.   }


  42.   if(85==x8)  //把常量85放在等于号的左边
  43.   {
  44.      a++;   //相当于a=a+1,用来统计等于85的总数
  45.   }



  46.   if(75!=x1)  //把常量75放在不等于号的左边
  47.   {
  48.      b++;   //相当于b=b+1,用来统计不等于75的总数
  49.   }


  50.   if(75!=x2)  //把常量75放在不等于号的左边
  51.   {
  52.      b++;   //相当于b=b+1,用来统计不等于75的总数
  53.   }



  54.   if(75!=x3)  //把常量75放在不等于号的左边
  55.   {
  56.      b++;   //相当于b=b+1,用来统计不等于75的总数
  57.   }



  58.   if(75!=x4)  //把常量75放在不等于号的左边
  59.   {
  60.      b++;   //相当于b=b+1,用来统计不等于75的总数
  61.   }




  62.   if(75!=x5)  //把常量75放在不等于号的左边
  63.   {
  64.      b++;   //相当于b=b+1,用来统计不等于75的总数
  65.   }


  66.   if(75!=x6)  //把常量75放在不等于号的左边
  67.   {
  68.      b++;   //相当于b=b+1,用来统计不等于75的总数
  69.   }



  70.   if(75!=x7)  //把常量75放在不等于号的左边
  71.   {
  72.      b++;   //相当于b=b+1,用来统计不等于75的总数
  73.   }



  74.   if(75!=x8)  //把常量75放在不等于号的左边
  75.   {
  76.      b++;   //相当于b=b+1,用来统计不等于75的总数
  77.   }

  78.       
  79.   GuiWdData0=a;   //把a这个变量放到窗口变量0里面显示
  80.   GuiWdData1=b;   //把b这个变量放到窗口变量1里面显示
  81.   
  82.         
  83. /*---C语言学习区域的结束---------------------------------------------------------------------------*/
  84.    while(1)  
  85.    {
  86.                   initial();
  87.       key_service();
  88.       display_service();
  89.    }

  90. }
复制代码


         查看运算结果的方法。如何在坚鸿51学习板上观察变量?按下S1或者S5按键即可切换显示不同的窗口,从而显示不同的变量。按下S9按键不松手就可以切换到十六进制的显示界面,松开手后会自动切换到十进制的界面。16个LED灯显示的就是当前变量的二进制数,亮代表1,灭代表0。上坚鸿51学习板观察程序执行的结果如下:
         变量a为2。(等于85的有x3,x8这2个)
         变量b为7。(不等于75的有x1,x2,x3,x4,x5,x6,x8这7个)
         下节预告:大于关系符“>”和大于等于关系符“>=”。
(未完待续)

乐于分享,勇于质疑!
48#
 楼主| 发表于 2015-10-4 09:15:18 | 显示全部楼层
本帖最后由 jianhong_wu 于 2015-10-4 10:18 编辑

第三十九节:大于关系符“>”和大于等于关系符“>=”。
        一. 再复习一遍if语句的通用格式:
if(条件)
{
    语句1;
    语句2;
}
语句3;
……
语句N;
       上述格式的含义是:如果if语句里的条件满足(为真),就执行大括号里的语句1和语句2;如果条件不满足(为假),直接跳过大括号里的语句1和语句2,从语句3开始继续往下执行。
if语句省略大括号时的执行顺序前面章节已经讲过了,本节和以后的章节就不再重复讲这方面的内容。
        二. 大于关系符“>”语句。
if(常量或变量>常量或变量)
       上述if条件的真假判断规则是:如果左边的数大于右边的数,此条件为真(条件满足)。否则,为假(条件不满足)。
        三. 大于等于关系符“>=”语句。
if(常量或变量>=常量或变量)
       上述if条件的真假判断规则是:如果左边的数大于或者等于右边的数,此条件为真(条件满足)。否则,为假(条件不满足)。
        现在编写一个实验程序,一共有8个给定的数,要统计其中数值大于79的数有几个,统计其中数值大于等于79的数有几个。最后把程序编译后下载到坚鸿51学习板观察结果。请直接复制第十节模板程序,修改的main程序代码如下:
  1. void main() //主程序
  2. {
  3. /*---C语言学习区域的开始---------------------------------------------------------------------------*/
  4.   unsigned char x1=90; //给定的第1个数     
  5.   unsigned char x2=65; //给定的第2个数   
  6.   unsigned char x3=85; //给定的第3个数   
  7.   unsigned char x4=79; //给定的第4个数   
  8.   unsigned char x5=95; //给定的第5个数   
  9.   unsigned char x6=65; //给定的第6个数   
  10.   unsigned char x7=75; //给定的第7个数   
  11.   unsigned char x8=85; //给定的第8个数  

  12.   unsigned char a=0; //统计大于79的变量总数
  13.   unsigned char b=0; //统计大于等于79的变量总数



  14.   if(x1>79)  //如果条件为真,则执行下面大括号里面的语句。
  15.   {
  16.      a++;   //相当于a=a+1,用来统计大于79的总数
  17.   }


  18.   if(x2>79)  //如果条件为真,则执行下面大括号里面的语句。
  19.   {
  20.      a++;   //相当于a=a+1,用来统计大于79的总数
  21.   }


  22.   if(x3>79)  //如果条件为真,则执行下面大括号里面的语句。
  23.   {
  24.      a++;   //相当于a=a+1,用来统计大于79的总数
  25.   }

  26.   if(x4>79)  //如果条件为真,则执行下面大括号里面的语句。
  27.   {
  28.      a++;   //相当于a=a+1,用来统计大于79的总数
  29.   }


  30.   if(x5>79)  //如果条件为真,则执行下面大括号里面的语句。
  31.   {
  32.      a++;   //相当于a=a+1,用来统计大于79的总数
  33.   }


  34.   if(x6>79)  //如果条件为真,则执行下面大括号里面的语句。
  35.   {
  36.      a++;   //相当于a=a+1,用来统计大于79的总数
  37.   }


  38.   if(x7>79)  //如果条件为真,则执行下面大括号里面的语句。
  39.   {
  40.      a++;   //相当于a=a+1,用来统计大于79的总数
  41.   }

  42.   if(x8>79)  //如果条件为真,则执行下面大括号里面的语句。
  43.   {
  44.      a++;   //相当于a=a+1,用来统计大于79的总数
  45.   }


  46.   if(x1>=79)  //如果条件为真,则执行下面大括号里面的语句。
  47.   {
  48.      b++;   //相当于b=b+1,用来统计大于等于79的总数
  49.   }


  50.   if(x2>=79)  //如果条件为真,则执行下面大括号里面的语句。
  51.   {
  52.      b++;   //相当于b=b+1,用来统计大于等于79的总数
  53.   }


  54.   if(x3>=79)  //如果条件为真,则执行下面大括号里面的语句。
  55.   {
  56.      b++;   //相当于b=b+1,用来统计大于等于79的总数
  57.   }
  58.       

  59.   if(x4>=79)  //如果条件为真,则执行下面大括号里面的语句。
  60.   {
  61.      b++;   //相当于b=b+1,用来统计大于等于79的总数
  62.   }


  63.   if(x5>=79)  //如果条件为真,则执行下面大括号里面的语句。
  64.   {
  65.      b++;   //相当于b=b+1,用来统计大于等于79的总数
  66.   }


  67.   if(x6>=79)  //如果条件为真,则执行下面大括号里面的语句。
  68.   {
  69.      b++;   //相当于b=b+1,用来统计大于等于79的总数
  70.   }


  71.   if(x7>=79)  //如果条件为真,则执行下面大括号里面的语句。
  72.   {
  73.      b++;   //相当于b=b+1,用来统计大于等于79的总数
  74.   }
  75.       

  76.   if(x8>=79)  //如果条件为真,则执行下面大括号里面的语句。
  77.   {
  78.      b++;   //相当于b=b+1,用来统计大于等于79的总数
  79.   }

  80.       
  81.   GuiWdData0=a;   //把a这个变量放到窗口变量0里面显示
  82.   GuiWdData1=b;   //把b这个变量放到窗口变量1里面显示
  83.   
  84.         
  85. /*---C语言学习区域的结束---------------------------------------------------------------------------*/
  86.    while(1)  
  87.    {
  88.                   initial();
  89.       key_service();
  90.       display_service();
  91.    }

  92. }
复制代码


         查看运算结果的方法。如何在坚鸿51学习板上观察变量?按下S1或者S5按键即可切换显示不同的窗口,从而显示不同的变量。按下S9按键不松手就可以切换到十六进制的显示界面,松开手后会自动切换到十进制的界面。16个LED灯显示的就是当前变量的二进制数,亮代表1,灭代表0。上坚鸿51学习板观察程序执行的结果如下:
        变量a为4。(大于79的有x1,x3, x5,x8这4个)
        变量b为5。(大于等于79的有x1,x3, x4, x5,x8这5个)
        下节预告:小于关系符“<”和小于等于关系符“<=”。
(未完待续)

乐于分享,勇于质疑!
49#
 楼主| 发表于 2015-10-4 10:34:54 | 显示全部楼层
第四十节:小于关系符“<”和小于等于关系符“<=”。
        一. 小于关系符“<”语句。
if(常量或变量<常量或变量)
       上述if条件的真假判断规则是:如果左边的数小于右边的数,此条件为真(条件满足)。否则,为假(条件不满足)。
        二. 小于等于关系符“<=”语句。
if(常量或变量<=常量或变量)
       上述if条件的真假判断规则是:如果左边的数小于或者等于右边的数,此条件为真(条件满足)。否则,为假(条件不满足)。
        现在编写一个实验程序,一共有8个给定的数,要统计其中数值小于79的数有几个,统计其中数值小于等于79的数有几个。最后把程序编译后下载到坚鸿51学习板观察结果。请直接复制第十节模板程序,修改的main程序代码如下:

  1. void main() //主程序
  2. {
  3. /*---C语言学习区域的开始---------------------------------------------------------------------------*/
  4.   unsigned char x1=90; //给定的第1个数     
  5.   unsigned char x2=65; //给定的第2个数   
  6.   unsigned char x3=85; //给定的第3个数   
  7.   unsigned char x4=79; //给定的第4个数   
  8.   unsigned char x5=95; //给定的第5个数   
  9.   unsigned char x6=65; //给定的第6个数   
  10.   unsigned char x7=75; //给定的第7个数   
  11.   unsigned char x8=85; //给定的第8个数  

  12.   unsigned char a=0; //统计小于79的变量总数
  13.   unsigned char b=0; //统计小于等于79的变量总数


  14.   if(x1<79)  //如果条件为真,则执行下面大括号里面的语句。
  15.   {
  16.      a++;   //相当于a=a+1,用来统计小于79的总数
  17.   }

  18.   if(x2<79)  //如果条件为真,则执行下面大括号里面的语句。
  19.   {
  20.      a++;   //相当于a=a+1,用来统计小于79的总数
  21.   }

  22.   if(x3<79)  //如果条件为真,则执行下面大括号里面的语句。
  23.   {
  24.      a++;   //相当于a=a+1,用来统计小于79的总数
  25.   }

  26.   if(x4<79)  //如果条件为真,则执行下面大括号里面的语句。
  27.   {
  28.      a++;   //相当于a=a+1,用来统计小于79的总数
  29.   }

  30.   if(x5<79)  //如果条件为真,则执行下面大括号里面的语句。
  31.   {
  32.      a++;   //相当于a=a+1,用来统计小于79的总数
  33.   }

  34.   if(x6<79)  //如果条件为真,则执行下面大括号里面的语句。
  35.   {
  36.      a++;   //相当于a=a+1,用来统计小于79的总数
  37.   }

  38.   if(x7<79)  //如果条件为真,则执行下面大括号里面的语句。
  39.   {
  40.      a++;   //相当于a=a+1,用来统计小于79的总数
  41.   }

  42.   if(x8<79)  //如果条件为真,则执行下面大括号里面的语句。
  43.   {
  44.      a++;   //相当于a=a+1,用来统计小于79的总数
  45.   }

  46.   if(x1<=79)  //如果条件为真,则执行下面大括号里面的语句。
  47.   {
  48.      b++;   //相当于b=b+1,用来统计小于等于79的总数
  49.   }


  50.   if(x2<=79)  //如果条件为真,则执行下面大括号里面的语句。
  51.   {
  52.      b++;   //相当于b=b+1,用来统计小于等于79的总数
  53.   }


  54.   if(x3<=79)  //如果条件为真,则执行下面大括号里面的语句。
  55.   {
  56.      b++;   //相当于b=b+1,用来统计小于等于79的总数
  57.   }

  58.   
  59.   if(x4<=79)  //如果条件为真,则执行下面大括号里面的语句。
  60.   {
  61.      b++;   //相当于b=b+1,用来统计小于等于79的总数
  62.   }

  63.   if(x5<=79)  //如果条件为真,则执行下面大括号里面的语句。
  64.   {
  65.      b++;   //相当于b=b+1,用来统计小于等于79的总数
  66.   }


  67.   if(x6<=79)  //如果条件为真,则执行下面大括号里面的语句。
  68.   {
  69.      b++;   //相当于b=b+1,用来统计小于等于79的总数
  70.   }


  71.   if(x7<=79)  //如果条件为真,则执行下面大括号里面的语句。
  72.   {
  73.      b++;   //相当于b=b+1,用来统计小于等于79的总数
  74.   }

  75.   
  76.   if(x8<=79)  //如果条件为真,则执行下面大括号里面的语句。
  77.   {
  78.      b++;   //相当于b=b+1,用来统计小于等于79的总数
  79.   }
  80.       
  81.   GuiWdData0=a;   //把a这个变量放到窗口变量0里面显示
  82.   GuiWdData1=b;   //把b这个变量放到窗口变量1里面显示
  83.   
  84.         
  85. /*---C语言学习区域的结束---------------------------------------------------------------------------*/
  86.    while(1)  
  87.    {
  88.                   initial();
  89.       key_service();
  90.       display_service();
  91.    }

  92. }
复制代码


         查看运算结果的方法。如何在坚鸿51学习板上观察变量?按下S1或者S5按键即可切换显示不同的窗口,从而显示不同的变量。按下S9按键不松手就可以切换到十六进制的显示界面,松开手后会自动切换到十进制的界面。16个LED灯显示的就是当前变量的二进制数,亮代表1,灭代表0。上坚鸿51学习板观察程序执行的结果如下:
         变量a为3。(小于79的有x2,x6, x7这3个)
         变量b为4。(小于等于79的有x2, x4,x6, x7这4个)

         下节预告:与“&&”,或“||”的关系符。
(未完待续)

乐于分享,勇于质疑!
50#
 楼主| 发表于 2015-10-11 06:59:36 | 显示全部楼层
第四十一节:与“&&”,或“||”的关系符。
       一.前面第30,31节内容讲了运算符的与或“&”“|”,它们与本节关系符的与或“&&”“||”有相似之处,同时又有什么区别呢?
     (1)一个叫运算符,一个叫关系符。
     (2)运算符是在一个变量二进制的位与位之间进行1和0的运算(1为真,0为假),而关系符是强调两个以上条件判断的整体与整体之间进行真和假的判断运算。
     (3)运算符的书写符号是“&”“|”, 关系符的书写符号是“&&”“||”。
      二.与“&&”语句。它的中文表达含义是:假如有两个条件判断,既满足第1个条件判断,又满足第2个条件判断,则此整体判断裁定为真(条件满足)。否则,只要一个条件判断不满足,此整体判断就裁定为假(条件不满足)。比如:
if(第1个条件判断&&第2个条件判断…&&第N个条件判断)
      在上述if括号的条件中,如果所有的关系判断都为真,则此整体判断为真(条件满足),否则,只要有一个关系判断为假,则此整体判断为假(条件不满足)。
      比如要取从70到80之间的所有数据,那么既要大于等于70,同时又要小于等于80,因此可以这样书写:
if(a>=70&&a<=80)
{
   语句1;
语句2;
……
语句N;
}
      三.或“||”语句。它的中文表达含义是:假如有两个条件判断,只要有一个条件判断为真,则此整体判断裁定为真(条件满足)。否则,必须所有的条件判断都不满足,此整体判断才会裁定为假(条件不满足)。比如:
if(第1个条件判断||第2个条件判断…||第N个条件判断)
      在上述if括号的条件中,只要有1个条件判断为真,此整体判断就裁定为真。否则,必须所有的条件判断为假,此整体判断才裁定为假。
      比如要取除了7080之间以外的所有数据,也就是要么小于70,或者要么大于80,可以这样写:
if(a<70||a>80)
{
   语句1;
语句2;
……
语句N;
}

       现在编写一个实验程序,一共有8个给定的数,要统计其中数值从70到80之间的数有几个,统计其中取除了70到80之间以外的数有几个。最后把程序编译后下载到坚鸿51学习板观察结果。请直接复制第十节模板程序,修改的main程序代码如下:

  1. void main() //主程序
  2. {
  3. /*---C语言学习区域的开始---------------------------------------------------------------------------*/
  4.   unsigned char x1=90; //给定的第1个数     
  5.   unsigned char x2=65; //给定的第2个数   
  6.   unsigned char x3=85; //给定的第3个数   
  7.   unsigned char x4=79; //给定的第4个数   
  8.   unsigned char x5=95; //给定的第5个数   
  9.   unsigned char x6=65; //给定的第6个数   
  10.   unsigned char x7=75; //给定的第7个数   
  11.   unsigned char x8=85; //给定的第8个数  

  12.   unsigned char a=0; //统计从70到80的变量总数
  13.   unsigned char b=0; //统计除了70到80以外的变量总数


  14.   if(x1>=70&&x1<=80)  //如果条件为真,则执行下面大括号里面的语句。
  15.   {
  16.      a++;   //相当于a=a+1,用来统计从70到80的总数
  17.   }


  18.   if(x2>=70&&x2<=80)  //如果条件为真,则执行下面大括号里面的语句。
  19.   {
  20.      a++;   //相当于a=a+1,用来统计从70到80的总数
  21.   }


  22.   if(x3>=70&&x3<=80)  //如果条件为真,则执行下面大括号里面的语句。
  23.   {
  24.      a++;   //相当于a=a+1,用来统计从70到80的总数
  25.   }

  26.   if(x4>=70&&x4<=80)  //如果条件为真,则执行下面大括号里面的语句。
  27.   {
  28.      a++;   //相当于a=a+1,用来统计从70到80的总数
  29.   }

  30.   if(x5>=70&&x5<=80)  //如果条件为真,则执行下面大括号里面的语句。
  31.   {
  32.      a++;   //相当于a=a+1,用来统计从70到80的总数
  33.   }


  34.   if(x6>=70&&x6<=80)  //如果条件为真,则执行下面大括号里面的语句。
  35.   {
  36.      a++;   //相当于a=a+1,用来统计从70到80的总数
  37.   }


  38.   if(x7>=70&&x7<=80)  //如果条件为真,则执行下面大括号里面的语句。
  39.   {
  40.      a++;   //相当于a=a+1,用来统计从70到80的总数
  41.   }

  42.   if(x8>=70&&x8<=80)  //如果条件为真,则执行下面大括号里面的语句。
  43.   {
  44.      a++;   //相当于a=a+1,用来统计从70到80的总数
  45.   }

  46.   if(x1<70||x1>80)  //如果条件为真,则执行下面大括号里面的语句。
  47.   {
  48.      b++;   //相当于b=b+1,用来统计除了70到80以外的总数
  49.   }

  50.   if(x2<70||x2>80)  //如果条件为真,则执行下面大括号里面的语句。
  51.   {
  52.      b++;   //相当于b=b+1,用来统计除了70到80以外的总数
  53.   }

  54.   if(x3<70||x3>80)  //如果条件为真,则执行下面大括号里面的语句。
  55.   {
  56.      b++;   //相当于b=b+1,用来统计除了70到80以外的总数
  57.   }

  58.   if(x4<70||x4>80)  //如果条件为真,则执行下面大括号里面的语句。
  59.   {
  60.      b++;   //相当于b=b+1,用来统计除了70到80以外的总数
  61.   }

  62.   if(x5<70||x5>80)  //如果条件为真,则执行下面大括号里面的语句。
  63.   {
  64.      b++;   //相当于b=b+1,用来统计除了70到80以外的总数
  65.   }

  66.   if(x6<70||x6>80)  //如果条件为真,则执行下面大括号里面的语句。
  67.   {
  68.      b++;   //相当于b=b+1,用来统计除了70到80以外的总数
  69.   }

  70.   if(x7<70||x7>80)  //如果条件为真,则执行下面大括号里面的语句。
  71.   {
  72.      b++;   //相当于b=b+1,用来统计除了70到80以外的总数
  73.   }

  74.   if(x8<70||x8>80)  //如果条件为真,则执行下面大括号里面的语句。
  75.   {
  76.      b++;   //相当于b=b+1,用来统计除了70到80以外的总数
  77.   }

  78.       
  79.   GuiWdData0=a;   //把a这个变量放到窗口变量0里面显示
  80.   GuiWdData1=b;   //把b这个变量放到窗口变量1里面显示
  81.   
  82.         
  83. /*---C语言学习区域的结束---------------------------------------------------------------------------*/
  84.    while(1)  
  85.    {
  86.                   initial();
  87.       key_service();
  88.       display_service();
  89.    }

  90. }
复制代码


        查看运算结果的方法。如何在坚鸿51学习板上观察变量?按下S1或者S5按键即可切换显示不同的窗口,从而显示不同的变量。按下S9按键不松手就可以切换到十六进制的显示界面,松开手后会自动切换到十进制的界面。16个LED灯显示的就是当前变量的二进制数,亮代表1,灭代表0。上坚鸿51学习板观察程序执行的结果如下:
        变量a为2。(数值从70到80之间的有x4, x7这2个)
        变量b为6。(除了70到80之间以外的有x1, x2,x3,x5, x6, x8这6个)
        下节预告:括号改变判断的优先级。
(未完待续)

乐于分享,勇于质疑!
51#
 楼主| 发表于 2015-10-18 05:36:35 | 显示全部楼层
本帖最后由 jianhong_wu 于 2015-10-18 05:38 编辑

第四十二节:小括号改变判断的优先级。
       小括号如何改变判断优先级? C语言有规定,凡是在判断语句里插入了小括号,程序就会优先执行最里面小括号的判断语句,之后才会根据判断符的优先级执行其它相关语句。
       小括号的意义何在?C语言中的判断符号众多,非常不利于程序员对各符号优先级的记忆,小括号却解决了这个问题。小括号因为可以改变判断的优先级,所以为实际项目带来了两个好处:一个是明确判断顺序,一个是改变判断顺序。
       比如在上一节提到的两个判断语:
if(a>=70&&a<=80)和if(a<70||a>80)
       有一些朋友喜欢插入两个小括号变成:
if((a>=70)&&(a<=80))和if((a<70)||(a>80))
       上述的修改,在不知道 “>,>=,<,<=” 这类语句跟 “&&,||” 这类语句哪个优先级更高的前提下,插入了小括号,可以更加明确判断的顺序,这种做法也挺好的,值得肯定。我个人平时在面对“>,>=,<,<=”这类语句跟 “&&,||” 这类语句时,也就是针对上述那种情况,由于我比较肯定的清楚“>,>=,<,<=”这类语句比“&&,||” 这类语句的优先级高,所以我不需要在此插入小括号来明确判断顺序。但是在下面将要提到的这种情况,我是会百分百插入小括号来明确和改变判断的顺序。什么情况呢?如下:
       if(判断条件1  ||  判断条件2  &&  判断条件3)
       到底是先“判断条件1” 跟“判断条件2”相或,最后再跟“判断条件3”相与?还是先“判断条件2” 跟“判断条件3”相与,最后再跟“判断条件1”相或?此时应该插入小括号明确它们判断的先后顺序。
       要么第一种顺序:
if((判断条件1  ||  判断条件2)  &&  判断条件3)
       要么第二种顺序:
if(判断条件1  ||  (判断条件2  &&  判断条件3))
       具体选择哪种一种判断顺序要根据项目的需要来决定。同样的3个判断条件,如果判断的顺序不一样,那么结果也可能出现不一样,比如,上述判断条件:
假设“判断条件1”为真,
假设“判断条件2”为真,
假设“判断条件3”为假,
        第一种顺序:
if((真||  真)  &&  假)
分析结论:先”真”和”真”相或结果为”真”,然后再把第一步判断结果的”真”和”假”相与,最后结果是”假”。
        第二种顺序:
if(真||  (真  &&  假))
分析结论:先”真”和” 假”相与结果为” 假”,然后再把第一步判断结果的” 假”和”真”相或,最后结果是”真”。
        现在编写一个实验程序验证上述两种判断顺序,最后把程序编译后下载到坚鸿51学习板观察结果。请直接复制第十节模板程序,修改的main程序代码如下:

  1. void main() //主程序
  2. {
  3. /*---C语言学习区域的开始---------------------------------------------------------------------------*/
  4.         
  5.   //x,y这三个变量作为条件判断的变量
  6.   unsigned char x=5;
  7.   unsigned char y=6;
  8.   
  9.   //a,b这两个变量作为输出判断结果的真假,0代表假,1代表真。
  10.   unsigned char a=0;  //默认为0,也就是默认为假
  11.   unsigned char b=0;  //默认为0,也就是默认为假
  12.   
  13.   if((x<y||y>x)&&x==y) //里面的条件是((真||真)&&假),最终结果判断是假
  14.   {
  15.      a=1;
  16.   }

  17.   if(x<y||(y>x&&x==y)) //里面的条件是(真||(真&&假)),最终结果判断是真
  18.   {
  19.      b=1;
  20.   }
  21.   
  22.         
  23.   GuiWdData0=a;   //把a这个变量结果放到窗口变量0里面显示
  24.   GuiWdData1=b;   //把b这个变量结果放到窗口变量1里面显示

  25.         
  26. /*---C语言学习区域的结束---------------------------------------------------------------------------*/
  27.    while(1)  
  28.    {
  29.       initial();
  30.       key_service();
  31.       display_service();
  32.    }

  33. }
复制代码


         查看运算结果的方法。如何在坚鸿51学习板上观察变量?按下S1或者S5按键即可切换显示不同的窗口,从而显示不同的变量。按下S9按键不松手就可以切换到十六进制的显示界面,松开手后会自动切换到十进制的界面。16个LED灯显示的就是当前变量的二进制数,亮代表1,灭代表0。上坚鸿51学习板观察程序执行的结果如下:
         变量a为0。(0代表此条件判断结果为假)
         变量b为1。(1代表此条件判断结果为真)
         下节预告:if,elseif,else的5种组合判断语句。
(未完待续)

乐于分享,勇于质疑!
52#
 楼主| 发表于 2015-10-25 00:45:30 | 显示全部楼层
本帖最后由 jianhong_wu 于 2015-10-25 00:47 编辑

第四十三节:if,else if,else的5种组合判断语句。
        if,else if,else可以组成5种组合判断语句,这类组合语句可以这样通俗的解读:在众多条件判断中,先从第一个条件开始判断,如果第一个条件是真,那么不管后面的条件是否为真,都不再判断,直接执行条件1大括号后面的语句,组合语句中其它剩下的条件不再判断直接跳过,否则,就挨个条件往下判断,只要其中一个条件满足,就不再判断剩余的条件,也就是我们日常所说的多选一,甚至某些组合语句如果所有条件都不满足,那么什么也不选。总之,在如此众多的条件中,最多只能执行一个条件后面大括号的语句。组合语句还有一个规律:if语句只能出现在第一个条件判断,而且只能出现一次;else只能出现在最后一个条件判断,而且也只能出现一次;而else if语句总是出现在中间,绝对不能出现在第一个条件判断,如果没有else,也可以出现在最后的条件判断。接下来挨个仔细分析这5种组合语句的特点。
        第一种:
if(条件1)   //if只能出现第一个条件,并且只能出现一次
{
    语句1;
}
else    //else只能出现最后,并且也只能出现一次。
{
    语句2;
}
       分析:如果“条件1”为真,就直接执行“条件1”后面大括号的“语句1”,不再执行else后面的“语句2”。否则,如果“条件1”为假,那么就不执行“条件1”后面大括号的“语句1”,而是直接执行else后面的大括号“语句2”。简单概括就是两个必选一个,如果第一个条件1为假,就直接执行else后面大括号里的语句,也就是本例子中的“语句2”。
       第二种:
if(条件1)   //if只能出现第一个条件,并且只能出现一次
{
    语句1;
}
else  if(条件2)  //else if只能出现中间,可以出现多次
{
    语句2;
}
       分析:如果“条件1”为真,就直接执行“条件1”后面大括号的“语句1”,这时不管else if后面的“条件2”是否为真,都不再判断的“条件2”,这种情况当然也不会执行到“语句2”。否则,如果“条件1”为假,那么就不执行“条件1”后面大括号的“语句1”,而是继续判断else if后面的“条件2”,如果“条件2”为真,就会执行后面大括号的“语句2”,否则如果“条件2”也为假,那么“语句2”也不会执行。简单概括就是在两个条件中最多只能选一个,如果两个条件都为假,那么都不选。
       第三种:
if(条件1)       //if只能出现第一个条件,并且只能出现一次
{
    语句1;
}
else  if(条件2)   //else if只能出现中间,可以出现多次
{
    语句2;
}
else      //else只能出现最后,并且也只能出现一次。
{
    语句3;
}
       分析:如果“条件1”为真,就直接执行“条件1”后面大括号的“语句1”,这时不管else if后面的“条件2”是否为真,都不再判断的“条件2”,这种情况当然也不会执行到后面的“语句2”,更加不会执行到else 后面的“语句3”。否则,如果“条件1”为假,那么就不执行“条件1”后面大括号的“语句1”,而是继续判断else if后面的“条件2”,如果“条件2”为真,就会执行后面大括号的“语句2”,而else后面的“语句3”就不会被执行到,否则如果“条件2”也为假,那么“语句2”也不会执行,此时就直接执行else后面的“语句3”。简单概括就是在三个条件中必须选一个,如果前面两个条件都为假,那么就直接执行else后面大括号里的语句,也就是本例子中的“语句3”。
       第四种:
if(条件1)       //if只能出现第一个条件,并且只能出现一次
{
    语句1;
}
else  if(条件2)   //else if只能出现中间,可以出现多次
{
    语句2;
}
……
else  if(条件N)   //else if只能出现中间,可以出现多次
{
    语句N;
}

        分析:从“条件1”开始往下判断,只要有一个条件满足了,就执行当前条件后面大括号的语句,剩余的条件不再判断直接跳过,如果所有的条件都不满足,那么里面的语句都不执行。简单概括就是在N个条件中最多只能选一个,如果所有的条件都为假,那么都不选。
        第五种:
if(条件1)       //if只能出现第一个条件,并且只能出现一次
{
    语句1;
}
else  if(条件2)   //else if只能出现中间,可以出现多次
{
    语句2;
}
……
else  if(条件N)   //else if只能出现中间,可以出现多次
{
    语句N;
}
else   
{
    语句N+1;
}

       分析:从“条件1”开始往下判断,只要有一个条件满足了,就执行当前条件后面大括号的语句,剩余的条件不再判断直接跳过,如果所有的条件都不满足,那么就直接执行else后面大括号里的语句,也就是本例子中的“语句N+1”。简单概括就是在N+1个条件中必须选一个,如果前面所有N个条件都为假,最后就直接执行else后面大括号的语句,也就是本例子中的“语句N+1”。
       现在编写一个程序来实验上述5种组合语句。最后把程序编译后下载到坚鸿51学习板观察结果。请直接复制第十节模板程序,修改的main程序代码如下:

  1. void main() //主程序
  2. {
  3. /*---C语言学习区域的开始---------------------------------------------------------------------------*/
  4.         
  5.   //x这个变量作为条件判断的变量
  6.   unsigned char x=5;


  7.   
  8.   //a,b,c,d,e这5个变量作为输出判断结果,0代表什么语句都没执行,1代表执行了语句1,
  9.   //2代表执行语句2,3代表执行语句3,4代表执行语句4,5代表执行语句5。
  10.   unsigned char a=0;  
  11.   unsigned char b=0;
  12.   unsigned char c=0;  
  13.   unsigned char d=0;
  14.   unsigned char e=0;  

  15.   //第一种
  16.   if(x>6)  //x默认是5
  17.   {
  18.      a=1;   //语句1
  19.   }
  20.   else
  21.   {
  22.      a=2;  //语句2
  23.   }


  24.   //第二种
  25.   if(x>6)  //x默认是5
  26.   {
  27.      b=1;   //语句1
  28.   }
  29.   else if(x==7)  //x默认是5
  30.   {
  31.      b=2;  //语句2
  32.   }


  33.   //第三种
  34.   if(x>6)  //x默认是5
  35.   {
  36.      c=1;   //语句1
  37.   }
  38.   else if(x==7)  //x默认是5
  39.   {
  40.      c=2;  //语句2
  41.   }
  42.   else
  43.   {
  44.      c=3;  //语句3
  45.   }

  46.   //第四种
  47.   if(x>6)  //x默认是5
  48.   {
  49.      d=1;   //语句1
  50.   }
  51.   else if(x==7)  //x默认是5
  52.   {
  53.      d=2;  //语句2
  54.   }
  55.   else if(x==5)  //x默认是5
  56.   {
  57.      d=3;  //语句3
  58.   }
  59.   else if(x==4)  //x默认是5
  60.   {
  61.      d=4;  //语句4
  62.   }

  63.   //第五种
  64.   if(x>6)  //x默认是5
  65.   {
  66.      e=1;   //语句1
  67.   }
  68.   else if(x==7)  //x默认是5
  69.   {
  70.      e=2;  //语句2
  71.   }
  72.   else if(x==5)  //x默认是5
  73.   {
  74.      e=3;  //语句3
  75.   }
  76.   else if(x==4)  //x默认是5
  77.   {
  78.      e=4;  //语句4
  79.   }
  80.   else
  81.   {
  82.      e=5;  //语句5
  83.   }

  84.         
  85.   GuiWdData0=a;   //把a这个变量结果放到窗口变量0里面显示
  86.   GuiWdData1=b;   //把b这个变量结果放到窗口变量1里面显示
  87.   GuiWdData2=c;   //把c这个变量结果放到窗口变量2里面显示
  88.   GuiWdData3=d;   //把d这个变量结果放到窗口变量3里面显示
  89.   GuiWdData4=e;   //把e这个变量结果放到窗口变量4里面显示

  90.         
  91. /*---C语言学习区域的结束---------------------------------------------------------------------------*/
  92.    while(1)  
  93.    {
  94.       initial();
  95.       key_service();
  96.       display_service();
  97.    }

  98. }
复制代码


         查看运算结果的方法。如何在坚鸿51学习板上观察变量?按下S1或者S5按键即可切换显示不同的窗口,从而显示不同的变量。按下S9按键不松手就可以切换到十六进制的显示界面,松开手后会自动切换到十进制的界面。16个LED灯显示的就是当前变量的二进制数,亮代表1,灭代表0。上坚鸿51学习板观察程序执行的结果如下:
        变量a为2。(2代表执行了语句2)
        变量b为0。(0代表什么语句都没执行)
        变量c为3。(3代表执行了语句3)
        变量d为3。(3代表执行了语句3)
        变量e为3。(3代表执行了语句3)

        下节预告:一维数组。
(未完待续)

乐于分享,勇于质疑!
53#
 楼主| 发表于 2015-10-31 02:26:11 | 显示全部楼层
本帖最后由 jianhong_wu 于 2015-10-31 02:36 编辑

第四十四节:一维数组能批量定义变量的特点。
       一维数组有两个特点:
       第一个:批量定义变量。我们之前的章节用unsigned  char, unsigned  int, unsigned long定义变量时,往往一条语句只习惯定义一个变量,而用数组可以一条语句定义N个变量,只要不超过单片机的RAM范围。
       第二个:数组的每个元素变量的地址都是挨个相临的。第一个元素变量的地址是该数组的首地址,后面的下标是以此首地址为原点的偏移地址。这个特点跟以后学到的循环语句或者指针配合起来,只需简单几行代码就可以实现很多复杂实用的算法。
       上述第二个特点的内容等以后学到循环语句和指针时再深入讲解,本节重点讲解一维数组的书写格式和第一个特点。
       一维数组未带初始化时的通用定义格式如下:
类型 数组名[数组元素个数N];
比如:
unsigned char  x[3];  //此处的3不是下标,而是元素个数
       分析:此数组一行代码定义了三个变量,分别是x[0], x[1], x[2],此时中括号里的0,1,2称为数组的下标,注意,数组的下标是从0开始的,从N-1结束,此时的N代表数组元素个数。因此,上述数组不存在x[3]这个元素变量,只有x[0], x[1], x[2]这三个变量,如果非要使用x[3]这个元素变量,那就会导致数组越界出现异常或者编译不通过。
      一维数组带初始化时的通用定义格式如下:
类型 数组名[数组元素个数N]={ 元素0, 元素1,…元素N-1};
比如:
unsigned char  y[3]={10,11,12};
       分析:此数组一行代码定义了三个变量,分别是y[0], y[1], y[2]。而y[0]初始化为10,y[1]初始化为11,y[2]初始化为12。
在程序中,调用数组某个变量元素时,下标可以是常量,比如y[0],此时的0就是常量;下标也可以是变量,比如y,此时的i就是变量。再强调一次,下标常量或者变量i的数值必须小于y数组定义时的元素个数,否则就会导致数组越界出现异常或者编译不通过。
       现在编写一个程序来熟悉一下一维数组的书写和使用格式。最后把程序编译后下载到坚鸿51学习板观察结果。请直接复制第十节模板程序,修改的main程序代码如下:

  1. void main() //主程序
  2. {
  3. /*---C语言学习区域的开始---------------------------------------------------------------------------*/
  4.         
  5.   unsigned char  x[3];  //此处的3不是下标,而是元素个数,里面的3个变量没有初始化
  6.   unsigned char  y[3]={10,11,12}; //里面三个元素变量y[0],y[1],y[2]分别初始化为10,11,12

  7.   unsigned char  i=0; //定义和初始化一个变量。用来做x数组的下标。

  8.   x[i]=25;  //此时下标i为0.相当于把25赋值给x[0]
  9.   i=i+1;    //i由0变成1.
  10.   x[i]=26;  //此时下标i为1.相当于把26赋值给x[1]
  11.   i=i+1;    //i由1变成2.
  12.   x[i]=27;  //此时下标i为2.相当于把27赋值给x[2]
  13.   x[i]=x[i]+1; //此时x[2]自加1变成了28


  14.         
  15.   GuiWdData0=x[0];   //把x[0]这个元素变量放到窗口变量0里面显示
  16.   GuiWdData1=x[1];   //把x[1]这个元素变量放到窗口变量1里面显示
  17.   GuiWdData2=x[2];   //把x[2]这个元素变量放到窗口变量2里面显示


  18.   GuiWdData3=y[0];   //把y[0]这个元素变量放到窗口变量3里面显示
  19.   GuiWdData4=y[1];   //把y[1]这个元素变量放到窗口变量4里面显示
  20.   GuiWdData5=y[2];   //把y[2]这个元素变量放到窗口变量5里面显示

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

  29. }
复制代码

       查看运算结果的方法。如何在坚鸿51学习板上观察变量?按下S1或者S5按键即可切换显示不同的窗口,从而显示不同的变量。按下S9按键不松手就可以切换到十六进制的显示界面,松开手后会自动切换到十进制的界面。16个LED灯显示的就是当前变量的二进制数,亮代表1,灭代表0。上坚鸿51学习板观察程序执行的结果如下:
        变量元素x[0]为25。
        变量元素x[1]为26。
        变量元素x[2]为28。
        变量元素y[0]为10。
       变量元素y[1]为11。
       变量元素y[2]为12。
       下节预告:二维数组能批量定义变量的特点。
(未完待续)
乐于分享,勇于质疑!
54#
 楼主| 发表于 2015-11-9 00:27:49 | 显示全部楼层
本帖最后由 jianhong_wu 于 2015-11-9 00:31 编辑

第四十五节:二维数组。
       上一节讲一维数组时漏讲了一个知识点,一维数组在定义时,如果预先给它填写若干个初始化的数据,也可以省略中括号[N]里面的元素个数N,这样编译器在编译时会根据初始化的个数来自动识别和定义此一维数组实际元素个数。比如:
unsigned char  y[3]={10,11,12};
        跟
unsigned char  y[]={10,11,12};
       的意义是一样的。注意,省略元素个数时必须要有初始化的数据,否则编译器不知道此数组的长度可能导致编译出错。
       继续回到本节的内容,二维数组。一维数组只有一个下标,像由很多点连成的一条直线,而二维数组有两个下标,布下了一行行的点像一张矩形的网,它的两个下标分别代表了行和列,行和列又像我们所学的y轴和x轴坐标,通过y轴和x轴坐标就可以找到所需的点,也就是数组的某个元素。
       上述是对二维数组的感性描述,二维数组是由一维数组发展而来,所以具备了很多一维数组的特点。二维数组的所有”网点”元素的地址都是挨个相临的,先第0行,再第1行,再第2行…再第N行,上一行尾元素跟下一行头元素的地址是相临连续的。
        二维数组未带初始化时的通用定义格式如下:
类型 数组名[行数Y][列数X];
比如:
unsigned char  a[2][3]; //此处的2代表有2行,3代表有3列。
分析:此二维数组定义了6个变量,跟一维数组一样,下标都是从0开始,到(N-1)时结束,此处的N代表行数或者列数。所以a[2][3]数组的元素挨个分别是a[0][0],a[0][1], a[0][2], a[1][0], a[1][1], a[1][2]这6个变量。
         二维数组有两种常用初始化格式,一种是逐行初始化,一种是整体初始化。
         第一种逐行初始化:
unsigned char   a[2][3]=
{
   {0,1,2},
   {3,4,5}
};
        在逐行初始化定义二维数组时,只要有初始化的数据,也可以省略行下标,但是列下标不能省略,比如:
unsigned char   a[][3]=
{
   {0,1,2},
   {3,4,5}
};
此时编译器会根据元素的个数来确定行数是多少。

        第二种整体初始化,跟一维数组一样,内部数据元素不需要额外增加大括号来分行。
unsigned char   a[2][3]=
{
   0,1,2,3,4,5
};
或者
unsigned char   a[2][3]=
{
   0,1,2,
   3,4,5
};
都行。
       C语言是很自由很丰富的语言,比如二维数组还允许不完全初始化的一些情况,我就不再深入讲解,我讲解的都是挑选一些针对以后单片机项目中可能会经常用到的语法。
       二维数组我在很多项目上还是经常用到的,比如用在一些需要把所得的信息进行查表判断的项目,在每一行里放一条关键词字符串信息,利用循环语句进行逐行查找匹配。至于二维数组如何存放字符串的知识点以后再讲。这节的重点是让大家对二维数组有个初步的认识。
       现在编写一个程序来熟悉一下二维数组的书写和使用格式。最后把程序编译后下载到坚鸿51学习板观察结果。请直接复制第十节模板程序,修改的main程序代码如下:

  1. void main() //主程序
  2. {
  3. /*---C语言学习区域的开始---------------------------------------------------------------------------*/
  4.         

  5.    unsigned char  a[2][3]=  //定义和初始化一个二维数组
  6.    {
  7.       {0,1,2},
  8.       {3,4,5}
  9.    };

  10.         
  11.   GuiWdData0=a[0][0];   //把a[0][0]这个元素变量放到窗口变量0里面显示
  12.   GuiWdData1=a[0][1];   //把a[0][1]这个元素变量放到窗口变量1里面显示
  13.   GuiWdData2=a[0][2];   //把a[0][2]这个元素变量放到窗口变量2里面显示
  14.   GuiWdData3=a[1][0];   //把a[1][0]这个元素变量放到窗口变量3里面显示
  15.   GuiWdData4=a[1][1];   //把a[1][1]这个元素变量放到窗口变量4里面显示
  16.   GuiWdData5=a[1][2];   //把a[1][2]这个元素变量放到窗口变量5里面显示
  17.         
  18. /*---C语言学习区域的结束---------------------------------------------------------------------------*/
  19.    while(1)  
  20.    {
  21.       initial();
  22.       key_service();
  23.       display_service();
  24.    }

  25. }
复制代码


    查看运算结果的方法。如何在坚鸿51学习板上观察变量?按下S1或者S5按键即可切换显示不同的窗口,从而显示不同的变量。按下S9按键不松手就可以切换到十六进制的显示界面,松开手后会自动切换到十进制的界面。16个LED灯显示的就是当前变量的二进制数,亮代表1,灭代表0。上坚鸿51学习板观察程序执行的结果如下:
    变量元素a[0][0]为0。
    变量元素a[0][1]为1。
    变量元素a[0][2]为2。
    变量元素a[1][0]为3。
    变量元素a[1][1]为4。
    变量元素a[1][2]为5。
    下节预告:while循环语句。
(未完待续)

乐于分享,勇于质疑!
55#
 楼主| 发表于 2015-11-14 02:22:00 | 显示全部楼层
本帖最后由 jianhong_wu 于 2015-11-14 02:25 编辑

第四十六节:while循环语句。

       46.1   程序的跑道
       “程序跑起来了吗?”同行交流经常用的一句话。程序在哪里跑?有跑道吗?有的。循环语句就像一条椭圆的跑道,程序在跑道上不停的跑,永无止境,一秒几百万圈的速度。单片机main主函数内往往有一条while(1)语句,这就是单片机的“循环跑道”,称之为主循环,主循环内还可以继续嵌套多层while循环语句。

       46.2   while循环的常见格式
while(条件)
{
    语句1;   
    语句2;
     ……   
    语句N;
}

       分析:
(1)先判断条件是否为真。如果为假,就不执行花括号循环体内的语句1至语句N。如果为真,才执行花括号循环体内的语句1至语句N,当执行完花括号循环体内最后的“语句N“时,单片机继续返回while(条件)处,继续判断条件是否为真,如果为假就跳过花括号循环体,如果为真就继续从“语句1“执行到“语句N“,然后再返回while(条件)处,依次循环下去,直到条件为假时才罢休,否则一直循环下去。
(2)while(条件)语句中,条件判断真假的规则跟if语句一模一样,有两种类型:一种是纯常量或者变量类型的,只要此数值不等于0就认为是真,所以while(1)也称死循环语句,因为里面的条件永远不为0,如果不遇到break,return,goto这些语句,那么就永远也别想跳出这个循环;另外一种是关系判断,以及关系语句之间的“与或”判断,跟if语句规则一样,不多讲。break,return,goto这些语句后面章节会讲到。

       46.3   while省略花括号,后面第一条语句前没带分号
while(条件)
         语句1;   
        语句2;
        ……   
        语句N;

        分析:
        跟if语句一样,此时循环体默认只包含“语句1”,相当于:  
while(条件)
{
         语句1;   
}
        语句2;
        ……   
         语句N;


         46.4   while省略花括号,后面第一条语句前带分号
        while(条件);
         语句1;   
        语句2;
        ……   
        语句N;

        分析:
        注意,此时循环体默认不包含“语句1”,而是相当于:   
while(条件)
          ;   //一个分号代表一条空语句,语法上要求加上分号
         语句1;
         语句2;
         ……   
         语句N;
         此时如果条件一直为真,单片机就一直在空循环耗着,执行不到语句1的语句。直到条件为假才罢休。


          46.5   编写程序
          编写一个程序来熟悉一下while语句的书写和使用格式。最后把程序编译后下载到坚鸿51学习板观察结果。请直接复制第十节模板程序,修改的main程序代码如下:

  1. void main() //主程序
  2. {
  3. /*---C语言学习区域的开始---------------------------------------------------------------------------*/
  4.         
  5.   unsigned char a=0;  //观察这个数最后的变化
  6.   unsigned char b=0;  //观察这个数最后的变化

  7.   unsigned char i;  //控制循环体的条件判断变量


  8.   i=3;   
  9.   while(i)  //i不断变为0时才跳出此循环体
  10.   {
  11.      a=a+1;
  12.      i=i-1; //循环的条件不断发生变化,不断减小
  13.   }


  14.   i=0;
  15.   while(i<3)  //i大于等于3时才跳出此循环体
  16.   {
  17.      b=b+2;
  18.      i=i+1;   //循环的条件不断发生变化,不断增加
  19.   }

  20.      
  21.   GuiWdData0=a;   //把a这个变量放到窗口变量0里面显示
  22.   GuiWdData1=b;   //把b这个变量放到窗口变量1里面显示

  23.         
  24. /*---C语言学习区域的结束---------------------------------------------------------------------------*/
  25.    while(1)  
  26.    {
  27.       initial();
  28.       key_service();
  29.       display_service();
  30.    }

  31. }
复制代码


           查看运算结果的方法。如何在坚鸿51学习板上观察变量?按下S1或者S5按键即可切换显示不同的窗口,从而显示不同的变量。按下S9按键不松手就可以切换到十六进制的显示界面,松开手后会自动切换到十进制的界面。16个LED灯显示的就是当前变量的二进制数,亮代表1,灭代表0。上坚鸿51学习板观察程序执行的结果如下:
           变量a为3。
            变量b为6。


            下节预告:while循环语句的嵌套与break语句。
(未完待续)

乐于分享,勇于质疑!
56#
 楼主| 发表于 2015-11-22 08:40:42 | 显示全部楼层
本帖最后由 jianhong_wu 于 2015-11-22 08:45 编辑

第四十七节:循环语句do while和for。
       47.1   do while语句的常见格式
do{
       语句1;   
       语句2;
       ……   
       语句N;
} while(条件);
      分析:
      单片机从上往下执行语句,先从do那里无条件进来,从语句1开始往下执行,一直执行到语句N,然后开始判断while(条件)的条件是否为真,如果为真继续返回到do的入口处,继续从语句1开始往下执行,依次循环。大家留意到了吗,do while和while语句有什么差别?差别是,dowhile是先无条件进来执行一次循环体(花括号里所有的程序代码),执行到循环体最底部才判断while(条件)的条件是否为真来决定是否继续循环,先上车再买票。而while语句是先判断条件是否为真再决定是否需要进入循环体,先买票再上车。


      47.2   for语句的简介
      for语句也是循环语句,任何for语句实现的功能都可以用while语句来编程实现同样的功能,那for语句和while语句有什么差别呢?for语句把变量初始化,变量的条件判断,变量在执行循环体后的步进变化这三个常见要素集成在语句内部,以标准的格式书写出来。在很多场合下,for在书写和表达方面比while语句显得更加简洁和直观。


      47.3   for语句的自加格式。
for(变量的初始化语句; 变量的条件判断;变量在执行一次循环体后自加的步进变化)
{
       语句1;
       语句2;
       ……
       语句N;
}
在把上述变成具体一点如下:
for(i=0; i<3;i++)
{
      语句1;
      语句2;
      ……
      语句N;
}
       分析:
       单片机从上往下,在进入循环体前,先把变量i初始化赋值0,然后判断i是否小于3这个条件,如果此条件为真,就开始从语句1往下执行到语句N,执行完一次循环体后,i因为“i++”语句就自加1,此时i从原来初始化的0变成了1,接着再返回来到for语句的第二句条件判断”i<3”那里,判断i是否继续小于3这个条件,如果此条件为真就继续往下执行,否则就跳过循环体。因此上述for语句的功能如果用while语句来写,相当于以下代码:

i=0;  //进入循环体之前先初始化给予初值
while(i<3)
{
     语句1;
     语句2;
     ……
     语句N;
     i++;   //执行一次循环体之后此变量自加发生变化
}
上述的循环语句只执行了3次循环体。


      47.4   for语句的自减格式
       刚才讲的for(i=0; i<3;i++)格式,它的变量i是不断自加的,还有一种比较常见的格式是i不断自减的。如下:
for(i=3; i>0;i--)
{
     语句1;
     语句2;
     ……
     语句N;
}
      上述自减的for语句功能如果用while语句来写,相当于以下代码:

i=3;  //进入循环体之前先初始化给予初值
while(i>0)
{
     语句1;
     语句2;
     ……
     语句N;
     i--;   //执行一次循环体之后此变量自减发生变化
}
     上述的循环语句也是只执行了3次循环体。

     47.5   for省略花括号,后面第一条语句前没带分号
for(i=0; i<3;i++)
         语句1;  
         语句2;
         ……   
         语句N;

       分析:
       跟if语句一样,此时循环体默认只包含“语句1”,相当于:  
for(i=0; i<3;i++)
{
         语句1;  
}
         语句2;
         ……   
          语句N;

       47.6   for省略花括号,后面第一条语句前带分号
for(i=0; i<3;i++);
         语句1;  
         语句2;
         ……   
         语句N;

    分析:
    注意,此时循环体默认不包含“语句1”,而是相当于:   
for(i=0; i<3;i++)
           ;  //一个分号代表一条空语句,语法上要求加上分号
       语句1;
       语句2;
       ……   
       语句N;
       此时循环体内先循环执行三次空语句,然后才会结束for循环,接着从语句1开始往下执行。

       47.7   编写程序
       编写一个程序来熟悉一下do while和for语句的使用。最后把程序编译后下载到坚鸿51学习板观察结果。请直接复制第十节模板程序,修改的main程序代码如下:
  1. void main() //主程序
  2. {
  3. /*---C语言学习区域的开始---------------------------------------------------------------------------*/
  4.         
  5.   unsigned char a=0;  //观察这个数最后的变化
  6.   unsigned char b=0;  //观察这个数最后的变化
  7.   unsigned char c=0;  //观察这个数最后的变化


  8.   unsigned char i;  //控制循环体的条件判断变量

  9.   i=3;   
  10.   do
  11.   {
  12.      a=a+1;  //每执行一次循环体a就增加1,此行代码被循环执行了3次
  13.          i=i-1;  //i不断变小
  14.   }while(i); //i不断变小,当i变为0时才跳出此循环体



  15.   for(i=0;i<3;i++)
  16.   {
  17.      b=b+2;  //此行代码被循环执行了3次
  18.   }


  19.   for(i=3;i>0;i--)
  20.   {
  21.      c=c+3;  //此行代码被循环执行了3次
  22.   }



  23.      
  24.   GuiWdData0=a;   //把a这个变量放到窗口变量0里面显示
  25.   GuiWdData1=b;   //把b这个变量放到窗口变量1里面显示
  26.   GuiWdData2=c;   //把c这个变量放到窗口变量1里面显示
  27.         
  28. /*---C语言学习区域的结束---------------------------------------------------------------------------*/
  29.    while(1)  
  30.    {
  31.       initial();
  32.       key_service();
  33.       display_service();
  34.    }

  35. }
复制代码


        查看运算结果的方法。如何在坚鸿51学习板上观察变量?按下S1或者S5按键即可切换显示不同的窗口,从而显示不同的变量。按下S9按键不松手就可以切换到十六进制的显示界面,松开手后会自动切换到十进制的界面。16个LED灯显示的就是当前变量的二进制数,亮代表1,灭代表0。上坚鸿51学习板观察程序执行的结果如下:
        变量a为3。
        变量b为6。
        变量c为9。
         下节预告:循环体内的continue和break语句。
(未完待续)

乐于分享,勇于质疑!
57#
 楼主| 发表于 2015-11-30 09:34:25 | 显示全部楼层
本帖最后由 jianhong_wu 于 2015-11-30 09:39 编辑

第四十八节:循环体内的continue和break语句。

48.1   continue语句
        通常情况下,单片机在循环体里从上往下执行,一直执行到最底部的花括号才会返回到循环体入口处准备第二次循环,但是,如果在循环体中途遇到continue语句,单片机虽然没有执行到最底部的花括号,也会马上返回到循环体入口处准备第二次循环,在continue语句之后至最底部花括号之间的语句没有被执行到。比如:

while(…)或者for(…)   //循环体的条件判断入口处
{    //循环体开始
    语句1;   
    语句2;
    continue;
    语句3;

    ……   
    语句N;
}    //循环体结束

       分析:
       上述语句中,单片机从语句1开始执行到continue语句,然后马上就返回到循环体的条件判断入口处,也就是语句3至语句N是不可能被执行到的,上述语句简化后相当于:

while(…)或者for(…)   //循环体的条件判断入口处
{    //循环体开始
    语句1;   
    语句2;
}    //循环体结束

       既然可以如此简化,还要continue语句有什么用呢?我们一般应用continue的时候不会像上面那样单独使用,而是配合这if条件判断语句来用,这样continue才有它存在价值,比如:

while(…)或者for(…)   //循环体的条件判断入口处
{    //循环体开始
    语句1;   
    语句2;
    if(某条件)
    {
         continue;
    }
    语句3;

    ……   
    语句N;
}    //循环体结束


48.2    break语句
         continue语句是提前结束当前这一次的循环,准备进入下一次的新循环,是某次结束的概念。而break语句是直接跳出当前循环体,结束当前循环体,是整体结束的概念。
while(…)或者for(…)   //循环体的条件判断入口处
{    //循环体开始
    语句1;   
    语句2;
    break;
    语句3;

    ……   
    语句N;
}    //循环体结束
语句(N+1);  //循环体之外语句

      分析:
      上述语句中,单片机从语句1开始执行到break语句,无需判断while或者for的条件,直接马上跳出循环体,执行到循环体之外的语句(N+1)。在实际项目中,break往往也是会配合if条件判断语句一起使用,比如:

while(…)或者for(…)   //循环体的条件判断入口处
{    //循环体开始
    语句1;   
    语句2;
    if(某条件)
    {
         break;
    }
    语句3;

    ……   
    语句N;
}    //循环体结束
语句(N+1);  //循环体之外语句


48.3    break语句能跳多远
         break语句能跳多远?预知答案请先分析以下这个例子:

while(…)
{  
      语句1;   
      语句2;
        while(…)
      {   
           语句3;   
           break;
           语句4;
     }   
     语句5;
}   
语句6;

       上述例子中,在while循环里面有藏着第二个while循环,这种循环之中还有循环,通常称之为循环嵌套。单片机从上往下执行语句,当遇到break后,它会跳到语句5那里呢,还是会跳到语句6那里?正确答案是语句5那里。说明了break语句跳远范围仅仅刚好能跳出当前的循环体。在上述循环嵌套的例子中,最内层的break只能跳出最内层的循环体,不能跳到最外层的语句6那里,如果需要继续跳出最外层的语句6那里,可以继续在外层的循环体内再增加一个break语句。


48.4    还有哪些语句可以无条件退出循环体
         还有return和goto语句可以跳出循环体。这部分的内容大家只需大概了解一下即可。return语句比break语句还厉害,它不仅仅跳出当前循环体,还是跳出了当前函数,也就是提前结束了当前函数,这部分的内容后面章节会讲到,暂时不用管。而goto语句在C语言中大家都公认不建议用,因为它很容易扰乱大家常用的C语言编程结构,我本人也从来没有用过goto语句,所以这条语句我也不再深入讲解它。


48.5   编写程序
         编写一个程序来熟悉一下continue和break语句的使用。最后把程序编译后下载到坚鸿51学习板观察结果。请直接复制第十节模板程序,修改的main程序代码如下:
  1. void main() //主程序
  2. {
  3. /*---C语言学习区域的开始---------------------------------------------------------------------------*/
  4.         
  5.   unsigned char a=0;  //观察这个数最后的变化
  6.   unsigned char b=0;  //观察这个数最后的变化
  7.   unsigned char c=0;  //观察这个数最后的变化
  8.   unsigned char d=0;  //观察这个数最后的变化

  9.   unsigned char i;  //控制循环体的条件判断变量


  10. //i<6的条件判断是在进入循环体之前判断,而i的自加1是在执行完一次循环体之后才自加的。
  11.   for(i=0;i<6;i++)  
  12.   {
  13.      a=a+1;    //被执行了6次,分别是第0,1,2,3,4,5次
  14.      if(i>=3)
  15.      {
  16.         continue;  //提前结束本次循环,准备进入下一次循环
  17.      }
  18.      b=b+1;  //被执行了3次,分别是第0,1,2次
  19.   }


  20. //i<6的条件判断是在进入循环体之前判断,而i的自加1是在执行完一次循环体之后才自加的。
  21.   for(i=0;i<6;i++)  
  22.   {
  23.      c=c+1;   //被执行了4次,分别是第0,1,2,3次
  24.      if(i>=3)
  25.      {
  26.         break; //马上跳出当前循环体
  27.      }
  28.      d=d+1;   //被执行了3次,分别是第0,1,2次
  29.   }

  30.      
  31.   GuiWdData0=a;   //把a这个变量放到窗口变量0里面显示
  32.   GuiWdData1=b;   //把b这个变量放到窗口变量1里面显示
  33.   GuiWdData2=c;   //把c这个变量放到窗口变量2里面显示
  34.   GuiWdData3=d;   //把d这个变量放到窗口变量3里面显示
  35.         
  36. /*---C语言学习区域的结束---------------------------------------------------------------------------*/
  37.    while(1)  
  38.    {
  39.       initial();
  40.       key_service();
  41.       display_service();
  42.    }

  43. }
复制代码


       查看运算结果的方法。如何在坚鸿51学习板上观察变量?按下S1或者S5按键即可切换显示不同的窗口,从而显示不同的变量。按下S9按键不松手就可以切换到十六进制的显示界面,松开手后会自动切换到十进制的界面。16个LED灯显示的就是当前变量的二进制数,亮代表1,灭代表0。上坚鸿51学习板观察程序执行的结果如下:
       变量a为6。
       变量b为3。
       变量c为4。     
       变量d为3。
       下节预告:for和while的循环嵌套。
(未完待续)

乐于分享,勇于质疑!
58#
 楼主| 发表于 2015-12-5 23:32:59 | 显示全部楼层
本帖最后由 jianhong_wu 于 2015-12-6 11:15 编辑

第四十九节:for和while循环体的嵌套。

        49.1      循环体嵌套的执行顺序
         for循环体内又包含了for循环体可以称为循环体嵌套。比如:
for(i=0;i<2;i++)  //大循环
{
       语句1;
       for(k=0;k<3;k++) //内嵌的小循环
       {
               语句2;
       }
       语句3;
}
         上述例子中,带i的for称为大循环,带k的for称为小循环,单片机从大循环入口进来,由上往下执行,执行第1次大循环,先执行1次“语句1”,接着进入小循环,小循环要连续循环执行3次“语句2”才跳出小循环,之后执行1次“语句3”,然后再返回到大循环入口判断i条件是否满足,此时条件满足,继续执行第2次大循环,1次“语句1”,3次“语句2”,1次“语句3”,第2次循环结束后又返回到大循环入口判断i条件,此时i已经等于2不再小于2了,因此条件不满足,结束整个循环嵌套。上述执行的语句顺序如下:
         语句1;   //第1次大循环开始
         语句2;   
         语句2;
         语句2;
         语句3;
         语句1;   //第2次大循环开始
         语句2;
         语句2;
         语句2;
         语句3;
         根据此顺序,再看一个具体的程序例子:
a=0;  
b=0;
for(i=0;i<2;i++)  //大循环
{
     a=a+1;  //被执行了2次
     for(k=0;k<3;k++) //内嵌的小循环
     {
           b= b+1;  //被执行了6次
     }
}
         上述例子中,执行完程序后,a的值变成了2,b的值变成了6。重点分析b的变化,“b=b+1”在内嵌循环体里被执行了6次,6次从何而来?就是i乘以k等于6。这个乘法次数是循环嵌套一个很重要的特性。上述程序如果用while语句来实现如下:
a=0;  
b=0;
i=0;  //控制大循环的变量初始化
while(i<2)  //大循环
{
     a=a+1;  //被执行了2次
     k=0;    //控制小循环的变量初始化
     while(k<3) //内嵌的小循环
     {
         b= b+1;  //被执行了6次
         k=k+1;
    }
     i=i+1;
}


        49.2   循环嵌套的常见用途---二维数组的应用
         前面章节讲到了二维数组a[2][3],它有6个变量,在没有学for语句之前,要依次把每个元素单独赋值清零真不容易,要写6次赋值语句如下:
a[0][0]=0;
a[0][1]=0;
a[0][2]=0;
a[1][0]=0;
a[1][1]=0;
a[1][2]=0;
         自从懂了for嵌套语句之后,直接写代码如下,简洁了许多:
  1. for(i=0;i<2;i++)  //大循环
  2. {
  3.      for(k=0;k<3;k++) //内嵌的小循环
  4.      {
  5.           a[i][k]=0;
  6.       }
  7. }
复制代码


        49.3     循环嵌套的常见用途---大延时
        以后接触单片机项目后,会经常会用到delay这个延时函数,大部分都是利用for循环来实现,小延时函数往往不用嵌套,直接如下编写:
for(k=0;k<N;k++);  
      上述的N是控制循环次数,每次循环都要消耗单片机一点时间,如果N越大需要消耗的时间就越多,起到延时的作用。但是N所能取的最大值受它所定义的类型所限制,比如是unsigned char类型时最大范围是255,是unsigned int类型时最大范围是65535,是unsigned long类型时最大范围是4294967295。如果要实现更大的延时怎么办?就可以用for的循环嵌套,利用循环嵌套次数的乘法翻倍特性,很容易编写大的延时函数。比如:
for(i=0;i<M;i++)  //大循环
{
      for(k=0;k<N;k++); //内嵌的小循环
}
      此时循环的次数是N乘以M的乘积。
      现在编写一个循环嵌套的练习程序,最后把程序编译后下载到坚鸿51学习板观察结果。请直接复制第十节模板程序,修改的main程序代码如下:
  1. void main() //主程序
  2. {
  3. /*---C语言学习区域的开始---------------------------------------------------------------------------*/
  4.         
  5.   unsigned char a=0;  //观察这个数最后的变化
  6.   unsigned char b=0;  //观察这个数最后的变化
  7.   unsigned char c=0;  //观察这个数最后的变化


  8.   unsigned char i;  //控制大循环体的条件判断变量
  9.   unsigned char k;  //控制内嵌小循环体的条件判断变量

  10.   for(i=0;i<2;i++)  //大循环
  11.   {
  12.      a=a+1;    //被执行了2次
  13.      for(k=0;k<3;k++)  //内嵌小循环
  14.      {  
  15.           b=b+1;  //被执行了6次,也就是i乘以k,2乘以3等于6.
  16.      }
  17.      c=c+1;    //被执行了2次
  18.   }

  19.      
  20.   GuiWdData0=a;   //把a这个变量放到窗口变量0里面显示
  21.   GuiWdData1=b;   //把b这个变量放到窗口变量1里面显示
  22.   GuiWdData2=c;   //把c这个变量放到窗口变量2里面显示

  23.         
  24. /*---C语言学习区域的结束---------------------------------------------------------------------------*/
  25.    while(1)  
  26.    {
  27.       initial();
  28.       key_service();
  29.       display_service();
  30.    }

  31. }
复制代码


          查看运算结果的方法。如何在坚鸿51学习板上观察变量?按下S1或者S5按键即可切换显示不同的窗口,从而显示不同的变量。按下S9按键不松手就可以切换到十六进制的显示界面,松开手后会自动切换到十进制的界面。16个LED灯显示的就是当前变量的二进制数,亮代表1,灭代表0。上坚鸿51学习板观察程序执行的结果如下:
         变量a为2。
          变量b为6。
          变量c为2。
          下节预告:switch语句。
(未完待续)


乐于分享,勇于质疑!
59#
 楼主| 发表于 2015-12-14 23:11:17 | 显示全部楼层
本帖最后由 jianhong_wu 于 2015-12-14 23:16 编辑

第五十节:switch语句。
         switch是非常重要的语句,我几乎所有的单片机项目都是用switch搭建程序主框架。如果说while和for是一对孪生兄弟,那么if-elseif和switch也是一对孪生兄弟,凡是用switch语句能实现的功能都可以用if-elseif实现。switch有条件分支的功能,在条件超过3个以上的条件分支功能里,switch书写会比if-else if更加直观清晰。
         50.1      switch语句的语法
         以下是switch语句常见的格式:

switch(变量)    //根据变量的数值大小从对应的case入口进来
{
     case 0:   //入口0
         语句0;
         break; //switch程序体的出口之一
     case 1:  //入口1
         语句1;
         break; //switch程序体的出口之一
     case 2: //入口2
         语句2;
         break; //switch程序体的出口之一
}    //最下面的花括号也是一个switch程序体的出口之一

        执行顺序分析:
        单片机从switch(变量)进来,根据变量的数值大小,进入对应的case入口里。假如变量等于1,就直接进入到case 1入口,执行“语句1”后,遇到break语句就跳出整个switch程序体。假如变量等于3,单片机从switch(变量)进来,因为没有发现case 3,所以直接跳出switch程序体没有执行任何语句。多补充一句,在case 2选项中,语句2最后的break可以省略,因为case 2是最后一个case,即使没有遇到break也会遇到最下面的花括号而跳出switch程序体。上述程序功能如果用if-elseif语句来实现如下:

if(变量==0)
{
    语句0;
}
else if(变量==1)
{
    语句1;
}
else if(变量==2)
{
    语句2;
}


        50.2      switch语句的break
        大家从50.1的例子中看到了三个关键字分别是:switch,case,break。其实并不是每个case都必须要break配套,break只是起到一个出口的功能。假如没有遇到break,程序会一直往下执行,直到遇到break或者switch最下面的花括号为止。比如:

switch(变量)    //根据变量的数值大小从对应的case入口进来
{
     case 0:   //入口0
         语句0;
         break;
     case 1:  //入口1
         语句1;
     case 2: //入口2
         语句2;
         break;
     case 3: //入口3
         语句3;
         break;
}   //最下面的花括号也是一个switch程序体的出口之一

        执行顺序分析:
        假如此时switch(变量)的变量等于1,就直接进入到case 1入口,执行“语句1”后,没有遇到break语句,继续执行“语句2”,紧接着遇到break语句,才跳出整个switch程序体。本例子中case 1没有break语句,就继续往下执行下面case2里面的语句,直到遇到break或者最下面的花括号为止。

        50.3      switch语句的case有规定顺序吗?必须连贯吗?
switch程序体内部可以写很多case入口,这些case入口是不是必须按从小到大的顺序?是不是规定必须case数字连贯?答:没有规定顺序,也没有规定case数字连贯,case的数值只是代表入口。比如以下两种写法都是合法的:

        50.3.1    case不按从小到大的顺序:

switch(变量)   
{
     case 2:
         语句2;
         break;
     case 0:  
         语句0;
         break;
     case 1:  
         语句1;
         break;
}   

         50.3.2    case的数字不连贯
switch(变量)   
{
    case 0:  
         语句0;
         break;
     case 3:
         语句3;
         break;
     case 9:  
         语句9;
         break;
}   


         50.4      switch语句的default。
         default和break一样,也不是必须的语句,应根据程序需要来选择。default相当于if-else if-else 语句中的else,也就是当switch(变量)的变量没有匹配的case入口时,就会默认进入default入口,就像if-else if-else 语句中当前面所有的条件不满足时,就进入else语句的程序体,比如:

switch(变量)    //根据变量的数值大小从对应的case入口进来
{
     case 0:   //入口0
         语句0;
         break; //switch程序体的出口之一
     case 1:  //入口1
         语句1;
         break; //switch程序体的出口之一
     case 2: //入口2
         语句2;
         break; //switch程序体的出口之一
     default:  //当所有的case不满足,就进入default入口
         语句3;
         break;
}    //最下面的花括号也是一个switch程序体的出口之一

        执行顺序分析:
        假如switch(变量)的变量等于35,因为没有找到case 35,所以就直接从默认的default入口进来执行” 语句3”,然后遇到break语句就跳出switch程序体。上述程序功能如果用if-elseif-else语句来实现如下:

if(变量==0)
{
    语句0;
}
else if(变量==1)
{
    语句1;
}
else if(变量==2)
{
    语句2;
}
else   //相当于switch中的default
{
    语句3;
}


         50.5      switch语句中内嵌switch
         if语句也可以内嵌if语句,while语句也可以内嵌while语句,switch语句当然也可以内嵌switch。比如

switch(a)
{
   case 1:
        switch(b)
        {
             case 1:
                  Break;
             case 2:
                  Break;
        }
        Break;
   case 2:
        Break;
}

       这种switch内嵌switch语句也是合法的,而且在实际项目中也很常用,大家目前先有个大概的了解即可,暂时不深入讲解。

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


  1. void main() //主程序
  2. {
  3. /*---C语言学习区域的开始---------------------------------------------------------------------------*/



  4.   unsigned char k;   //此变量为switch的入口判断变量

  5.   unsigned char a; //观察此变量的变化来理解switch的执行顺序

  6.   a=0;
  7.   k=2;

  8.   switch(k)
  9.   {
  10.      case 0:  //入口0
  11.        a++;
  12.        break; //跳出switch
  13.      case 1:  //入口1
  14.        a++;
  15.      case 2:  //入口2,上述k等于2所以从这里进来
  16.        a++;
  17.      case 3:  //入口3
  18.        a++;
  19.      case 4:  //入口4
  20.        a++;
  21.        break;  //跳出switch
  22.      case 5:  //入口5
  23.        a++;
  24.        break;  //跳出switch
  25.      default: //入口default,相当于else。当前面没有遇到对应的case入口时,就默认进入此default入口
  26.        a++;
  27.        break;  //跳出switch
  28.   }            //最后一个switch的花括号也是跳出switch
  29.       
  30.   GuiWdData0=a;   //把a这个变量放到窗口变量0里面显示

  31.   
  32.         
  33. /*---C语言学习区域的结束---------------------------------------------------------------------------*/
  34.    while(1)  
  35.    {
  36.       initial();
  37.       key_service();
  38.       display_service();
  39.    }

  40. }
复制代码


        查看运算结果的方法。如何在坚鸿51学习板上观察变量?按下S1或者S5按键即可切换显示不同的窗口,从而显示不同的变量。按下S9按键不松手就可以切换到十六进制的显示界面,松开手后会自动切换到十进制的界面。16个LED灯显示的就是当前变量的二进制数,亮代表1,灭代表0。上坚鸿51学习板观察程序执行的结果如下:
        变量a为3。
        下节预告:空返回空形参的函数。
(未完待续)

乐于分享,勇于质疑!
60#
 楼主| 发表于 2015-12-20 01:20:41 | 显示全部楼层
本帖最后由 jianhong_wu 于 2015-12-20 01:25 编辑

第五十一节:函数的三要素和执行顺序。

        51.1   增加子函数内容后如何运用第10节模板程序调试
        前面章节讲的内容因为没有涉及到子函数,范例程序的编辑调试只需要在一个main主函数里操作就可以,原来的调试方式如下:
  1. void main() //主函数
  2. {
  3. /*---C语言学习区域的开始---------------------------------------------------------------------------*/
  4. unsigned char  a;  //普通局部变量的定义     
  5.   unsigned char  b;  //普通局部变量的定义   
  6.   ……     //一些程序代码
  7.   ……
  8.   ……
  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. }
复制代码

         本节开始增加子函数内容,所以以后的调试方式如下:

  1. /*---C语言学习区域的开始---------------------------------------------------------------------------*/
  2. void hanshu(void);  //子函数的声明
  3. unsigned char  x;  //全局变量的定义     
  4. unsigned char  y;  //全局变量的定义   
  5. void hanshu(void)  //子函数的定义
  6. {
  7.    unsigned char  c;  //普通局部变量的定义子函数的语句;
  8. ……
  9. }
  10. void main() //主函数
  11. {
  12. unsigned char  a;  //普通局部变量的定义     
  13.   unsigned char  b;  //普通局部变量的定义   
  14. ……     //其它一些程序代码
  15. hanshu() ; //子函数的调用
  16.   ……     //其它一些程序代码
  17. GuiWdData0=a;   //把a这个变量放到窗口变量0里面显示
  18. GuiWdData1=b;   //把b这个变量放到窗口变量1里面显示
  19.   ……      
  20. /*---C语言学习区域的结束---------------------------------------------------------------------------*/
  21.   while(1)  
  22.   {
  23.      initial();
  24.      key_service();
  25.      display_service();
  26.   }
  27. }
复制代码

        对比原来,现在的“C语言学习区域的开始”分割线往上移动增大了范围,其它部分内容不用变,还是直接在第10节的模板程序里更改和添加这部分的内容就可以了。


        51.2   函数的三要素。
        有的人习惯把函数称为程序,比如主程序,子程序,这时的主程序对应主函数,子程序对应子函数,是一回事,只是每个人的表达习惯不一样而已。函数的三要素是声明,定义,调用。新构造一个函数时,尽量遵守这个三个要素来做就可以减少一些差错。什么叫函数的声明,定义,调用?先让大家有一个感性的认识,请先看下面这个例程:

  1.   /*---C语言学习区域的开始---------------------------------------------------------------------------*/
  2. void hanshu(void);   //子函数的声明
  3. void hanshu(void)    //子函数的定义
  4. {
  5. ……     //子函数的代码语句
  6. }
  7. void main() //主函数
  8. {
  9. hanshu() ;      //子函数的调用
  10. /*---C语言学习区域的结束---------------------------------------------------------------------------*/
  11.   while(1)  
  12.   {
  13.       ……
  14.   }
  15. }
复制代码



         51.3   子函数在主函数里的执行顺序
        子函数被其它函数调用时,子函数的名字就相当于一个跳转地址,而子函数的定义就是要跳转的实际地址,单片机在主函数里遇到子函数名称,就直接跳转到子函数定义那里执行子函数定义部分的代码,执行完子函数后再返回到主函数,继续执行子函数名称后面部分的代码,请看下面这个代码的执行顺序,就可以一目了然:

  1. /*---C语言学习区域的开始---------------------------------------------------------------------------*/
  2. void hanshu(void);   //子函数的声明
  3. void hanshu(void)    //子函数的定义
  4. {
  5. 语句1;
  6. 语句2;
  7. }
  8. void main() //主函数
  9. {
  10. 语句3;
  11. hanshu() ;      //子函数的调用
  12. 语句4;
  13. /*---C语言学习区域的结束---------------------------------------------------------------------------*/
  14.   while(1)  
  15.   {
  16.       ……
  17.   }
  18. }
复制代码

        执行顺序分析:
        单片机从主函数main那里进来往下执行,先执行“语句3”,接着遇到hanshu名称的跳转地址,然后马上跳转到hanshu的定义部分,执行“语句1”,“语句2”,执行完子函数hanshu的定义部分,就马上返回到主函数,继续执行hanshu名称后面的“语句4”。整个执行语句的先后顺序如下:
        语句3;
        语句1;
        语句2;
        语句4;

        下节预告:普通局部变量和全局变量在函数里的作用域和优先级。
(未完待续)

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

本版积分规则

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

GMT+8, 2024-5-3 18:27 , Processed in 0.249588 second(s), 14 queries .

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