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

2019-12-26 18:55发布

本帖最后由 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;
  }
  }
}

现象
发帖.jpg (179.57 KB, 下载次数: 2) 下载附件 通信现象 2014-2-10 16:18 上传

代码
代码.rar (5.45 KB, 下载次数: 160) 2014-2-10 16:20 上传 点击文件名下载附件
代码




友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。
该问题目前已经被作者或者管理员关闭, 无法添加新回复
52条回答
犬火
1楼-- · 2020-01-01 22:03
楼主这个是stm8l硬件i2c主机通信,在中断中发送数据的么?我也是用st官方demo的主从通信,但是不知道为什么中断进了一次I2C_EVENT_MASTER_BYTE_TRANSMITTING,然后下一次中断就进了I2C_EVENT_MASTER_BYTE_TRANSMITTED,然后就停止发送数据了
lovepig200
2楼-- · 2020-01-01 22:05
犬火 发表于 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
在连续发送数据的时候  发送了一个字节以后的状态就是发送完毕,应该继续写入下一个字节。
犬火
3楼-- · 2020-01-01 23:40
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.51STM8L15x_StdPeriph_Lib_V1.5.1ProjectSTM8L15x_StdPeriph_ExamplesI2CI2C_TwoBoardsI2C_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));
lovepig200
4楼-- · 2020-01-02 00:18
 精彩回答 2  元偷偷看……
犬火
5楼-- · 2020-01-02 03:47
lovepig200 发表于 2015-8-29 13:41
INTERRUPT_HANDLER(I2C1_SPI2_IRQHandler, 29)
{
  m++;

你的意思是在中断里面一口气全部发完,不是每次进入一次中断发一个,要是要发送很多数据的话,缓冲不是直接溢出了?还有它的缓冲有多大,可以发多少个字节?
犬火
6楼-- · 2020-01-02 08:54
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了

一周热门 更多>