zhang_yg188 发表于 2023-8-21 15:21:03

stc8G1k-sop8封装I2C功能怪怪问题请教

本帖最后由 zhang_yg188 于 2023-8-21 15:21 编辑

以前用STC8H-tssop20的MCU,功能已经OK,就是STC的P32和P33口作为I2C从机,接受上位机指令,P10点亮8个WS2812。现在准备换STC8G的SOP8封装,只是更改了驱动2812的管脚定义,发现不能亮灯,上位机也扫描不到STC的I2C,IO和I2C的设置都是用的官网上的库函数。焊接了一个试验板,P54连接一个普通LED的负极加电阻,试验闪灯功能,发现只要I2C用I2C_P14_P15,功能OK ,用I2C_P24_P25和 I2C_P33_P32,不能闪灯。请教下是什么问题,程序如下:
////*************主程序
#include      "config.h"
#include      "GPIO.h"
#include      "timer.h"
#include      "I2C.h"
#include      "delay.h"
#include<all.h>
/*************      本地变量声明      **************/
u8 from_maser_data = 0x01;                                                      //从i2c主机得到的命令符,
u8 to_maser_data;                                                                        //返回给主机的按键的电平
u8 dt=100;
u8 time_counter=0;
u8 delay_each = 5000 ,delay_cy=8;                                                               
/******************** IO口配置 ********************/
void      GPIO_config(void)
{
      GPIO_InitTypeDef      GPIO_InitStructure;                                                                                                                                                                        //结构定义
      GPIO_InitStructure.Pin= GPIO_Pin_All;                                                                                                                                                                //指定要初始化的IO, GPIO_Pin_0 ~ GPIO_Pin_7
      GPIO_InitStructure.Mode = GPIO_PullUp;                                                                                                                                                                //指定IO的输入或输出方式,GPIO_PullUp,GPIO_HighZ,GPIO_OUT_OD,GPIO_OUT_PP
      GPIO_Inilize(GPIO_P1,&GPIO_InitStructure);                                                                                                                              //P1口初始化,预备接8个LED,设置成准双向标准接口。
      GPIO_InitStructure.Pin= GPIO_Pin_All;                                                                                                                                                                //指定要初始化的IO, GPIO_Pin_0 ~ GPIO_Pin_7
      GPIO_InitStructure.Mode = GPIO_PullUp;                                                                                                                                                                //指定IO的输入或输出方式,GPIO_PullUp,GPIO_HighZ,GPIO_OUT_OD,GPIO_OUT_PP
      GPIO_Inilize(GPIO_P3,&GPIO_InitStructure);                                                                                                                              //P3口初始化,设置成准双向标准接口,作为I2C和触摸按键接口。
      
      GPIO_InitStructure.Pin= GPIO_Pin_All;                                                                                                                                                                //指定要初始化的IO, GPIO_Pin_0 ~ GPIO_Pin_7
      GPIO_InitStructure.Mode = GPIO_PullUp;                                                                                                                                                                //指定IO的输入或输出方式,GPIO_PullUp,GPIO_HighZ,GPIO_OUT_OD,GPIO_OUT_PP
      GPIO_Inilize(GPIO_P5,&GPIO_InitStructure);                                                                                                                               //P5口初始化,设置成准双向标准接口,作为I2C和触摸按键接口。         
}
/************************ 定时器配置 ****************************/
void      Timer_config(void)
{      
      TIM_InitTypeDef                TIM_InitStructure;                                                //结构定义
      TIM_InitStructure.TIM_Interrupt = ENABLE;                                        //中断是否允许,   ENABLE或DISABLE. (注意: Timer2固定为16位自动重装, 中断固定为低优先级)
      TIM_InitStructure.TIM_ClkSource = TIM_CLOCK_1T;                //指定时钟源,   TIM_CLOCK_1T,TIM_CLOCK_12T,TIM_CLOCK_Ext
      TIM_InitStructure.TIM_ClkOut    = DISABLE;                              //是否输出高速脉冲, ENABLE或DISABLE
      TIM_InitStructure.TIM_Value   = 65536UL - (MAIN_Fosc / 1000);                              //初值
      TIM_InitStructure.TIM_Run       = ENABLE;                                        //是否初始化后启动定时器, ENABLE或DISABLE
      Timer_Inilize(Timer2,&TIM_InitStructure);                                        //初始化Timer2          Timer0,Timer1,Timer2,Timer3,Timer4                                       1毫秒/次
}

/****************I2C初始化函数 *****************/
void      I2C_config(void)
{
      I2C_InitTypeDef                I2C_InitStructure;
      I2C_InitStructure.I2C_Mode      = I2C_Mode_Slave;                                        //从机                                                //主从选择   I2C_Mode_Master, I2C_Mode_Slave
      I2C_InitStructure.I2C_Enable    = ENABLE;                                                                                                                                                //I2C功能使能,   ENABLE, DISABLE
      I2C_InitStructure.I2C_SL_ESTAI= ENABLE;                                                                                                                                                //从机接收START信号中断使能,ENABLE, DISABLE
      I2C_InitStructure.I2C_SL_ERXI   = ENABLE;                                                                                                                                                //从机接收1字节数据中断使能,ENABLE, DISABLE
      I2C_InitStructure.I2C_SL_ETXI   = ENABLE;                                                                                                                                                //从机发送1字节数据中断使能,ENABLE, DISABLE
      I2C_InitStructure.I2C_SL_ESTOI= ENABLE;                                                                                                                                                //从机接收STOP信号中断使能,   ENABLE, DISABLE
      I2C_InitStructure.I2C_SL_MA   = ENABLE;                                                                                                                                                //使能从机地址比较功能,   ENABLE, DISABLE
      I2C_InitStructure.I2C_SL_ADR    = 94;                                                //从机地址
      //I2C_InitStructure.I2C_IoUse   = I2C_P14_P15;                                        //用P14和P15,LED闪烁功能OK
      //I2C_InitStructure.I2C_IoUse   = I2C_P24_P25;                                        //用P24和P25,LED不闪烁
      I2C_InitStructure.I2C_IoUse   = I2C_P33_P32;                                    //用P32和P33,LED也不闪烁//      IO口切换   I2C_P14_P15, I2C_P24_P25, I2C_P33_P32,接口为:P33(SDA),P32(SCL)
      I2C_Init(&I2C_InitStructure);
}
void main(void)
{
      u8 dt=500;
      GPIO_config();
      Timer_config();
      //I2C_config();                                                       //注释这句,闪灯OK;如果打开注释,I2C_InitStructure.I2C_IoUse   = I2C_P14_P15; 闪灯OK,其余两个不闪烁。
      EA = 1;
      while(1){
                P54 =1;
                delay_ms(dt);
                P54 = 0;
                delay_ms(dt);
      }
}


/****************I2C库函数 *****************/
#include      "I2C.h"
//#define Software_I2C                                                                                                      //使能软件模拟I2C;不用SOFTI2C
u8         I2C_BUF_type I2C_Buffer;
I2C_IsrTypeDef I2CIsr;
//extern bit DisplayFlag;
extern u8 from_maser_data;                                                //从i2c主机得到的命令符,
extern u8 to_maser_data;                                                      //返回给主机的触摸按键的电平

//========================================================================
// 函数: void      I2C_Init(I2C_InitTypeDef *I2Cx)
// 描述: I2C初始化程序.
// 参数: I2Cx: 结构参数,请参考I2C.h里的定义.
// 返回: none.
// 版本: V1.0, 2020-09-16
//========================================================================
void      I2C_Init(I2C_InitTypeDef *I2Cx)
{
      EAXSFR();                /* MOVX A,@DPTR/MOVX @DPTR,A指令的操作对象为扩展SFR(XSFR) */
      
      if(I2Cx->I2C_Mode == I2C_Mode_Master)
      {
                I2C_Master();                                                                                                                                                                                                                        //设为主机      
                I2CMSST = 0x00;                                                                                                                                                                                                                //清除I2C主机状态寄存器
                I2C_Master_Inturrupt(I2Cx->I2C_MS_Interrupt);
                I2C_SetSpeed(I2Cx->I2C_Speed);
                if(I2Cx->I2C_MS_WDTA == ENABLE)                I2C_WDTA_EN();                                                                        //使能自动发送
                else                                                                        I2C_WDTA_DIS();                                                                                                                        //禁止自动发送
      }
      else
      {
                I2C_Slave();      //设为从机
                I2CSLST = 0x00;                //清除I2C从机状态寄存器
                if(I2Cx->I2C_SL_ESTAI == ENABLE)                I2C_ESTAI_EN();                                                                //使能从机接收START信号中断
                else                                                                        I2C_ESTAI_DIS();                                                                                                                //禁止从机接收START信号中断
                if(I2Cx->I2C_SL_ERXI == ENABLE)                I2C_ERXI_EN();                                                                        //使能从机接收1字节数据中断
                else                                                                        I2C_ERXI_DIS();                                                                                                                        //禁止从机接收1字节数据中断
                if(I2Cx->I2C_SL_ETXI == ENABLE)                I2C_ETXI_EN();                                                                        //使能从机发送1字节数据中断
                else                                                                        I2C_ETXI_DIS();                                                                                                                        //禁止从机发送1字节数据中断
                if(I2Cx->I2C_SL_ESTOI == ENABLE)                I2C_ESTOI_EN();                                                                //使能从机接收STOP信号中断
                else                                                                        I2C_ESTOI_DIS();                                                                                                                //禁止从机接收STOP信号中断
                I2C_Address(I2Cx->I2C_SL_ADR);
                if(I2Cx->I2C_SL_MA == ENABLE)                I2C_MATCH_EN();                                                                              //从机地址比较功能,只接受相匹配地址
                else                                                                        I2C_MATCH_DIS();                                                                                                                //禁止从机地址比较功能,接受所有设备地址
      }
      
      P_SW2 = (P_SW2 & ~(3<<4)) | I2Cx->I2C_IoUse;
      I2C_Function(I2Cx->I2C_Enable);
      
      I2CIsr.isda = 1;
      I2CIsr.isma = 1;
      I2CIsr.addr = 0;
      I2CTXD = I2C_Buffer;

      EAXRAM();                /* MOVX A,@DPTR/MOVX @DPTR,A指令的操作对象为扩展RAM(XRAM) */
}

#ifdef Software_I2C

#define SLAW    0x5A
#define SLAR    0x5B

sbit    SDA = P0^1; //定义SDA
sbit    SCL = P0^0; //定义SCL

/****************************/
void I2C_Delay(void) //for normal MCS51, delay (2 * dly + 4) T, for STC12Cxxxx delay (4 * dly + 10) T
{
      u8dly;
      dly = MAIN_Fosc / 2000000UL;      //按2us计算
      while(--dly);
}

/****************************/
void I2C_Start(void)               //start the I2C, SDA High-to-low when SCL is high
{
      SDA = 1;
      I2C_Delay();
      SCL = 1;
      I2C_Delay();
      SDA = 0;
      I2C_Delay();
      SCL = 0;
      I2C_Delay();
}      


void I2C_Stop(void)               //STOP the I2C, SDA Low-to-high when SCL is high
{
      SDA = 0;
      I2C_Delay();
      SCL = 1;
      I2C_Delay();
      SDA = 1;
      I2C_Delay();
}

void S_ACK(void)            //Send ACK (LOW)
{
      SDA = 0;
      I2C_Delay();
      SCL = 1;
      I2C_Delay();
      SCL = 0;
      I2C_Delay();
}

void S_NoACK(void)         //Send No ACK (High)
{
      SDA = 1;
      I2C_Delay();
      SCL = 1;
      I2C_Delay();
      SCL = 0;
      I2C_Delay();
}
      
void I2C_Check_ACK(void)         //Check ACK, If F0=0, then right, if F0=1, then error
{
      SDA = 1;
      I2C_Delay();
      SCL = 1;
      I2C_Delay();
      F0= SDA;
      SCL = 0;
      I2C_Delay();
}

/****************************/
void I2C_WriteAbyte(u8 dat)   //write a byte to I2C
{
      u8 i;
      i = 8;
      do
      {
                if(dat & 0x80)SDA = 1;
                else            SDA = 0;
                dat <<= 1;
                I2C_Delay();
                SCL = 1;
                I2C_Delay();
                SCL = 0;
                I2C_Delay();
      }
      while(--i);
}

/****************************/
u8 I2C_ReadAbyte(void)          //read A byte from I2C
{
      u8 i,dat;
      i = 8;
      SDA = 1;
      do
      {
                SCL = 1;
                I2C_Delay();
                dat <<= 1;
                if(SDA)   dat++;
                SCL= 0;
                I2C_Delay();
      }
      while(--i);
      return(dat);
}

/****************************/
void WriteNbyte(u8 addr, u8 *p, u8 number)          /*WordAddress,First Data Address,Byte lenth   */
{
      I2C_Start();
      I2C_WriteAbyte(SLAW);
      I2C_Check_ACK();
      if(!F0)                                           //F0=0,right, F0=1,error
      {
                I2C_WriteAbyte(addr);
                I2C_Check_ACK();
                if(!F0)
                {
                        do
                        {
                              I2C_WriteAbyte(*p); p++;
                              I2C_Check_ACK();
                              if(F0)break;
                        }
                        while(--number);
                }
      }
      I2C_Stop();
}


/****************************/
void ReadNbyte(u8 addr, u8 *p, u8 number)       /*WordAddress,First Data Address,Byte lenth   */
{
      I2C_Start();
      I2C_WriteAbyte(SLAW);
      I2C_Check_ACK();
      if(!F0)
      {
                I2C_WriteAbyte(addr);
                I2C_Check_ACK();
                if(!F0)
                {
                        I2C_Start();
                        I2C_WriteAbyte(SLAR);
                        I2C_Check_ACK();
                        if(!F0)
                        {
                              do
                              {
                                        *p = I2C_ReadAbyte();   p++;
                                        if(number != 1)   S_ACK();    //send ACK
                              }
                              while(--number);
                              S_NoACK();          //send no ACK
                        }
                }
      }
      I2C_Stop();
}

#else

#define SLAW    0xA2
#define SLAR    0xA3
//========================================================================
// 函数: void      Wait (void)
// 描述: 等待主机模式I2C控制器执行完成I2CMSCR.
// 参数: none.
// 返回: none.
// 版本: V1.0, 2012-11-22
//========================================================================
void Wait()
{
      while (!(I2CMSST & 0x40));
      I2CMSST &= ~0x40;
}

//========================================================================
// 函数: void Start (void)
// 描述: I2C总线起始函数.
// 参数: none.
// 返回: none.
// 版本: V1.0, 2020-09-15
//========================================================================
void Start()
{
      I2CMSCR = 0x01;                         //发送START命令
      Wait();
}

//========================================================================
// 函数: void SendData (char dat)
// 描述: I2C发送一个字节数据函数.
// 参数: 发送的数据.
// 返回: none.
// 版本: V1.0, 2020-09-15
//========================================================================
void SendData(char dat)
{
      I2CTXD = dat;                           //写数据到数据缓冲区
      I2CMSCR = 0x02;                         //发送SEND命令
      Wait();
}

//========================================================================
// 函数: void RecvACK (void)
// 描述: I2C获取ACK函数.
// 参数: none.
// 返回: none.
// 版本: V1.0, 2020-09-15
//========================================================================
void RecvACK()
{
      I2CMSCR = 0x03;                         //发送读ACK命令
      Wait();
}

//========================================================================
// 函数: char RecvData (void)
// 描述: I2C读取一个字节数据函数.
// 参数: none.
// 返回: 读取数据.
// 版本: V1.0, 2020-09-15
//========================================================================
char RecvData()
{
      I2CMSCR = 0x04;                         //发送RECV命令
      Wait();
      return I2CRXD;
}

//========================================================================
// 函数: void SendACK (void)
// 描述: I2C发送ACK函数.
// 参数: none.
// 返回: none.
// 版本: V1.0, 2020-09-15
//========================================================================
void SendACK()
{
      I2CMSST = 0x00;                         //设置ACK信号
      I2CMSCR = 0x05;                         //发送ACK命令
      Wait();
}

//========================================================================
// 函数: void SendNAK (void)
// 描述: I2C发送NAK函数.
// 参数: none.
// 返回: none.
// 版本: V1.0, 2020-09-15
//========================================================================
void SendNAK()
{
      I2CMSST = 0x01;                         //设置NAK信号
      I2CMSCR = 0x05;                         //发送ACK命令
      Wait();
}

//========================================================================
// 函数: void Stop (void)
// 描述: I2C总线停止函数.
// 参数: none.
// 返回: none.
// 版本: V1.0, 2020-09-15
//========================================================================
void Stop()
{
      I2CMSCR = 0x06;                         //发送STOP命令
      Wait();
}

//========================================================================
// 函数: void      WriteNbyte(u8 addr, u8 *p, u8 number)
// 描述: I2C写入数据函数.
// 参数: addr: 指定地址, *p写入数据存储位置, number写入数据个数.
// 返回: none.
// 版本: V1.0, 2020-09-15
//========================================================================
void WriteNbyte(u8 addr, u8 *p, u8 number)/*WordAddress,First Data Address,Byte lenth   */
{
      EAXSFR();                /* MOVX A,@DPTR/MOVX @DPTR,A指令的操作对象为扩展SFR(XSFR) */
      Start();                              //发送起始命令
      SendData(SLAW);                         //发送设备地址+写命令
      RecvACK();
      SendData(addr);                         //发送存储地址
      RecvACK();
      do
      {
                SendData(*p++);
                RecvACK();
      }
      while(--number);
      Stop();                                 //发送停止命令
      EAXRAM();                /* MOVX A,@DPTR/MOVX @DPTR,A指令的操作对象为扩展RAM(XRAM) */
}

//========================================================================
// 函数: void      ReadNbyte(u8 addr, u8 *p, u8 number)
// 描述: I2C读取数据函数.
// 参数: addr: 指定地址, *p读取数据存储位置, number读取数据个数.
// 返回: none.
// 版本: V1.0, 2020-09-15
//========================================================================
void ReadNbyte(u8 addr, u8 *p, u8 number)   /*WordAddress,First Data Address,Byte lenth   */
{
      EAXSFR();                /* MOVX A,@DPTR/MOVX @DPTR,A指令的操作对象为扩展SFR(XSFR) */
      Start();                              //发送起始命令
      SendData(SLAW);                         //发送设备地址+写命令
      RecvACK();
      SendData(addr);                         //发送存储地址
      RecvACK();
      Start();                              //发送起始命令
      SendData(SLAR);                         //发送设备地址+读命令
      RecvACK();
      do
      {
                *p = RecvData();
                p++;
                if(number != 1) SendACK();          //send ACK
      }
      while(--number);
      SendNAK();                              //send no ACK      
      Stop();                                 //发送停止命令
      EAXRAM();                /* MOVX A,@DPTR/MOVX @DPTR,A指令的操作对象为扩展RAM(XRAM) */
}

#endif
//========================================================================
// 函数: void I2C_Isr (void) interrupt I2C_VECTOR
// 描述: I2C中断函数.
// 参数: none.
// 返回: none.
// 版本: V1.0, 2020-09-15
//========================================================================
void I2C_Isr() interrupt I2C_VECTOR
{
      char store;
      
      store = P_SW2;
      P_SW2 |= 0x80;

      if (I2CSLST & 0x40)
      {
                I2CSLST &= ~0x40;                     //处理START事件
      }
      else if (I2CSLST & 0x20)
      {
                I2CSLST &= ~0x20;                     //处理RECV事件,SLACKO设置为0
                if (I2CIsr.isda)
                {
                        I2CIsr.isda = 0;                           //处理RECV事件(RECV DEVICE ADDR)
                }
                else if (I2CIsr.isma)
                {
                        I2CIsr.isma = 0;                           //处理RECV事件(RECV MEMORY ADDR)
                        I2CIsr.addr = I2CRXD;
                        I2CTXD = I2C_Buffer;
                }
                else
                {
                        I2C_Buffer = I2CRXD;            //处理RECV事件(RECV DATA)
                        from_maser_data = I2CRXD;
                }
      }
      else if (I2CSLST & 0x10)
      {
                I2CSLST &= ~0x10;                     //处理SEND事件
                if (I2CSLST & 0x02)
                {
                        //I2CTXD = 0xff;
                        I2CTXD =to_maser_data;                        //      0x88;;                                                //0x88;
                }
                else
                {
                        I2CTXD = I2C_Buffer[++I2CIsr.addr];                        
                }
      }
      else if (I2CSLST & 0x08)
      {
                I2CSLST &= ~0x08;                     //处理STOP事件
                I2CIsr.isda = 1;
                I2CIsr.isma = 1;
//                DisplayFlag = 1;
      }

      P_SW2 = store;
}





zhang_yg188 发表于 2023-8-21 17:53:17

下载是,已经勾选了“复位脚用作IO”。

乘风飞扬 发表于 2023-8-21 19:09:18

用I2C_P24_P25和 I2C_P33_P32时,P2.4,P2.5 / P3.3,P3.2的IO口模式初始化了没有?

zhang_yg188 发表于 2023-8-22 08:51:46

本帖最后由 zhang_yg188 于 2023-8-22 09:00 编辑

void      GPIO_config(void)
{
      GPIO_InitTypeDef      GPIO_InitStructure;                                                                                                                                                                        //结构定义
      GPIO_InitStructure.Pin= GPIO_Pin_All;                                                                                                                                                                //指定要初始化的IO, GPIO_Pin_0 ~ GPIO_Pin_7
      GPIO_InitStructure.Mode = GPIO_PullUp;                                                                                                                                                                //指定IO的输入或输出方式,GPIO_PullUp,GPIO_HighZ,GPIO_OUT_OD,GPIO_OUT_PP
      GPIO_Inilize(GPIO_P1,&GPIO_InitStructure);                                                                                                                              //P1口初始化,预备接8个LED,设置成准双向标准接口。
      
      GPIO_InitStructure.Pin= GPIO_Pin_All;                                                                                                                                                                //指定要初始化的IO, GPIO_Pin_0 ~ GPIO_Pin_7
      GPIO_InitStructure.Mode = GPIO_PullUp;                                                                                                                                                                //指定IO的输入或输出方式,GPIO_PullUp,GPIO_HighZ,GPIO_OUT_OD,GPIO_OUT_PP
      GPIO_Inilize(GPIO_P2,&GPIO_InitStructure);                                                                                                                              //P2口初始化,设置成准双向标准接口,作为I2C和触摸按键接口。
               
      GPIO_InitStructure.Pin= GPIO_Pin_All;                                                                                                                                                                //指定要初始化的IO, GPIO_Pin_0 ~ GPIO_Pin_7
      GPIO_InitStructure.Mode = GPIO_PullUp;                                                                                                                                                                //指定IO的输入或输出方式,GPIO_PullUp,GPIO_HighZ,GPIO_OUT_OD,GPIO_OUT_PP
      GPIO_Inilize(GPIO_P3,&GPIO_InitStructure);                                                                                                                              //P3口初始化,设置成准双向标准接口,作为I2C和触摸按键接口。
      
      GPIO_InitStructure.Pin= GPIO_Pin_All;                                                                                                                                                                //指定要初始化的IO, GPIO_Pin_0 ~ GPIO_Pin_7
      GPIO_InitStructure.Mode = GPIO_PullUp;                                                                                                                                                                //指定IO的输入或输出方式,GPIO_PullUp,GPIO_HighZ,GPIO_OUT_OD,GPIO_OUT_PP
      GPIO_Inilize(GPIO_P5,&GPIO_InitStructure);                                                                                                                              //P5口初始化
}

P1,P2,P3,P5初始化了,还是一样。本身SOP8脚的只有P3和P5口有引脚。

zhang_yg188 发表于 2023-8-22 08:58:31

现在只是想用P3口设置为I2C,P5口作为普通输入、输出,但是P5口不受控制。

神农鼎 发表于 2023-8-25 07:41:00

用仿真功能去发现错在哪,不要猜


用 STC-USB Link1D 仿真 STC8 系列 MCU - 编译器/仿真器/ISP下载/做自己的ISP - 国芯论坛-STC全球32位8051爱好者互助交流社区 - STC全球32位8051爱好者互助交流社区 (stcaimcu.com)

最帅不过阿良 发表于 2023-12-20 15:04:11

#define        I2C_P33_P32                                0       //STC8G1K08-8pin系列 ,STC8G1K08A-8pin系列
修改这个gpio的配置

Albert 发表于 2024-4-3 15:22:05

最帅不过阿良 发表于 2023-12-20 15:04
#define        I2C_P33_P32                                0       //STC8G1K08-8pin系列 ,STC8G1K08A-8pin系列
修改这个gpio的配置 ...

看到这个,真的很关键,还好看到这个贴子,谢谢博主,真实有效!!
页: [1]
查看完整版本: stc8G1k-sop8封装I2C功能怪怪问题请教