📄 twi.lst
字号:
1 .file "twi.c"
2 .arch atmega16
3 __SREG__ = 0x3f
4 __SP_H__ = 0x3e
5 __SP_L__ = 0x3d
6 __tmp_reg__ = 0
7 __zero_reg__ = 1
8 .global __do_copy_data
9 .global __do_clear_bss
11 .text
12 .Ltext0:
130 .global TWI_RW
132 TWI_RW:
1:twi.c **** /***********************************************
2:twi.c **** **** AVR TWI读写读写范例 ***
3:twi.c **** **** ***
4:twi.c **** **** 作者: HJJourAVR ***
5:twi.c **** **** 编译器:WINAVR20050214 ***
6:twi.c **** **** ***
7:twi.c **** **** www.OurAVR.com 2005.10.18 ***
8:twi.c **** ***********************************************/
9:twi.c **** /*
10:twi.c **** 本程序简单的示范了如何使用ATMEGA16的TWI 读写AT24C02 IIC EEPROM
11:twi.c **** TWI协议
12:twi.c **** (即IIC协议,请认真参考IIC协议的内容,否则根本就不能掌握)
13:twi.c **** 一主多从的应用,M16作主机
14:twi.c **** (M16做从机和多主多从的应用不多,请自行参考相关文档)
15:twi.c **** 中断模式
16:twi.c **** (因为AVR的速度很高,而IIC的速度相对较低,
17:twi.c **** 采用查询模式会长时间独占CPU,令CPU的利用率明显下降。
18:twi.c **** 特别是IIC速度受环境影响只能低速通讯时,对系统的实时性产生严重的影响。
19:twi.c **** 查询模式可以参考其它文档和软件模拟IIC的文档)
20:twi.c **** AT24C02/04/08的操作特点
21:twi.c ****
22:twi.c **** 出于简化程序考虑,各种数据没有对外输出,学习时建议使用JTAG ICE硬件仿真器
23:twi.c **** */
24:twi.c ****
25:twi.c **** #include "config.h"
26:twi.c ****
27:twi.c ****
28:twi.c **** //定义全局变量
29:twi.c **** uint8 BUFFER[10]; //缓冲区,可以装载整个AC24C02的数据
30:twi.c ****
31:twi.c **** struct str_TWI //TWI数据结构
32:twi.c **** {
33:twi.c **** volatile uint8 STATUS; //TWI_操作状态
34:twi.c **** uint8 SLA; //从设备的器件地址
35:twi.c **** uint16 ADDR; //从设备的数据地址
36:twi.c **** uint8 *pBUF; //数据缓冲区指针
37:twi.c **** uint16 DATALEN; //数据长度
38:twi.c **** uint8 STATE; //TWI读写操作步骤
39:twi.c **** uint8 FAILCNT; //失败重试次数
40:twi.c **** };
41:twi.c ****
42:twi.c **** struct str_TWI strTWI; //TWI的数据结构变量
43:twi.c ****
44:twi.c **** //仿真时在watch窗口,监控这些全局变量。
45:twi.c ****
46:twi.c ****
47:twi.c **** //AT24C02的读写函数(包括随机读,连续读,字节写,页写)
48:twi.c **** //根据sla的最低位决定(由中断程序中判断)
49:twi.c **** //bit0=1 TW_READ 读
50:twi.c **** //bit0=0 TW_WRITE 写
51:twi.c **** // sla 器件地址(不能搞错)
52:twi.c **** // addr EEPROM地址(0~1023)
53:twi.c **** // *ptr 读写数据缓冲区
54:twi.c **** // len 读数据长度(1~1024),写数据长度(1 or 8 or 16)
55:twi.c **** // 返回值 是否能执行当前操作
56:twi.c **** uint8 TWI_RW(uint8 sla,uint16 addr,uint8 *ptr,uint16 len)
57:twi.c **** {
134 .LM1:
135 /* prologue: frame size=0 */
136 /* prologue end (size=0) */
137 0000 982F mov r25,r24
58:twi.c **** // uint8 i;
59:twi.c **** if (strTWI.STATUS==TW_BUSY)
139 .LM2:
140 0002 8091 0000 lds r24,strTWI
141 0006 8823 tst r24
142 0008 19F4 brne .L2
60:twi.c **** {//TWI忙,不能进行操作
61:twi.c **** return OP_BUSY;
144 .LM3:
145 000a 80E0 ldi r24,lo8(0)
146 000c 90E0 ldi r25,hi8(0)
147 000e 0895 ret
148 .L2:
62:twi.c **** }
63:twi.c **** strTWI.STATUS=TW_BUSY;
150 .LM4:
151 0010 1092 0000 sts strTWI,__zero_reg__
64:twi.c **** // i=(addr>>8)<<1;
65:twi.c **** // i&=0x06; strTWI.SLA=sla+i; //考虑了24C04/08的EEPROM地址高位放在SLA里面
66:twi.c **** strTWI.SLA=sla;
153 .LM5:
154 0014 9093 0000 sts strTWI+1,r25
67:twi.c **** strTWI.ADDR=addr;
156 .LM6:
157 0018 7093 0000 sts (strTWI+2)+1,r23
158 001c 6093 0000 sts strTWI+2,r22
68:twi.c **** strTWI.pBUF=ptr;
160 .LM7:
161 0020 5093 0000 sts (strTWI+4)+1,r21
162 0024 4093 0000 sts strTWI+4,r20
69:twi.c **** strTWI.DATALEN=len;
164 .LM8:
165 0028 3093 0000 sts (strTWI+6)+1,r19
166 002c 2093 0000 sts strTWI+6,r18
70:twi.c **** strTWI.STATE=ST_START;
168 .LM9:
169 0030 81E0 ldi r24,lo8(1)
170 0032 8093 0000 sts strTWI+8,r24
71:twi.c **** strTWI.FAILCNT=0;
172 .LM10:
173 0036 1092 0000 sts strTWI+9,__zero_reg__
72:twi.c **** TWCR=(1<<TWSTA)|TW_ACT; //启动start信号
175 .LM11:
176 003a 85EA ldi r24,lo8(-91)
177 003c 86BF out 86-0x20,r24
73:twi.c **** return OP_RUN;
179 .LM12:
180 003e 81E0 ldi r24,lo8(1)
181 0040 90E0 ldi r25,hi8(1)
74:twi.c **** }
183 .LM13:
184 0042 0895 ret
185 /* epilogue: frame size=0 */
186 /* epilogue: noreturn */
187 /* epilogue end (size=0) */
188 /* function TWI_RW size 34 (34) */
190 .Lscope0:
192 .global __vector_17
194 __vector_17:
75:twi.c ****
76:twi.c **** /*
77:twi.c **** TWI中断函数
78:twi.c **** 这个函数流程只是考虑了器件地址后有一个字节数据(命令)地址的IIC器件
79:twi.c **** (大部分IIC接口器件都是这种类型,常见的例如AT24C01/02/04/08/16,DS1307,DS1721等)
80:twi.c **** 对于有两个字节数据地址的IIC器件(例如AT24C32/64/128/256等大容量EEPROM),请稍作改动
81:twi.c ****
82:twi.c **** //根据strTWI.SLA的最低位决定
83:twi.c **** //bit0=1 TW_READ 读
84:twi.c **** //bit0=0 TW_WRITE 写
85:twi.c ****
86:twi.c **** 虽然中断服务程序很长,但每次只执行一个 case,所以耗时并不长。
87:twi.c **** */
88:twi.c **** SIGNAL(SIG_2WIRE_SERIAL)
89:twi.c **** {//IIC中断
196 .LM14:
197 /* prologue: frame size=0 */
198 0044 1F92 push __zero_reg__
199 0046 0F92 push __tmp_reg__
200 0048 0FB6 in __tmp_reg__,__SREG__
201 004a 0F92 push __tmp_reg__
202 004c 1124 clr __zero_reg__
203 004e 2F93 push r18
204 0050 3F93 push r19
205 0052 4F93 push r20
206 0054 5F93 push r21
207 0056 8F93 push r24
208 0058 9F93 push r25
209 005a EF93 push r30
210 005c FF93 push r31
211 /* prologue end (size=13) */
90:twi.c **** uint8 action,state,status;
91:twi.c **** action=strTWI.SLA&TW_READ; //取操作模式
213 .LM15:
214 005e 3091 0000 lds r19,strTWI+1
215 0062 532F mov r21,r19
216 0064 5170 andi r21,lo8(1)
92:twi.c **** state=strTWI.STATE;
218 .LM16:
219 0066 4091 0000 lds r20,strTWI+8
93:twi.c **** status=TWSR&0xF8; //屏蔽预分频位
221 .LM17:
222 006a 21B1 in r18,33-0x20
223 006c 287F andi r18,lo8(-8)
94:twi.c **** if ((status>=0x60)||(status==0x00))
225 .LM18:
226 006e 822F mov r24,r18
227 0070 8150 subi r24,lo8(-(-1))
228 0072 8F35 cpi r24,lo8(95)
229 0074 08F0 brlo .+2
230 0076 BAC0 rjmp .L3
95:twi.c **** {//总线错误或从机模式引发的中断,不予处理
96:twi.c **** return;
97:twi.c **** }
98:twi.c **** switch(state)
232 .LM19:
233 0078 842F mov r24,r20
234 007a 9927 clr r25
235 007c 8430 cpi r24,4
236 007e 9105 cpc r25,__zero_reg__
237 0080 09F4 brne .+2
238 0082 4AC0 rjmp .L17
239 0084 8530 cpi r24,5
240 0086 9105 cpc r25,__zero_reg__
241 0088 4CF4 brge .L38
242 008a 8230 cpi r24,2
243 008c 9105 cpc r25,__zero_reg__
244 008e B1F0 breq .L9
245 0090 8330 cpi r24,3
246 0092 9105 cpc r25,__zero_reg__
247 0094 24F5 brge .L12
248 0096 0197 sbiw r24,1
249 0098 61F0 breq .L6
250 009a 92C0 rjmp .L37
251 .L38:
252 009c 8630 cpi r24,6
253 009e 9105 cpc r25,__zero_reg__
254 00a0 09F4 brne .+2
255 00a2 43C0 rjmp .L25
256 00a4 8630 cpi r24,6
257 00a6 9105 cpc r25,__zero_reg__
258 00a8 E4F1 brlt .L20
259 00aa 0797 sbiw r24,7
260 00ac 09F4 brne .+2
261 00ae 65C0 rjmp .L32
262 00b0 87C0 rjmp .L37
263 .L6:
99:twi.c **** {
100:twi.c **** case ST_START: //START状态检查
101:twi.c **** if(status==TW_START)
265 .LM20:
266 00b2 2830 cpi r18,lo8(8)
267 00b4 09F0 breq .+2
268 00b6 84C0 rjmp .L37
102:twi.c **** {//发送start信号成功
103:twi.c **** TWDR=strTWI.SLA&0xFE; //发送器件地址写SLAW
270 .LM21:
271 00b8 3E7F andi r19,lo8(-2)
272 00ba 31C0 rjmp .L48
273 .L9:
104:twi.c **** TWCR=TW_ACT; //触发下一步动作,同时清start发送标志
105:twi.c **** }
106:twi.c **** else
107:twi.c **** {//发送start信号出错
108:twi.c **** state=ST_FAIL;
109:twi.c **** }
110:twi.c **** break;
111:twi.c **** case ST_SLAW: //SLAW状态检查
112:twi.c **** if(status==TW_MT_SLA_ACK)
275 .LM22:
276 00bc 2831 cpi r18,lo8(24)
277 00be 09F0 breq .+2
278 00c0 7FC0 rjmp .L37
113:twi.c **** {//发送器件地址成功
114:twi.c **** TWDR=(strTWI.ADDR>>8); //发送eeprom地址高位
280 .LM23:
281 00c2 2091 0000 lds r18,strTWI+2
282 00c6 3091 0000 lds r19,(strTWI+2)+1
283 00ca 832F mov r24,r19
284 00cc 9927 clr r25
285 00ce 83B9 out 35-0x20,r24
115:twi.c **** strTWI.ADDR <<=8;
287 .LM24:
288 00d0 922F mov r25,r18
289 00d2 8827 clr r24
290 00d4 9093 0000 sts (strTWI+2)+1,r25
291 00d8 8093 0000 sts strTWI+2,r24
292 00dc 68C0 rjmp .L43
293 .L12:
116:twi.c **** TWCR=TW_ACT; //触发下一步动作
117:twi.c **** }
118:twi.c **** else
119:twi.c **** {//发送器件地址出错
120:twi.c **** state=ST_FAIL;
121:twi.c **** }
122:twi.c **** break;
123:twi.c **** case ST_WADDR: //ADDR状态检查
124:twi.c **** if(status==TW_MT_DATA_ACK)
295 .LM25:
296 00de 2832 cpi r18,lo8(40)
297 00e0 09F0 breq .+2
298 00e2 6EC0 rjmp .L37
125:twi.c **** {//发送eeprom地址成功
126:twi.c **** if (action==TW_READ)
300 .LM26:
301 00e4 5130 cpi r21,lo8(1)
302 00e6 11F4 brne .L14
127:twi.c **** {//读操作模式
128:twi.c **** TWCR=(1<<TWSTA)|TW_ACT; //发送restart信号,下一步将跳到RESTART分支
304 .LM27:
305 00e8 85EA ldi r24,lo8(-91)
306 00ea 62C0 rjmp .L44
307 .L14:
129:twi.c **** }
130:twi.c **** else
131:twi.c **** {//写操作模式
132:twi.c **** TWDR=*strTWI.pBUF++; //写第一个字节
309 .LM28:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -