单片机如何赋值16位_单片机高八位赋值 - CSDN
  • 之前使用单片机编程时,通常会使用一些较为不专业的语句,现在和大家一起学习下常见的单片机赋值操作; 一、把变量的某清零 //定义一个变量 a = 1001 1111 b (二进制数) unsigned char a = 0x9f; //对 bit2 清零...

    之前使用单片机编程时,通常会使用一些较为不专业的语句,现在和大家一起学习下常见的单片机赋值操作;
    一、把变量的某位清零

    //定义一个变量 a = 1001 1111 b (二进制数) 
    unsigned char a = 0x9f;  
    //对 bit2 清零 
    a &= ~(1<<2); 
    //括号中的 1 左移两位,(1<<2)得二进制数:0000 0100 b  
    //按位取反,~(1<<2)得 1111 1011 b 
    //假如 a 中原来的值为二进制数: a = 1001 1111 b 
    //所得的数与 a 作”位与&”运算,a = (1001 1111 b)&(1111 1011 b), 
    //经过运算后,a 的值 a=1001 1011 b 13 // a 的 bit2 位被被零,而其它位不变
    

    使用 a&=~(1<<x);可以将第x位清零;

    二、把变量的某几个连续位清零

    //若把 a 中的二进制位分成 2 个一组  
    //即 bit0、bit1 为第 0 组,bit2、bit3 为第 1 组,  
    //  bit4、bit5 为第 2 组,bit6、bit7 为第 3 组 
    //要对第 1 组的 bit2、bit3 清零   
    a &= ~(3<<2*1);   
    
    //括号中的 3 左移两位,(3<<2*1)得二进制数:0000 1100 b 
    //按位取反,~(3<<2*1)得 1111 0011 b 
    //假如 a 中原来的值为二进制数: a = 1001 1111 b  
    //所得的数与 a 作”位与&”运算,a = (1001 1111 b)&(1111 0011 b),  
    //经过运算后,a 的值 a=1001 0011 b 14 // a 的第 1 组的 bit2、bit3 被清零,而其它位不变。 
    //上述(~(3<<2*1))中的(1)即为组编号;如清零第 3 组 bit6、bit7 此处应为 3 
    //括号中的(2)为每组的位数,每组有 2 个二进制位;若分成 4 个一组,此处即为 4 
    //括号中的(3)是组内所有位都为 1 时的值;若分成 4 个一组,此处即为二进制数“1111 b” 
    
    //例如对第 2 组 bit4、bit5 清零 
    a &= ~(3<<2*2);
    

    使用a&=~((2^m-1)<<m*n) m个为一组 第n组清零

    三、对变量的某几位进行赋值

    //a = 1000 0011 b 
    //此时对清零后的第 2 组 bit4、bit5 设置成二进制数“01 b ” 
     a |= (1<<2*2); 
    //a = 1001 0011 b,成功设置了第 2 组的值,其它组不变 
    

    使用a|=(Q<<m*n) m个为一组,设置第n组的值为Q

    四、对变量的某位取反

    //a = 1001 0011 b 
    //把 bit6 取反,其它位不变 
    a ^=(1<<6); 
    //a = 1101 0011 b 
    

    使用a^=(1<<m) 使第m位取反

    小结:赋值使用或|,清零使用与&,取反使用异或^

    希望可以对大家学习起到帮助。

    展开全文
  • =0xfe)//0xfe是结束,如果是0xfe也不进行数组赋值 { a[num1]=temp; num1++; } else if(temp==0xfe) //如果是接受到0xfe,那么结束,begin赋值0,不进入下次赋值,一直到接受到0XFF为止 { begin=0; num1=0;//...
  • 在8位单片机中没有16位数的操作指令,所有的int型数据都要通过两个字节分开操作,使用的方法不用,生成的代码也不相同,当然效率也不一样,通过指针对16位数进行操作可以得到高效的代码。 比如通过串行口接收数据,...

    在8位单片机中没有16位数的操作指令,所有的int型数据都要通过两个字节分开操作,使用的方法不用,生成的代码也不相同,当然效率也不一样,通过指针对16位数进行操作可以得到高效的代码。

        比如通过串行口接收数据,或者从串行的EEPROM中读取的数据,或者从大于8位的A/D读取的数据,由于8位单片机的数据线是8位的,高于8位的数据都要分成两个字节分别读取,然后写入到RAM中去再进行计算,或者把16位的int型数据从RAM中读出再分别把高低字节存到EEPROM或者送到D/A,或者通过串行口发送出去,方法有很多种,下面用多种方法进行实现该操作,这里只演示写入到16位的情况,读取的情况非常相似,不赘述。
    (1)使用联合 (union)
    typedef union{
        unsigned int i;
        unsigned char c[2];
    }u_int;
       unsigned char dH = 0x11, dL=0x22;
      unsigned int d;
    u_int ud;
    ud.c[0] = dH;
    ud.c[1] = dL;
    d = ud.i;
    此时d = 0x1122;
    (2) 使用移位指令
    数据定义与前面相同
    d = ((unsigned int)dH)<<8 +  dL;
    或者
    d = dH;
    d <<= 8;   // or: d = d<<8; 但后者编译的代码可能不是最简的
    d |= dL;    // or: d = d | dL;  后者编译的代码可能不是最简的
    (3)使用指针
    unsigned char *cptr;
    cptr = (unsigned char*)(&d);
    cptr[0] = dH;
    cptr[1] = dL;
    (4)强制指针类型转换
    *((unsigned char*)(&d)) = dH;
    *((unsigned char*)(&d)+1) = dL;

    ((unsigned char*)(&d))[0] = dH;
    ((unsigned char*)(&d))[1] = dL;
    这两种方式看似相同但由Keil编译出的代码是不用的,前都有一次加法运算,而后者没有,后者生成的代码更简洁,这种方式与用联合成生的代码是完全一样的,
    在这几种方法中第(1)与第(4)的第二种生成的代码是最乘洁的,是推荐使用的,从软件工程的角度出发,推荐使用方法(1),这样没有强制类型转换,没有用到指针,更不容易出错。从书写的代码来讲,第(4)的第二种方法是最好的,代码简洁而且效率最高,但语法有点儿复杂。

    展开全文
  • [存储种类] 数据类型 [存储器类型] 变量名表  在定义格式中除了数据类型和变量名表是必要的,其它都是可选项。存储种类有四种:自动(auto),外部(extern),静态(static)和寄存器(register),缺省类型为...

    [存储种类] 数据类型 [存储器类型] 变量名表

      在定义格式中除了数据类型和变量名表是必要的,其它都是可选项。存储种类有四种:自动(auto),外部(extern),静态(static)和寄存器(register),缺省类型为自动(auto)。
      而这里的数据类型则是和我们在第四课中学习到的名种数据类型的定义是一样的。说明了一个变量的数据类型后,还可选择说明该变量的存储器类型。存储器类型的说明就是指定该变量在C51硬件系统中所使用的存储区域,并在编译时准确的定位。表6-1中是KEIL uVision2所能认别的存储器类型。注意的是在AT89C51芯片中RAM只有低128位,位于80H到FFH的高128位则在52芯片中才有用,并和特殊寄存器地址重叠。特殊寄存器(SFR)的地址表请看附录二 AT89C51特殊功能寄存器列表

    存储器类型

    说 明

    data

    直接访问内部数据存储器(128字节),访问速度最快

    bdata

    可位寻址内部数据存储器(16字节),允许位与字节混合访问

    idata

    间接访问内部数据存储器(256字节),允许访问全部内部地址

    pdata

    分页访问外部数据存储器(256字节),用MOVX @Ri指令访问

    xdata

    外部数据存储器(64KB),用MOVX @DPTR指令访问

    code

    程序存储器(64KB),用MOVC @A+DPTR指令访问


    表6-1 存储器类型
      如果省略存储器类型,系统则会按编译模式SMALL,COMPACT或LARGE所规定的默认存储器类型去指定变量的存储区域。无论什么存储模式都可以声明变量在任何的8051存储区范围,然而把最常用的命令如循环计数器和队列索引放在内部数据区可以显著的提高系统性能。还有要指出的就是变量的存储种类与存储器类型是完全无关的。
       SMALL存储模式把所有函数变量和局部数据段放在8051系统的内部数据存储区这使访问数据非常快,但SMALL存储模式的地址空间受限。在写小型的应用程序时,变量和数据放在data内部数据存储器中是很好的因为访问速度快,但在较大的应用程序中data区最好只存放小的变量、数据或常用的变量(如循环计数、数据索引),而大的数据则放置在别的存储区域。
       COMPACT存储模式中所有的函数和程序变量和局部数据段定位在8051系统的外部数据存储区。外部数据存储区可有最多256字节(一页),在本模式中外部数据存储区的短地址用@R0/R1。
       LARGE存储模式所有函数和过程的变量和局部数据段都定位在8051系统的外部数据区外部数据区最多可有64KB,这要求用DPTR数据指针访问数据。
       之前提到简单提到sfr,sfr16,sbit定义变量的方法,下面我们再来仔细看看。
       sfr和sfr16可以直接对51单片机的特殊寄存器进行定义,定义方法如下:
         sfr 特殊功能寄存器名= 特殊功能寄存器地址常数;
         sfr16 特殊功能寄存器名= 特殊功能寄存器地址常数;

       我们可以这样定义AT89C51的P1口
    sfr P1 = 0x90; //定义P1 I/O口,其地址90H
       sfr关键定后面是一个要定义的名字,可任意选取,但要符合标识符的命名规则,名字最好有一定的含义如P1口可以用P1为名,这样程序会变的好读好多。等号后面必须是常数,不允许有带运算符的表达式,而且该常数必须在特殊功能寄存器的地址范围之内(80H-FFH),具体可查看附录中的相关表。sfr是定义8位的特殊功能寄存器而sfr16则是用来定义16位特殊功能寄存器,如8052的T2定时器,可以定义为:
         sfr16 T2 = 0xCC; //这里定义8052定时器2,地址为T2L=CCH,T2H=CDH
    用sfr16定义16位特殊功能寄存器时,等号后面是它的低位地址,高位地址一定要位于物理低位地址之上。注意的是不能用于定时器0和1的定义。
       sbit可定义可位寻址对象。如访问特殊功能寄存器中的某位。其实这样应用是经常要用的如要访问P1口中的第2个引脚P1.1。我们可以照以下的方法去定义:

    (1)sbit 位变量名=位地址

    sbit P1_1 = Ox91;
    这样是把位的绝对地址赋给位变量。同sfr一样sbit的位地址必须位于80H-FFH之间。
    (2)Sbit 位变量名=特殊功能寄存器名^位位置
    sft P1 = 0x90;
    sbit P1_1 = P1 ^ 1; //先定义一个特殊功能寄存器名再指定位变量名所在的位置
    当可寻址位位于特殊功能寄存器中时可采用这种方法
    (3)sbit 位变量名=字节地址^位位置
    sbit P1_1 = 0x90 ^ 1;
       这种方法其实和2是一样的,只是把特殊功能寄存器的位址直接用常数表示。
      在C51存储器类型中提供有一个bdata的存储器类型,这个是指可位寻址的数据存储器,位于单片机的可位寻址区中,可以将要求可位录址的数据定义为bdata,如:
    unsigned char bdata ib; //在可位录址区定义ucsigned char类型的变量ib
    int bdata ab[2]; //在可位寻址区定义数组ab[2],这些也称为可寻址位对象
    sbit ib7=ib^7 //用关键字sbit定义位变量来独立访问可寻址位对象的其中一位
    sbit ab12=ab[1]^12;
       操作符"^"后面的位位置的最大值取决于指定的基址类型,char0-7,int0-15,long0-31。
    下面我们用上一课的电路来实践一下这一课的知识。同样是做一下简单的跑马灯实验,项目名为RunLED2。程序如下:

    sfr P1 = 0x90; //这里没有使用预定义文件,
    sbit P1_0 = P1 ^ 0; //而是自己定义特殊寄存器
    sbit P1_7 = 0x90 ^ 7; //之前我们使用的预定义文件其实就是这个作用
    sbit P1_1 = 0x91; //这里分别定义P1端口和P10,P11,P17引脚
    void main(void)
    {
    unsigned int a;
    unsigned char b;
    do{
    for (a=0;a<50000;a++)
    P1_0 = 0; //点亮P1_0
    for (a=0;a<50000;a++)
    P1_7 = 0; //点亮P1_7
    for (b=0;b<255;b++)
    {
    for (a=0;a<10000;a++)
    P1 = b; //用b的值来做跑马灯的花样
    }
    P1 = 255; //熄灭P1上的LED
    for (b=0;b<255;b++)
    {
    for (a=0;a<10000;a++) //P1_1闪烁
    P1_1 = 0;
    for (a=0;a<10000;a++)
    P1_1 = 1;
    }
    }while(1);
    }


    转自:http://blog.sina.com.cn/s/blog_739afc250100vbpj.html



    展开全文
  • 玩了接近三年的单片机,816位、32的都玩过,突然间一个问题就让我发现我就是一个渣!!! 816位、32都代表什么意思呢?我就根据搜集的知识,简单的对自己科普一下:  1)、 从CPU的发展史来看,从以前...

            玩了接近三年的单片机,8位、16位、32位的都玩过,突然间一个问题就让我发现我就是一个渣!!!

    8位、16位、32位都代表什么意思呢?我就根据搜集的知识,简单的对自己科普一下:

          1)、 从CPU的发展史来看,从以前的8位到现在的64位,8位也就是CPU在一个时钟周期内可并行处理8位二进字符0或是1,那么16就以此类推是64位就64位二进制。

          2)、8位、16位、32位单片机的区别还有就是寄存器位数的区别,8位的单片机其寄存器也是8位,以此类推32位的MCU也就是有32位的寄存器(当然他也可以有16或者是8位的寄存器)。

            还有在学习ARM里遇到的一个问题:寻址空间的问题。

            寻址空间一般指的是CPU对于内存寻址的能力。Intel公司早期的CPU产品的地址总线和地址寄存器的宽度为20位,即CPU的寻址能力为2^20=1024*1024字节=1024K字节

    =1M字节;286的地址总线和地址寄存器的宽度为24位,CPU的寻址能力为2^24=1024*4*1024*4B=4*1024*4KB=16M;386及386以上的地址总线和地址寄存器的宽度为32位,

    CPU的寻址能力为2^32=4096M字节=4G字节。 也就是说,如果机器的CPU过早,即使有很大的内存也不能得到利用,而对于现在的PⅡ级的CPU,其寻址能力已远远超过目前的

    内存容量。

            在这里有一个很重要的概念:CPU的寻址能力以字节为单位 。以32位的单片机为例(最近在上手K60),对地址0x4000 0001进行赋值也就是对一个字节进行操作,32位的寄

    存器就需要占用4个地址(8*4=32),那它占有的地址就为0x4000 0000----0x4000 0003。32位就代表了2^32的寻址空间也就是4G。

            一些简单的问题写出来,有什么不对之处,烦请各位过路的朋友指正!

    展开全文
  • 816位、32是指单片机的“字长”,也就是一次运算中参与运算的数据长度,这个是指二进制。以8为例,8二进制的表达范围是0000,0000~1111,1111即进制的0~255,即每次参与运算的数据最大不能超过255。...

    8位、16位、32位是指单片机的“字长”,也就是一次运算中参与运算的数据长度,这个位是指二进制位。以8位为例,8位二进制的表达范围是0000,0000~1111,1111即十进制的0~255,即每次参与运算的数据最大不能超过255。而16位机的字长是16位,其数据表达范围是0~65535,即每次参与运算的数据最大不能超过65535;32位单片机的字长是32位,其数据表达范围是0~4294967295,即每次参与运算的数据最大不能超过4294967295。

    8位、16位、32位与单片机的性能密切相关,通常32位机的性能要高于16位机,而16位机的性能又要高于8位机。为什么会这样呢?这要从2个方面来分析。第一,位数不同,运算效率不同。对于8位机而言,由于在一次运算中的每一个数都不能超过8位,因此即便如100+200=300这样的运算,它也不能一次完成,因为300已超过了8位所能表达的最大范围(255),因此,要对这样的一个式子进行运算,就要编写一段程序,将运算分步完成,最后合成起来得到一个正确的结果。而如果采用16位单片机来运算的话,那么一次运算就够了,显然分步完成所需要的时间要远远大于单步完成所需要的时间。同样道理,当某个运算的结果或者中间值大于65535时,16位机也不能一次运算,要分步实现它,而32位机则可以一次运算完成。第二,商业因素。通常运算能力越高,表示这个单片机性能越强,当然,价格高一些人们也可以接受,有了价格空间,生产商通常都会在这些芯片中提供更多的其他的功能,使得芯片的整体性能得到更大的提升。

    典型的单片机中,80C51系列,PIC系列,AVR系列都是8位单片机;80C196、MSP430系列是16位机;而目前非常热门的ARM系列则是32位机。

     

    另外在CSDN的讨论中的一些比较好的回答:
    =================================
    8位单片机,典型的是51系列的,再高级点用AVR、pic的,功能方面,似乎都不会很复杂,一般可能是控制类的多一下。一般不跑嵌入式OS。
    16位的单片机,我接触的主要是MSP430,感觉16位的单片机比较尴尬,高不成低不就,要求低一点,8位MCU就够,高级点不如用32位MCU。一般不跑嵌入式OS。16位就不说了
    32位的,就高级点了,一般能跑嵌入式OS,例如ucos2,ucos3,uclinux等等,能做更多复杂的功能。用OS和不用OS的话,编程的思路差异比较大。功能一般有面向控制的,也有简单消费类电子的。
    ================================
    8位16位32位的区别就在于地址位和数据位位宽不同。其实都一样。比如8位的51单片,网上同样有人在上面移植ucos。16位的如430就更不用说了。32位的目前大多数是arm架构的,与前面的8位、16位的指令集不同。除掉前面的boot会用一小段汇编(主要是来clear寄存器,初使化堆栈--有些书上也叫栈)其它大多用C.只要用对应架构和平台的编译器就可以了。故而作为一个c的RD,不需要考虑太多。
    =================================
    都玩过,单纯C写代码没啥区别,一般编译器把初始化都做了,需要改的不多。汇编或者调试的时候会有区别,指令集不一样,寄存器也会有点差异(尤其是跟汇编的时候),参数传递时会有差异(因编译器而异),8位51单片机是(R0-R7),32位ARM是R0-R15(PC),然后就是int类型,8/16位通常是16bit,32位下是32bit(最蛋疼的是64位下int还是32bit)
    =================================
    学嵌入式的网友,接触到的 32 位机往往是 ARM 内核的,运行 Linux。

    但实际上,32 位的微处理器远不止这一类。有些就是增强版本的微处理器,例如 M*Core 内核的微处理器。

    32 位机的功能模块寄存器可以是 32-bit 的(当然也可以是 8-/16-bit),而且存取都是单时钟周期。CPU 的算逻单元也是 32 位的,当然,运算会更快。

    32 位机的一个重要注意事项是 32-bit 字的自然边界问题,也就是字对齐问题。例如,要从 RAM 中将一个 32-bit 的字写入一个 32-bit 寄存器,那么,这个字在 RAM 中的地址必须是 32-bit 对齐的,也就是说地址最低十六进制位是 0, 4, 8, c。如果不是这样(比如数据类型是 char,又恰好其起始地址未 4 字节对齐),需要先将此字复制到一个 32-bit 对齐的缓存,再赋值。

    还有一个比较麻烦的事,就是用户定义的结构中各个成员的对齐。如果在一个 32-bit 类型的成员前面,有 char 及 short 类型成员,且没有凑齐到 32-bit 自然边界,那么编译器将会自动补 NULL 来填充。有不少从 8 位向 32 位机移植代码的朋友,都在取成员长度的时候发生疑惑。问题往往是出在 32-bit 对齐上。

    在有就是不同编译器的规约差异。

    不过,用过两种微处理器之后,就会渐渐熟悉起来,相互移植也不会有很大困难。

    =============================

    数据总线的宽度为8、16、32。同时寄存器也达到相同位数。
    ============================
    多少位宽不是指总线宽度,也不是存储器的宽度,像51单片机的地址总线是16位的,但是它是8位机。像ARM的存储器也有八位的,但是它是32位机。而是指CPU处理的数据的宽度,也就是CPU一次数据的吞吐量。比如同一条指令:MOV R0 R2
    在51单片机里面,R0和R2都是8位的,所以51的CPU一次只能处理8位数据。
    在ARM里面,R0和R2是32位的,所以ARM的CPU一次能处理32位数据。这就是区别

     

    转载于:https://www.cnblogs.com/qsyll0916/p/7726595.html

    展开全文
  • 单片机 数组 赋初值

    2019-07-14 11:13:40
    C:char 数组赋值 2018年11月26日 20:51:15SSS_369阅读数 47 版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/sss_369/article/details/84556179 定义一个数组char a[10]; 怎么给这...
  • 在对单处机进行编程的过程中,对位的操作是经常遇到的。...在这一节中将详细讲解C51中的操作及其应用。 1、运算符 C51提供了几种操作符,如下表所示: 运算符 含义 运算符 含义
  • 操作特殊寄存器,有时需要对同一寄存器配置多次,而每一次如果进行直接赋值的话,会把前一次的赋值覆盖掉,这样就不能实现应有的功能。所以为了不改变前面的设置,而用逻辑与或进行配置。 如果要将某一位置1,其他...
  •  今天在做单片机的一个小程序,本来以为改一改例子程序很简单,结果耗费了一一整天时间。程序中用了很多strcat函数对字符串进行拷贝,我为了增强程序的通用性,就把原来字符串的地方用char数组代替。结果出现了很多...
  • 单片机通信是指单片机与计算机或单片机单片机之间的信息交换。通信方式有并行和串行两种方式。由于单片机的接口资源是比较宝贵的,采用并口通信会占用比较多的接口资源,所以信息的交换多采用串行通信的方式。 ...
  • 单片机操作知识

    2019-11-02 19:23:50
    void main(void) { while (1) { gLed1 = 0; // 点亮LED Delay(); // 延时一段时间 gLed1 = 1; // 熄灭LED Delay(); // 延时一段时间 } ... // 0b01111111,左边数第1颗LED...
  • bit,sbit,sfr,sfr16都用于单片机的C语言编程。 bit—定义变量,定义变量时可以为变量赋值,但不能指定变量的地址。定义格式:bit 变量名=变量值。 sbit—此类型变量只要用于访问可寻址的特殊功能寄存器中的...
  • 目的:利用“模块化单片机教学实验平台”,加深对单片机与LED数码管的接口电路设计以及程序设计的理解。 任务:完成单片机与LED数码管的接口电路设计以及程序设计。 实验内容 使用AT89S52单片机的I/O口控制两个...
  • 将变量a的第30位置1,其他保持不变。 a|=1<<30; 将变量a的第24、30位置1,其他保持不变。 a|=(1<<30)|(1<<24); 将变量a的第30取反,其他保持不变。 a^=(1<<30); 将变量a的第...
  • //串口引脚切换 //参数说明 port :串口号 ConfigPin :引脚指定 void UartChangePin(u8 port,u8 ConfigPin) { if(0==port) { /* // P_SW1 = 0x00; //RXD /P3.0, TXD /P3.1 // P...
  • 51单片机作为下机程序,本代码段实现两个功能: 1、控制LED灯按指定规则显示 2、将接收的上位机数据返回给上位机 源代码在这儿:http://download.csdn.net/detail/tingzhiyi/9173485 #include #include ...
  • 单片机的C语言中操作用法作者:郭天祥 在对单处机进行编程的过程中,对位的操作是经常遇到的。C51对位的操控能力是非常强大的。从这一点上,就可以看出C不光具有高级语言的灵活性,又有低级语言贴近硬件的特点。...
  • 寻址指的是这个寄存器中各位值可以直接调用 如:可寻址的IE中有八位EA - ET2 ES ET1 EX1 ET0 EX0可以直接用ET2=1来操作; 不可寻址的TMOD只能用TMOD=0... 不可以未开控制其中的某一,不可以单独赋值给某一
1 2 3 4 5 ... 20
收藏数 8,647
精华内容 3,458
关键字:

单片机如何赋值16位