Files
102_STC_I2C_SCAN/Listings/main.lst

375 lines
15 KiB
Plaintext
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

C51 COMPILER V9.55 MAIN 04/10/2026 09:44:22 PAGE 1
C51 COMPILER V9.55, COMPILATION OF MODULE MAIN
OBJECT MODULE PLACED IN .\Objects\main.obj
COMPILER INVOKED BY: C:\Keil_v5\C51\BIN\C51.EXE main.c OPTIMIZE(8,SPEED) BROWSE DEBUG OBJECTEXTEND PRINT(.\Listings\main
-.lst) TABS(2) OBJECT(.\Objects\main.obj)
line level source
1 /*
2 * 文件名: main.c
3 * 功能: STC8G1K08 I2C设备扫描器
4 * 描述:
5 * 1. 作为I2C主机扫描所有7位地址0x00-0x7F接收并记录所有应答
6 * 2. 每5秒自动进行一次扫描
7 * 3. 每次扫描完成后通过UART输出所有应答地址
8 * 芯片: STC8G1K08
9 * 系统时钟: 11.0592MHz
10 */
11
12 #include "reg51.h"
13 #include "intrins.h"
14 #include <stdio.h>
15
16 /* 定义STC8G专用寄存器 */
17 sfr P_SW2 = 0xba; // 端口切换寄存器
18 sfr AUXR = 0x8e; // 辅助寄存器
19 sfr T2L = 0xd7; // 定时器2低字节
20 sfr T2H = 0xd6; // 定时器2高字节
21
22 /* 定义I2C相关寄存器使用xdata指针访问扩展SFR */
23 #define I2CCFG (*(unsigned char volatile xdata *)0xfe80) // I2C配置寄存器
24 #define I2CMSCR (*(unsigned char volatile xdata *)0xfe81) // I2C主机控制寄存器
25 #define I2CMSST (*(unsigned char volatile xdata *)0xfe82) // I2C主机状态寄存器
26 #define I2CSLCR (*(unsigned char volatile xdata *)0xfe83) // I2C从机控制寄存器
27 #define I2CSLST (*(unsigned char volatile xdata *)0xfe84) // I2C从机状态寄存器
28 #define I2CSLADR (*(unsigned char volatile xdata *)0xfe85) // I2C从机地址寄存器
29 #define I2CTXD (*(unsigned char volatile xdata *)0xfe86) // I2C数据发送寄存器
30 #define I2CRXD (*(unsigned char volatile xdata *)0xfe87) // I2C数据接收寄存器
31
32 /* 定义端口模式寄存器 */
33 sfr P1M1 = 0x91; // P1模式配置寄存器1
34 sfr P1M0 = 0x92; // P1模式配置寄存器0
35
36 /* 定义I2C引脚 */
37 sbit SDA = P1^4; // I2C数据线
38 sbit SCL = P1^5; // I2C时钟线
39
40 /* 定义LED引脚 */
41 sbit LED = P1^2; // 状态指示LED
42
43 /* 全局变量 */
44 bit busy; // I2C忙碌标志位
45
46 /**
47 * @brief I2C中断服务函数
48 * @note 用于处理I2C通信完成事件
49 */
50 void I2C_Isr() interrupt 24 // 关键修复中断号从24改为7
51 {
52 1 _push_(P_SW2); // 保存P_SW2寄存器
53 1 P_SW2 |= 0x80; // 访问扩展寄存器
54 1 if (I2CMSST & 0x40) // 检查中断标志位BIT6: 主机操作完成)
C51 COMPILER V9.55 MAIN 04/10/2026 09:44:22 PAGE 2
55 1 {
56 2 I2CMSST &= ~0x40; // 清除中断标志
57 2 busy = 0; // 清除忙碌标志
58 2 }
59 1 _pop_(P_SW2); // 恢复P_SW2寄存器
60 1 }
61
62 /**
63 * @brief 延时函数
64 * @param ms 延时毫秒数
65 * @note 系统时钟11.0592MHz
66 */
67 void Delay_ms(unsigned int ms)
68 {
69 1 unsigned int i, j;
70 1 for (i = 0; i < ms; i++)
71 1 {
72 2 for (j = 0; j < 1100; j++); // 修正延时参数更准确的1ms
73 2 }
74 1 }
75
76 /**
77 * @brief 等待I2C操作完成
78 */
79 void I2C_Wait()
80 {
81 1 while(!(I2CMSST & 0x40)); // 等待中断标志置位
82 1 I2CMSST &= ~0x40; // 清除中断标志
83 1 }
84
85 /**
86 * @brief 发送I2C起始信号
87 */
88 void I2C_Start()
89 {
90 1 busy = 1; // 设置忙碌标志
91 1 I2CMSCR = 0x81; // 发送START命令0x80=主机模式0x01=START
92 1 while (busy); // 等待操作完成
93 1 }
94
95 /**
96 * @brief 发送I2C数据
97 * @param dat 要发送的数据
98 */
99 void I2C_SendData(unsigned char dat)
100 {
101 1 I2CTXD = dat; // 写数据到发送缓冲区
102 1 busy = 1; // 设置忙碌标志
103 1 I2CMSCR = 0x82; // 发送SEND命令0x80=主机模式0x02=SEND
104 1 while (busy); // 等待操作完成
105 1 }
106
107 /**
108 * @brief 接收I2C应答信号
109 */
110 void I2C_RecvACK()
111 {
112 1 busy = 1; // 设置忙碌标志
113 1 I2CMSCR = 0x83; // 发送读ACK命令0x80=主机模式0x03=RECV ACK
114 1 while (busy); // 等待操作完成
115 1 }
116
C51 COMPILER V9.55 MAIN 04/10/2026 09:44:22 PAGE 3
117 /**
118 * @brief 发送I2C停止信号
119 */
120 void I2C_Stop()
121 {
122 1 busy = 1; // 增加busy标志保持逻辑一致
123 1 I2CMSCR = 0x86; // 发送STOP命令0x80=主机模式0x06=STOP
124 1 while (busy); // 等待操作完成
125 1 }
126
127 /**
128 * @brief I2C初始化函数
129 * @note 配置P1.4为SDAP1.5为SCL设置50kHz通信速率启用中断
130 */
131 void I2C_Init()
132 {
133 1 /* 配置端口模式 */
134 1 P1M0 = 0x04; // P1.2设置为推挽输出LEDP1.4和P1.5保持准双向口
135 1 P1M1 = 0x00;
136 1
137 1 /* 访问扩展寄存器 */
138 1 P_SW2 = 0x80;
139 1
140 1 /* 配置I2C参数 */
141 1 // 0xF3 = 11110011
142 1 // bit7=1: 启用I2C
143 1 // bit6=1: 主机模式
144 1 // bit5=1: 启用I2C中断关键修复开启中断
145 1 // bit4~0=0x13: MSSPEED=19计算50kHz11059200/(2*(19+4)*2)=~50kHz
146 1 I2CCFG = 0xF3;
147 1
148 1 /* 初始化I2C状态 */
149 1 I2CMSST = 0x00;
150 1
151 1 /* 启用全局中断和I2C中断 */
152 1 EA = 1; // 全局中断使能
153 1 }
154
155 /* I2C扫描缓冲区用于存储检测到的设备地址 */
156 unsigned char xdata i2c_scan_buffer[128]; // 7位地址最多128个
157 unsigned char scan_count = 0; // 扫描到的设备数量
158
159 /**
160 * @brief 扫描指定I2C 7位地址
161 * @param addr 要扫描的7位I2C地址0x00-0x7F
162 * @return 1表示收到应答0表示无应答
163 */
164 bit I2C_ScanAddress(unsigned char addr)
165 {
166 1 bit ack_received = 0; // 应答接收标志
167 1
168 1 /* 跳过保留地址0x00通用呼叫地址 */
169 1 if (addr == 0x00)
170 1 {
171 2 return 0;
172 2 }
173 1
174 1 I2C_Start(); // 发送起始信号
175 1 I2C_SendData(addr << 1); // 7位地址左移+读写位0=写)
176 1 I2C_RecvACK(); // 接收应答信号
177 1
178 1 /* 检查是否收到ACKI2CMSST的bit1为0表示收到ACK */
C51 COMPILER V9.55 MAIN 04/10/2026 09:44:22 PAGE 4
179 1 if (!(I2CMSST & 0x02))
180 1 {
181 2 ack_received = 1; // 收到应答
182 2 }
183 1
184 1 I2C_Stop(); // 发送停止信号
185 1
186 1 return ack_received;
187 1 }
188
189 /**
190 * @brief 扫描所有I2C 7位地址0x00-0x7F
191 * @note 将所有应答的设备地址存储到缓冲区中
192 */
193 void I2C_ScanAllAddresses(void)
194 {
195 1 unsigned char i;
196 1 scan_count = 0; // 清零扫描计数
197 1
198 1 /* 遍历所有7位I2C地址规范扫描范围 */
199 1 for (i = 0; i < 128; i++)
200 1 {
201 2 if (I2C_ScanAddress(i)) // 如果收到应答
202 2 {
203 3 /* 防止缓冲区溢出 */
204 3 if (scan_count < 128)
205 3 {
206 4 i2c_scan_buffer[scan_count++] = i; // 将7位地址存入缓冲区
207 4 }
208 3 Delay_ms(1); // 短暂延时,避免总线冲突
209 3 }
210 2 }
211 1 }
212
213 /**
214 * @brief UART1初始化函数
215 * @note 波特率115200bps系统时钟11.0592MHz
216 */
217 void uart1_init(void)
218 {
219 1 SCON = 0x50; // 8位UART允许接收
220 1 AUXR |= 0x01; // 串口1选择定时器2为波特率发生器
221 1 AUXR &= 0xFB; // 定时器2时钟为12T模式
222 1 T2L = 0xFE; // 设置定时器2初值
223 1 T2H = 0xFF; // 设置定时器2初值
224 1 AUXR |= 0x10; // 启动定时器2
225 1 TI = 1; // 设置TI标志用于printf重定向
226 1 }
227
228 /**
229 * @brief putchar重定向函数用于printf输出
230 * @param c 要输出的字符
231 * @return 输出的字符
232 */
233 char putchar(char c)
234 {
235 1 SBUF = c; // 写入发送缓冲区
236 1 while (!TI); // 等待发送完成
237 1 TI = 0; // 清除发送完成标志
238 1 return c;
239 1 }
240
C51 COMPILER V9.55 MAIN 04/10/2026 09:44:22 PAGE 5
241 /**
242 * @brief 通过UART打印I2C扫描结果
243 * @note 输出格式化的扫描结果,包括设备数量和地址列表
244 */
245 void UART_PrintScanResults(void)
246 {
247 1 unsigned char i;
248 1
249 1 printf("\r\n=== I2C扫描结果 ===\r\n");
250 1 // printf("检测到的7位I2C设备数量: %d\r\n", scan_count);
251 1
252 1 if (scan_count > 0)
253 1 {
254 2 printf("应答地址列表7位:\r\n");
255 2 for (i = 0; i < scan_count; i++)
256 2 {
257 3 printf("0x%02X ", i2c_scan_buffer[i]); // 以十六进制格式输出7位地址
258 3 if ((i + 1) % 8 == 0) // 每8个地址换行
259 3 {
260 4 printf("\r\n");
261 4 }
262 3 }
263 2 printf("\r\n");
264 2 printf("对应发送地址8位写模式:\r\n");
265 2 for (i = 0; i < scan_count; i++)
266 2 {
267 3 printf("0x%02X ", i2c_scan_buffer[i] << 1);
268 3 if ((i + 1) % 8 == 0) // 每8个地址换行
269 3 {
270 4 printf("\r\n");
271 4 }
272 3 }
273 2 printf("\r\n");
274 2 }
275 1 else
276 1 {
277 2 printf("未检测到任何I2C设备\r\n");
278 2 }
279 1 printf("==================\r\n");
280 1 }
281
282
283
284 void Delay5000ms(void) //@11.0592MHz
285 {
286 1 unsigned char data i, j, k;
287 1
288 1 _nop_();
289 1 _nop_();
290 1 i = 211;
291 1 j = 30;
292 1 k = 11;
293 1 do
294 1 {
295 2 do
296 2 {
297 3 while (--k);
298 3 } while (--j);
299 2 } while (--i);
300 1 }
301
302 /**
C51 COMPILER V9.55 MAIN 04/10/2026 09:44:22 PAGE 6
303 * @brief 主函数
304 */
305 void main()
306 {
307 1 /* 初始化各模块 */
308 1 I2C_Init(); // 初始化I2C
309 1 uart1_init(); // 初始化UART1
310 1
311 1 LED = 0; // 点亮LED推挽输出低电平点亮
312 1
313 1 /* 输出启动信息 */
314 1 printf("\r\n");
315 1 printf("========================================\r\n");
316 1 printf(" STC8G1K08 I2C设备扫描器\r\n");
317 1 printf("========================================\r\n");
318 1 printf("系统初始化完成...\r\n");
319 1 printf("每5秒自动扫描一次I2C总线\r\n");
320 1 printf("========================================\r\n");
321 1
322 1 /* 主循环 */
323 1 while (1)
324 1 {
325 2 /* LED闪烁指示扫描开始 */
326 2 LED = 1; // 熄灭LED
327 2 Delay_ms(100);
328 2 LED = 0; // 点亮LED
329 2
330 2 printf("\r\n[开始扫描...]\r\n");
331 2 I2C_ScanAllAddresses(); // 执行I2C扫描
332 2 printf("[扫描完成]\r\n");
333 2
334 2 UART_PrintScanResults(); // 输出扫描结果
335 2
336 2 scan_count = 0; // 清零扫描计数,准备下一次扫描
337 2
338 2 Delay5000ms(); // 等待5秒后再次扫描
339 2 }
340 1 }
MODULE INFORMATION: STATIC OVERLAYABLE
CODE SIZE = 576 ----
CONSTANT SIZE = 342 ----
XDATA SIZE = 128 ----
PDATA SIZE = ---- ----
DATA SIZE = 1 1
IDATA SIZE = ---- ----
BIT SIZE = 1 1
END OF MODULE INFORMATION.
C51 COMPILATION COMPLETE. 0 WARNING(S), 0 ERROR(S)