搜索
bottom↓
回复: 52

stm8l I2C 双机通信 互为主从(写的不好,能工作)官方版整合

[复制链接]

出0入0汤圆

发表于 2014-2-10 16:21:44 | 显示全部楼层 |阅读模式
本帖最后由 lovepig200 于 2014-2-10 16:23 编辑

两个stm8l 互为主从,默认从机模式,按键后切换为主机模式发送。两个mcu可以互为主从。


main.c

#include "stm8l15x.h"
//#include "stm8_eval.h"
#include "main.h"


/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
#define KEYESC_PORT GPIOD        // 退出出键
#define KEYESC_PIN GPIO_Pin_4
#define KEYNEX_PORT GPIOD        //下一个键
#define KEYNEX_PIN GPIO_Pin_5

#define KEYESC_DOWN  GPIO_ReadInputDataBit(KEYESC_PORT, KEYESC_PIN) == RESET
#define KEYNEX_DOWN  GPIO_ReadInputDataBit(KEYNEX_PORT, KEYNEX_PIN) == RESET

#define LED_PORT GPIOB
#define LED_REDPIN GPIO_Pin_3
#define LED_GREPIN GPIO_Pin_4

/* Private macro -------------------------------------------------------------*/
extern uint8_t HEADER_ADDRESS_Read = (((SLAVE_ADDRESS & 0xFF00) >> 7) | 0xF1);
extern uint8_t HEADER_ADDRESS_Write;
/* Private variables ---------------------------------------------------------*/
__IO uint8_t Rx_Idx = 0, Tx_Idx = 0;
__IO uint8_t SL_Rx_Idx = 0, SL_Tx_Idx = 0;
__IO uint8_t NumByteToRead = BUFFERSIZE;
__IO uint8_t NumOfBytes = BUFFERSIZE;

unsigned char IIC_STA = 0;

uint8_t i = 0;
uint8_t p = 0;
__IO uint8_t RxBuffer[BUFFERSIZE];
TestStatus TransferStatus1 = FAILED;
extern __IO uint8_t TxBuffer[BUFFERSIZE];
/* Private function prototypes -----------------------------------------------*/
TestStatus Buffercmp(uint8_t* pBuffer1, uint8_t* pBuffer2, uint16_t BufferLength);
void Delay(__IO uint32_t nCount);
/* Private functions ---------------------------------------------------------*/

/**
  * @brief  Main program.
  * @param  None
  * @retval None
  */

static void GPIO_Config(void)
{

  
//GPIO_Init(PINA_PORT,PINA_PIN,GPIO_Mode_In_PU_No_IT);
//GPIO_Init(PINB_PORT,PINB_PIN,GPIO_Mode_In_PU_No_IT);
//GPIO_Init(OKKEY_PORT,OKKEY_PIN,GPIO_Mode_In_PU_No_IT);
GPIO_Init(LED_PORT,LED_REDPIN | LED_GREPIN,GPIO_Mode_Out_PP_Low_Slow);
//GPIO_Init(MOTER_PORT,PUL_PIN | EN_PIN | DIR_PIN,GPIO_Mode_Out_PP_Low_Slow);
//GPIO_Init(AIRP_PORT,AIRP_PIN,GPIO_Mode_In_PU_No_IT);
GPIO_Init(KEYNEX_PORT,KEYNEX_PIN,GPIO_Mode_In_PU_No_IT);
GPIO_Init(KEYESC_PORT,KEYESC_PIN,GPIO_Mode_In_PU_No_IT);
}

void I2C_SETUP(unsigned char Addr)
{
   /* I2C  clock Enable*/
  CLK_PeripheralClockConfig(CLK_Peripheral_I2C1, ENABLE);  
  /* Initialize I2C peripheral */
  I2C_Init(I2C1, 100000, Addr,
           I2C_Mode_I2C, I2C_DutyCycle_2,
           I2C_Ack_Enable, I2C_AcknowledgedAddress_7bit);
}
unsigned char I2C_MASTER_SEND(void) //应用此函数前 需要准备好要发送的数据,存在TxBuffer[]中,并设置好发送接收数据数量
{
unsigned char timeout = 0;
  /* Enable Buffer and Event Interrupt*/
  I2C_ITConfig(I2C1, (I2C_IT_TypeDef)(I2C_IT_EVT | I2C_IT_BUF) , ENABLE);
  I2C_AcknowledgeConfig(I2C1, ENABLE);
    /* Send START condition */
  I2C_GenerateSTART(I2C1, ENABLE);
  while (NumOfBytes)
  {
    Delay(0x000F);
    timeout++;
    if(timeout > 10)
    {
      return 2;
    }
  }
  while (I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY));
  return 1;
}

void I2C_MASTER_RECEIVE(__IO uint8_t *RxBuffer,unsigned char ByteToRead)
{
  unsigned char Rx_Idx = 0;
   /*****  reception phase ***/
  /*  Wait while the bus is busy */
  while (I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY));

  /* Send START condition */
  I2C_GenerateSTART(I2C1, ENABLE);

  /* Test on EV5 and clear it */
  while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT));

  /* Send slave Address for write */
  I2C_Send7bitAddress(I2C1, SLAVE_ADDRESS, I2C_Direction_Receiver);

  /* Test on EV6 and clear it */
  while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED));


  /* While there is data to be read */
  while (ByteToRead)
  {
    if (ByteToRead == 1)
    {
      /* Disable Acknowledgement */
      I2C_AcknowledgeConfig(I2C1, DISABLE);

      /* Send STOP Condition */
      I2C_GenerateSTOP(I2C1, ENABLE);

      /* Poll on RxNE Flag */
      while ((I2C_GetFlagStatus(I2C1, I2C_FLAG_RXNE) == RESET));
      /* Read a byte from the Slave */
      RxBuffer[Rx_Idx] = I2C_ReceiveData(I2C1);

      /* Point to the next location where the byte read will be saved */
      Rx_Idx++;

      /* Decrement the read bytes counter */
      ByteToRead--;
    }

    /* Test on EV7 and clear it */
    if (I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_RECEIVED) )
    {
      /* Read a byte */
      RxBuffer[Rx_Idx] = I2C_ReceiveData(I2C1);

      /* Point to the next location where the byte read will be saved */
      Rx_Idx++;

      /* Decrement the read bytes counter */
      ByteToRead--;
    }

  }
}

void main()
{

  CLK_SYSCLKDivConfig(CLK_SYSCLKDiv_2);
  GPIO_Config();
  I2C_SETUP(SLAVE_ADDRESS);
  I2C_ITConfig(I2C1, (I2C_IT_TypeDef)(I2C_IT_ERR | I2C_IT_EVT | I2C_IT_BUF), ENABLE);
  enableInterrupts();
while(1)
  {
if(KEYESC_DOWN)
{
  IIC_STA = 1;
  I2C_SETUP(MASTER_ADDRESS);
  GPIO_SetBits(LED_PORT,  LED_REDPIN );
  NumByteToRead = BUFFERSIZE;
  NumOfBytes = BUFFERSIZE;
  Tx_Idx = 0;
  /* TXBuffer initialization */
  for (i = 0; i < BUFFERSIZE; i++)
  {
    TxBuffer = i;
  }
  p = I2C_MASTER_SEND();

  /* Add a delay to be sure that communication is finished */
  Delay(0x0FFF);
  
I2C_MASTER_RECEIVE(RxBuffer,NumByteToRead);
Delay(0xfFFF);
Delay(0xfFFF);
GPIO_ResetBits(LED_PORT,  LED_REDPIN );
I2C_SETUP(SLAVE_ADDRESS);
I2C_ITConfig(I2C1, (I2C_IT_TypeDef)(I2C_IT_ERR | I2C_IT_EVT | I2C_IT_BUF), ENABLE);
IIC_STA = 0;
}
  }
}



/**
  * @brief  Inserts a delay time.
  * @param  nCount: specifies the delay time length.
  * @retval None
  */
void Delay(__IO uint32_t nCount)
{
  for (; nCount != 0; nCount--);
}





stm8l15x_it.c

#include "stm8l15x_it.h"
#include "main.h"

extern uint8_t HEADER_ADDRESS_Write = (((SLAVE_ADDRESS & 0xFF00) >> 7) | 0xF0);
extern uint8_t HEADER_ADDRESS_Read;
/* Private variables ---------------------------------------------------------*/
__IO uint8_t TxBuffer[BUFFERSIZE];
__IO uint8_t Slave_Buffer_Rx[5];
unsigned char m;
extern __IO uint8_t NumOfBytes;
extern __IO uint8_t Tx_Idx;
extern unsigned char IIC_STA ;
extern __IO uint8_t SL_Rx_Idx ;
extern __IO uint8_t  SL_Tx_Idx;

INTERRUPT_HANDLER(I2C1_SPI2_IRQHandler, 29)
{
  m++;
  if(IIC_STA == 1)
  {
  switch (I2C_GetLastEvent(I2C1))
  {
      /* EV5 */
    case I2C_EVENT_MASTER_MODE_SELECT :
      
      /* Send slave Address for write */
      I2C_Send7bitAddress(I2C1, SLAVE_ADDRESS, I2C_Direction_Transmitter);
      break;

      /* EV6 */
    case I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED:
      if (NumOfBytes != 0)
      {
        /* Send the first Data */
        I2C_SendData(I2C1, TxBuffer[Tx_Idx++]);

        /* Decrement number of bytes */
        NumOfBytes--;
      }
      if (NumOfBytes == 0)
      {
        I2C_ITConfig(I2C1, I2C_IT_BUF, DISABLE);
      }
      break;

      /* EV8 */
    case I2C_EVENT_MASTER_BYTE_TRANSMITTING:
      /* Transmit Data */
      I2C_SendData(I2C1, TxBuffer[Tx_Idx++]);

      /* Decrement number of bytes */
      NumOfBytes--;

      if (NumOfBytes == 0)
      {
        I2C_ITConfig(I2C1, I2C_IT_BUF, DISABLE);
      }
      break;

      /* EV8_2 */
    case I2C_EVENT_MASTER_BYTE_TRANSMITTED:
      /* Send STOP condition */
      I2C_GenerateSTOP(I2C1, ENABLE);

      I2C_ITConfig(I2C1, I2C_IT_EVT, DISABLE);
      break;

    default:
      break;
  }
  }
  else
  {
     /* Read SR2 register to get I2C error */
  if (I2C_ReadRegister(I2C1, I2C_Register_SR2))
  {
    /* Clears SR2 register */
    I2C1->SR2 = 0;
  }  
  switch (I2C_GetLastEvent(I2C1))
  {
      /******* Slave transmitter ******/
      /* check on EV1 */
    case I2C_EVENT_SLAVE_TRANSMITTER_ADDRESS_MATCHED:
      SL_Tx_Idx = 0;
      break;

      /* check on EV3 */
    case I2C_EVENT_SLAVE_BYTE_TRANSMITTING:
      I2C_SendData(I2C1, 0x22);
      break;
      /******* Slave receiver **********/
      /* check on EV1*/
    case I2C_EVENT_SLAVE_RECEIVER_ADDRESS_MATCHED:
      break;

      /* Check on EV2*/
    case I2C_EVENT_SLAVE_BYTE_RECEIVED:
      Slave_Buffer_Rx[SL_Rx_Idx++] = I2C_ReceiveData(I2C1);
      break;

      /* Check on EV4 */
    case (I2C_EVENT_SLAVE_STOP_DETECTED):
            /* write to CR2 to clear STOPF flag */
            I2C1->CR2 |= I2C_CR2_ACK;
            SL_Rx_Idx=0;
      break;

    default:
      break;
  }
  }
}

现象


代码




本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

阿莫论坛20周年了!感谢大家的支持与爱护!!

一只鸟敢站在脆弱的枝条上歇脚,它依仗的不是枝条不会断,而是自己有翅膀,会飞。

出0入0汤圆

发表于 2014-2-10 17:11:27 | 显示全部楼层
顶一个。

出0入0汤圆

发表于 2014-2-10 17:13:29 | 显示全部楼层
biaoji yixia

出0入0汤圆

发表于 2014-2-10 23:44:07 | 显示全部楼层
顶一个!

出0入0汤圆

发表于 2014-2-11 22:29:47 | 显示全部楼层
抽空试试看,先mark

出0入10汤圆

发表于 2014-2-11 22:52:10 | 显示全部楼层
赞一个。~~~~~~~~~~~

出0入0汤圆

发表于 2014-2-20 10:10:51 | 显示全部楼层
好东西,试验一下,谢谢哈

出0入0汤圆

发表于 2014-5-2 13:52:16 | 显示全部楼层
你好,刚才看了你写的那个双机iic通讯的库例子,我现在也是在做这个例子,但是呢?我要做的是主机发命令给从机,然后从机发数据给主机,我主机是软件模拟iic,不知道你这边能不能提供下,我现在是用寄存器来写的

出0入0汤圆

 楼主| 发表于 2014-5-2 19:27:56 | 显示全部楼层
先确定你从机需要发送的数据有几种。
如果只有一种,那么直接 主机切换到主模式,发送从机地址(读),然后从机发送数据。
如果有多种,那么直接 主机切换到主模式,发送从机地址(写),发送数据指令,等待一段时间,发送从机地址(读),从机发回数据。

如果你用模拟iic 可以参考我这个帖子
http://www.amobbs.com/thread-5577411-1-1.html
不过这个是主机模式,想变成从机,你需要先写一个中断程序。
在CLK下降沿进入中断,然后检查START等标识,比较麻烦的。

如果IIC要作为从机,最好还是硬件IIC好一点,我感觉。

出0入0汤圆

 楼主| 发表于 2014-5-2 19:28:17 | 显示全部楼层
dhw5qq 发表于 2014-5-2 13:52
你好,刚才看了你写的那个双机iic通讯的库例子,我现在也是在做这个例子,但是呢?我要做的是主机发命令给 ...


先确定你从机需要发送的数据有几种。
如果只有一种,那么直接 主机切换到主模式,发送从机地址(读),然后从机发送数据。
如果有多种,那么直接 主机切换到主模式,发送从机地址(写),发送数据指令,等待一段时间,发送从机地址(读),从机发回数据。

如果你用模拟iic 可以参考我这个帖子
http://www.amobbs.com/thread-5577411-1-1.html
不过这个是主机模式,想变成从机,你需要先写一个中断程序。
在CLK下降沿进入中断,然后检查START等标识,比较麻烦的。

如果IIC要作为从机,最好还是硬件IIC好一点,我感觉。

出0入0汤圆

发表于 2014-5-2 20:22:25 | 显示全部楼层
   主机不需要切换模式啊,只是主机先发送,然后接收,

从机硬件中断里面接收,然后发送。我现在调试的不知道哪里出问题呢,好像从机停止位可以监测的到,其他都监测不到,为什么?

出0入0汤圆

 楼主| 发表于 2014-5-2 20:47:17 | 显示全部楼层
dhw5qq 发表于 2014-5-2 20:22
主机不需要切换模式啊,只是主机先发送,然后接收,

从机硬件中断里面接收,然后发送。我现在调试的不 ...

我上面写的需要切换模式。

你用硬件IIC的时候作为从机,ACK一定要配置好。

主机和从机的ACK要配置好。

你如果有逻辑分析仪最好了,可以看看到底哪个步骤有问题。

出0入0汤圆

发表于 2014-5-5 15:43:46 | 显示全部楼层
lovepig200 发表于 2014-5-2 20:47
我上面写的需要切换模式。

你用硬件IIC的时候作为从机,ACK一定要配置好。

  不知道你的io是怎么配置的,我主机是开漏输出,从机也是开漏 输出,现在从机只能进到中断,我用数据分析仪看了波形,都是高电平,请问下,你两边的io口是怎么配置的

出0入0汤圆

发表于 2014-5-5 16:39:45 | 显示全部楼层
这是我用工具抓的波形,但是很奇怪,为什么没有scl呢,我吧从机地址设置成0xaa,我主机一直在发01命令给从机,现在SCL抓不出来,好奇怪!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

出0入0汤圆

发表于 2014-5-5 16:41:56 | 显示全部楼层
lovepig200 发表于 2014-5-2 20:47
我上面写的需要切换模式。

你用硬件IIC的时候作为从机,ACK一定要配置好。

不晓得是不是主机模拟的时序太快了,我记得我调试avr的时候,也出现过这种情况,后来我不知道改了哪里就好了!

出0入0汤圆

发表于 2014-5-5 17:18:31 | 显示全部楼层
我去,找到原因了,原来时钟延展这个位没有使能,但是现在从机发送好像不行,我不知道哪里的问题!

出0入0汤圆

发表于 2014-5-5 17:25:48 | 显示全部楼层
lovepig200 发表于 2014-5-2 20:47
我上面写的需要切换模式。

你用硬件IIC的时候作为从机,ACK一定要配置好。
  1.                                 while((I2C_SR1 & 0x80) == 0);                //等待发送寄存器为空
  2.                                                 switch(temp)
  3.                                         {
  4.                                                  case 0x01:
  5.                                                  I2C_DR = 0x02;                                                                        //发送要写入的数据
  6.                                                         break;
  7.                                                  case 0x02:
  8.                                                  I2C_DR = 0x04;                                                                        //发送要写入的数据
  9.                                                  break;
  10.                                                  default:
  11.                                                  break;
  12.                                         }                                       
  13.                                         while((I2C_SR1 & 0x04) == 0);                //等待发送完成                 
复制代码


如果我从机在接收到数据后,想发送数据给主机的话,需要做什么吗?
为什么我这里判断发送寄存器是否为空,想吧数据发给主机就不行呢?

出0入0汤圆

 楼主| 发表于 2014-5-5 17:36:09 | 显示全部楼层
dhw5qq 发表于 2014-5-5 17:25
如果我从机在接收到数据后,想发送数据给主机的话,需要做什么吗?
为什么我这里判断发送寄存器是否为 ...

stm8l 硬件IIC 一般不用配置IO 自动就会配置成開漏。

注意我例子里面 中断函数里的这两句

/* check on EV3 */
    case I2C_EVENT_SLAVE_BYTE_TRANSMITTING:
      I2C_SendData(I2C1, 0x22);
      break;

当主机发送地址给从机,从机地址匹配后,主机继续发送时钟,这个时候从机进入 EV3 这个时候轮到从机发送数据
我这个例子发送的只有一个数0X22 ,你可以改成你要发送的。

你看看官方的stm8l的手册关于iic的事件之间的关系就清楚了。

出0入0汤圆

 楼主| 发表于 2014-5-5 17:42:33 | 显示全部楼层
dhw5qq 发表于 2014-5-5 17:25
如果我从机在接收到数据后,想发送数据给主机的话,需要做什么吗?
为什么我这里判断发送寄存器是否为 ...

你看看这个时序图,就清楚了。在数据手册上有。
402页

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

出0入0汤圆

发表于 2014-5-5 17:48:32 | 显示全部楼层
请问楼主用什么工具抓的波形,非常不错。

出0入0汤圆

发表于 2014-5-5 17:59:25 | 显示全部楼层
收藏啦!!!

出0入0汤圆

发表于 2014-5-5 18:01:22 | 显示全部楼层
hongfadg 发表于 2014-5-5 17:48
请问楼主用什么工具抓的波形,非常不错。

数据分析仪啊!

出0入0汤圆

发表于 2014-5-5 18:08:22 | 显示全部楼层
lovepig200 发表于 2014-5-5 17:42
你看看这个时序图,就清楚了。在数据手册上有。
402页

我现在抓了波形,从机还是无法发送数据,
我主机发0x11,从机接收到了数据,但是从机发送不了数据给主机,
问题在哪呢,我看了你的程序,你的EV3也是这样判断的啊!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

出0入0汤圆

发表于 2014-5-5 18:09:06 | 显示全部楼层
   我从机地址是0xaa,时序是我自己模拟的,
我主机发地址+命令
从机收到命令后,发数据给主机!

出0入0汤圆

 楼主| 发表于 2014-5-5 19:59:51 | 显示全部楼层
dhw5qq 发表于 2014-5-5 18:09
我从机地址是0xaa,时序是我自己模拟的,
我主机发地址+命令
从机收到命令后,发数据给主机! ...

你用的模拟 iic么?

你在读的时候为什么发了两次地址?紧接着就是一个nack和stop?


一个数据的模式
应该是 主机发从机地址(读),从机一个ack,然后从机发数据,主机nack 主机stop

多个数据
应该是 主机发从机地址(读),从机一个ack,然后从机发数据1,数据2,数据n,(主机决定接受数据的个数,提供sck)主机nack 主机stop

你按照这个顺序才对。

出0入0汤圆

 楼主| 发表于 2014-5-5 20:00:55 | 显示全部楼层
lovepig200 发表于 2014-5-5 19:59
你用的模拟 iic么?

你在读的时候为什么发了两次地址?紧接着就是一个nack和stop?

如果你用模拟IIC 作为从机 在中断程序里你一定要做好状态判断,然后在中断函数中 进行 ACK ,NACK等操作。

出0入0汤圆

 楼主| 发表于 2014-5-5 20:10:20 | 显示全部楼层
dhw5qq 发表于 2014-5-5 18:09
我从机地址是0xaa,时序是我自己模拟的,
我主机发地址+命令
从机收到命令后,发数据给主机! ...

作为从机要判断的事件有。

start

地址是否匹配

主机是要写,还是要读

写的情况下 : 发送ACK 》》接收数据》》数据接收完毕发送nack或者等待主机停止》》主机stop

读的情况下: 发送ACK》》发送数据》》等待主机ACK 主机ACK后继续发送,主机NACK 停止发送,等待STOP》》主机STOP

这些你都要做好判断。

出0入0汤圆

发表于 2014-5-5 20:11:33 | 显示全部楼层
不啊,我就是主机发命令给从机,从机然后把数据发给主机,

现在主机收到的数据是ff,我不知道为什么没有发出去

出0入0汤圆

发表于 2014-5-5 20:17:02 | 显示全部楼层
你看嘛,  我现在发命令给从机后,从机已经收到命令了,但是从机发数据的时候,就不对了!ack是从机硬件发的啊,nack是主机读取完数据后发给从机的啊,你看,时序都没有问题的额!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

出0入0汤圆

发表于 2014-5-5 20:38:45 | 显示全部楼层
这个协议不是我自己杜撰的,因为我用avr已经调试好了,但是现在用在这个就出现这个问题!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

出0入0汤圆

发表于 2014-5-5 21:13:40 | 显示全部楼层
lovepig200 发表于 2014-5-5 20:10
作为从机要判断的事件有。

start

谢谢调出来 了,居然是读2遍,奇怪!
  1. u8 read_gasgauge(void)
  2. {
  3.      u8 temp=0,a;
  4.      I2C_start();        
  5.           delay_us(1);
  6.          I2C_write(bq3050_read_address);         
  7.          a=I2C_read(1);         
  8.           temp=I2C_read(0);
  9.          I2C_stop();
  10.          return temp;
  11. }
复制代码

出0入0汤圆

 楼主| 发表于 2014-5-5 21:34:02 | 显示全部楼层
本帖最后由 lovepig200 于 2014-5-5 21:40 编辑
dhw5qq 发表于 2014-5-5 21:13
谢谢调出来 了,居然是读2遍,奇怪!


你的 哪几个子函数都怎么写的啊?

读数据和诊断ACK的时候,如果是模拟IIC需要先切换成输入模式。

我写过一个模拟IIC的,不过只有主机部分
http://www.amobbs.com/thread-5577411-1-1.html

你的IO配置是什么?

如果你没有开启硬件IIC 怎么会硬件发送ACK ?

出0入0汤圆

发表于 2014-5-5 23:15:29 | 显示全部楼层
赞赞赞一个

出0入0汤圆

发表于 2014-5-6 08:41:11 | 显示全部楼层
lovepig200 发表于 2014-5-5 21:34
你的 哪几个子函数都怎么写的啊?

读数据和诊断ACK的时候,如果是模拟IIC需要先切换成输入模式。

我主机是软件模拟的,从机是硬件iic中断,  我从机只需要去配置ack使能,主机软件模拟也可以发ack和nack啊!

出0入0汤圆

发表于 2014-5-6 10:07:56 | 显示全部楼层
抽空试试看,先mark

出0入0汤圆

 楼主| 发表于 2014-5-6 12:39:57 | 显示全部楼层
本帖最后由 lovepig200 于 2014-5-6 12:43 编辑
dhw5qq 发表于 2014-5-6 08:41
我主机是软件模拟的,从机是硬件iic中断,  我从机只需要去配置ack使能,主机软件模拟也可以发ack和nack ...


主机需要当从机要在每次应答一次ACK以后再次设置ACK使能才能第二次应答ACK否则就会发出NACK。

你现在应该先检查一下程序,解决主机连续发两次的问题,有可能是因为这个从机无法发送数据。

出0入0汤圆

发表于 2014-5-7 12:58:53 | 显示全部楼层
lovepig200 发表于 2014-5-6 12:39
主机需要当从机要在每次应答一次ACK以后再次设置ACK使能才能第二次应答ACK否则就会发出NACK。

你现在应 ...

  我记得avr上次硬件iic也是这个问题,我不记得当时是怎么搞定了,这个我再花点时间解决下!

出0入0汤圆

发表于 2014-6-13 11:15:00 | 显示全部楼层
不错啊........................

出0入0汤圆

发表于 2014-6-23 07:31:31 | 显示全部楼层
顶一个  嘎嘎

出0入0汤圆

发表于 2014-6-24 09:36:51 | 显示全部楼层

大神  有没有stm8l   iic硬件作为从机的程序啊

出0入0汤圆

 楼主| 发表于 2014-6-24 12:34:22 | 显示全部楼层
霸气侧漏 发表于 2014-6-24 09:36
大神  有没有stm8l   iic硬件作为从机的程序啊

这个互为主从的,默认状态就是硬件 从机模式
主机模式是靠切换状态的

出0入0汤圆

发表于 2014-6-24 13:04:20 | 显示全部楼层
本帖最后由 霸气侧漏 于 2014-6-24 13:05 编辑
lovepig200 发表于 2014-6-24 12:34
这个互为主从的,默认状态就是硬件 从机模式
主机模式是靠切换状态的


嘿嘿   对了这个程序兼容stm8l101f3p6不  

出0入0汤圆

 楼主| 发表于 2014-6-24 18:05:01 | 显示全部楼层
霸气侧漏 发表于 2014-6-24 13:04
嘿嘿   对了这个程序兼容stm8l101f3p6不

应该兼容吧,我手里没有那个,我的都是L15X的

出0入0汤圆

发表于 2015-8-28 14:56:00 | 显示全部楼层
楼主这个是stm8l硬件i2c主机通信,在中断中发送数据的么?我也是用st官方demo的主从通信,但是不知道为什么中断进了一次I2C_EVENT_MASTER_BYTE_TRANSMITTING,然后下一次中断就进了I2C_EVENT_MASTER_BYTE_TRANSMITTED,然后就停止发送数据了

出0入0汤圆

 楼主| 发表于 2015-8-29 08:15:12 | 显示全部楼层
犬火 发表于 2015-8-28 14:56
楼主这个是stm8l硬件i2c主机通信,在中断中发送数据的么?我也是用st官方demo的主从通信,但是不知道为什么 ...

数据是在中断里发送的
在配置的时候 你开了  I2C_AcknowledgeConfig(I2C1, ENABLE) 么?不然在接受了从机的应答以后会没有反应。
I2C_ITConfig(I2C1, (I2C_IT_TypeDef)(I2C_IT_EVT | I2C_IT_BUF) , ENABLE);  设置了么?IT EVT 和 IT buf 都要有,要不然发送了一个字节以后进入不了中断,当一个数据发送完毕 it buf 会中断,中断中进入状态 transmisting
在连续发送数据的时候  发送了一个字节以后的状态就是发送完毕,应该继续写入下一个字节。

出0入0汤圆

发表于 2015-8-29 10:58:30 | 显示全部楼层
lovepig200 发表于 2015-8-29 08:15
数据是在中断里发送的
在配置的时候 你开了  I2C_AcknowledgeConfig(I2C1, ENABLE) 么?不然在接受了从机 ...

开了  I2C_AcknowledgeConfig(I2C1, ENABLE),I2C_ITConfig(I2C1, (I2C_IT_TypeDef)(I2C_IT_EVT | I2C_IT_BUF) , ENABLE);  设置了,
发送了一个字节以后进入中断,但问题是中断中进入状态 I2C_EVENT_MASTER_BYTE_TRANSMITTED:而不是进入I2C_EVENT_MASTER_BYTE_TRANSMITTING,为什么会这样的,
程序参考st的官方demo的stm8l15x_stdperiph_lib1.51的stm8l15x_stdperiph_lib1.51\STM8L15x_StdPeriph_Lib_V1.5.1\Project\STM8L15x_StdPeriph_Examples\I2C\I2C_TwoBoards\I2C_DataExchange,代码初始化如下:
/* Initialize LEDs mounted on STM8L1526-EVAL board */


  /* Initialize I2C peripheral */
  I2C_Init(I2C1, I2C_SPEED, 0xA0,
           I2C_Mode_I2C, I2C_DutyCycle_2,
           I2C_Ack_Enable, I2C_AcknowledgedAddress_7bit);

  /* Enable Buffer and Event Interrupt*/
  I2C_ITConfig(I2C1, (I2C_IT_TypeDef)(I2C_IT_EVT | I2C_IT_BUF) , ENABLE);
        I2C_AcknowledgeConfig(I2C1, ENABLE);
  enableInterrupts();

  /* TXBuffer initialization */
  for (i = 0; i < BUFFERSIZE; i++)
    TxBuffer = 0x08;

  /* Send START condition */
  I2C_GenerateSTART(I2C1, ENABLE);
  while (NumOfBytes);
  while (I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY));

出0入0汤圆

 楼主| 发表于 2015-8-29 13:41:47 | 显示全部楼层
犬火 发表于 2015-8-29 10:58
开了  I2C_AcknowledgeConfig(I2C1, ENABLE),I2C_ITConfig(I2C1, (I2C_IT_TypeDef)(I2C_IT_EVT | I2C_IT ...

INTERRUPT_HANDLER(I2C1_SPI2_IRQHandler, 29)
{
  m++;
  if(IIC_STA == 1)
  {
  switch (I2C_GetLastEvent(I2C1))
  {
      /* EV5 */
    case I2C_EVENT_MASTER_MODE_SELECT :
      
      /* Send slave Address for write */
      I2C_Send7bitAddress(I2C1, SLAVE_ADDRESS, I2C_Direction_Transmitter);
      break;

      /* EV6 */
    case I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED:
      if (NumOfBytes != 0)
      {
        /* Send the first Data */
        I2C_SendData(I2C1, TxBuffer[Tx_Idx++]);

        /* Decrement number of bytes */
        NumOfBytes--;
      }
      if (NumOfBytes == 0)
      {
        I2C_ITConfig(I2C1, I2C_IT_BUF, DISABLE);
      }
      break;

      /* EV8 */
    case I2C_EVENT_MASTER_BYTE_TRANSMITTING:
      /* Transmit Data */
      I2C_SendData(I2C1, TxBuffer[Tx_Idx++]);

      /* Decrement number of bytes */
      NumOfBytes--;

      if (NumOfBytes == 0)
      {
        I2C_ITConfig(I2C1, I2C_IT_BUF, DISABLE);
      }
      break;

      /* EV8_2 */
    case I2C_EVENT_MASTER_BYTE_TRANSMITTED:
      /* Send STOP condition */
      I2C_GenerateSTOP(I2C1, ENABLE);

      I2C_ITConfig(I2C1, I2C_IT_EVT, DISABLE);
      break;

    default:
      break;
  }
  }
  else
  {
     /* Read SR2 register to get I2C error */
  if (I2C_ReadRegister(I2C1, I2C_Register_SR2))
  {
    /* Clears SR2 register */
    I2C1->SR2 = 0;
  }  
  switch (I2C_GetLastEvent(I2C1))
  {
      /******* Slave transmitter ******/
      /* check on EV1 */
    case I2C_EVENT_SLAVE_TRANSMITTER_ADDRESS_MATCHED:
      SL_Tx_Idx = 0;
      break;

      /* check on EV3 */
    case I2C_EVENT_SLAVE_BYTE_TRANSMITTING:
      I2C_SendData(I2C1, 0x22);
      break;
      /******* Slave receiver **********/
      /* check on EV1*/
    case I2C_EVENT_SLAVE_RECEIVER_ADDRESS_MATCHED:
      break;

      /* Check on EV2*/
    case I2C_EVENT_SLAVE_BYTE_RECEIVED:
      Slave_Buffer_Rx[SL_Rx_Idx++] = I2C_ReceiveData(I2C1);
      break;

      /* Check on EV4 */
    case (I2C_EVENT_SLAVE_STOP_DETECTED):
            /* write to CR2 to clear STOPF flag */
            I2C1->CR2 |= I2C_CR2_ACK;
            SL_Rx_Idx=0;
      break;

    default:
      break;
  }
  }
}


注意看这个

case I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED:
      if (NumOfBytes != 0)
      {
        /* Send the first Data */
        I2C_SendData(I2C1, TxBuffer[Tx_Idx++]);

        /* Decrement number of bytes */
        NumOfBytes--;
      }
      if (NumOfBytes == 0)
      {
        I2C_ITConfig(I2C1, I2C_IT_BUF, DISABLE);
      }
      break;

中断里面判断是不是继续发送给数据。不是在主程序里面。

出0入0汤圆

发表于 2015-8-30 19:30:11 | 显示全部楼层
lovepig200 发表于 2015-8-29 13:41
INTERRUPT_HANDLER(I2C1_SPI2_IRQHandler, 29)
{
  m++;

你的意思是在中断里面一口气全部发完,不是每次进入一次中断发一个,要是要发送很多数据的话,缓冲不是直接溢出了?还有它的缓冲有多大,可以发多少个字节?

出0入0汤圆

发表于 2015-8-31 11:09:15 | 显示全部楼层
lovepig200 发表于 2015-8-29 13:41
INTERRUPT_HANDLER(I2C1_SPI2_IRQHandler, 29)
{
  m++;

if (NumOfBytes != 0),这个在中断里面也只是执行一次而已,而不是while(NumOfBytes != 0),另外我实际测试中断进入I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED也只有一次而已,确实是中断里面判断是不是继续发送给数据。不是在主程序里面。但是中断他只进入一次I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED而已,然后就是进入中断I2C_EVENT_MASTER_BYTE_TRANSMITTING了

出0入0汤圆

 楼主| 发表于 2015-8-31 17:52:59 | 显示全部楼层
本帖最后由 lovepig200 于 2015-8-31 18:14 编辑
犬火 发表于 2015-8-31 11:09
if (NumOfBytes != 0),这个在中断里面也只是执行一次而已,而不是while(NumOfBytes != 0),另外我实际测 ...


这个会每发送一个数据都进来一次的。因为中断设置里面有 event 和 buf 两个,每次发送完成一个字节 buf都会触发中段第一次会有 I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED: 然后发送第一个字节,第二个字节以后在进入 就会进入 I2C_EVENT_MASTER_BYTE_TRANSMITTING:

每个里面都加了  
I2C_SendData(I2C1, TxBuffer[Tx_Idx++]);

      /* Decrement number of bytes */
      NumOfBytes--;

      if (NumOfBytes == 0)
      {
        I2C_ITConfig(I2C1, I2C_IT_BUF, DISABLE);
      }

是因为有可能只发送一个字节的情况,这种情况就不会进入到I2C_EVENT_MASTER_BYTE_TRANSMITTING:
传送完最后一个 关闭 buf 中断 ,这样传送完成后不给 buf 写入字节,会触发 btf  event 就是传送完成 事件,然后发送一个stop 结束传送。


在传送完成前,是 开始 触发 主机选择模式,发送从机地址,进入主机选择模式,发送第一个字节,进入正在发送模式,传送其余字节,最有一个字节关闭buf ,进入完成模式,发送stop 结束

出0入0汤圆

发表于 2015-11-6 16:24:02 | 显示全部楼层
想用I2C的方式实现母板与人机界面的通迅,如楼上所讨论的,母板的MCU配置成从机,人机界面的MCU配置成主机,请问有没有相关的资料可以共享。谢谢

出0入0汤圆

发表于 2015-11-7 10:23:59 | 显示全部楼层
赞一个。好东西。

出0入0汤圆

发表于 2017-7-31 19:26:28 | 显示全部楼层
感谢,正需要!
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-5-21 13:56

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表