春卷の爱 发表于 2014-2-15 18:15:51

51单片机MOV P1,55h 结果P1口上8个灯全亮

本帖最后由 春卷の爱 于 2014-2-15 20:53 编辑

设置P1=AAh (1010 1010B),接在P1口上的8个灯,亮 灭 亮 灭 亮 灭 亮 灭
生成的机器码:85 AA 90


设置P1=55h (0101 0101B),应该是 灭 亮 灭 亮 灭 亮 灭 亮, 结果8个灯全亮。。。请问这是为什么?
生成的机器码:85 55 90

还有一个很奇怪的问题,编译生成的HEX文件,用UE打开看到的和用ISP下载工具看到的完全不一样,UE打开后好像多了很多代码,也找不到85 55 90这样的代码了

春卷の爱 发表于 2014-2-19 08:37:51

没人知道吗?

惜今怀远 发表于 2014-2-19 09:02:08

话说你是用C编写的,还是汇编编写的,我都是用C编写的,对P1口赋值是0xaa,51单片机应该是低电平点亮led灯吧,没关注过hex文件里的东西

春卷の爱 发表于 2014-2-19 20:25:20

惜今怀远 发表于 2014-2-19 09:02 static/image/common/back.gif
话说你是用C编写的,还是汇编编写的,我都是用C编写的,对P1口赋值是0xaa,51单片机应该是低电平点亮led灯吧 ...

我是用汇编编写的,就一条指令: MOV P1 0XAA, 生成3个字节的机器码。所以想不明白错误在哪里。

关于HEX的问题,我找到答案了,HEX不是简单的BIN文件的16进制表示, HEX文件也有文件头,CHECKSUM等自动生成的信息,所以不止3个字节。

春卷の爱 发表于 2014-2-23 10:59:46

我知道问题了, 要改成
mov P1, #0aah

春卷の爱 发表于 2014-2-23 11:00:35

就为这我弄了半个小时, 查了ATMEL的规格书和INTEL 8051指令集. 写了一堆记录. 哈哈.

汇编:
org 0000h
mov p1, 55h
end

机器码:85 55 90
失败

C语言:
#inlucde <reg52.h>
void main()
{
    P1=0x55;
}

机器码: 0000-080F
0000:    02 08 00 00 ..   
反汇编:
02 08 00:    LJMP 08 00    跳转到地址0800
Opcode: 0x02    instruction: LJMP code addr    Bytes: 3    Flags: none

0800:    78 7F E4 F6 D8 FD 75 81 07 02 08 0C 75 90 55 22   
反汇编:
78 7F:    mov R0, 7Fh         0x78    mov R0, #data    2bytes
E4    :    CLR A                      0xE4    CLR A                   1byte               clear register A
F6    :    mov @R0, A            0xF6    mov @R0, A      1byte
单片机mov R0, A和mov @R0, A的区别: mov R0, A 是把累加器中的数送给寄存器R0. mov @R0, A 是把累加器中的数, 送给R0内存储的地址单元. 这里是给7Fh地址赋值0
D8 FD:                                 0xD8    DJNZ R0, reladdr    2bytes      decrement and jump if not zero
R0的值-1, 等于7Eh, 判断不为0, 向前跳转3BYTE, 也就是跳过了 D8 FD, 跳过了 F6, 开始从F6执行: 给地址7Eh赋值0. 如此循环.....直到R0的值为1, 给地址01h赋值0执行D8 FD时, R0的值-1 等于0, 执行后面的语句 (地址00h的值没有被改变). 经过以上程序, 地址01-7F的值全部为0, 不明觉厉啊

75 81 07:    mov iram addr, #data   把07h赋给internal RAM 81h;   查ATMEL的datasheet, 地址81h就是大名鼎鼎的SP (stack pointer). 难道上面那段代码是为了建立占空间? 为什么不把80h也改成0. 为什么不把00h也改成0
02 08 0C:   ljmp code addr   这句可以不要,因为080C就在下面
75 90 55:      mov iram addr, #data把55h赋给90. 慢着, 8051instruction set关于MOV指令里有一行字:
** Note: In the case of "MOV iram addr,iram addr", the operand bytes of the instruction are stored in reverse order. That is, the instruction consisting of the bytes 0x85, 0x20, 0x50 means "Move the contents of Internal RAM location 0x20 to Internal RAM location 0x50" whereas the opposite would be generally presumed.
也就是说第一: 我上面那个汇编程序, 想把idata (55h)赋值给p1, 结果编译成了把地址55h里的值赋给90, 鬼知道地址55h里是什么数. 难怪出错. 因为没有查看8051的指令集, 想当然用了mov p1, 55h这样的赋值语句.
第二: 85这个opcode执行顺序是倒过来的, 就是把oprand 1 给oprand 2. 不过这个是机器的小癖好, 编译的时候两个操作数的顺序是倒着写的, 也就是负负为正了. 不需要特别留意.

22:                ret

成功

汇编:
org 0000h
mov p1, #55h
end

机器码: 75 90 55

成功

心得: 没有汇编, 可以问别人, 发帖子, 程序也可以修改正确, 但我永远都不知道发生了什么.
页: [1]
查看完整版本: 51单片机MOV P1,55h 结果P1口上8个灯全亮