[51单片机]

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

[复制链接]
楼主: jianhong_wu
手机看帖
扫描二维码
随时随地手机跟帖
huaiqiao| | 2015-5-29 08:50 | 显示全部楼层
顶,吴大哥的原创

使用特权

评论回复
jianhong_wu|  楼主 | 2015-5-31 07:50 | 显示全部楼层
第二十节:减法运算的5种常见格式。
      请先看以下的减法语法格式:
       “保存变量”=“减数1”-“减数2”-...-“减数N”;
        含义是:右边的“减数”与“减数”相减,并且把最终的运算结果赋值给左边的“保存变量”。注意,这里的符号“=”不是等于号的意思,而是赋值的意思。左边的“保存变量”必须是变量,不能是常量,否则编译时会报错。右边的“减数”既可以是变量,也可以是常量,也可以是“保存变量”本身自己。多说一句,何谓变量和常量?变量是可以在程序中被更改的,是被分配的一个RAM空间。常量往往是数字,或者是被分配在ROM空间的一个具体数值。下面根据右边“被减数”与“减数”的不同组合,列出了减法运算的5种常见格式。
      第1种:“减数1”是常量,“减数2”是常量。比如:
unsigned char a;
a=15-3;
数字“15”和“3”都是常量。执行上述语句后,保存变量a变成了12。
      第2种:“减数1”是变量,“减数2”是常量。比如:
unsigned char b;
unsigned char x=15;
b=x-10;
x是变量,“10”是常量。由于原来x变量里面的数值是15,执行上述语句后,保存变量b变成了5。而变量x则保持不变,x还是15。
      第3种:“减数1”是变量,“减数2”是变量。比如:
unsigned char c;
unsigned char x=15;
unsigned char y=6;
c=x-y;
x是变量,y也是变量。由于原来x变量里面的数值是15,y变量里面的数值是6,执行上述语句后,保存变量c变成了9。而变量x和y则保持不变,x还是15,y还是6。
      第4种:“减数1”是保存变量本身,“减数2”是常量。比如:
unsigned char d=18;
d=d-2;
d=d-7;
d是保存变量,“2”和“7”都是常量。这类语句有一个特点,具备了自减功能,可以更改自己本身自己的数值。比如原来保存变量d的数值是18,执行“d=d-2;”语句后,d变成了16,接着再执行完“d=d-7;”语句后,d最后变成了9。
      第5种:“减数1”是保存变量本身,“减数2”是变量。比如:
unsigned char e=28;
unsigned char x=15;
unsigned char y=6;
e=e-x;
e=e-y;
e是保存变量,x与y都是变量。这类语句有一个特点,具备了自减功能,可以更改自己本身自己的数值。比如原来保存变量e的数值是28,执行“e=e-x;”语句后,e变成了13,接着再执行完“e=e-y;”语句后,e最后变成了7。
       现在编写一个程序来练习上述5种格式的减法语句,最后把程序编译后下载到坚鸿51学习板观察结果。请直接复制第十节模板程序,修改的main程序代码如下:

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

  //第1种:“减数1”是常量,“减数2”是常量。
  a=15-3;
        
        
  //第2种:“减数1”是变量,“减数2”是常量。
  b=x-10;
        
        
  //第3种:“减数1”是变量,“减数2”是变量。
  c=x-y;
        
        
  //第4种:“减数1”是保存变量本身,“减数2”是常量。
  d=d-2;
  d=d-7;
        
        
  //第5种:“减数1”是保存变量本身,“减数2”是变量。
  e=e-x;
  e=e-y;


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

        
/*---C语言学习区域的结束---------------------------------------------------------------------------*/
   while(1)  
   {
      initial();
      key_service();
      display_service();
   }

}

        如何在坚鸿51学习板上观察a,b,c,d,e这5个变量?按下S1或者S5按键即可切换显示不同的窗口,从而显示不同的变量。上坚鸿51学习板观察程序执行的结果如下:
变量a为12。
变量b为5。
变量c为9。
变量d为9。
变量e为7。
     下节预告:减法的连写和自减运算的简写。
(未完待续)

使用特权

评论回复
huaxiang600| | 2015-5-31 15:02 | 显示全部楼层
更新快点呗

使用特权

评论回复
yuanquan12345| | 2015-6-1 16:24 | 显示全部楼层
学习。

使用特权

评论回复
tony0727| | 2015-6-2 20:45 | 显示全部楼层
一直在学,一直学不深,有什么建议么,鸿哥

使用特权

评论回复
787833238| | 2015-6-5 15:22 | 显示全部楼层
学习了

使用特权

评论回复
jianhong_wu|  楼主 | 2015-6-8 07:51 | 显示全部楼层
第二十一节:减法的连写和自减运算的简写。
     连减。上一节我列举的减法例子中,右边的减数只有一个。实际上,C语言规则没有限制减数的个数,它的通用格式如下:
      “保存变量”=“被减数”-“减数1”-“减数2”-...-“减数N”;
      被减数与减数的属性。当右边的减数个数总共超过1个的时候,就是我所说的“连减”。被减数和减数的属性没有限定,可以是常量,也可以是变量。比如:
     a=68-3-15;     //被减数和减数全部是常量。
     b=q-x-y-k;    //被减数和减数全部是变量。
     c=63-x-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);
       自减的特殊简写。在自减运算中,只有一个减数,并且这个减数是常数1时,格式如下:
     “保存变量”=“保存变量”-1;
       这时候,可以把上述格式简写成如下两种格式:
     “保存变量”--;
     --“保存变量”;
       这两种格式也是俗称的“自减1”操作。比如:
      g--;  //相当于g=g-1或者g-=1;
      --h;  //相当于h=h-1或者h-=1;
        自减1符号“--”可以在变量的左边,也可以在变量的右边,它们在这里本质是一样的,没有差别。当然,如果是在循环条件语句中,这时自减1符号“--”在左边还是在右边是有一点点微弱的差别,这方面的内容以后再讲。
        上机练习。现在编写一个程序来练习刚才讲到的内容,最后把程序编译后下载到坚鸿51学习板观察结果。请直接复制第十节模板程序,修改的main程序代码如下:

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

        
  unsigned char q=50;    //定义一个变量q,并且分配了1个字节的RAM空间。初始化默认为50.
  unsigned char x=3;    //定义一个变量x,并且分配了1个字节的RAM空间。初始化默认为3.
  unsigned char y=6;     //定义一个变量y,并且分配了1个字节的RAM空间。初始化默认为6.        
  unsigned char k=2;     //定义一个变量k,并且分配了1个字节的RAM空间。初始化默认为2.

  //第1个知识点:连减。
  a=68-3-15;//被减数和减数全部是常量。a的结果为:50。
  b=q-x-y-k;//被减数和减数全部是变量。b的结果为:39。
  c=63-x-5-k;//被减数和减数,有的是常量,有的是变量。c的结果为:53。
       
       
  //第2个知识点:自减的常规格式。   
  d-=6;//相当于d=d-6;  d的结果为:59。
  e-=x;//相当于e=e-x;  e的结果为:35。
  f-=18-y-k;//相当于f=f-(18-y-k);  f的结果为:19。
       
       
  //第3个知识点:自减的特殊格式。
  g--;//相当于g=g-1或者g-=1;  g的结果为:4。
  --h;//相当于h=h-1或者h-=1;  d的结果为:4。
         

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



        
/*---C语言学习区域的结束---------------------------------------------------------------------------*/
   while(1)  
   {
      initial();
      key_service();
      display_service();
   }

}

      查看运算结果的方法。如何在坚鸿51学习板上观察a,b,c,d,e,f,g,h这8个变量?按下S1或者S5按键即可切换显示不同的窗口,从而显示不同的变量。上坚鸿51学习板观察程序执行的结果如下:
      变量a为50。
      变量b为39。
      变量c为53。
      变量d为59。
      变量e为35。
      变量f为19。
      变量g为4。
      变量h为4。
       下节预告:减法运算的溢出。
(未完待续)

使用特权

评论回复
czdo| | 2015-6-8 09:03 | 显示全部楼层
不错,再支持一下!!!

使用特权

评论回复
czdo| | 2015-6-8 09:10 | 显示全部楼层
写的很不错啊!!楼主有知识啊

使用特权

评论回复
ayl439| | 2015-6-9 15:38 | 显示全部楼层
楼主的**还是很好的~支持一下

使用特权

评论回复
ansile| | 2015-6-10 13:05 | 显示全部楼层
强烈支持


http://www.szsybdz.com

使用特权

评论回复
单片机亚| | 2015-6-10 22:31 | 显示全部楼层
赞~~

使用特权

评论回复
aaron96031| | 2015-6-12 08:55 | 显示全部楼层
LZ很有心,有时间多写写,将来也可以为后来人作为一个借鉴。加油!

使用特权

评论回复
jianhong_wu|  楼主 | 2015-6-17 21:49 | 显示全部楼层
本帖最后由 jianhong_wu 于 2015-6-17 21:52 编辑

第二十二节:减法运算的溢出。
        在开始本章节之前,先纠正一下前面第17节内容的一个小bug。我原文中写道:
        “保存变量”+=“加数1”+“加数2”+...+“加数N”;
相当于:
       “保存变量”=“保存变量”+“加数1”+“加数2”+...+“加数N”;
当时我没有考虑到优先级,漏了一个括号,修改后,相当于:
       “保存变量”=“保存变量”+(“加数1”+“加数2”+...+“加数);这样才算比较准确。同理,我后面所举的例子:
         f+=18+y+k; //相当于f=f+18+y+k;
在注释中也漏了一个括号,应该是:
        f+=18+y+k; //相当于f=f+(18+y+k);
       上述多一个括号或者少一个括号虽然看似不影响运算结果,但是运算顺序是有点不一样的。




        现在正式开始讲本节减法溢出的问题。英文“unsigned”的中文意思就是”无符号的”,延伸含义是“无负号无负数”的意思,所以unsigned char ,unsigned int ,unsigned long这三种类型数据都是无负号无负数的,取值只能是0和正数,那么问题来了,当被减数小于减数的时候,运算结果会是什么样子,有什么规律?
(1)第一个例子:
unsigned char a;
a=0-1;

分析:
左边的“保存变量”a的数据长度是1个字节8位,a=0-1可以看成是十六进制的a=0x00-0x01。由于0x000x01小,所以假想一下需要向高位借位,借位后成了a=0x100-0x01。所以a的最终结果是0xff(十进制是255)。根据”假想借位”这个规律,如果是b也是unsigned char 类型,那么b=2-5自然就相当于b=0x102-0x05,运算结果b等于0xfd(十进制是253)
(2)第二个例子:
unsigned int c;
c=0-1;

分析:
左边的“保存变量”c的数据长度是2个字节16位,c=0-1可以看成是十六进制的c=0x0000-0x0001。由于0x00000x0001小,所以假想一下需要向高位借位,借位后成了c=0x10000-0x0001。所以c的最终结果是0xffff(十进制是65535)。根据”假想借位”这个规律,如果是d也是unsigned  int 类型,那么d=2-5自然就相当于b=0x10002-0x0005,运算结果b等于0xfffd(十进制是65533)
         为了验证上述抛出的”假想借位”,现在编写一个程序来练习刚才讲到的内容,最后把程序编译后下载到坚鸿51学习板观察结果。请直接复制第十节模板程序,修改的main程序代码如下:


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

        
        
  unsigned char a;       //定义一个变量a,并且分配了1个字节的RAM空间。
  unsigned char b;       //定义一个变量b,并且分配了1个字节的RAM空间。
  unsigned int c;        //定义一个变量c,并且分配了2个字节的RAM空间。
  unsigned int d;        //定义一个变量d,并且分配了2个字节的RAM空间。

   //第一个例子,针对a与b都是unsigned char类型数据。     
   a=0-1;  
   b=2-5;
        
        
        //第二个例子,针对c与d都是unsigned int类型的数据。
   c=0-1;
   d=2-5;        


   GuiWdData0=a;   //把变量a这个数值放到窗口变量0里面显示
   GuiWdData1=b;   //把变量b这个数值放到窗口变量1里面显示
   GuiWdData2=c;   //把变量c这个数值放到窗口变量2里面显示
   GuiWdData3=d;   //把变量d这个数值放到窗口变量3里面显示
        
/*---C语言学习区域的结束---------------------------------------------------------------------------*/
   while(1)  
   {
                  initial();
      key_service();
      display_service();
   }

}


      查看运算结果的方法。如何在坚鸿51学习板上观察a,b,c,d这4个变量?按下S1或者S5按键即可切换显示不同的窗口,从而显示不同的变量。按下S9按键不松手就可以切换到十六进制的显示界面,松开手后会自动切换到十进制的界面。上坚鸿51学习板观察程序执行的结果如下:

      变量a为0xff(十进制是255)
      变量b为0xfd(十进制是253)
      变量c为0xffff(十进制是65535)
      变量d为0xfffd(十进制是65533)

       下节预告:建议减法运算前先把所有变量转换成同一数据类型再参与运算。
(未完待续)

使用特权

评论回复
yuanquan12345| | 2015-6-18 16:38 | 显示全部楼层
谢了。

使用特权

评论回复
jianhong_wu|  楼主 | 2015-6-21 08:43 | 显示全部楼层
第二十三节:建议把所有参与减法运算的变量都转换成unsigned long数据类型。
    不管是以前讲的加法,现在讲的减法,还是未来讲的乘法和除法,我都会强烈建议“请把所有参与运算的变量都转成unsigned long类型”。unsigned long变量是三种数据类型中取值范围最大的数,取值范围可达04294967295之间,用了此类型变量的运算,不会轻易导致运算溢出的问题。有细心读者会问,万一数据超过了4294967295怎么办?答:可用BCD码的数组方式进行运算。这种数组运算的方法我在《从业将近十年,手把手教你单片机程序框架》里用了好几个章节跟大家介绍过,初学者暂时不用深入学习它。
变量转换的方法是引入中间变量,有多少个需要转换的变量就引入多少个中间变量,请看下面这个例子。
转换之前:
unsigned int  a;
unsigned char x=195;
unsigned long y=101;
a=x-y;

分析:上述公式用到3个变量,其中ax都不是unsigned long变量,因此需要为它们分别引入中间变量ts
转换之后:
unsigned int  a;
unsigned char x=195;
unsigned long y=101;

unsigned long t; //引入的中间变量,用来替代a
unsigned long s; //引入的中间变量,用来替代x。

s=0;  //s在接收x原数据之前先把高位和低位全部清零。因为s和x的数据宽度不一。
s=x;  //接收x原数据,相当于把x转换成unsigned long中间变量。

t=s-y;  //此处的t就默认代表了变量a。

本章虽短,但是此方法在实际项目中很重要,大家不可大意。
     下节预告:乘法运算的5种常见格式。
(未完待续)

使用特权

评论回复
xmlovelives| | 2015-6-24 20:24 | 显示全部楼层
学习

使用特权

评论回复
vilan| | 2015-6-25 09:38 | 显示全部楼层
泛泛之谈

使用特权

评论回复
ghl137| | 2015-6-26 21:35 | 显示全部楼层
准备学习学习

使用特权

评论回复
ghl137| | 2015-6-26 21:40 | 显示全部楼层
jianhong_wu 发表于 2015-2-25 21:01
非常赞同。先学会使用才能进一步研究它的原理。

好主意

使用特权

评论回复
发新帖 本帖赏金 10.00元(功能说明)我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则