八位单片机ad如何采集20位AD发出的有符号数

单片机中带符号数的表示法及运算规则
一、机器数与真值 二、原码 按上所述,正数的符号位用 0 表示,负数的符号位用 1 表示,这种表示法就称为原码。 X =+ 105 [X] 原=
X =- 105 [X] 原=
三、反码 正数的反码表示与原码相同,最高位为符号位,用 0 表示正,其余位为数值
X105 [X]X105 [X]
4100 0 0 0 0 1 0 0
31100 0 0 1 1 1 1 1127100 1 1 1 1 1 1 1 内容来自单片机之家www.dpj100.com 4100 0 0 0 0 1 0 0
4101 1 1 1 1 0 1 1 ----
31100 0 0 1 1 1 1 131101 1 1 0 0 0 0 0 ----
127100 1 1 1 1 1 1 1127101 0 0 0 0 0 0 0 ----
00 0 0 0 0 0 0 001 1 1 1 1 1 1 1 ----
4440 0 0 0 0 1 0 0
1271271270 1 1 1 1 1 1 1
1 40 0 0 0 0 1 0 0 内容来自单片机之家www.dpj100.com 41 1 1 1 1 0 1 1 4
41 1 1 1 1 1 0 0 1310 0 0 1 1 1 1 1 内容来自单片机之家www.dpj100.com
311 1 1 0 0 0 0 0311 1 1 0 0 0 0 1
00 0 0 0 0 0 0 001 1 1 1 1 1 1 1
00 0 0 0 0 0 0 081000 0 0 0 0 0 0 0
28127128 内容来自单片机之家www.dpj100.com 3&0&)&1&1
X1 0 0 1 0 1 0 0 0 0 1 0 1 0 0
1 1 0 1 0 1 111 1 0 1 1 0 010810
641064106410 内容来自单片机之家www.dpj100.com 640 1 0 0 0 0 0 0100 0 0 0 1 0 1 0101 1 1 1 0 1 1 0
64 0 1 0 0 0 0 0 010
0 0 0 0 1 0 1 0 内容来自单片机之家www.dpj100.com
-------------- ----- -----------------------------------------------------------------------------------------------54 0 0 1 1 0 1 1 064 0 1 0 0 0 0 0 010 ------& (+) 1 1 1 1 0 1 1 0
-------------- ----- ----------------------------------------------------------------------------------------------1 0 0 1 1 0 1 1 018 内容来自单片机之家www.dpj100.com 734-68=34+68
340 0 1 0 0 0 1 0680 1 0 0 0 1 0 0
681 0 1 1 1 1 0 034 0 0 1 0 0 0 1 0+(-68) + 1 0 1 1 1 1 0 0
-------------- ----- -------------------------------------&--------------------------------------------------------------- 34 1 1 0 1 1 1 1 0 1
0 1 0 0 0 1 03434 内容来自单片机之家www.dpj100.com
8D7D6D0 内容来自单片机之家www.dpj100.com 01XB91
------分隔线----------------------------
手工汇编的概念:在汇编语言程序设计中,简单的程序可用手工的方式编程,即采用键盘输...
单片机的内部有ROM、有RAM、有并行I/O口,那么,除了这些东西之外,单片机内部究竟还...
要让灯持续地闪烁,这就有一定的实用价值了,比如能把它当成汽车上的一个信号灯用了。...05-1502-1602-1602-1602-1602-1602-1602-1602-1602-16最新范文01-0101-0101-0101-0101-0101-0101-0101-0101-0101-0101-0101-0101-0101-0101-01能不能把高八位和低八位合起来,成为一个16位数
例如TH1=0DH,TL1=EFH,把他们合起来成为0DEFH放在寄存器里
temp=(TH1&&8)|TL1;
2楼的不行的
TH1左移8位后是0
楼上有试过吗?
【3楼】 chess01 =CHESS
你为什么不去写一下再说呢?
我并没有改变TH1和TL1的值,我只读取它们的值。
2楼的写法的确在不同的编译器或不同的优化下,会有不同的结果
1楼的写法比较可靠
【6楼】 avr741
你可以举个例子说明下在哪种编译器的编译结果会不正确。
如果你想要多打几个字或要标准的话,那你可以这么用,不过我觉得有点多余。
temp=((unsigned int)(TH1&&8))|TL1;
&&temp=((unsigned int)(TH1&&8))|TL1;
这样的结果还是和2楼的差不多,有两个可能的转换点会出错
第一&&TH1是8位的 (TH1&&8) 就有可能是用8位的移位 , 移完的结果 = 0
第二&&TL1也是8位的, 16位和8位的作逻辑操作, 也有可能只用8位的运算,结果也是8位的,再赋值给16位的temp,也只是高8位補0而已
【8楼】 avr741
请用你说的这种编译器切图出来说明你说的是对的。
我在5楼说过了,我只是读取TH1和TL1,并没有对TH1和TL1进行移位等操作。
而且一般的编译器对这种移位8次不是实际的移位,而是真接赋值,将低位的值直接赋值给高位。
而且对TL1的或运算也是直接赋值的,而不会进行或运算。(这样效率相当高)
我用联合体的。。-。-!
我也觉得联合体比较方便,既方便拆分,又方便合起来,而且没有计算过程,
可以看下这个帖子http://www.wang1jin.com/bbs/viewthread.php?tid=464&highlight=%C1%AA%BA%CF%CC%E5
联合体也是一种高效的方法,但是需要定义,写的麻烦。
我的方法实际上的操作跟联合体是一样的操作(没有计算过程),但不需要定义。
逆过程用:
unsigned char x,y;
x=temp&&8;&&//取高位
y=& &&&//取低位
我一时没法找到之前会出问题的旧编译器
但我贴上另一种写法16+16=32,就是用IAR AVR 4.30A
(原文件名:test.JPG)
1楼的写法结果完全正确
而2楼写法会报错,编出来的代码也不对
【13楼】 avr741
我觉得不是编译器的问题,是你的问题,你有没想过1楼的为什么能通过,而我的通不过?
我想编译器默认的类型为16的整型,
我取一个8位数移动8位,它还在16位的范围内,
而你将一个16位数移16位,已经超出了16位的范围,所以你是错的,正确的写法是这样,你可以试试:
temp=(((unsigned long)OCR1B)&&16)|OCR1A;
(原文件名:test2.JPG)
结果是正确的,也就是5楼的会比2楼的好
5L:&如果你想要多打几个字或要标准的话,那你可以这么用,不过我觉得有点多余。 &
结论,不是多余的!
注意我红线标出来的警告,那又是另一个问题
还有,用联合体要注意,不是每个编译器都高8位和低8位在内存的摆放顺序都是一样的,就是大端和小端的差别
真是不嫌麻烦,我都用 (TH1*256+TL1) ,还没遇到哪个编译器能傻到连乘2^N都真的产生乘法指令.
【16楼】 avr741
。。。我很无语,7楼是对之前所说的(temp=((unsigned int)(TH1&&8))|TL1;)情况。
你把它放到了16+16上能怪谁呢? 能有简单的写法,或默认值,你何必要去写复杂的呢?
你指的红线的问题可以不用管,如果你一定要去掉这个警告,请这么写代码:
unsigned int h,l;
temp=(((unsigned long)h)&&16)|l;
回复【17楼】shark
真是不嫌麻烦,我都用 (th1*256+tl1) ,还没遇到哪个编译器能傻到连乘2^n都真的产生乘法指令.
-----------------------------------------------------------------------
我也一直这么干的
其实方法是很多了
(th1*256+tl1)也是一个不错的方法, 因为数据量很小,但是这个应该是不够高效的
th1*256没问题,问题在后面+tl1,是一个16位的加法。
&。。。我很无语,7楼是对之前所说的(temp=((unsigned int)(TH1&&8))|TL1;)情况。 &
&你把它放到了16+16上能怪谁呢? 能有简单的写法,或默认值,你何必要去写复杂的呢? &
&我想编译器默认的类型为16的整型, &
既然你的前提是默认值是16位,如果碰到默认值不是16位整型的C编译器呢? 也许是8位的,也许是32位的
1楼的方法不但8+8可以用,16+16也没问题
我之所以故意要用16+16来让IAR出错,只是要点出,你2楼的方法不能算是通用的,就算在现今大多主流的编译器都没问题
但是这样的写法当要移植到别的编译器或芯片,可能会出错,编译器会报错那还算是好事
如果编译器不会报错,编出来的代码,你就慢慢DEBUG吧!
【21楼】 avr741
引用&我之所以故意要用16+16来让IAR出错&
你牛,原来是你故意出错的啊?(我希望真的是这样的)
temp=(TH1&&8)|TL1;
还是那句话,你给我找个会编译得不到正确结果的编译器。
我从来没说一楼的方法不好或不对,如果认为一楼好就用一楼了,就算我多嘴好了。
我只是想给大家一个更好的方法而以,没办法,再多嘴一句,如果用一楼的需要改改:
temp+=TL1;& &//原内容
temp|=TL1;& &//改动的地方
这样就是一个纯赋值语句了,代码量会少,执行时间也会变短。
回复【23楼】hsztc
我从来没说一楼的方法不好或不对,如果认为一楼好就用一楼了,就算我多嘴好了。
我只是想给大家一个更好的方法而以,没办法,再多嘴一句,如果用一楼的需要改改:
temp=th1;&&
temp&&=8;&&
temp+=tl1;& &//原内容
temp=th1;&&
temp&&=8;&&
temp|=tl1;& &//改动的地方
这样就是一个纯赋值语句了,代码量会少,执行时间也会变短。
-----------------------------------------------------------------------
同意【23楼】 hsztc ,效率高而且可靠不容易出错~
这个 就用1楼的就可以了
就这么一两行程序没必要那么较真&&影响不到哪儿去
看来TFT的16位数据可以这样写了
赞同hsztc 的方法,我也认为hsztc 的方法技高一筹。
晕,没想到这么一个问题引发了这么大的讨论
回复【17楼】shark
真是不嫌麻烦,我都用 (th1*256+tl1) ,还没遇到哪个编译器能傻到连乘2^n都真的产生乘法指令.
-----------------------------------------------------------------------
我一般也是这么干的,有时候用指针+强制类型转换
u8 * t[2];
x=*((u16 *)t);
x即为所求;注意不同的单片机下高低字节顺序不同,像avr和stm32就是相反的,用时需要注意th与tl的顺序。
建议直接使用数组里的元素替代tl与th,x可以是个u16的指针,初始化的时候直接指向t,这样转换起来几乎不花时间。
此法在读16位以上adc的spi时很方便,一个指针传过去,spi寄存器的值直接写到u8的数组里,读的时候强制类型转换成u16就行了。也可以把一个u16数的地址转换成u8的当函数变量,函数结束后u16数的值就是所需的了。用法多样,很灵活。
特别是有24位、或者多路数据的时候,特别节省运算时间。
【29楼】 ilawp
你的方法其实就是共用体(联合体)的变型了。
union uni2Byte
& && &&&unsigned char t[2];
union uni2B
x.t[0]=TH1;
x.t[1]=TL1;
x.all就是所求的16位数。(同样要注意大小端问题)
这种方法效率是最高的,数据量大时可以这么用,数据量不大感觉写的麻烦。
简单点,就是个联合体,如楼上所说,最简单
typedef union LONGDATA{& && && && && & // Access LONGDATA as an
& && && && && && &// unsigned long variable or
& &unsigned char Byte[4];& && && && &&&// 4 unsigned byte variables
}LONGDATA;
static LONGDATA rawV
rawValue.Byte[Byte3] = 0x00;
rawValue.Byte[Byte2] = (unsigned char)ADC0H;
rawValue.Byte[Byte1] = (unsigned char)ADC0M;
rawValue.Byte[Byte0] = (unsigned char)ADC0L;
mV = rawValue.result / 6710;& && &&&// Because of bounds issues, this
union & & & &
{& & & & /*定义占用一个字的共用体,可以实现字或两个字节的存取*/
& & & & uint16_t d16;
& & & & uint8_t&&d8[2];& & & & //d8[0]存放dat16低位,d8[1]存放dat16高位
回复【17楼】shark&&
真是不嫌麻烦,我都用 (th1*256+tl1) ,还没遇到哪个编译器能傻到连乘2^n都真的产生乘法指令.
-----------------------------------------------------------------------
th1是8位的,不会溢出?
回复【33楼】rube 永丰庵
回复【17楼】shark& &
真是不嫌麻烦,我都用 (th1*256+tl1) ,还没遇到哪个编译器能傻到连乘2^n都真的产生乘法指令.
-----------------------------------------------------------------------
th1是8位的,不会溢出?
-----------------------------------------------------------------------
又不把结果放入th1
我五楼就说了这么写只是读取TH1的值,并没有操作TH1,很多人都认为TH1是8位的,怎么移位都是8位的。
(原文件名:447.JPG)
注意这三行.尤其是第三行,就是 (TH1&&8) , 结果等于 0
22&&MOV& &A, 0x22& &&&[& & 34]
50&&MOV& &0x10, A& &&&[& & 16]
D0&&CLR& &0x10& && &&&[& & 16]
但是1楼的写法编出来的代码没问题
& & temp=((unsigned short int)(TH1&&8))|TL1;
编出来的代码
22&&MOV& &A, 0x22& &&&[& & 34]& &TH1
52&&MOV& &0x12, A& &&&[& & 18]
D2&&CLR& &0x12& && &&&[& & 18]& &&&8
12&&MOV& &A, 0x12& &&&[& & 18]& &(unsigned short int)
52&&MOV& &0x12, A& &&&[& & 18]
D3&&CLR& &0x13& && &&&[& & 19]
23&&MOV& &A, 0x23& &&&[& & 35]& &TL1
00000A: 0050&&MOV& &0x10, A& &&&[& & 16]
00000B: 00D1&&CLR& &0x11& && &&&[& & 17]
00000C: 0410&&MOV& &A, 0x10& &&&[& & 16]& &|
00000D: 0252&&OR& & 0x12, A& &&&[& & 18]
00000E: 0411&&MOV& &A, 0x11& &&&[& & 17]
00000F: 0253&&OR& & 0x13, A& &&&[& & 19]
12&&MOV& &A, 0x12& &&&[& & 18]& &temp=
60&&MOV& &0x20, A& &&&[& & 32]
13&&MOV& &A, 0x13& &&&[& & 19]
61&&MOV& &0x21, A& &&&[& & 33]
12&&RET& && && && && && && &
和2楼的结果一样,是错的
&我五楼就说了这么写只是读取TH1的值,并没有操作TH1,很多人都认为TH1是8位的,怎么移位都是8位的。 &
回家好好把C语言的型(type)及型转换(type casting)看一遍,就会知道为什么 &很多人& 都说 &TH1是8位的,怎么移位都是8位的&
【38楼】 avr741
7楼应该是个笔误,你试试这个(请参考15楼的写法)
temp=(((unsigned short int)TH1)&&8)|TL1;
如果这样还不行的话,说明你的译编器OUT了。
叫我回去看书的你是第二个,请推存本书能够说明我这句话是错的
&我五楼就说了这么写只是读取TH1的值,并没有操作TH1,很多人都认为TH1是8位的,怎么移位都是8位的。 &
to【40楼】 hsztc&&
--------------------------------
印象中按C语言标准,移位操作前char应自动转换int然后再执行,所以
TH1&&8的值应该等价于 ((int)(TH1))&&8 ,但不排除某些8位机编译器不做这个转换(比如36楼的EMC的编译器),所以后者可以算作加了一个保险吧。
这个编译器我试过了, 15楼的 和 17楼的TH1*256+TL1 都是正确的, 这个编译器是这家公司的网站上目前最新的版本(2009年的)
不是这个编译器OUT, 也不是我牛,能让IAR出错(16+16时)
而是你在2楼和7楼的写法就是有潜在的问题!
我想任何一本C语言的书都会提到 型转换(type casting) 而且还有分 指示性(强制性的)和非指示性(自动的)型转换
你的问题就在于 &非指示性(自动的)型转换& 出了问题, 这个你自己回去去看书吧 网上也找得着这类的说明
以你上面的态度,我提醒你的已经够多了
【42楼】 avr741
我说的有错吗?请回答我40楼问题,如果temp=(((unsigned short int)TH1)&&8)|TL1;&&
这样写还有问题的话,这编译器真OUT了,切出图来看看?
不过有一点我真得认错,temp=(TH1&&8)|TL1; 还真有编译&出错&的编译器,确实有不一样的情况,长见识了。
IAR并没有出错,出错的是你,IAR只是对你写的内容进行编译,只能说编译的结果和你想要的不一样而以。
如果你表达清楚了你的意思,IAR就能编译出你所要的结果。
每个方法都有特定的局限性,如果不知道怎么灵活应用,只会照搬的话难免出错。
出错了又知道怎么去改,就出来大叫,这样会让我很郁闷,还得花大把时间跟你解释,
如果你知道哪里有问题你直接说出来就行了,把你可行的方法说出来,而不是举反面例子。
至于你为什么叫我看型类转换我真搞不明白。
关于态度问题,你应该得反省下,随便叫人回家看书是不尊重人的,你去坛里转转有几个敢这么说别人的。
&请回答我40楼问题,如果temp=(((unsigned short int)TH1)&&8)|TL1;&&&
我都说了,15楼(也就是40楼)的算法没错,你看仔细点
&不过有一点我真得认错,temp=(TH1&&8)|TL1; 还真有编译&出错&的编译器,确实有不一样的情况,长见识了。 &
现在肯认错了就好 如果还不认错,我就学习1楼的不解释 3楼的不回应以保持论坛的和谐
等那天你设计生产出来的产品出了这个问题,你去跟老板认错吧!
&每个方法都有特定的局限性,如果不知道怎么灵活应用,只会照搬的话难免出错。 &
1楼的方法没有一个编译器会出问题,包括16+16=32也不会
17楼的 TH1*256+TL1 也不会出问题
为什么你2楼的算法就有局限性? 自己出了问题还怪别人&不知道怎么灵活应用,只会照搬&?
&出错了又知道怎么去改,就出来大叫,&& &应该是少了一个&不&&&&出错了又不知道怎么去改&
看看我的原文 &注意我红线标出来的警告,那又是另一个问题& 这只是我提醒你还有别的问题
你当真以为我是天堂里的猪脑袋,不知道怎么改吗? 来求你告诉我怎么改吗?
&关于态度问题,你应该得反省下,随便叫人回家看书是不尊重人的,你去坛里转转有几个敢这么说别人的。 &
因为这是很基本的问题,书上都有,叫你回家看书的我也不是第一个(这是你说的,我也不知道还有谁也叫你回家看书)
我只是提醒你的写法可能会有问题,那你动不动叫我截图出来给你看,动不动叫我花时间去找编译器,就不会不尊重人吗?
&如果你知道哪里有问题你直接说出来就行了,把你可行的方法说出来,而不是举反面例子。 &
&至于你为什么叫我看型类转换我真搞不明白。&
其实真正的问题,我在这个主题其中一个贴子已经解释过了
可能你看我积分很少,认为我所说的话都是没价值的,是不可信的,甚至是错的,所以你根本不用心看
才会叫你回家看书,因为书上说的,你总不能不信吧!
hsztc 并没有理解数据类型转换,而且太不谦虚。
avr741 很有耐心。
简单的说有些编译器能自动转换数据类型,但不是所有的编译器都会这么做,TH1&&8的结果是什么取决于TH1的数据类型!
之所以 TH1&&8 或 TH1*256 能得到正确的结果是因为编译器自动进行了转换。
2楼的写法垃圾。
鉴定完毕。
回复【47楼】aviator
hsztc 并没有理解数据类型转换,而且太不谦虚。
avr741 很有耐心。
简单的说有些编译器能自动转换数据类型,但不是所有的编译器都会这么做,th1&&8的结果是什么取决于th1的数据类型!
之所以 th1&&8 或 th1*256 能得到正确的结果是因为编译器自动进行了转换。
-----------------------------------------------------------------------
*256应该比较安全,因为256已经超过u8的范围了,编译器只要不傻就会自动转换成int来算
【44楼】 avr741
&请回答我40楼问题,如果temp=(((unsigned short int)TH1)&&8)|TL1;&&&
我都说了,15楼(也就是40楼)的算法没错,你看仔细点
------------------------------------------------------------------------------
这个很说明问题了,你就是来显的,既然你看出了问题,你在8楼就应该指出
“temp=((unsigned int)(TH1&&8))|TL1;”
这么写是错的,应该这么写
“temp=(((unsigned int)TH1)&&8)|TL1;”
下面就少浪费多少时间在这上面。而7楼的写法确实是有问题的,后来才发现的
(unsigned int)放错了位置,在40楼已经指出了。之所以要省掉这句(unsigned int)就是为了写法上的简化
真没想到会有编译器不能正确编译,所以在7楼把(unsigned int)加了上去,但没注意看加错了位置。
而且我真没遇到过不能编译的正确编译器,所以基本省略掉了这句,你不切个图我无法相信。
-----------------------------------------------------------------------------------------
&每个方法都有特定的局限性,如果不知道怎么灵活应用,只会照搬的话难免出错。 &
1楼的方法叫通用性强,我指的是我的方法存在的优化有局限性,我的方法在写法上和算法上存在优化,
而优化不是随随便便都行的,需要跟踞不同的编译器和不同类型的单片机而有所不同。
而我7楼给出的是在写法上没有省略的写法,所以可以和一楼一样通用,不存在局限性。
(别在这挑骨头,指的是7楼修正后的“temp=(((unsigned int)TH1)&&8)|TL1;”)
&出错了又知道怎么去改,就出来大叫,&& &应该是少了一个&不&&&&出错了又不知道怎么去改&
看看我的原文 &注意我红线标出来的警告,那又是另一个问题& 这只是我提醒你还有别的问题
你当真以为我是天堂里的猪脑袋,不知道怎么改吗? 来求你告诉我怎么改吗?
-------------------------------------------------------------------------
我知道你知道怎么改,但你就是不改,你得说我的不行啊,改了怎么显的你是对的呢?
叫你截图我觉得不存在问题,我确实没见过会出错的编译器,所以想看看。
不过看了你编译器出的代码,感觉这个编译器效率很低,简单的算法生成一堆代码。
至于叫我回家看书的确实你不是第一个,还有个我们坛的年过60的老前辈,刚搜了下地址,见22楼
学学人家是怎么说的。积分不是问题,你看看这个前辈积分多少,不过积分少的来找事的确实会多点。
先上一张截图,是别的网站的,部分ID已隐去
(原文件名:60elder.JPG)
先看看别人是如何立马认错的,再看看你自己的态度又是如何
看来你还是没有找到问题的关键,只会在什么7楼,15楼,40楼,编译器的效率很低上面作文章
【5楼】 hsztc
积分:1112
等级:------
来自:福建省
【3楼】 chess01 =CHESS
你为什么不去写一下再说呢?
我并没有改变TH1和TL1的值,我只读取它们的值。&&
==========================================
不是搞人身攻攻击哈,你在2楼的写法想都不用想,它就是错的。
TH1与TL1是没变,但var=(TH1&&8)这个var始终是0
回复【52楼】MZ_Guo
不是搞人身攻攻击哈,你在2楼的写法想都不用想,它就是错的。
th1与tl1是没变,但var=(th1&&8)这个var始终是0
-----------------------------------------------------------------------
看看C99的标准是怎么说的:
(原文件名:shift.JPG)
&& 操作符要求两个操作数都是integer类型的,如果不是则自动提升为integer类型。
所以TH&&8和((int)(TH))&&8 是等价的,不过某些编译器没有遵循标准。
&&& 操作符要求两个操作数都是integer类型的,如果不是则自动提升为integer类型&
&所以TH&&8和((int)(TH))&&8 是等价的,&
这个是对的!
&不过某些编译器没有遵循标准。 &
如过你是说EMC的话, 这个不是事实
既然你遇到问题已经有去查书了,比起 hsztc 好太多,我就提醒你看一下我在21楼的
&既然你的前提是默认值是16位,如果碰到默认值不是16位整型的C编译器呢? 也许是8位的,也许是32位的 &
应该可以解释你在41楼的疑惑
【51楼】 avr741
你扯远了,我不想在这问题上再和你浪费时间。
不过得说在2楼和7楼上确实犯了错。
2楼没有考虑到某些编译器的问题。
7楼存在笔误,正确写法在15楼和40楼。
【52楼】 MZ_Guo
不是搞人身攻攻击哈,你在2楼的写法想都不用想,它就是错的。
-----------------------------------------------------------
想都不用想?今天让你开开眼界。
“TH1与TL1是没变,但var=(TH1&&8)这个var始终是0 ”
如果var为int呢?
var=TH1&&8;&&这还是始终是0吗?
希望大家看了以上两行能明白我说的。
我也切些图给你看看。
最后回复一次,是非由大家自己分辩。
我说话是很直,但很真,从不拐弯抹角,没办法天生就这样,得罪人的请多包含。
51的KEIL够专业吧,难道它也会错,IAR呢? ICCAVR呢?我电脑上就这几个C编译器,很负责的告诉你
这几个软件编译2楼temp=(TH1&&8)|TL1; 都是又简捷又准确。
KEIL,IAR FOR 51 ,ICCAVR,IAR FOR AVR 没有一个编译(temp=(TH1&&8)|TL1; )这段代码结果超过5条汇编指令的。
对比【36楼】 avr741 到 【38楼】 avr741&&的这个软件,生成一堆堆的汇编又是错的。
所以遇到偏冷的编译器的时候还是老老实实的写全代码。
(原文件名:iarfor511.PNG)
(原文件名:iarfor512.PNG)
这是IAR FOR 51的结果,红色框内为生成的(temp=(TH1&&8)|TL1;)
(原文件名:keil1.PNG)
(原文件名:keil2.PNG)
这是KEIL C51的结果,红色框内为生成的(temp=(TH1&&8)|TL1;)
(原文件名:icc1.PNG)
(原文件名:icc2.PNG)
这是ICCAVR的结果,红色框内为生成的(temp=(TH1&&8)|TL1;)
(原文件名:iarforavr1.PNG)
(原文件名:iarforavr2.PNG)
这是IAR FOR AVR的结果,红色框内为生成的(temp=(TH1&&8)|TL1;)
打个注解:刚回来看到有回复了,所以在这边写回复,没想到写的时间长了点,当时并没有看到53楼和54楼,提交后才看到的。
回复【54楼】avr741
如过你是说emc的话, 这个不是事实
-----------------------
我只用过GCCAVR,IAR,KEILC,PC上用过VC,BC,GCC ,没用过EMC编译器,如果EMC的int是16位的话,你的截图看来,EMC并没有遵循标准,当然如果它的int是8位的另当别论,但它实际上并不是8位的int。
&既然你的前提是默认值是16位,如果碰到默认值不是16位整型的c编译器呢? 也许是8位的,也许是32位的 &
-----------------------------------------------------------------------
或许4位机的int是8位的,不过我没接触过。
32位的毫无问题,32位编译器的int就是32位的,标准只要求&&的操作数是int类型,其它的是程序员的责任。
回复【57楼】shark
-----------------------------------------------------------------------
&当然如果它的int是8位的另当别论,但它实际上并不是8位的int。 &&&错!它就是8位的
你可能还是没有注意到,EMC的 int 就是8位的,我程序里的 temp 是 unsigned short int 是16位的, long int 是32位
正如你53楼截图,C语言书里面没有一句话提到8位或16位 只说是integer type
还有,int是8/16/32没有一定,要看编译器和CPU的定位以及容量,EMC是8位MCU,int是8位,8051也是8位MCU,但IAR51,KEIL51的int都是16位
很多人都有这样的刻板印象,char == 8, int == 16, long == 32 这个不是完全对的
粗略的看了下楼上各位的说法:
我也乱说几句。
(1)首先 很重要一点就是avr741 说的, 就是byte是8位的。但是其余的像int、long int 这些玩意到底是几位的 不同编译器可能就会不一样& &所以 如果哪位的解释没有主意到这点&&那么你的解释就可能让别人误解
(2)有人提到 C99标准。还引用了原文。 这个没有必要研究。编译器也没有必要完全遵守C标准。要清楚,我们搞的是嵌入式的编译器 ,我们的C语言和C发明者发明的C语言的是有区别的。
比如说 一般c语言说讲 指针运行会比数组快。但是,比如KEIL C51编译器中,数组要比指针快!
(3)有人提出要用联合体。我个人非常不喜欢用联合体,因为可能会带来大小端问题&&移植差
(4)可以考虑用 那个&&H1 * 256 + L1
(5)一般来讲&&移位 和 “|” 一起用 不会出现什么问题
& & 但要特别注意: 移位 和 “取反~”一起用 在“不用的位数”的片子下 特别容易出问题
(6)依靠编译器进行自动转换 这种做法个人感觉比较不放心&&还是强制转转 比较安心
EMC的单片机因为内存很少,而且大多是很小很简单的程序,所以这个编译器把 int 定成8位,以节省 int 变量占内存的容量
不排除也可以找到类似容量小的8051或PIC的编译器, int 也是8位的,并不是51的 int 就一定是16位的
&TH1&&8的值应该等价于 ((int)(TH1))&&8 ,但不排除某些8位机编译器不做这个转换(比如36楼的EMC的编译器),&
&不过某些编译器没有遵循标准。 &
因为2楼的(TH1 && 8),在EMC的编译器里它还是有把 TH1 从 char 提升到 int 再作移位
但因为 int 还是8位而造成溢出,就不能说是EMC编译器没有遵循C99的标准了
1楼和15楼的方法因为有强制提升到16位再作移位,自然就没问题
2楼就认为TH1一定会有强制提升到16位再作移位,事实上是强制提升到 integer 再作移位, 当integer小于16位(8位)时,就错了
最后我还发现一个最大的问题,楼主只学了51汇编,根本没学C语言,我们吵了几天,完全不对题
to【59楼】 xlsbz
(2)有人提到 C99标准。还引用了原文。 这个没有必要研究。编译器也没有必要完全遵守C标准。要清楚,我们搞的是嵌入式的编译器 ,我们的C语言和C发明者发明的C语言的是有区别的。
-----------------------------------------------------------
除了扩展语法,基本语法上嵌入式编译器还是要遵循C标准的,否则还定什么标准。
我知道没有什么编译器是100%符合C标准的,但基本语法和原则是没有异议的。
比如说 一般c语言说讲 指针运行会比数组快。但是,比如KEIL C51编译器中,数组要比指针快!
------------------------------
这个和标准无关,标准没有规定哪个快,实际上我实验的结果正好相反,指针要快一点。
【60楼】 avr741
如果EMC的int是8位的,那我同意60楼观点,不过这个编译器真是奇怪,short int比 int 还 “long& ,呵呵。
那在EMC中,常量256是什么类型,short int还是int, 如果它是int,那TH1*256结果也会是int,也会溢出,变成零,如何解释,请指教。
恩,用指针拼合最快了,直接就编译成MOV指令了,4-6周期搞定。
恩,用指针拼合最快了,直接就编译成MOV指令了,4-6周期搞定。
(原文件名:type.JPG)
&常量256是什么类型,short int还是int&
&如果它是int,那TH1*256结果也会是int,也会溢出,变成零,如何解释,请指教。&
当然是16位的short int,见上图
8位*16位,自然会自动提升成16*16,就不会有溢出的问题
这也是UCOS等OS都是用 u8 u16 u32 等 data type 来替代 char int long 的原因,才不容易搞错
回复【61楼】shark
-----------------------------------------------------------------------
你说的对& &不过C发明者说 C规则是给编写编译器的人看的&&所以没有太多时间的话 还是不看为妙
多花点时间在别的方面 比如刚出的CM3内核上&&
这个不会过时 有用
看看ucosii的源码是怎么写的
os_mutex.c中的一个函数:
OS_EVENT&&*OSMutexCreate (INT8U prio, INT8U *perr)
& & OS_EVENT&&*
#if OS_CRITICAL_METHOD == 3& && && && && && && && && && &&&/* Allocate storage for CPU status register */
& & OS_CPU_SR&&cpu_sr = 0;
#if OS_ARG_CHK_EN & 0
& & if (perr == (INT8U *)0) {& && && && && && && && && && &/* Validate 'perr'& && && && && && && && &&&*/
& && &&&return ((OS_EVENT *)0);
& & if (prio &= OS_LOWEST_PRIO) {& && && && && && && && &&&/* Validate PIP& && && && && && && && && &&&*/
& && &&&*perr = OS_ERR_PRIO_INVALID;
& && &&&return ((OS_EVENT *)0);
& & if (OSIntNesting & 0) {& && && && && && && && && && &&&/* See if called from ISR ...& && && && && &*/
& && &&&*perr = OS_ERR_CREATE_ISR;& && && && && && && && & /* ... can't CREATE mutex from an ISR& && & */
& && &&&return ((OS_EVENT *)0);
& & OS_ENTER_CRITICAL();
& & if (OSTCBPrioTbl[prio] != (OS_TCB *)0) {& && && && && &/* Mutex priority must not already exist& & */
& && &&&OS_EXIT_CRITICAL();& && && && && && && && && && &&&/* Task already exist at priority ...& && & */
& && &&&*perr = OS_ERR_PRIO_EXIST;& && && && && && && && & /* ... inheritance priority& && && && && &&&*/
& && &&&return ((OS_EVENT *)0);
& & OSTCBPrioTbl[prio] = OS_TCB_RESERVED;& && && && && && &/* Reserve the table entry& && && && && && &*/
& & pevent& && && && & = OSEventFreeL& && && && && && &/* Get next free event control block& && &&&*/
& & if (pevent == (OS_EVENT *)0) {& && && && && && && && & /* See if an ECB was available& && && && &&&*/
& && &&&OSTCBPrioTbl[prio] = (OS_TCB *)0;& && && && && && &/* No, Release the table entry& && && && &&&*/
& && &&&OS_EXIT_CRITICAL();
& && &&&*perr& && && && &&&= OS_ERR_PEVENT_NULL;& && && &&&/* No more event control blocks& && && && & */
& && &&&return (pevent);
& & OSEventFreeList& && &&&= (OS_EVENT *)OSEventFreeList-&OSEventP& &/* Adjust the free list& && &&&*/
& & OS_EXIT_CRITICAL();
& & pevent-&OSEventType& & = OS_EVENT_TYPE_MUTEX;
& & pevent-&OSEventCnt& &&&= (INT16U)((INT16U)prio && 8) | OS_MUTEX_AVAILABLE; /* Resource is avail.& &*/
& & pevent-&OSEventPtr& &&&= (void *)0;& && && && && && && && && && && &/* No task owning the mutex& & */
#if OS_EVENT_NAME_SIZE & 1
& & pevent-&OSEventName[0] = '?';
& & pevent-&OSEventName[1] = OS_ASCII_NUL;
& & OS_EventWaitListInit(pevent);
& & *perr& && && && && && &= OS_ERR_NONE;
& & return (pevent);
将高八位数据按照无符号数乘以8后与低八位数据相加。
一段程序引发的血案。。~~其实楼主的问题早解决了,~~
both are wrong, strictly speaking, and right, loosely speaking.
the issue here is type promotion in C. data types are promoted to &integer& before they are procssed. on a platform where int is of 8-bit, both approaches will result in TH&&8 to be 0.
the right approach is to explicitly force a promotion before shifting:
(((unsigned long/short) (TH)) && 8) | TL.
note that 1) I used &long&/&short& not &int& as long is always defined as 32-bit and short 16-bit but int can be anything. and 2) I forced a type promotion before shifting TH.
hope it helps.
靠,都在这里打口水仗,自己直接上计算机编程序模拟一下就知道了啊,在这里问还浪费不少时间。
这个我都是用指针操作!也很方便!
收益匪牵。
联合体与结构体共用。。。即可以整体操作,也可以单独操作!
unsigned int timer1;
& & timer1 = (unsigned int)(TH1 && 8) | TL1;
}while ( (timer1 && 8 ) != TH1 );
LZ要知道一个问题,你用的是51单片机吧?8位的,得到16位的数字还不是用两个8位的字节来保存的?无论你怎么操作,最终还是以字节方式保存,所以别想的那么复杂了。比如这个程序编译的结果,Keil:
& &&&5:& && && && && &&&unsigned int A;
& &&&6:& && && && && &&&unsigned char B,C;
& &&&7:& && && && && &&&A=0x55AA;
& &&&8:& && && && && &&&B=0x11;
& &&&9:& && && && && &&&C=0x19;
& & 10:& && && && && &&&A=B*256+C;
C:0x0003& & 7C00& &&&MOV& && &R4,#0x00
C:0x0005& & E4& && & CLR& && &A
C:0x0006& & 2419& &&&ADD& && &A,#0x19
C:0x0008& & FF& && & MOV& && &R7,A
C:0x0009& & EC& && & MOV& && &A,R4
C:0x000A& & 3411& &&&ADDC& &&&A,#0x11
C:0x000C& & FE& && & MOV& && &R6,A
可以判断出无符号整形变量A占用的地址是R6:R7,变量C根本没出现,就直接被复制到R7(低字节)了,变量B复制到A后,加上可能的进位就复制到R6,乘法没出现,更没有移位,只是简单的数据移动。
最简单的方法 C语言中 一个UNION 就 搞定!
学习了,呵呵!
我终于相信了金庸小说中的华山论剑舞林大会,高手对决就是不一样,收益匪浅啊。其实这样的讨论多一些还是好的。
這裡的人很強大...
& & 18: ((unsigned char*) (&temp))[0] = TH1;
C:0x0B60& & 858D30& &MOV& && &0x30,TH1(0x8D)
& & 19: ((unsigned char*) (&temp))[1] = TL1;
C:0x0B63& & 858B31& &MOV& && &0x31,TL1(0x8B)
KEIL 51里这样用最简最优.注意移植性不好,要考虑大小端.
用移位法移植性好,但KIEL C做了很多无用功,目标代码长很多.
temp = ( (TH1&&8) | TL1);
C:0x0B60& & AF8D& &&&MOV& && &R7,TH1(0x8D)
C:0x0B62& & EF& && & MOV& && &A,R7& && && && && &&&---它到底想干啥?
C:0x0B63& & AD8B& &&&MOV& && &R5,TL1(0x8B)
C:0x0B65& & F530& &&&MOV& && &0x30,A
C:0x0B67& & ED& && & MOV& && &A,R5& && && && && &&&---它到底想干啥?
C:0x0B68& & F531& &&&MOV& && &0x31,A
高手有时候也会遇到更高的高手,呵呵。都消消火,心平气和说清楚不就结了,花这么多口水盖这么高的楼。。。
联合不可靠,不同的编译器int高低字节顺序是不同的,这样代码移植时会有麻烦。int = (((int)char_H)&&8)|chat_L 应该可靠的。
不记得在哪里看到的如下的声明了,个人觉得还是比较好用的
#define MakeWord(a, b)& & & & ((WORD)(((BYTE)(a)) | ((WORD)((BYTE)(b))) && 8))
#define MakeDWord(a, b)& & & & ((DWORD)(((WORD)(a)) | ((DWORD)((WORD)(b))) && 16))
另外关于数据类型转换还是自己做的比较好,以后再阅读代码也比较省心。即使更新了单片机,程序还可以跑起来。
很多人吃过亏回复【81楼】zhiwei
高手有时候也会遇到更高的高手,呵呵。都消消火,心平气和说清楚不就结了,花这么多口水盖这么高的楼。。。
-----------------------------------------------------------------------
人之常情.站在越高的楼上越容易往楼下看风景,因为更高的楼已经很少了,所以看到更高的楼时,第一反应会认为那是幻影.
更认同 avr741 的观点。他的思路更多地考虑了程序的可靠性。也许这样写出来的程序会稍显冗长,多花一些时间输入,但是在调试的时候,就会体会到这样的时间花的值得。这更多地体现的是一种编程风格。
感觉 hsztc 更倾向于代码的简练和效率,个人觉得这种风格在一些资源及其有限的项目中会有价值。但是从日常的使用来说,不建议采用这种编程风格。尤其在一个产品生命和维护周期很长,会由不同的人来负责这些代码的情况下,这种风格的程序可能就会是一个 bug 的来源了。
回复【80楼】rainyss
-----------------------------------------------------------------------
回复【80楼】rainyss
-----------------------------------------------------------------------
a=ds1820rd();//取温度低8位
&&b=ds1820rd();//取温度高八位
&&tvalue=b;
&&tvalue&&=8;
&&tvalue=tvalue|a;//第八位和高八位合在一起
13楼正解!
阿莫电子论坛, 原"中国电子开发网"
, 原www.ourdev.cn, 原www.ouravr.com

我要回帖

更多关于 stc 单片机的ad采集电路 的文章

 

随机推荐