第1篇_8H1K17 I2C从机如何/何时发送ACK/NACK
我的8H1K17 I2C作为从机,如果主机要读寄存器,是直接将数据赋值给I2CTXD,它就会自动启动发送数据给主机,是吗?还是说要做其他设置1, I/O 设置成开漏,外部加10K 上拉电阻,或提前打开内部上拉电阻
2,这有现成的参考程序
#include "reg51.h"
#include "intrins.h"
sfr P_SW2 = 0xba;
#define I2CCFG (*(unsigned char volatile xdata *)0xfe80)
#define I2CMSCR (*(unsigned char volatile xdata *)0xfe81)
#define I2CMSST (*(unsigned char volatile xdata *)0xfe82)
#define I2CSLCR (*(unsigned char volatile xdata *)0xfe83)
#define I2CSLST (*(unsigned char volatile xdata *)0xfe84)
#define I2CSLADR (*(unsigned char volatile xdata *)0xfe85)
#define I2CTXD (*(unsigned char volatile xdata *)0xfe86)
#define I2CRXD (*(unsigned char volatile xdata *)0xfe87)
sfr P1M1 = 0x91;
sfr P1M0 = 0x92;
sfr P0M1 = 0x93;
sfr P0M0 = 0x94;
sfr P2M1 = 0x95;
sfr P2M0 = 0x96;
sfr P3M1 = 0xb1;
sfr P3M0 = 0xb2;
sfr P4M1 = 0xb3;
sfr P4M0 = 0xb4;
sfr P5M1 = 0xc9;
sfr P5M0 = 0xca;
sbit SDA = P1^4;
sbit SCL = P1^5;
bit isda; //设备地址标志
bit isma; //存储地址标志
unsigned char addr;
unsigned char pdata buffer;
void I2C_Isr() interrupt 24
{
_push_(P_SW2);
P_SW2 |= 0x80;
if (I2CSLST & 0x40)
{
I2CSLST &= ~0x40; //处理START事件
}
else if (I2CSLST & 0x20)
{
I2CSLST &= ~0x20; //处理RECV事件
if (isda)
{
isda = 0; //处理RECV事件(RECV DEVICE ADDR)
}
else if (isma)
{
isma = 0; //处理RECV事件(RECV MEMORY ADDR)
addr = I2CRXD;
I2CTXD = buffer;
}
else
{
buffer = I2CRXD; //处理RECV事件(RECV DATA)
}
}
else if (I2CSLST & 0x10)
{
I2CSLST &= ~0x10; //处理SEND事件
if (I2CSLST & 0x02)
{
I2CTXD = 0xff; //接收到NAK则停止读取数据
}
else
{
I2CTXD = buffer[++addr]; //接收到ACK则继续读取数据
}
}
else if (I2CSLST & 0x08)
{
I2CSLST &= ~0x08; //处理STOP事件
isda = 1;
isma = 1;
}
_pop_(P_SW2);
}
void main()
{
P0M0 = 0x00;
P0M1 = 0x00;
P1M0 = 0x00;
P1M1 = 0x00;
P2M0 = 0x00;
P2M1 = 0x00;
P3M0 = 0x00;
P3M1 = 0x00;
P4M0 = 0x00;
P4M1 = 0x00;
P5M0 = 0x00;
P5M1 = 0x00;
P_SW2 = 0x80;
I2CCFG = 0x81; //使能I2C从机模式
I2CSLADR = 0x5a; //设置从机设备地址寄存器I2CSLADR=0101_1010B
//即I2CSLADR=010_1101B,MA=0B。
//由于MA为0,主机发送的的设备地址必须与
//I2CSLADR相同才能访问此I2C从机设备。
//主机若需要写数据则要发送5AH(0101_1010B)
//主机若需要读数据则要发送5BH(0101_1011B)
I2CSLST = 0x00;
I2CSLCR = 0x78; //使能从机模式中断
EA = 1;
isda = 1; //用户变量初始化
isma = 1;
addr = 0;
I2CTXD = buffer;
while (1);
}
从机是把数据放到寄存器然后等主机来读,通信需要时钟,从机又不能主动发时钟 DebugLab 发表于 2025-3-18 17:30
从机是把数据放到寄存器然后等主机来读,通信需要时钟,从机又不能主动发时钟 ...
我设置的是主机先发送设备地址,再发送寄存器地址,然后读取I2CTXD的值,那主机要怎么读I2CTXD?STC8H将值赋值给I2CTXD,它什么时候会把逻辑值推送到SDA引脚?收到起始信号,就把I2CTXD的逻辑值推送到SDA引脚吗? 主机发送完设备地址,寄存器地址,之后再发送起始信号,然后呢?从机通过什么方式把数据放到SDA引脚上?
参考手册例程:
ercircle 发表于 2025-3-18 17:56
参考手册例程:
我发的图就是手册的这一部分 图里不是收到主机事件,将数据放到寄存器了嘛,放了SDA引脚应该就有反应了。
你是想问怎么绑定SDA引脚?
按照一楼的说法,看来STC8H1K17不支持寄存器读取的操作,因为你一发读写操作,就要给I2CTXD赋值,此时我主机还没把寄存器地址发送过去呢,但即使是这种情况,仍然可以实现我的目的,我只需要将MA设置为1,设置从机接受所有设备地址,然后把我的不同的寄存器地址统统设置为不同的设备地址,这样只要我一读设备地址,从机就给我发数据 ercircle 发表于 2025-3-18 18:11
图里不是收到主机事件,将数据放到寄存器了嘛,放了SDA引脚应该就有反应了。
I2C中读数据分三步,第一步发送设备地址,第二步发送寄存器地址,第三步发送时钟信号,此时主机去读SDA线上的电平。我想问的就是第三步,我要怎么操作STC单片机(从机),它会在第三步把逻辑电平推送到SDA引脚 按照你数据手册从机中断的代码例程,当我发送完设备地址后(读寄存器),此时给I2CTXD赋值,等我再发寄存器地址(此时主机在发SCL)时,从机就会和主机抢SDA线的控制权