STM8S207采用硬件I2C读写时需要在读写函数间添加延时5ms

STM8S207采用硬件I2C读写时,需要在读写函数间添加延时5ms,否则,程序会进入死循环。

程序测试可以通过,就是不明白为什么需要添加5ms延时?

i2c_ee.c

#include "i2c_ee.h"
#include "tim1.h"

//硬件I2C引脚:  I2C_SCL-PE1,I2C_SDA-PE2

//函数功能:根据系统时钟,设置硬件I2C输出时钟频率为100KHz,自身地址为0xA0,并指定从机地址长度为7位
void I2C_EEInit(void)
{
  u32 Input_Clock = 0x0;

  Input_Clock = CLK_GetClockFreq();//获取系统时钟频率
  Input_Clock = Input_Clock / 1000000;//单位为MHz	

  I2C_Cmd(ENABLE);//必须先启用硬件I2C功能模块
  I2C_Init(I2C_Speed, I2C1_SLAVE_ADDRESS7, I2C_DUTYCYCLE_2,I2C_ACK_CURR, I2C_ADDMODE_7BIT, Input_Clock);
  //设置硬件I2C输出时钟频率为100KHz
  //设置硬件I2C自身地址为0xA0
  //设置硬件I2C时钟占空比为2
  //设置硬件I2C应答:对当前字节执行应答
  //设置从机地址长度为7位,7-bit slave address (10-bit address not acknowledged)
  //设置系统时钟,单位为MHz
}

//函数功能:将pBuffer所指向的存储数据写入EEPROM中地址为WriteAddr处
//写单一字节
void I2C_EE_ByteWrite(u8* pBuffer, u16 WriteAddr)
{
  bool status=FALSE;
  uint8_t tmpDeviceAddress;//EEPROM器件地址:1010+A2+A1+A0+R/W
  uint8_t tmp;//方便计算中间量

  delay_ms(5);//必须加延时,否则,硬件I2C会出错

  tmp=(u8)(WriteAddr>>8);//读取"EEPROM高3位地址"
  tmp=(u8)(tmp<<1);
  if (WriteAddr>255) tmpDeviceAddress=EEPROM_DEVICE_ADDRESS+tmp;//地址在256~2048之间时,需要将高3位地址放在器件地址中的A2,A1,A0位置
  else tmpDeviceAddress=EEPROM_DEVICE_ADDRESS;

  I2C_GenerateSTART(ENABLE);//发送I2C起动条件,Send STRAT condition
  status=FALSE;
  while(status!=TRUE)//循环检测主机启动条件发送完成标志
  {
    status = I2C_CheckEvent(I2C_EVENT_MASTER_START_SENT);
    //读"主机启动条件发送完成标志"
    //Test on EV5 and clear it
  }

  I2C_Send7bitAddress(tmpDeviceAddress, I2C_DIRECTION_TX);//发送器件写地址
  //发送EEPROM写器件地址
  //Send EEPROM address for write
  status=FALSE;
  while(status!=TRUE)//循环检测"主机发送EEPROM写器件地址结束标志"是否建立
  {
    status = I2C_CheckEvent(I2C_EVENT_MASTER_ADDRESS_ACKED);
    //读"主机发送EEPROM写器件地址结束标志",需要从机应答
    //Test on EV6 and clear it
  }
  I2C_ClearFlag(I2C_FLAG_ADDRESSSENTMATCHED);
  //清除"写器件地址已被发送标志"

  I2C_SendData((u8)(WriteAddr&0x00FF));//主机发送从机器件子地址低8位
  status=FALSE;
  while (status!=TRUE)//循环检测"主机发送从机器件子地址低8位完成标志"
  {
    status = I2C_CheckEvent(I2C_EVENT_MASTER_BYTE_TRANSMITTED);
    //读"主机发送从机器件子地址低8位完成标志"
    //Test on EV8 and clear it
  }

  I2C_SendData(*pBuffer);
  //主机将pBuffer所指向的存储数据发送给从机
  //Send the byte to be written
  status=FALSE;
  while (status!=TRUE)
  {
    status = I2C_CheckEvent(I2C_EVENT_MASTER_BYTE_TRANSMITTED);
    //读"主机发送数据字节结束标志"
    //Test on EV8 and clear it
  }

  I2C_GenerateSTOP(ENABLE);//主机发送I2C停止条件,Send STOP condition
}

//函数功能:将pBuffer[]中前count个字节写入EEPROM中,起始地址为firstaddress
//注意:支持页内写和跨页写,pBuffer[count],count必须小于等于Page_Byte_Size,才可使用;
void I2C_EE_PageWrite(unsigned char *pBuffer, u16 WriteAddr, u8 count)
{
  unsigned char tmpOffsetAddress;
  bool status;
  unsigned char i;

  uint8_t  tmpDeviceAddress;//EEPROM器件地址:1010+A2+A1+A0+R/W
  uint8_t tmp;//方便计算中间量

  i=count;//记录有count个字节写入
  tmpOffsetAddress=WriteAddr%Page_Byte_Size;  //计算在当前页中的地址偏移量;
  tmpOffsetAddress=Page_Byte_Size-tmpOffsetAddress;  //计算距离下一页的边界有多少个字节;
  if( tmpOffsetAddress<count )//若所写的字节要跨过一页,则执行下面;
  {
    delay_ms(5);//必须加延时,否则,硬件I2C会出错

    tmp=(u8)(WriteAddr>>8);//读取"EEPROM高3位地址"
    tmp=(u8)(tmp<<1);
    if (WriteAddr>255) tmpDeviceAddress=EEPROM_DEVICE_ADDRESS+tmp;//地址在256~2048之间时,需要将高3位地址放在器件地址中的A2,A1,A0位置 
    else tmpDeviceAddress=EEPROM_DEVICE_ADDRESS;

    status=TRUE;
    while(status)//循环检测"硬件I2C总线忙标志"
    {
      status=I2C_GetFlagStatus(I2C_FLAG_BUSBUSY);//读"硬件I2C总线忙标志"
    }

    I2C_GenerateSTART(ENABLE);//发送I2C起动条件,Send STRAT condition
    status=FALSE;
    while(status!=TRUE)//循环检测主机启动条件发送完成标志
    {
      status = I2C_CheckEvent(I2C_EVENT_MASTER_START_SENT);
      //读"主机启动条件发送完成标志"
      //Test on EV5 and clear it
    }

    I2C_Send7bitAddress(tmpDeviceAddress, I2C_DIRECTION_TX);//发送器件写地址
    //发送EEPROM写器件地址
    //Send EEPROM address for write
    status=FALSE;
    while(status!=TRUE)//循环检测"主机发送EEPROM写器件地址结束标志"是否建立
    {
      status = I2C_CheckEvent(I2C_EVENT_MASTER_ADDRESS_ACKED);
      //读"主机发送EEPROM写器件地址结束标志",需要从机应答
      //Test on EV6 and clear it
    }
    I2C_ClearFlag(I2C_FLAG_ADDRESSSENTMATCHED);
    //清除"写器件地址已被发送标志"

    I2C_SendData((u8)(WriteAddr&0x00FF));//主机发送从机器件子地址低8位
    status=FALSE;
    while (status!=TRUE)//循环检测"主机发送从机器件子地址低8位完成标志"
    {
      status = I2C_CheckEvent(I2C_EVENT_MASTER_BYTE_TRANSMITTED);
      //读"主机发送从机器件子地址低8位完成标志"
      //Test on EV8 and clear it
    }

    for(i=0; i<tmpOffsetAddress; i++)
    {
      I2C_SendData(*pBuffer);
      //主机将pBuffer所指向的存储数据发送给从机
      //Send the byte to be written
      status=FALSE;
      while (status!=TRUE)
      {
        status = I2C_CheckEvent(I2C_EVENT_MASTER_BYTE_TRANSMITTED);
        //读"主机发送数据字节结束标志"
        //Test on EV8 and clear it
      }
      pBuffer++;//Point to the next byte to be written 
    }
    I2C_GenerateSTOP(ENABLE);//主机发送I2C停止条件,Send STOP condition

    i=(count-tmpOffsetAddress);      //计算还有多少个字没有写入EEPROM;
    WriteAddr=WriteAddr+tmpOffsetAddress;  //计算下一页的首地址;
  }

  if(i!=0)
  {
    delay_ms(5);//必须加延时,否则,硬件I2C会出错
    tmp=(u8)(WriteAddr>>8);//读取"EEPROM高3位地址"
    tmp=(u8)(tmp<<1);
    if (WriteAddr>255) tmpDeviceAddress=EEPROM_DEVICE_ADDRESS+tmp;//地址在256~2048之间时,需要将高3位地址放在器件地址中的A2,A1,A0位置
    else tmpDeviceAddress=EEPROM_DEVICE_ADDRESS;

    status=TRUE;
    while(status)//循环检测"硬件I2C总线忙标志"
    {
      status=I2C_GetFlagStatus(I2C_FLAG_BUSBUSY);//读"硬件I2C总线忙标志"
    }

    I2C_GenerateSTART(ENABLE);//发送I2C起动条件,Send STRAT condition
    status=FALSE;
    while(status!=TRUE)//循环检测主机启动条件发送完成标志
    {
      status = I2C_CheckEvent(I2C_EVENT_MASTER_START_SENT);
      //读"主机启动条件发送完成标志"
      //Test on EV5 and clear it
    }

    I2C_Send7bitAddress(tmpDeviceAddress, I2C_DIRECTION_TX);//发送器件写地址
    //发送EEPROM写器件地址
    //Send EEPROM address for write
    status=FALSE;
    while(status!=TRUE)//循环检测"主机发送EEPROM写器件地址结束标志"是否建立
    {
      status = I2C_CheckEvent(I2C_EVENT_MASTER_ADDRESS_ACKED);
      //读"主机发送EEPROM写器件地址结束标志",需要从机应答
      //Test on EV6 and clear it
    }
    I2C_ClearFlag(I2C_FLAG_ADDRESSSENTMATCHED);
    //清除"写器件地址已被发送标志"

    I2C_SendData((u8)(WriteAddr&0x00FF));//主机发送从机器件子地址低8位
    status=FALSE;
    while (status!=TRUE)//循环检测"主机发送从机器件子地址低8位完成标志"
    {
      status = I2C_CheckEvent(I2C_EVENT_MASTER_BYTE_TRANSMITTED);
      //读"主机发送从机器件子地址低8位完成标志"
      //Test on EV8 and clear it
    }

    for(; i!=0; i--)
    {
      I2C_SendData(*pBuffer);
      //主机将pBuffer所指向的存储数据发送给从机
      //Send the byte to be written
      status=FALSE;
      while (status!=TRUE)
      {
        status = I2C_CheckEvent(I2C_EVENT_MASTER_BYTE_TRANSMITTED);
        //读"主机发送数据字节结束标志"
        //Test on EV8 and clear it
      }
      pBuffer++;//Point to the next byte to be written 
    }
    I2C_GenerateSTOP(ENABLE);//主机发送I2C停止条件,Send STOP condition
  }
}

//函数功能:从EEPROM中地址ReadAddr开始,连续读NumByteToRead个字节,保存到pBuffer[]中
void I2C_EE_BufferRead(u8* pBuffer, u16 ReadAddr, u8 NumByteToRead)
{
  bool status;

  uint8_t tmpDeviceAddress;//EEPROM器件地址:1010+A2+A1+A0+R/W
  uint8_t tmp;//方便计算中间量

  tmp=(u8)(ReadAddr>>8);
  tmp=(u8)(tmp<<1);
  if (ReadAddr>255) tmpDeviceAddress=EEPROM_DEVICE_ADDRESS+tmp;//地址在256~2048之间时,需要将高3位地址放在器件地址中的A2,A1,A0位置 
  else tmpDeviceAddress=EEPROM_DEVICE_ADDRESS;

  delay_ms(5);//须加延时,否则硬件I2C会出错
  status=TRUE;
  while(status)//循环检测"硬件I2C总线忙标志"
  {
    status=I2C_GetFlagStatus(I2C_FLAG_BUSBUSY);//读"硬件I2C总线忙标志"
  }

  I2C_AcknowledgeConfig(I2C_ACK_CURR);//产生应答信号

  I2C_GenerateSTART(ENABLE);//发送I2C起动条件,Send STRAT condition
  status=FALSE;
  while(status!=TRUE)//循环检测主机启动条件发送完成标志
  {
    status = I2C_CheckEvent(I2C_EVENT_MASTER_START_SENT);
    //读"主机启动条件发送完成标志"
    //Test on EV5 and clear it
  }

  I2C_Send7bitAddress(tmpDeviceAddress, I2C_DIRECTION_TX);//发送器件写地址
  //发送EEPROM写器件地址
  //Send EEPROM address for write
  status=FALSE;
  while(status!=TRUE)//循环检测"主机发送EEPROM写器件地址结束标志"是否建立
  {
    status = I2C_CheckEvent(I2C_EVENT_MASTER_ADDRESS_ACKED);
    //读"主机发送EEPROM写器件地址结束标志",需要从机应答
    //Test on EV6 and clear it
  }
  I2C_ClearFlag(I2C_FLAG_ADDRESSSENTMATCHED);
  //清除"写器件地址已被发送标志"

  I2C_SendData((u8)(ReadAddr&0x00FF));//发送数据地址;
  status=FALSE;
  while (status!=TRUE)//循环检测"主机发送从机器件子地址低8位完成标志"
  {
    status = I2C_CheckEvent(I2C_EVENT_MASTER_BYTE_TRANSMITTED);
    //读"主机发送从机器件子地址低8位完成标志"
    //Test on EV8 and clear it
  }

///发送重启条件
  I2C_GenerateSTART(ENABLE);//发送I2C起动条件,Send STRAT condition
  status=FALSE;
  while(status!=TRUE)//循环检测主机启动条件发送完成标志
  {
    status = I2C_CheckEvent(I2C_EVENT_MASTER_START_SENT);
    //读"主机启动条件发送完成标志"
    //Test on EV5 and clear it
  }

  I2C_Send7bitAddress(tmpDeviceAddress, I2C_DIRECTION_RX);//发送器件读地址
  //发送EEPROM读器件地址
  //Send EEPROM address for write
  status=FALSE;
  while(status!=TRUE)//循环检测"主机发送EEPROM读器件地址结束标志"是否建立
  {
    status = I2C_CheckEvent(I2C_EVENT_MASTER_ADDRESS_ACKED);
    //读"主机发送EEPROM读器件地址结束标志",需要从机应答
    //Test on EV6 and clear it
  }
  I2C_ClearFlag(I2C_FLAG_ADDRESSSENTMATCHED);
  //清除"读器件地址已被发送标志"

  while(NumByteToRead)  
  {
    if(NumByteToRead == 1)//I2C读最后一个字节不需要应答
    {
      I2C_AcknowledgeConfig(I2C_ACK_NONE);//最后一个字节不产生应答信号
    }
    while (!I2C_CheckEvent(I2C_EVENT_MASTER_BYTE_RECEIVED));//等待数据接收完成

    *pBuffer = I2C_ReceiveData();  //读出数据
    pBuffer++;   //读出数据缓存地址递加
    NumByteToRead--;      //接收数据数目减1  
  }
  I2C_GenerateSTOP(ENABLE);
  I2C_AcknowledgeConfig(I2C_ACK_CURR);
  //设置硬件I2C应答:对当前字节执行应答,为下次访问I2C做准备
  //Enable Acknowledgement to be ready for another reception
}

i2c_ee.h

#ifndef __I2C_EE_H
#define __I2C_EE_H

#include "stm8s.h"
//包含CPU头文件,使能int8_t,int16_t,int32_t,uint8_t,uint15_t,uint32_t,s8,s16,s32,u8,u16,u32,bool
//signed char,signed short,signed long,unsigned char,unsigned short,unsigned long
//FALSE,TRUE
//RESET,SET
//DISABLE,ENABLE
//ERROR,SUCCESS

#define I2C_Speed              100000    //I2C时钟为100KHz
#define I2C1_SLAVE_ADDRESS7    0xA0      //硬件I2C自身地址为0xA0

//AT24C01AN-10SU-2.7封装SOP8/2.7V~5.5V
//AT24C01AN-10SU-1.8封装SOP8/1.8V~5.5V
//AT24C16AN-10SU-2.7封装SOP8/2.7V~5.5V
//AT24C16AN-10SU-1.8封装SOP8/1.8V~5.5V
"EEPROM每页有多少个字节定义"开始
//本程序支持AT24C01,AT24C02,AT24C04,AT24C08.AT24C16
#define EEPROM_DEVICE_ADDRESS  0xA0      //EEPROM写器件地址
//地址在256~2048之间时,需要将高3位地址放在器件地址中

//#define EEPROM_Select  1  //AT24C01
#define EEPROM_Select  2  //AT24C02
//#define EEPROM_Select  3  //AT24C04
//#define EEPROM_Select  4  //AT24C08
//#define EEPROM_Select  6  //AT24C16

#if EEPROM_Select == 1   //AT24C01
#define Page_Byte_Size         ((u8)8)   //EEPROM每页只有8个字节
#elif EEPROM_Select == 2 //AT24C02
#define Page_Byte_Size         ((u8)8)   //EEPROM每页只有8个字节
#elif EEPROM_Select == 3 //AT24C04
#define Page_Byte_Size         ((u8)16)   //EEPROM每页只有16个字节
#elif EEPROM_Select == 4 //AT24C08
#define Page_Byte_Size         ((u8)16)   //EEPROM每页只有16个字节
#elif EEPROM_Select == 5 //AT24C16
#define Page_Byte_Size         ((u8)16)   //EEPROM每页只有16个字节
#endif
"EEPROM每页有多少个字节定义"结束

void I2C_EEInit(void);
void I2C_EE_ByteWrite(u8* pBuffer, u16 WriteAddr);
void I2C_EE_PageWrite(unsigned char *pBuffer, u16 firstaddress, u8 count);
void I2C_EE_BufferRead(u8* pBuffer, u16 ReadAddr, u8 NumByteToRead);
#endif /* __I2C_EE_H */

main.c

#include "stm8s.h"
//包含CPU头文件,使能int8_t,int16_t,int32_t,uint8_t,uint15_t,uint32_t,s8,s16,s32,u8,u16,u32,bool
//signed char,signed short,signed long,unsigned char,unsigned short,unsigned long
//FALSE,TRUE
//RESET,SET
//DISABLE,ENABLE
//ERROR,SUCCESS
#include "i2c_ee.h"
#include "uart.h"
#include "tim1.h"

u8 WriteEEPROMBuffer[8];
u8 ReadEEPROMBuffer[8];

int main(void)
{
  u8 i;

  CLK_HSIPrescalerConfig(CLK_PRESCALER_HSIDIV1);//配置HSI时钟分配器值为1分频,时钟到外围设备和核心为16MHz

  USART_Configuration();
  //UART1串口初始化:波特率115200,N81,无奇偶效验位,非同步模式,允许接收和发送,启用UART1
  //USART1 config 115200 8-N-1

  printf("\r\nCPU reaet!\r\n");

  Tim1_Init();//设置TIM1中断周期为1ms,并允许TIM1中断

  __enable_interrupt();

  I2C_EEInit();//根据系统时钟,设置硬件I2C输出时钟频率为100KHz,自身地址为0xA0,并指定从机地址长度为7位

  for(i=0;i<8;i++) WriteEEPROMBuffer[i]=i;
  for(i=0;i<8;i++)
  {
    printf("\r\nWriteEEPROMBuffer[%u]=0x%02X",i,(u8)(WriteEEPROMBuffer[i]));
  }
  printf("\r\n");
  I2C_EE_PageWrite(WriteEEPROMBuffer, 20, 8);
  I2C_EE_BufferRead(ReadEEPROMBuffer, 20, 8);
  for(i=0;i<8;i++)
  {
    printf("\r\nReadEEPROMBuffer[%u]=0x%02X",i,ReadEEPROMBuffer[i]);
  }
  printf("\r\n");
  for(i=0;i<8;i++) WriteEEPROMBuffer[i]=(u8)(i+8);
  for(i=0;i<8;i++)
  {
    printf("\r\nWriteEEPROMBuffer[%u]=0x%02X",i,(u8)(WriteEEPROMBuffer[i]));
  }
  printf("\r\n");
  I2C_EE_PageWrite(WriteEEPROMBuffer, 28, 8);
  I2C_EE_BufferRead(ReadEEPROMBuffer, 28, 8);
  for(i=0;i<8;i++)
  {
    printf("\r\nReadEEPROMBuffer[%u]=0x%02X",i,ReadEEPROMBuffer[i]);
  }
  printf("\r\n");

  for(i=0;i<8;i++) WriteEEPROMBuffer[i]=(u8)(i+16);
  for(i=0;i<8;i++)
  {
    printf("\r\nWriteEEPROMBuffer[%u]=0x%02X",i,(u8)(WriteEEPROMBuffer[i]));
  }
  printf("\r\n");
  for(i=0;i<8;i++)
    I2C_EE_ByteWrite( WriteEEPROMBuffer+i,(u8)(36+i) );
  I2C_EE_BufferRead(ReadEEPROMBuffer, 36, 8);
  for(i=0;i<8;i++)
  {
    printf("\r\nReadEEPROMBuffer[%u]=0x%02X",i,ReadEEPROMBuffer[i]);
  }
  printf("\r\n");

  while (1)
  {
    delay_ms(1000);
  }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
stm8s硬件I2C是指STM8系列单片机上集成的硬件I2C模块。I2C是一种串行通信协议,用于在芯片之进行通信。在STM8S系列单片机中,硬件I2C模块可以通过配置相应的寄存器来实现各种功能。 在进行I2C总线初始化需要注意以下几个寄存器的配置。首先,I2C_CR1寄存器的bit0用于控制I2C模块的启动/禁用。在配置TRISER相关寄存器之前,需要先禁用I2C模块才能进行写操作。 其次,I2C_OARH和I2C_OARL寄存器用于设置I2C模块的从机地址。这两个寄存器需要I2C模块禁用的状态下改变值。 另外,如果希望特定事件以中断形式通知,可以使用I2C_ITR寄存器。例如,写入一字节数据至I2C_DR寄存器后,CPU可以处理其他事件。当收到TXE触发的中断事件后,再写入下一字节数据。这样,CPU在处理整个I2C读写事件的过程中可以不需要进行循环判断等待。 总之,通过配置相应的寄存器,我们可以实现对STM8S硬件I2C模块的初始化和功能定制。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [总结stm8硬件IIC主模式的寄存器设置及调试心得](https://blog.csdn.net/chounanwang/article/details/78326983)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值