分享

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

 个人图书收藏38 2017-08-19



第三十五节:移位运算的右移。
        右移的运算符号是“>>”,语法格式如下:
        保存变量=被移数>>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)。

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


662#jianhong_wu

2015-9-13 08:59:49
第三十六节:括号改变优先级。
        C语言的加减乘除,与或取反,左移右移等运算符是有严格优先级顺序的,但是我本人记忆力有限,做项目哪能记住这么多优先级的前后顺序,只是大概明白乘除的优先级比加减的优先级高,其它方面真的记不住那么多,怎么办?为了确保万一,我用到了括号。
       括号的用法跟我们日常的数据运算公式的用法一直,先运行括号里面的运算,再执行其它运算。比如:
a=a<>
       到底是先把变量a左移2位后再加5,还是先2加5等于7再让变量a左移7位?对于像我这样不能熟记C语言运算优先级顺序的人,这条语句很容易让我搞混。但是加上括号就明了:
a=(a<>
a=a<>
      不用多说,加上括号后,上述两行代码传递了清晰的优先级顺序。再看一个例子:
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;  >
  10.   b=b<(2+5);  >

  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判断语句和等于关系符“==”。
     (未完待续)


663#求知大单

2015-9-13 14:19:30
很好。学习一下学习一下学习一下

664#好学生=我要学习

2015-9-13 20:02:13
写的很好,简单易懂,好好学习

665#jttanians

2015-9-17 21:30:12

说的很好,学习了............

666#jttanians

2015-9-17 21:33:45

谢谢楼主的帖子,学习了

667#jttanians

2015-9-17 21:37:17

很好的帖子!学习学习

668#zbg39

2015-9-18 11:30:15
多谢楼主。要好好看看。希望对自己有帮助。

669#yit1268

2015-9-18 11:32:12
谢谢你,学习了不少东西

670#yit1268

2015-9-18 11:33:09
继续学习,当一个好学生

671#saberwt

2015-9-18 11:49:58
dddddddddddddddddddddddddddd

672#yit1268

2015-9-18 14:09:36
好东西,不断学习中

673#yit1268

2015-9-18 14:17:26
引用: jianhong_wu 发表于 2015-4-16 20:08
第十三节:二进制与字节单位,以及各种定义变量的取值范围。       为什么是二进制?人类日常生活明明是十进制的,为何数字电子领域偏要选择二进制?这是由数字硬件电路决定的。人有十个手指头,人可以发出十种不同声音来命名0,1,2,3...9这些数字,人可以肉眼识别十种不同状态的信息,但是数字电路要直接处理十进制却很难, ...

写的非常好,受教了

674#yit1268

2015-9-18 15:48:50
支持,继续学习

675#yit1268

2015-9-18 16:06:47
说的很好,通俗易懂

676#jianhong_wu

2015-9-20 06:20:43
第三十七节: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。
         下节预告:等于关系符“==”和不等于关系符“!=”。
(未完待续)

677#qq741931893

2015-9-20 10:25:03
顶一下你  你也辛苦了

678#暴躁的小黄瓜

2015-9-24 16:37:50
吴老师我想问下 if(常量)这个语句的具体应用有哪些 因为在小括号里放一个常量这个的语句似乎不多见

679#偶尔路过

2015-9-24 18:10:21
不断学习不断解决问题!

680#jianhong_wu

2015-9-26 09:58:11
第三十八节:等于关系符“==”和不等于关系符“!=”。
       上一节讲了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. }


    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多