#include <reg52.h> #include <intrins.h>
#define LCDClear() LCDWriteCmd(0x01)
sbit RS = P2^0; sbit RW = P2^1; sbit E = P2^2; sbit BF = P0^7;
sbit SCL = P3^4; sbit SDA = P3^5;
void delay(unsigned int n) { unsigned char i; while (n--) for (i = 0; i < 115; i++); }
void LCDBusyTest(void) { E = 0; RS = 0; RW = 1; E = 1; BF = 1; while (BF); E = 0; }
void LCDWriteCmd(unsigned char cmd) { LCDBusyTest(); RS = 0; RW = 0; E = 1; P0 = cmd; E = 0; }
void LCDWriteData(unsigned char dat) { LCDBusyTest(); RS = 1; RW = 0; E = 1; P0 = dat; E = 0; }
void LCDWriteString(char *s) { while (*s) LCDWriteData(*s++); }
void LCDWriteNumber(unsigned char num) { char str[4]; str[0] = num / 100 + '0'; str[1] = num % 100 / 10 + '0'; str[2] = num % 10 + '0'; str[3] = '\0'; if (str[0] == '0') { if (str[1] == '0') LCDWriteString(str + 2); else LCDWriteString(str + 1); } else LCDWriteString(str); }
void LCDInit(void) { delay(40); LCDWriteCmd(0x30); delay(10); LCDWriteCmd(0x30); delay(10); LCDWriteCmd(0x0c); delay(1); LCDWriteCmd(0x01); }
void I2CStart(void) { // SCL为高电平时, SDA必须稳定 // 所以必须先置位SDA, 后置位SCL, 顺序绝不能颠倒过来 SDA = 1; SCL = 1; _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); SDA = 0; _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); }
void I2CStop(void) { SDA = 0; SCL = 1; _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); SDA = 1; _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); }
// 检查从器件的应答 bit I2CAck(void) { bit ack; SDA = 1; SCL = 0; _nop_(); _nop_(); SCL = 1; _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); ack = SDA; SCL = 0; return !ack; }
// 主器件主动应答 // 1为应答, 0为非应答 void I2CSendAck(bit ack) { SDA = !ack; SCL = 0; _nop_(); _nop_(); SCL = 1; _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); SCL = 0; }
bit I2CWrite(unsigned char dat) { unsigned char i; for (i = 0; i < 8; i++) { SCL = 0; SDA = dat & 0x80; dat <<= 1; SCL = 1; _nop_(); _nop_(); } SCL = 0; return I2CAck(); }
unsigned char I2CRead(void) { unsigned char i; unsigned char dat = 0; SDA = 1; for (i = 0; i < 8; i++) { SCL = 1; dat <<= 1; if (SDA) dat |= 1; SCL = 0; _nop_(); _nop_(); } return dat; }
// 跳转到指定地址 bit EEPGoto(unsigned int addr, bit read) { unsigned char cmd = 0xa0; cmd |= addr >> 7 & 0x06; if (!I2CWrite(cmd)) // slave address for WRITING return 0; if (!I2CWrite(addr & 0xff)) // byte address return 0; if (read) { I2CStart(); return I2CWrite(cmd | read); // slave address again for reading } else return 1; }
// 单字节写 bit EEPWriteByte(unsigned int addr, unsigned char dat) { bit result = 0; I2CStart(); if (EEPGoto(addr, 0)) result = I2CWrite(dat); I2CStop(); if (result) delay(1); // 等待器件擦写完毕 return result; }
// 页写 // 返回成功写入的字节数 // 24C08中每页为16字节,一次只能写一页, 如果在0地址处写入20个字符,那么第17~20个字符将会被写回0~3地址处 // 如果在2地址处写入16个字符,那么第15~16个字符就会被写入到0~1地址处 unsigned char EEPWritePage(unsigned int addr, unsigned char dat[], unsigned char size) { unsigned char n = 0; if (size == 0) return 0; I2CStart(); if (EEPGoto(addr, 0)) { while (n < size) { if (!I2CWrite(dat[n])) break; n++; } } I2CStop(); if (n > 0) delay(1); return n; }
// 选择性读 bit EEPReadByte(unsigned int addr, unsigned char *dat) { bit result = 0; I2CStart(); if (EEPGoto(addr, 1)) { result = 1; *dat = I2CRead(); } I2CSendAck(0); I2CStop(); return result; }
// 立即地址读 // 读到整个存储器最后一个字节时会自动跳回0地址 bit EEPReadByteIn(unsigned char slave_addr, unsigned char *dat) { bit result = 0; I2CStart(); if (I2CWrite(slave_addr)) { result = 1; *dat = I2CRead(); } I2CSendAck(0); // NOACK I2CStop(); return result; }
// 由选择性读启动连续读 unsigned char EEPReadPage(unsigned int addr, unsigned char dat[], unsigned char size) { unsigned char n = 0; if (size == 0) return 0; I2CStart(); if (EEPGoto(addr, 1)) { while (n < size) { if (n != 0) I2CSendAck(1); // 应答表示主器件要求更多的数据 dat[n] = I2CRead(); n++; } } I2CSendAck(0); // 非应答表示停止发送 I2CStop(); return n; }
// 由立即地址读启动连续读 unsigned char EEPReadPageIn(unsigned char slave_addr, unsigned char dat[], unsigned char size) { unsigned char n = 0; if (size == 0) return 0; I2CStart(); if (I2CWrite(slave_addr)) { while (n < size) { if (n != 0) I2CSendAck(1); dat[n] = I2CRead(); n++; } } I2CSendAck(0); I2CStop(); return n; }
void test(void) { char buf[16]; char ch; unsigned char i, n; unsigned char cnt = 0; /* 测试单字节写 */ // 24C08的地址范围: 0x000~0x3ff cnt += (unsigned char)EEPWriteByte(0x3fd, 'K'); cnt += (unsigned char)EEPWriteByte(0x3fe, 'e'); cnt += (unsigned char)EEPWriteByte(0x3ff, 'y'); /* 测试单字节读 */ LCDClear(); cnt += (unsigned char)EEPReadByte(0x3fd, &ch); LCDWriteData(ch); cnt += (unsigned char)EEPReadByte(0x3fe, &ch); LCDWriteData(ch); cnt += (unsigned char)EEPReadByte(0x3ff, &ch); LCDWriteData(ch); /* 测试页写 */ cnt += EEPWritePage(0x302, "简体中文abcd1234繁", 18); // 由于一次只能写一页, 每页16字节 // 所以最后的34被写到了0x300~0x301处, "繁"字把"简"字覆盖了 /* 测试立即地址连续读 */ // 当前地址位于"繁"字后面,也就是0x304处 n = EEPReadPageIn(0xa7, buf, 8); // A2接的是低电平, 且要读的区域为第三区域, 所以参数1的第3位为0, 第2~1位为11 LCDWriteCmd(0x90); // 跳至第二行 for (i = 0; i < n; i++) LCDWriteData(buf[i]); cnt += n; /* 测试立即地址读 */ // 当前地址位于"b"字后面, 也就是0x30c处 LCDWriteData('-'); cnt += (unsigned char)EEPReadByteIn(0xa7, &ch); LCDWriteData(ch); cnt += (unsigned char)EEPReadByteIn(0xa7, &ch); LCDWriteData(ch); /* 测试选择性连续读 */ n = EEPReadPage(0x300, buf, 16); LCDWriteCmd(0x88); // 跳至第三行 for (i = 0; i < n; i++) LCDWriteData(buf[i]); cnt += n; LCDWriteCmd(0x98); // 跳至第四行 LCDWriteString("共成功操作了"); LCDWriteNumber(cnt); LCDWriteString("B"); }
int main(void) { LCDInit(); test(); while (1); }
|