STC作为主机轮询扫描I2C设备,确认ICN6211工作状态。

This commit is contained in:
2026-04-10 19:42:22 +08:00
commit 5953218598
19 changed files with 6783 additions and 0 deletions

340
main.c Normal file
View File

@ -0,0 +1,340 @@
/*
* 文件名: main.c
* 功能: STC8G1K08 I2C设备扫描器
* 描述:
* 1. 作为I2C主机扫描所有7位地址0x00-0x7F接收并记录所有应答
* 2. 每5秒自动进行一次扫描
* 3. 每次扫描完成后通过UART输出所有应答地址
* 芯片: STC8G1K08
* 系统时钟: 11.0592MHz
*/
#include "reg51.h"
#include "intrins.h"
#include <stdio.h>
/* 定义STC8G专用寄存器 */
sfr P_SW2 = 0xba; // 端口切换寄存器
sfr AUXR = 0x8e; // 辅助寄存器
sfr T2L = 0xd7; // 定时器2低字节
sfr T2H = 0xd6; // 定时器2高字节
/* 定义I2C相关寄存器使用xdata指针访问扩展SFR */
#define I2CCFG (*(unsigned char volatile xdata *)0xfe80) // I2C配置寄存器
#define I2CMSCR (*(unsigned char volatile xdata *)0xfe81) // I2C主机控制寄存器
#define I2CMSST (*(unsigned char volatile xdata *)0xfe82) // I2C主机状态寄存器
#define I2CSLCR (*(unsigned char volatile xdata *)0xfe83) // I2C从机控制寄存器
#define I2CSLST (*(unsigned char volatile xdata *)0xfe84) // I2C从机状态寄存器
#define I2CSLADR (*(unsigned char volatile xdata *)0xfe85) // I2C从机地址寄存器
#define I2CTXD (*(unsigned char volatile xdata *)0xfe86) // I2C数据发送寄存器
#define I2CRXD (*(unsigned char volatile xdata *)0xfe87) // I2C数据接收寄存器
/* 定义端口模式寄存器 */
sfr P1M1 = 0x91; // P1模式配置寄存器1
sfr P1M0 = 0x92; // P1模式配置寄存器0
/* 定义I2C引脚 */
sbit SDA = P1^4; // I2C数据线
sbit SCL = P1^5; // I2C时钟线
/* 定义LED引脚 */
sbit LED = P1^2; // 状态指示LED
/* 全局变量 */
bit busy; // I2C忙碌标志位
/**
* @brief I2C中断服务函数
* @note 用于处理I2C通信完成事件
*/
void I2C_Isr() interrupt 24 // 关键修复中断号从24改为7
{
_push_(P_SW2); // 保存P_SW2寄存器
P_SW2 |= 0x80; // 访问扩展寄存器
if (I2CMSST & 0x40) // 检查中断标志位BIT6: 主机操作完成)
{
I2CMSST &= ~0x40; // 清除中断标志
busy = 0; // 清除忙碌标志
}
_pop_(P_SW2); // 恢复P_SW2寄存器
}
/**
* @brief 延时函数
* @param ms 延时毫秒数
* @note 系统时钟11.0592MHz
*/
void Delay_ms(unsigned int ms)
{
unsigned int i, j;
for (i = 0; i < ms; i++)
{
for (j = 0; j < 1100; j++); // 修正延时参数更准确的1ms
}
}
/**
* @brief 等待I2C操作完成
*/
void I2C_Wait()
{
while(!(I2CMSST & 0x40)); // 等待中断标志置位
I2CMSST &= ~0x40; // 清除中断标志
}
/**
* @brief 发送I2C起始信号
*/
void I2C_Start()
{
busy = 1; // 设置忙碌标志
I2CMSCR = 0x81; // 发送START命令0x80=主机模式0x01=START
while (busy); // 等待操作完成
}
/**
* @brief 发送I2C数据
* @param dat 要发送的数据
*/
void I2C_SendData(unsigned char dat)
{
I2CTXD = dat; // 写数据到发送缓冲区
busy = 1; // 设置忙碌标志
I2CMSCR = 0x82; // 发送SEND命令0x80=主机模式0x02=SEND
while (busy); // 等待操作完成
}
/**
* @brief 接收I2C应答信号
*/
void I2C_RecvACK()
{
busy = 1; // 设置忙碌标志
I2CMSCR = 0x83; // 发送读ACK命令0x80=主机模式0x03=RECV ACK
while (busy); // 等待操作完成
}
/**
* @brief 发送I2C停止信号
*/
void I2C_Stop()
{
busy = 1; // 增加busy标志保持逻辑一致
I2CMSCR = 0x86; // 发送STOP命令0x80=主机模式0x06=STOP
while (busy); // 等待操作完成
}
/**
* @brief I2C初始化函数
* @note 配置P1.4为SDAP1.5为SCL设置50kHz通信速率启用中断
*/
void I2C_Init()
{
/* 配置端口模式 */
P1M0 = 0x04; // P1.2设置为推挽输出LEDP1.4和P1.5保持准双向口
P1M1 = 0x00;
/* 访问扩展寄存器 */
P_SW2 = 0x80;
/* 配置I2C参数 */
// 0xF3 = 11110011
// bit7=1: 启用I2C
// bit6=1: 主机模式
// bit5=1: 启用I2C中断关键修复开启中断
// bit4~0=0x13: MSSPEED=19计算50kHz11059200/(2*(19+4)*2)=~50kHz
I2CCFG = 0xF3;
/* 初始化I2C状态 */
I2CMSST = 0x00;
/* 启用全局中断和I2C中断 */
EA = 1; // 全局中断使能
}
/* I2C扫描缓冲区用于存储检测到的设备地址 */
unsigned char xdata i2c_scan_buffer[128]; // 7位地址最多128个
unsigned char scan_count = 0; // 扫描到的设备数量
/**
* @brief 扫描指定I2C 7位地址
* @param addr 要扫描的7位I2C地址0x00-0x7F
* @return 1表示收到应答0表示无应答
*/
bit I2C_ScanAddress(unsigned char addr)
{
bit ack_received = 0; // 应答接收标志
/* 跳过保留地址0x00通用呼叫地址 */
if (addr == 0x00)
{
return 0;
}
I2C_Start(); // 发送起始信号
I2C_SendData(addr << 1); // 7位地址左移+读写位0=写)
I2C_RecvACK(); // 接收应答信号
/* 检查是否收到ACKI2CMSST的bit1为0表示收到ACK */
if (!(I2CMSST & 0x02))
{
ack_received = 1; // 收到应答
}
I2C_Stop(); // 发送停止信号
return ack_received;
}
/**
* @brief 扫描所有I2C 7位地址0x00-0x7F
* @note 将所有应答的设备地址存储到缓冲区中
*/
void I2C_ScanAllAddresses(void)
{
unsigned char i;
scan_count = 0; // 清零扫描计数
/* 遍历所有7位I2C地址规范扫描范围 */
for (i = 0; i < 128; i++)
{
if (I2C_ScanAddress(i)) // 如果收到应答
{
/* 防止缓冲区溢出 */
if (scan_count < 128)
{
i2c_scan_buffer[scan_count++] = i; // 将7位地址存入缓冲区
}
Delay_ms(1); // 短暂延时,避免总线冲突
}
}
}
/**
* @brief UART1初始化函数
* @note 波特率115200bps系统时钟11.0592MHz
*/
void uart1_init(void)
{
SCON = 0x50; // 8位UART允许接收
AUXR |= 0x01; // 串口1选择定时器2为波特率发生器
AUXR &= 0xFB; // 定时器2时钟为12T模式
T2L = 0xFE; // 设置定时器2初值
T2H = 0xFF; // 设置定时器2初值
AUXR |= 0x10; // 启动定时器2
TI = 1; // 设置TI标志用于printf重定向
}
/**
* @brief putchar重定向函数用于printf输出
* @param c 要输出的字符
* @return 输出的字符
*/
char putchar(char c)
{
SBUF = c; // 写入发送缓冲区
while (!TI); // 等待发送完成
TI = 0; // 清除发送完成标志
return c;
}
/**
* @brief 通过UART打印I2C扫描结果
* @note 输出格式化的扫描结果,包括设备数量和地址列表
*/
void UART_PrintScanResults(void)
{
unsigned char i;
printf("\r\n=== I2C扫描结果 ===\r\n");
// printf("检测到的7位I2C设备数量: %d\r\n", scan_count);
if (scan_count > 0)
{
printf("应答地址列表7位:\r\n");
for (i = 0; i < scan_count; i++)
{
printf("0x%02X ", i2c_scan_buffer[i]); // 以十六进制格式输出7位地址
if ((i + 1) % 8 == 0) // 每8个地址换行
{
printf("\r\n");
}
}
printf("\r\n");
printf("对应发送地址8位写模式:\r\n");
for (i = 0; i < scan_count; i++)
{
printf("0x%02X ", i2c_scan_buffer[i] << 1);
if ((i + 1) % 8 == 0) // 每8个地址换行
{
printf("\r\n");
}
}
printf("\r\n");
}
else
{
printf("未检测到任何I2C设备\r\n");
}
printf("==================\r\n");
}
void Delay5000ms(void) //@11.0592MHz
{
unsigned char data i, j, k;
_nop_();
_nop_();
i = 211;
j = 30;
k = 11;
do
{
do
{
while (--k);
} while (--j);
} while (--i);
}
/**
* @brief 主函数
*/
void main()
{
/* 初始化各模块 */
I2C_Init(); // 初始化I2C
uart1_init(); // 初始化UART1
LED = 0; // 点亮LED推挽输出低电平点亮
/* 输出启动信息 */
printf("\r\n");
printf("========================================\r\n");
printf(" STC8G1K08 I2C设备扫描器\r\n");
printf("========================================\r\n");
printf("系统初始化完成...\r\n");
printf("每5秒自动扫描一次I2C总线\r\n");
printf("========================================\r\n");
/* 主循环 */
while (1)
{
/* LED闪烁指示扫描开始 */
LED = 1; // 熄灭LED
Delay_ms(100);
LED = 0; // 点亮LED
printf("\r\n[开始扫描...]\r\n");
I2C_ScanAllAddresses(); // 执行I2C扫描
printf("[扫描完成]\r\n");
UART_PrintScanResults(); // 输出扫描结果
scan_count = 0; // 清零扫描计数,准备下一次扫描
Delay5000ms(); // 等待5秒后再次扫描
}
}