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 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)