AT24C04测试程序 供参考
工作频率: 12.000MHz
**************************************
SCL BIT P2.0 AT24C04的时钟线
SDA BIT P2.1 AT24C04的数据线
BUF EQU 30H数据缓存区
**************************************
ORG 0
JMP Reset
ORG 100H
Reset:
CALL AT24C04_WritePage 写一页数据
CALL Delay5ms 写一页数据需延时5ms
CALL AT24C04_ReadPage 读一页数据
JMP $
**************************************
向AT24C04写1页(16字节)数据
将TESTDATA开始的16个测试数据写如设备的00~0F地址中
入口参数:无
出口参数:无
**************************************
AT24C04_WritePage:
CALL AT24C04_Start 起始信号
MOV A,#0A0H 发送设备地址+写信号
CALL AT24C04_SendByte 发送
MOV A,#00H 发送存储单元地址
CALL AT24C04_SendByte 发送
MOV R0,#16 16字节计数器
MOV DPTR,#TESTDATA 测试数据首地址
WriteNext:
CLR A 读取测试数据
MOVC A,@A+DPTR
CALL AT24C04_SendByte 写入设备
INC DPTR准备下一个数据的地址
DJNZ R0,WriteNext 判断16字节是否完成
CALL AT24C04_Stop 停止信号
RET
TESTDATA:
DB 000H,011H,022H,033H,044H,055H,066H,077H
DB 088H,099H,0AAH,0BBH,0CCH,0DDH,0EEH,0FFH
**************************************
从AT24C04读取1页(16字节)数据
将设备的00~0F地址中的数据读出存放在DATA区的BUF中
入口参数:无
出口参数:无
**************************************
AT24C04_ReadPage:
CALL AT24C04_Start 起始信号
MOV A,#0A0H 发送设备地址+写信号
CALL AT24C04_SendByte 发送
MOV A,#00H 发送存储单元地址
CALL AT24C04_SendByte 发送
CALL AT24C04_Start 起始信号
MOV A,#0A1H 发送设备地址+读信号
CALL AT24C04_SendByte 发送
MOV R0,#16 16字节计数器
MOV R1,#BUF 数据缓冲区首地址
ReadNext:
CALL AT24C04_RecvByte 读取数据
MOV @R1,A 保存数据
CJNE R0,#2,$+3 判断回应ACK还是NAK
CALL AT24C04_SendACK发送应答信号
INC R1 缓冲区地址加1
DJNZ R0,ReadNext判断16字节是否完成
CALL AT24C04_Stop 停止信号
RET
**************************************
延时5微秒
不同的工作环境,需要调整此函数
入口参数:无
出口参数:无
**************************************
Delay5us: 2 当改用1T的MCU时,请调整此延时函数
NOP 1
RET 2
**************************************
延时5毫秒
不同的工作环境,需要调整此函数
入口参数:无
出口参数:无
**************************************
Delay5ms: 2 当改用1T的MCU时,请调整此延时函数
PUSH ACC2
PUSH DPL2
PUSH DPH2
MOV DPTR,#-500 2
Delay5ms1:
NOP 1
NOP 1
NOP 1
NOP 1
INC DPTR2
MOV A,DPL 1
ORL A,DPH 1
JNZ Delay5ms1 2
POP DPH 2
POP DPL 2
POP ACC 2
RET 2
**************************************
起始信号
入口参数:无
出口参数:无
**************************************
AT24C04_Start:
SETB SDA
SETB SCL拉高时钟线
CALL Delay5us 延时
CLR SDA 产生下降沿
CALL Delay5us 延时
CLR SCL 拉低时钟线
RET
**************************************
停止信号
入口参数:无
出口参数:无
**************************************
AT24C04_Stop:
CLR SDA
SETB SCL拉高时钟线
CALL Delay5us 延时
SETB SDA产生上升沿
CALL Delay5us 延时
RET
**************************************
发送应答信号
入口参数:C (0:ACK 1:NAK)
出口参数:无
**************************************
AT24C04_SendACK:
MOV SDA,C 写应答信号
SETB SCL拉高时钟线
CALL Delay5us 延时
CLR SCL 拉低时钟线
CALL Delay5us 延时
RET
**************************************
接收应答信号
入口参数:无
出口参数:C
**************************************
AT24C04_RecvACK:
SETB SCL拉高时钟线
CALL Delay5us 延时
MOV C,SDA 读应答信号
CLR SCL 拉低时钟线
CALL Delay5us 延时
RET
**************************************
向IIC总线发送一个字节数据
入口参数:ACC
出口参数:无
**************************************
AT24C04_SendByte:
PUSH 0
MOV 0,#88位计数器
SendNext:
RLC A 移出数据的最高位
MOV SDA,C 送数据口
SETB SCL拉高时钟线
CALL Delay5us 延时
CLR SCL 拉低时钟线
CALL Delay5us 延时
DJNZ 0,SendNext 判断8位数据是否发送完成
POP 0
JMP AT24C04_RecvACK 接收应答信号
RET
**************************************
从IIC总线接收一个字节数据
入口参数:无
出口参数:ACC
**************************************
AT24C04_RecvByte:
SETB SDA使能内部上拉,准备读取数据
PUSH 0
MOV 0,#88位计数器
RecvNext:
SETB SCL拉高时钟线
CALL Delay5us 延时
MOV C,SDA 读数据口
RLC A 保存数据
CLR SCL 拉低时钟线
CALL Delay5us 延时
DJNZ 0,RecvNext 判断8位数据是否接收完成
POP 0
RET
**************************************
END
没有去查I2C的协议,但是读写位是LSB(低位)方向的,而读写位后发,所以可以推测应该是MSB(高位)先发的。上面两段程序如果只从SDA的赋值情况的话(其他逻辑我没有细看),两段程序有可能都可以:
1. 先把最高位移到CY里面,再赋值,应该很好理解
2. 先由temp&0x80判断的temp的最高位,并把结果赋给SDA:这种赋值法要看编译器支持,因为SDA是一位,temp&0x80的结果是一个byte,也有写成SDA=(temp&0x80 != 0)就是把表达式的结果true or false当成1,0赋值给SDA, 实际上翻译过来就是
if(temp&0x80 != 0)
{
SDA=1
}
else
{
SDA=0
}
这些都要看编译器支持,然后才移位。怎么知道你的编译器是否支持这种写法呢?很简单,你要查看编译器生成的汇编文件,看看汇编代码是否正确。
不过强烈建议不要用这种写法,尽量让你的代码比较通用。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)