📄 eeprom读写演示程序.lst
字号:
_delay_EEPROM:
a --> R20
b --> R22
n --> R16
050A 940E06A5 CALL push_gset2
FILE: E:\学习专区\AVR专区\个人创作区\AVR单片机开发平台\EEPROM读写演示程序\24Cxx.C
(0001) /**************************************************
(0002) EEPROM读写操作
(0003) 晶振:内部 8M
(0004) ***************************************************/
(0005) #include<iom16v.h>
(0006) #include<macros.h>
(0007) #define uchar unsigned char
(0008) #define uint unsigned int
(0009) #define ulong unsigned long
(0010) uchar syserr;
(0011) void delay_EEPROM(uchar n) //延时
(0012) {
(0013) unsigned int a,b;
(0014) for(a=0;a<n;a++)
050C 2744 CLR R20
050D 2755 CLR R21
050E C00B RJMP 0x051A
(0015) for(b=0;b<100;b++)
050F 2766 CLR R22
0510 2777 CLR R23
0511 C002 RJMP 0x0514
0512 5F6F SUBI R22,0xFF
0513 4F7F SBCI R23,0xFF
0514 3664 CPI R22,0x64
0515 E0E0 LDI R30,0
0516 077E CPC R23,R30
0517 F3D0 BCS 0x0512
0518 5F4F SUBI R20,0xFF
0519 4F5F SBCI R21,0xFF
051A 2E20 MOV R2,R16
051B 2433 CLR R3
051C 1542 CP R20,R2
051D 0553 CPC R21,R3
051E F380 BCS 0x050F
051F 940E0693 CALL pop_gset2
0521 9508 RET
_wt24c:
n --> R10
num --> R12
ad_dst --> R14
p_rsc --> Y+11
0522 940E0614 CALL push_arg4
0524 940E069F CALL push_gset5
0526 0179 MOVW R14,R18
0527 9721 SBIW R28,1
0528 84CF LDD R12,Y+15
0529 88D8 LDD R13,Y+16
(0016) ;
(0017) }
(0018) //------在此设定芯片型号------
(0019) #define e2prom 256 // <---在此设定芯片型号, 1代表24C01; 16代表24C16; 512代表24C512
(0020)
(0021) #if e2prom==1
(0022) #define PAGE_SIZE 8
(0023) #define SIZE 0x007f
(0024) #elif e2prom==2
(0025) #define PAGE_SIZE 8
(0026) #define SIZE 0x00ff
(0027) #elif e2prom==4
(0028) #define PAGE_SIZE 16
(0029) #define SIZE 0x01ff
(0030) #elif e2prom==8
(0031) #define PAGE_SIZE 16
(0032) #define SIZE 0x03ff
(0033) #elif e2prom==16
(0034) #define PAGE_SIZE 16
(0035) #define SIZE 0x07ff
(0036) #elif e2prom==32
(0037) #define PAGE_SIZE 32
(0038) #define SIZE 0x0fff
(0039) #elif e2prom==64
(0040) #define PAGE_SIZE 32
(0041) #define SIZE 0x1fff
(0042) #elif e2prom==128
(0043) #define PAGE_SIZE 64
(0044) #define SIZE 0x3fff
(0045) #elif e2prom==256
(0046) #define PAGE_SIZE 64
(0047) #define SIZE 0x7fff
(0048) #elif e2prom==512
(0049) #define PAGE_SIZE 128
(0050) #define SIZE 0xffff
(0051) #endif
(0052) //--------------------------
(0053)
(0054) //--------在此设定芯片地址-------
(0055) #define W_ADD_COM 0xa0 //写字节命令及器件地址(根据地址实际情况改变), 1010 A2 A1 A0 0
(0056) #define R_ADD_COM 0xa1 //读命令字节及器件地址(根据地址实际情况改变), 1010 A2 A1 A0 1
(0057) //-------------------------------
(0058)
(0059)
(0060)
(0061) #define SLAW 0x18 //SLA_W 已正常发送代码,判断器件是否正常应答的常量.
(0062)
(0063) //-----在此改变预置错误号-----
(0064) #define ERR_SLAW 10//写字节命令及器件地址错, 在此也就是读写器件错!!
(0065) //---------------------------
(0066)
(0067)
(0068)
(0069) //-----------4个I2总线公用函数, 可供其它I2总线器件的程序调用--------------
(0070) void i2cstart(void); //总线上起动开始条件
(0071) uchar i2cwt(uchar a); //把一个字节数据输入器件, 返回TWI状态
(0072) uchar i2crd(void); //i2c读要调用的函数
(0073) void i2cstop(void); //总线上起动停止条件
(0074) //------------------------------------------------------------------------
(0075)
(0076) uchar * wt24c_fc(uchar *p, uint ad, uchar n); //向24Cxx写入数据wt24c_h()所要调用的函数
(0077)
(0078) //向24Cxx写入数据
(0079) //参数: *p_rsc要输出数据的主机内存地址指针; ad_dst要写入数据的i2c的地址(双字节); num数据个数
(0080) //参数条件: ad_dst: ad_dst+(num-1)不能大于器件的最高地址; num必须>0;
(0081) void wt24c(uchar *p_rsc, uint ad_dst, uint num)
(0082) { uint n;
(0083)
(0084) n=ad_dst/PAGE_SIZE; //确定地址与块地址的差
052A E026 LDI R18,6
052B E030 LDI R19,0
052C 0187 MOVW R16,R14
052D 940E06E3 CALL lsr16
052F 0158 MOVW R10,R16
(0085) if(n)
0530 3000 CPI R16,0
0531 0701 CPC R16,R17
0532 F0E1 BEQ 0x054F
(0086) n=(ulong)PAGE_SIZE*(n+1)-ad_dst;
0533 01C5 MOVW R24,R10
0534 9601 ADIW R24,1
0535 011C MOVW R2,R24
0536 2444 CLR R4
0537 2455 CLR R5
0538 E440 LDI R20,0x40
0539 E050 LDI R21,0
053A E060 LDI R22,0
053B E070 LDI R23,0
053C 925A ST R5,-Y
053D 924A ST R4,-Y
053E 923A ST R3,-Y
053F 922A ST R2,-Y
0540 018A MOVW R16,R20
0541 019B MOVW R18,R22
0542 940E0663 CALL empy32s
0544 0118 MOVW R2,R16
0545 0129 MOVW R4,R18
0546 0137 MOVW R6,R14
0547 2488 CLR R8
0548 2499 CLR R9
0549 1826 SUB R2,R6
054A 0837 SBC R3,R7
054B 0848 SBC R4,R8
054C 0859 SBC R5,R9
054D 0151 MOVW R10,R2
054E C005 RJMP 0x0554
(0087) else
(0088) n=PAGE_SIZE-ad_dst;
054F E480 LDI R24,0x40
0550 E090 LDI R25,0
0551 015C MOVW R10,R24
0552 18AE SUB R10,R14
0553 08BF SBC R11,R15
(0089)
(0090) if(n>=num) //如果ad_dst所在的数据块的末尾地址 >= ad_dst + num, 就直接写入num个数据
0554 14AC CP R10,R12
0555 04BD CPC R11,R13
0556 F058 BCS 0x0562
(0091) {
(0092) wt24c_fc(p_rsc, ad_dst, num);
0557 82C8 STD Y+0,R12
0558 0197 MOVW R18,R14
0559 850B LDD R16,Y+11
055A 851C LDD R17,Y+12
055B D077 RCALL _wt24c_fc
(0093) if(syserr!=0)
055C 902000AE LDS R2,syserr
055E 2022 TST R2
055F F409 BNE 0x0561
0560 C034 RJMP 0x0595
(0094) return;
0561 C033 RJMP 0x0595
(0095) }
(0096) else //如果ad_dst所在的数据块末尾地址 < ad_dst + num, 就先写入ad_dst所在的数据块末尾地址与 ad_dst 之差个数据
(0097) {
(0098) p_rsc=wt24c_fc(p_rsc, ad_dst, n);
0562 82A8 STD Y+0,R10
0563 0197 MOVW R18,R14
0564 850B LDD R16,Y+11
0565 851C LDD R17,Y+12
0566 D06C RCALL _wt24c_fc
0567 871C STD Y+12,R17
0568 870B STD Y+11,R16
(0099) if(syserr!=0)
0569 902000AE LDS R2,syserr
056B 2022 TST R2
056C F009 BEQ 0x056E
(0100) return;
056D C027 RJMP 0x0595
(0101)
(0102) num-=n; //更新剩下数据个数
056E 18CA SUB R12,R10
056F 08DB SBC R13,R11
(0103) ad_dst+=n; //更新剩下数据的起始地址
0570 0CEA ADD R14,R10
0571 1CFB ADC R15,R11
0572 C015 RJMP 0x0588
(0104)
(0105) //把剩下数据写入器件
(0106) while(num>=PAGE_SIZE) //先按PAGE_SIZE为长度一页一页的写入
(0107) { p_rsc=wt24c_fc(p_rsc, ad_dst, PAGE_SIZE);
0573 E480 LDI R24,0x40
0574 8388 STD Y+0,R24
0575 0197 MOVW R18,R14
0576 850B LDD R16,Y+11
0577 851C LDD R17,Y+12
0578 D05A RCALL _wt24c_fc
0579 871C STD Y+12,R17
057A 870B STD Y+11,R16
(0108) if(syserr!=0) return;
057B 902000AE LDS R2,syserr
057D 2022 TST R2
057E F009 BEQ 0x0580
057F C015 RJMP 0x0595
(0109)
(0110) num-=PAGE_SIZE; //更新剩余数据个数
0580 01C6 MOVW R24,R12
0581 5480 SUBI R24,0x40
0582 4090 SBCI R25,0
0583 016C MOVW R12,R24
(0111) ad_dst+=PAGE_SIZE; //更新剩下数据的起始地址
0584 01C7 MOVW R24,R14
0585 5C80 SUBI R24,0xC0
0586 4F9F SBCI R25,0xFF
0587 017C MOVW R14,R24
0588 01C6 MOVW R24,R12
0589 3480 CPI R24,0x40
058A E0E0 LDI R30,0
058B 079E CPC R25,R30
058C F730 BCC 0x0573
(0112) }
(0113)
(0114) if(num) //把最后剩下的小于一个PAGE_SIZE长度的数据写入器件
058D 3080 CPI R24,0
058E 0789 CPC R24,R25
058F F029 BEQ 0x0595
(0115) wt24c_fc(p_rsc, ad_dst, num);
0590 82C8 STD Y+0,R12
0591 0197 MOVW R18,R14
0592 850B LDD R16,Y+11
0593 851C LDD R17,Y+12
0594 D03E RCALL _wt24c_fc
(0116) }
0595 9621 ADIW R28,1
0596 940E069C CALL pop_gset5
0598 9624 ADIW R28,4
0599 9508 RET
(0117) }
(0118)
(0119)
(0120) //从24cxx读出数据
(0121) //参数: *p_dst要读入数据的主机内存地址指针; ad_rsc要输出数据的i2c的地址(整形); num数据个数(整形)
(0122) //参数条件: ad_dst+(num-1)不能大于器件的最高地址; num必须>0;
(0123) void port_init(void)
(0124) {
(0125)
(0126) PORTC = 0xFF;
_port_init:
059A EF8F LDI R24,0xFF
059B BB85 OUT 0x15,R24
(0127) DDRC &= 0xfc;
059C B384 IN R24,0x14
059D 7F8C ANDI R24,0xFC
059E BB84 OUT 0x14,R24
059F 9508 RET
(0128) }
(0129) //TWI initialize
(0130) // bit rate:100
(0131) void twi_init(void)
(0132) {
(0133) TWCR= 0x00; //disable twi
_twi_init:
05A0 2422 CLR R2
05A1 BE26 OUT 0x36,R2
(0134) TWBR= 0x20; //set bit rate
05A2 E280 LDI R24,0x20
05A3 B980 OUT 0x00,R24
(0135) TWSR= 0x00; //set prescale
05A4 B821 OUT 0x01,R2
(0136) TWAR= 0x00; //set slave address
05A5 B822 OUT 0x02,R2
(0137) TWCR= 0x04; //enable twi
05A6 E084 LDI R24,4
05A7 BF86 OUT 0x36,R24
05A8 9508 RET
_rd24c:
t --> R10
num --> R22
ad_rsc --> R12
p_dst --> R20
05A9 940E06A1 CALL push_gset4
05AB 0169 MOVW R12,R18
05AC 01A8 MOVW R20,R16
05AD 8568 LDD R22,Y+8
05AE 8579 LDD R23,Y+9
(0138) }
(0139) void rd24c(uchar *p_dst, uint ad_rsc, uint num)
(0140) {
(0141) uchar t=0;
05AF 24AA CLR R10
(0142) #if e2prom<32
(0143) t=ad_rsc>>8;
(0144) t<<=1;
(0145) #endif
(0146) i2cstart(); //发送起始信号
05B0 D049 RCALL _i2cstart
(0147) if(i2cwt(W_ADD_COM+t)==SLAW)//发送SLA_W, 写字节命令及器件地址
05B1 2D0A MOV R16,R10
05B2 5600 SUBI R16,0x60
05B3 D04C RCALL _i2cwt
05B4 3108 CPI R16,0x18
05B5 F4B1 BNE 0x05CC
(0148) {
(0149) #if e2prom>=32
(0150) i2cwt(ad_rsc>>8); //ad_rsc的高位, 发送要读出数据的地址
05B6 0186 MOVW R16,R12
05B7 2F01 MOV R16,R17
05B8 2711 CLR R17
05B9 D046 RCALL _i2cwt
(0151) #endif
(0152) i2cwt(ad_rsc); //ad_rsc的低位
05BA 2D0C MOV R16,R12
05BB D044 RCALL _i2cwt
(0153)
(0154) i2cstart(); //再发送起始信号
05BC D03D RCALL _i2cstart
(0155) i2cwt(R_ADD_COM+t); //发送SLA_R, 读命令字节及器件地址
05BD 2D0A MOV R16,R10
05BE 550F SUBI R16,0x5F
05BF D040 RCALL _i2cwt
(0156)
(0157) for(;num>0;num--)
05C0 C007 RJMP 0x05C8
(0158) {
(0159) *p_dst=i2crd(); //从器件读出一个字节
05C1 D048 RCALL _i2crd
05C2 01FA MOVW R30,R20
05C3 8300 STD Z+0,R16
(0160) p_dst++;
05C4 5F4F SUBI R20,0xFF
05C5 4F5F SBCI R21,0xFF
05C6 5061 SUBI R22,1
05C7 4070 SBCI R23,0
05C8 3060 CPI R22,0
05C9 0767 CPC R22,R23
05CA F7B1 BNE 0x05C1
(0161) }
(0162) }
05CB C003 RJMP 0x05CF
(0163) else
(0164) syserr=ERR_SLAW; //写字节命令及器件地址错或对方无应答
05CC E08A LDI R24,0xA
05CD 938000AE STS syserr,R24
(0165)
(0166) i2cstop();
05CF D041 RCALL _i2cstop
05D0 940E0699 CALL pop_gset4
05D2 9508 RET
_wt24c_fc:
t --> R12
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -