375 lines
15 KiB
Plaintext
375 lines
15 KiB
Plaintext
|
|
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为SDA,P1.5为SCL,设置50kHz通信速率,启用中断
|
|||
|
|
130 */
|
|||
|
|
131 void I2C_Init()
|
|||
|
|
132 {
|
|||
|
|
133 1 /* 配置端口模式 */
|
|||
|
|
134 1 P1M0 = 0x04; // P1.2设置为推挽输出(LED),P1.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,计算50kHz:11059200/(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 /* 检查是否收到ACK(I2CMSST的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)
|