3548938166 发表于 2026-1-23 17:37:35

STC8的硬件IIC怎么样

请教一下,STC8系列的单片机硬件I2C怎么样?

计划使用STC8G1K08A,用来给其他IC加载初始化配置,需要发送的内容大概五百多字节。

ercircle 发表于 2026-1-23 18:47:26

好,够用

_奶咖君_ 发表于 2026-1-24 09:15:56

可以用

一笔长空 发表于 2026-1-24 11:06:11

好用

angmall 发表于 2026-1-24 12:01:19


//20.5.6 测试 I2C 从机模式代码的主机代码
//测试工作频率为 11.0592MHz
#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   =   P3^3;
sbit    SCL   =   P3^2;

void Wait()
{
    while (!(I2CMSST & 0x40));
    I2CMSST &= ~0x40;
}

void Start()
{
    I2CMSCR = 0x01;                           //发送START命令
    Wait();
}

void SendData(char dat)
{
    I2CTXD = dat;                               //写数据到数据缓冲区
    I2CMSCR = 0x02;                           //发送SEND命令
    Wait();
}

void RecvACK()
{
    I2CMSCR = 0x03;                           //发送读ACK命令
    Wait();
}

char RecvData()
{
    I2CMSCR = 0x04;                           //发送RECV命令
    Wait();
    return I2CRXD;
}

void SendACK()
{
    I2CMSST = 0x00;                           //设置ACK信号
    I2CMSCR = 0x05;                           //发送ACK命令
    Wait();
}

void SendNAK()
{
    I2CMSST = 0x01;                           //设置NAK信号
    I2CMSCR = 0x05;                           //发送ACK命令
    Wait();
}

void Stop()
{
    I2CMSCR = 0x06;                           //发送STOP命令
    Wait();
}

void Delay()
{
    int i;

    for (i=0; i<3000; i++)
    {
      _nop_();
      _nop_();
      _nop_();
      _nop_();
    }
}

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;
                                                //( STC8G1K08-8Pin 系列、 STC8G1K08A 系列)
    P_SW2 = 0x00;                               //SCL/P3.2, SDA/P3.3
//P_SW2 = 0x10;                               //SCL_2/P5.4, SDA_2/P5.5

//因传统8051的SFR地址空间有限,新增的SFR位于xdata区域(XSFR),必须先打开EAXFR才能访问 XSFR和XDATA共用地址,
//只有访问62.5K以上的XDATA时才需要关闭EAXFR 现有型号,只要不是扩展了片外64K SRAM(外接并口SRAM芯片),
//初始化时果断先打开EAXFR,并且不需要再关闭,不要犹豫!

    P_SW2 |= 0x80;                //外设端口切换寄存器 2   EAXFR=1
//可以在上电系统初始化时将 EAXFR 寄存器设置为 1(例如: P_SW2 |= 0x80;),后续一直保持为 1 不用再修改,即可正常访问 XFR 区域。

    I2CCFG = 0xe0;                              //使能I2C主机模式
    I2CMSST = 0x00;

    Start();                                    //发送起始命令
    SendData(0x5a);                           //发送设备地址(010_1101B)+写命令(0B)
    RecvACK();
    SendData(0x00);                           //发送存储地址
    RecvACK();
    SendData(0x12);                           //写测试数据1
    RecvACK();
    SendData(0x78);                           //写测试数据2
    RecvACK();
    Stop();                                     //发送停止命令

    Start();                                    //发送起始命令
    SendData(0x5a);                           //发送设备地址(010_1101B)+写命令(0B)
    RecvACK();
    SendData(0x00);                           //发送存储地址高字节
    RecvACK();
    Start();                                    //发送起始命令
    SendData(0x5b);                           //发送设备地址(010_1101B)+读命令(1B)
    RecvACK();
    P0 = RecvData();                            //读取数据1
    SendACK();
    P2 = RecvData();                            //读取数据2
    SendNAK();
    Stop();                                     //发送停止命令

    //P_SW2 = 0x00; //后续一直保持为 1 不用再修改
    //若用户不使用外部扩展 RAM 或者外部扩展 RAM 的最大地址不超过 0FA00H(例如只外扩 32K RAM),

    while (1);
}




//20.5.4 I2C 从机模式(中断方式)
//测试工作频率为 11.0592MHz
#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   =   P3^3;
sbit    SCL   =   P3^2;

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; //将 EAXFR 寄存器设置为 1 ,即可正常访问 XFR 区域。

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



//20.5.5 I2C 从机模式(查询方式)
//测试工作频率为 11.0592MHz
#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   =   P3^3;
sbit    SCL   =   P3^2;

bit isda;                                       //设备地址标志
bit isma;                                       //存储地址标志
unsigned char addr;
unsigned char pdata buffer;

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;   //将 EAXFR 寄存器设置为 1 ,即可正常访问 XFR 区域。

    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 = 0x00;                           //禁止从机模式中断

    isda = 1;                                 //用户变量初始化
    isma = 1;
    addr = 0;
    I2CTXD = buffer;

    while (1)
    {
      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;
      }
    }
}

DebugLab 发表于 2026-1-24 12:46:40

几个I2C例程供参考:
https://www.stcaimcu.com/thread-4612-1-1.html
https://www.stcaimcu.com/thread-4613-1-1.html
https://www.stcaimcu.com/thread-4698-1-1.html
页: [1]
查看完整版本: STC8的硬件IIC怎么样