打印
[STM8]

硬件IIC初始化后启动不了

[复制链接]
2503|22
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
dengdc|  楼主 | 2018-5-25 12:21 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
stm8s105k6t6c
沙发
wyjie| | 2018-5-25 12:26 | 只看该作者
楼主详细说说怎么回事啊,这么说太笼统了

使用特权

评论回复
板凳
dengdc|  楼主 | 2018-5-25 12:33 | 只看该作者
在IAR下编译的 ,调用"void Single_WriteI2C(uchar REG_Address,uchar REG_data)"函数时,用硬件仿真一直停留在这里"  while(I2C_SR3 & 0x02); //等待总线空闲."

使用特权

评论回复
地板
heweibig| | 2018-5-25 13:12 | 只看该作者
不知道是不是IIC初始的原因还是 IAR需要设置哪里

使用特权

评论回复
5
mmuuss586| | 2018-5-25 13:51 | 只看该作者
硬件IIC超时了吧

使用特权

评论回复
6
wuhany| | 2018-5-25 14:47 | 只看该作者
楼主程序可以公开吗?贴程序看下吧,这么说看不出什么原因

使用特权

评论回复
7
dengdc|  楼主 | 2018-5-25 14:52 | 只看该作者

#include "stm8s105k6t6.h"

void Init_IIC(void )
{
         
        CLK_PCKENR1 |= 0x01;
        I2C_FREQR |= 0x10;         //输入外设时钟频率为16MHz
        I2C_CR1   &= ~0x01;         //禁止I2C外设
        I2C_CCRH  &= ~0xcf;
        I2C_CCRL  &= ~0xff;        
        I2C_TRISER = 0x11;
        I2C_CCRL   = 0x10;
        I2C_CCRH   = 0x00;      
        I2C_CR1   |= 0x01;        //开启I2C外设
        I2C_CR2   |= 0x04;        //当前接收字节返回应答
        I2C_CR2   &= ~0x08;
        I2C_OARL   = 0x86;       //自身地址
        I2C_OARH   = 0x40;
              
}

//**************************************
//向I2C设备写入一个字节数据
////**************************************
void Single_WriteI2C(uchar REG_Address,uchar REG_data)
{
    I2C_CR2 &=~ 0x04; //不返回应答

    while(I2C_SR3 & 0x02); //等待总线空闲

    I2C_CR2 |= 0x01; //产生起始位
    while(!(I2C_SR1 & 0x01)); //等待START发送完

    I2C_DR = SlaveAddress; //发器件地址
    while(!(I2C_SR1 & 0x02)); //等特7位器件地址发送完
   
    I2C_DR = REG_Address;
    while(!(I2C_SR1 & 0x04));
   
    I2C_DR = REG_data;
    while(!(I2C_SR1 & 0x04));
   
    I2C_CR2 |= 0x02; //产生停止位

}
//**************************************
//从I2C设备读取一个字节数据
//**************************************
uchar Single_ReadI2C(uchar REG_Address)
{
    uchar reg_value;
    while(I2C_SR3 & 0x02); //等待总线空闲

    I2C_CR2 |= 0x01; //产生起始位
    while(!(I2C_SR1 & 0x01)); //等待START发送完

    I2C_DR = SlaveAddress; //发器件地址
    while(!(I2C_SR1 & 0x02)); //等特7位器件地址发送完
   
    I2C_DR = REG_Address;   
    while(!(I2C_SR1 & 0x84));
   
    I2C_CR2 |= 0x01; //产生重复起始位
    while(!(I2C_SR1 & 0x01)); //等待START发送完
   


    I2C_DR = SlaveAddress+1; //读
    while(!(I2C_SR1 & 0x02)); //等特7位器件地址发送完
   
    while(!(I2C_SR1 & 0x40)); //等待START发送完
    reg_value = I2C_DR;
    I2C_CR2 |= 0x04;
    I2C_CR2 &= ~0x08;
   
    I2C_CR2 |= 0x02; //产生停止位
    return   reg_value;
}

使用特权

评论回复
8
lizye| | 2018-5-25 14:56 | 只看该作者

然后呢?你是怎么应对这个的呢

使用特权

评论回复
9
dengdc|  楼主 | 2018-5-25 15:01 | 只看该作者
用硬件仿真时“ I2C_SR3”寄存器一直是0x02。仿真复位后还是0x02。下面这条指令执行完后“I2C_CR1   &= ~0x01; //禁止I2C外设”还是0x02。怎么IIC一直是忙啊  用示波器抓SDA和CLK都是高电平

使用特权

评论回复
10
spark周| | 2018-5-25 15:05 | 只看该作者
选错脚了

使用特权

评论回复
11
dengdc|  楼主 | 2018-5-25 15:09 | 只看该作者
我用的是硬件IIC. 这个单片机就只有一个硬件IIC啊。 选错脚了怎么理解啊?  高手可以说的详细点吗?

使用特权

评论回复
12
liliang9554| | 2018-5-25 15:15 | 只看该作者

你没有选错脚,你仔细看看手册,IIC脚的SDA和SCL是用方括号括起来了

使用特权

评论回复
13
zhaoxqi| | 2018-5-25 15:19 | 只看该作者

也就是说这款芯片在出厂时PB4和PB5接到ADC上去了

使用特权

评论回复
14
huangchui| | 2018-5-25 15:24 | 只看该作者
你要用STTools设置PB4和PB5,将其改成SDA和SCL就行了,我为这个折腾了好几天了!

使用特权

评论回复
15
dengdc|  楼主 | 2018-5-25 15:27 | 只看该作者
确实操作option byte就可以了。但是程序还是没有工作起来

使用特权

评论回复
16
dengdc|  楼主 | 2018-5-25 15:35 | 只看该作者

硬件调试时 I2C_DR = REG_Address;
           while(!(I2C_SR1 & 0x04));卡在这里了

使用特权

评论回复
17
dengdc|  楼主 | 2018-5-25 15:38 | 只看该作者
为什么我在IAR环境下 用ST-LINK修改了option byte中的AFR6成为alternate active以后硬件IIC还是如此:用硬件仿真时“ I2C_SR3”寄存器一直是0x02。仿真复位后还是0x02。下面这条指令执行完后“I2C_CR1   &= ~0x01; //禁止I2C外设”还是0x02。怎么IIC一直是忙啊  用示波器抓SDA和CLK都是高电平

使用特权

评论回复
18
wyjie| | 2018-5-25 15:44 | 只看该作者
这是我最近工程中的I2C程序,工作模式参考了意法半导体的I2C中断模式例程,你参考一下吧!
由于是工程中的一部分,有些东西对你可能没用,但你可以参考一下。
该工程项目S105B-1024中,主器件:ADP2013V1-08(使用STM8S105),从器件:YB125003,DS1307;
主器件每100ms读取从器件寄存器,项目产品在重型车间运行1个多月未停机,所有数据正常。

/*******************************************************************************
// STM8系列MCU的I2C主模式程序(直接运行,无中断)
//
// 输出函数:
// extern void I2CM_Init(void);
//   模块初始化
// extern void I2CM_RunTimeOut(void);
//   模块超时计数
// extern uchar I2CM_Write(uchar SlaveAddr,uchar RegAddr,uchar NumByte,uchar *DataBuf);
//   I2C主器件向从器件写入数据函数
// extern uchar I2CM_Read(uchar SlaveAddr,uchar RegAddr,uchar NumByte,uchar *DataBuf);
//   I2C主器件从从器件读取数据函数
// extern uchar I2CM_RandomRead(uchar SlaveAddr, uchar NumByte, uchar *DataBuf);
//   I2C主器件直接读取从器件(不指定寄存器地址)函数(内部使用)
//   
// 说明:
// 1、当发生超时错误后,EState保存第一次错误现场状态;
// 2、所有有返回结果的函数,返回0:操作失败;返回1:操作成功;
//
// 注意:
// 1、部分MCU在默认情况下,PB4、PB5端口的复用为ADC输入,若强行启动I2C,SR3的BUSY为恒为1
//    若要将I2C的SDA、SCL连接到PB4、PB5上,需要使用STTools将复用设置给为I2C
//
// 调试:
// 1、在独立项目中,主器件:ADP2013V1-08,从器件:YB125003、DS1307
//    读写操作成功:2013-10-25
// 2、在项目S105B-1024中,主器件:ADP2013V1-08,从器件:YB125003、DS1307
//    读写操作成功:2013-10-25
*******************************************************************************/
#ifndef __STM8I2CMaster
#define __STM8I2CMaster

#include "iostm8s105k4.h"

#ifndef uchar
#define uchar unsigned char
#endif
#ifndef uint
#define uint unsigned int
#endif
#ifndef ulong
#define ulong unsigned long
#endif

/** @addtogroup I2C_Registers_Bits_Definition
  * @{
  */
#define I2C_CR2POS   ((uchar)0x08) /*!< Acknowledge */
#define I2C_CR2ACK   ((uchar)0x04) /*!< Acknowledge Enable */
#define I2C_CR2STOP  ((uchar)0x02) /*!< Stop Generation */
#define I2C_CR2START ((uchar)0x01) /*!< Start Generation */
#define I2C_SR1RXNE  ((uchar)0x40) /*!< Data Register not Empty (receivers) */
#define I2C_SR1BTF   ((uchar)0x04) /*!< Byte Transfer Finished */
#define I2C_SR1ADDR  ((uchar)0x02) /*!< Address sent (master mode)/matched (slave mode) */
#define I2C_SR1SB    ((uchar)0x01) /*!< Start Bit (Master mode) */
#define I2C_SR3BUSY    ((uchar)0x02) /*!< Bus Busy */

#define INI_00 00

// Write states 0x
#define SB_01 01
#define ADDR_03 03
#define BTF_04 04
#define REGADDR_05 05
#define STOP_06 06

// Read states 1x
#define SB_11 11
#define ADDR_13 13
#define BTF_14 14
#define BTF_15 15
#define RXNE_16 16
#define RXNE_17 17
#define STOP_18 18

#define I2C_TOUT  20
#define I2C_BECount 300

uchar STATE = 0;
uchar EState = 0;
uint ETCount = 0;
uint EBusy = 0;

extern void I2CM_Init(void);
extern void I2CM_RunTimeOut(void);
extern uchar I2CM_GetLastError(void);
extern uchar I2CM_Write(uchar SlaveAddr,uchar RegAddr,uchar NumByte,uchar *DataBuf);
extern uchar I2CM_Read(uchar SlaveAddr,uchar RegAddr,uchar NumByte,uchar *DataBuf);
extern uchar I2CM_RandomRead(uchar SlaveAddr, uchar NumByte, uchar *DataBuf);

static void SetSTATE(uchar iState);


void I2CM_Init( void )
{
  CLK_PCKENR1 |= 0x01;            // 打开f(MASTER)与外设I2C的连接
  
  //define SDA, SCL outputs 可以不需要设置
  PB_DDR_DDR4 = 1;                // 设置为输出
  PB_CR1_C14 = 1;                 // 设置为推挽
  PB_CR2_C24 = 0;
  
  PB_DDR_DDR5 = 1;                // 设置为输出
  PB_CR1_C15 = 1;                 // 设置为推挽
  PB_CR2_C25 = 0;
  
  
  I2C_CR1_PE = 0;
  I2C_FREQR = 8;                 // input clock to I2C - 16MHz
  I2C_CCRH = 0x00;                // standard mode, duty 1/1 bus speed 100kHz
  I2C_CCRL = 0xA0;                // CCR= 40 - (SCLhi must be at least 4000+1000=5000ns!)
  I2C_TRISER = 5;                // 1000ns/(125ns) + 1  (maximum 1000ns)
  I2C_OARH |= 0x40;
  I2C_OARL = 0xA0;               // own address A0;
  //I2C_ITR = 7;                 // enable Event & error interrupts
  I2C_CR2 |= 0x04;               // ACK=1, Ack enable
  I2C_CR1 &= ~0x80;              // Stretch enable
  
  I2C_CR1_PE = 1;              

  SetSTATE(INI_00);
}

/******************************************************************************
I2C主模式写入函数
参数:
uchar SlaveAddr,   从器件地址
uchar RegAddr,     从器件寄存器地址
uchar NumByte,     要写入的数据字节数
uchar *DataBuf     要写入的数据
输出:
0:写入失败
1:写入成功
*******************************************************************************/
uchar I2CM_Write(uchar SlaveAddr,uchar RegAddr,uchar NumByte,uchar *DataBuf)
{
  uchar i;
  
  SetSTATE(INI_00);
  if (!EBusy){EBusy = 1;}
  /*--------------- BUSY? -> STOP request ---------------------*/
   if ((I2C_SR3 & I2C_SR3BUSY)||I2C_CR2_SWRST)
  {
    return 0;
  }   
  /*--------------- Start communication -----------------------*/  
  I2C_CR2 |= I2C_CR2START;                                     // START=1, generate start
  SetSTATE(SB_01);  
  while((!EState)&&(!(I2C_SR1 & I2C_CR2START)));         // wait for start bit detection (SB)
  /*------------------ Address send ---------------------------*/     
  I2C_DR = SlaveAddr<<1;                                 // Send 7-bit device address & Write (R/W = 1/0)
  SetSTATE(ADDR_03);
  while((!EState)&&(!(I2C_SR1 & I2C_SR1ADDR)));          // Wait for address ACK (ADDR)
  
  I2C_SR1;
  I2C_SR3;
  /*--------------- Register/Command send ----------------------*/
  I2C_DR = RegAddr;                                     // 发送寄存器地址
  SetSTATE(REGADDR_05);
  while((!EState)&&(!(I2C_SR1 & I2C_CR2ACK)));          // Wait for address ACK
  /*------------------- Data Write --------------------------*/
  for(i=0;i<NumByte;i++)                                // 发送数据(如果有数据)
  {
    I2C_SR3;
    I2C_DR = *(DataBuf+i);                              // Reading next data byte
    SetSTATE(BTF_04);
    while((!EState)&&(!(I2C_SR1 & I2C_CR2ACK)));
  }
  /*--------------- Stop                -----------------------*/  
  SetSTATE(STOP_06);
  I2C_CR2 |= I2C_CR2STOP;                               //产生停止位
  while((!EState)&&(I2C_CR2 & I2C_CR2STOP));            // Wait until stop is performed (STOPF = 1)  
  /*--------------- All Data Writed -----------------------*/  
  SetSTATE(INI_00);
  if (EBusy){EBusy = 0;}

  return !EState;
}

/******************************************************************************
I2C主模式从指定寄存器开始读取函数
参数:
uchar SlaveAddr,   从器件地址
uchar RegAddr,     从器件寄存器地址
uchar NumByte,     要写入的数据字节数
uchar *DataBuf     要写入的数据
输出:
0:读取失败
1:读取成功
*******************************************************************************/
uchar I2CM_Read(uchar SlaveAddr,uchar RegAddr,uchar NumByte,uchar *DataBuf)
{
  if (I2CM_Write(SlaveAddr,RegAddr,0,DataBuf))          // 从器件寄存器地址指针移动到目标位置
  {
   return I2CM_RandomRead(SlaveAddr,NumByte,DataBuf);
  }
  else
  {return 0;}
}

/******************************************************************************
I2C主模式直接读取函数
参数:
uchar SlaveAddr,   从器件地址
uchar NumByte,     要写入的数据字节数
uchar *DataBuf     要写入的数据
输出:
0:读取失败
1:读取成功
*******************************************************************************/
uchar I2CM_RandomRead(uchar SlaveAddr, uchar NumByte, uchar *DataBuf)
{
  SetSTATE(INI_00);
  if (!EBusy){EBusy = 0;}
  /*--------------- BUSY? -> STOP request ---------------------*/
  if ((I2C_SR3 & I2C_SR3BUSY)||I2C_CR2_SWRST)
  {
    return 0;
  }   
      
  I2C_CR2 |= I2C_CR2ACK;                                      // ACK=1, Ack enable
  /*--------------- Start communication -----------------------*/  
  I2C_CR2 |= I2C_CR2START;                                    // START=1, generate start
  SetSTATE(SB_11);  
  while((!EState)&&(!(I2C_SR1 & I2C_CR2START)));        // wait for start bit detection (SB)

  /*------------------ Address send ---------------------------*/        
  I2C_DR = (uchar)(SlaveAddr << 1) | 1;                       // Send 7-bit device address & Write (R/W = 1/0)
  SetSTATE(ADDR_13);
  while((!EState)&&(!(I2C_SR1 & I2C_SR1ADDR)));         // Wait for address ACK (ADDR)

  /*------------------- Data Receive --------------------------*/
  if (NumByte > 2)  
    // *** more than 2 bytes are received? ***
  {
    I2C_SR3;                                             // ADDR clearing sequence   
    while(NumByte > 3 )                                       // not last three bytes?
    {
      SetSTATE(BTF_14);
      while((!EState)&&((I2C_SR1 & I2C_SR1BTF) == 0));         // Wait for BTF
      *DataBuf++ = I2C_DR;                                   // Reading next data byte
      --NumByte;                                        // Decrease Numbyte to reade by 1
    }
    SetSTATE(BTF_14);                                                                                                                                                                                                                //last three bytes should be read
    while((!EState)&&((I2C_SR1 & I2C_SR1BTF) == 0));        // Wait for BTF
    I2C_CR2 &=~I2C_CR2ACK;                              // Clear ACK
    *DataBuf++ = I2C_DR;                                     // Read 1st byte
    I2C_CR2 |= I2C_CR2STOP;                               // Generate stop here (STOP=1)
    *DataBuf++ = I2C_DR;                                     // Read 2nd byte
    SetSTATE(RXNE_16);        
    while((!EState)&&((I2C_SR1 & I2C_SR1RXNE)==0));        // Wait for RXNE
    *DataBuf++ = I2C_DR;                                   /// Read 3rd Data byte
    SetSTATE(STOP_18);
  }
  else
  {
    if(NumByte == 2)                                       
      // *** just 2 bytes are received? ***
    {
      I2C_CR2 |= I2C_CR2POS;                              // Set POS bit (NACK at next received byte)
      I2C_SR3;                                               // Clear ADDR Flag
      I2C_CR2 &=~I2C_CR2ACK;                                // Clear ACK
      SetSTATE(BTF_15);        
      while((!EState)&&((I2C_SR1 & I2C_SR1BTF) == 0));        // Wait for BTF
      I2C_CR2 |= I2C_CR2STOP;                               // Generate stop here (STOP=1)
      *DataBuf++ = I2C_DR;                                     // Read 1st Data byte
      *DataBuf = I2C_DR;                                // Read 2nd Data byte
      SetSTATE(STOP_18);
    }
    else                                                      
      // *** only 1 byte is received ***
    {
      I2C_CR2 &=~I2C_CR2ACK;;                             // Clear ACK
      I2C_SR3;                                               // Clear ADDR Flag   
      I2C_CR2 |= I2C_CR2STOP;                               // generate stop here (STOP=1)               
      SetSTATE(RXNE_17);
      while((!EState)&&((I2C_SR1 & I2C_SR1RXNE) == 0));        // test EV7, wait for RxNE
      *DataBuf = I2C_DR;                                     // Read Data byte
      SetSTATE(STOP_18);
    }
  }
  /*--------------- All Data Received -----------------------*/
  while((!EState)&&(I2C_CR2 & I2C_CR2STOP));            // Wait until stop is performed (STOPF = 1)
  I2C_CR2 &=~I2C_CR2POS;                                // return POS to default state (POS=0)
  SetSTATE(INI_00);
  if (EBusy){EBusy = 0;}

  return !EState;  
}

/******************************************************************************
I2C主模式工作状态设置函数
参数:
uchar iState    I2C当前工作状态
说明:
1、当前如果错误状态(EState)不为0,所有设置无效
*******************************************************************************/
void SetSTATE(uchar iState)
{
  if (!EState)
  {
    STATE = iState;
    EState = 0;
    if (STATE)
    {ETCount = 1;}
    else
    {ETCount = 0;}
  }
}

/******************************************************************************
I2C主模式超时计数函数
说明:
1、该函数必须放在100us定时器中断事件中运行,保证每个I2C操作计算超时;
2、以下状态,超时不计数;
   A、当错误状态(EState)不为0;
   B、当I2C工作状态(STATE)为0;
   C、计数器(ETCount)为0;
3、当第一次发生超时,将I2C当前工作状态(STATE)保存到错误状态(EState)中;
*******************************************************************************/
void I2CM_RunTimeOut(void)
{
  if (I2C_CR2_SWRST)
  {I2C_CR2_SWRST = 0;}
  if ((!EState)&&STATE&&ETCount&&(++ETCount>I2C_TOUT))
  {
    ETCount = 0;
    EState = STATE;
  }
  if (EBusy&&(++EBusy>20))
  {
    I2C_SR3;
    I2C_CR2 |= I2C_CR2ACK;
    I2C_CR2 |= I2C_CR2START;  
    I2C_DR = EBusy;
    I2C_CR2 |= I2C_CR2STOP;
    I2C_CR2_SWRST = 1;
   
    EBusy = 0;
  }
}

uchar I2CM_GetLastError(void)
{
  uchar iResult;  
  iResult = EState;
  EState = 0;
  return iResult;
}
#endif //__STM8I2CMaster

使用特权

评论回复
19
shimx| | 2018-5-25 15:51 | 只看该作者

初始化后启动不了,说明你还是没正常的初始化,看看官方的例程怎么搞得。

使用特权

评论回复
20
dengdc|  楼主 | 2018-5-25 15:55 | 只看该作者

结贴了,多谢大家讨论这么多哈,呵呵

使用特权

评论回复
评论
SarahHXC 2018-9-6 11:03 回复TA
楼主,你解决了吗?求问咋整呐?产生起始条件后SCL一起拉低了。。。。 
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

892

主题

13885

帖子

7

粉丝