stm32 IIC 从机模式

1、IIC简介

 

第二节代码会用到该部分内容,对于IIC来说,从机是不能主动发送数据的,开始条件都是由主机生成。 

 

1.1、主机发送数据流程

 

  1) 主机在检测到总线为“空闲状态”(即 SDA、SCL 线均为高电平)时,发送一个启动信号“S”,开始一次通信的开始

  2) 主机接着发送一个命令字节。该字节由 7 位的外围器件地址和 1 位读写控制位 R/W组成(此时 R/W=0)

  3) 相对应的从机收到命令字节后向主机回馈应答信号 ACK(ACK=0)

  4) 主机收到从机的应答信号后开始发送第一个字节的数据

  5) 从机收到数据后返回一个应答信号 ACK

  6) 主机收到应答信号后再发送下一个数据字节

  7) 当主机发送最后一个数据字节并收到从机的 ACK 后,通过向从机发送一个停止信号P结束本次通信并释放总线。从机收到P信号后也退出与主机之间的通信

 

1.2、主机接收数据流程

 

  1) 主机发送启动信号后,接着发送命令字节(其中 R/W=1)

  2) 对应的从机收到地址字节后,返回一个应答信号并向主机发送数据

  3) 主机收到数据后向从机反馈一个应答信号

  4) 从机收到应答信号后再向主机发送下一个数据 

  5) 当主机完成接收数据后,向从机发送一个“非应答信号(ACK=1)”,从机收到ASK=1 的非应答信号后便停止发送

  6) 主机发送非应答信号后,再发送一个停止信号,释放总线结束通信

 

1.3、处理器的I2C模块会在如下所述的情况产生中断信号

 

  RX_UNDER   当处理器通过IC_DATA_CMD寄存器读取接收缓冲器为空时置位

  RX_OVER    当接收缓冲器被填满,而且还有数据从外设发送过来时被置位;缓冲器被填满后接收的数据将会丢失

  RX_FULL    当接收缓冲器达到或者超过IC_RX_TL寄存器中规定的阈值时被置位;当数据低于阈值时标志位将被自动清除

  TX_OVER    当发送缓冲器被填满,而且处理器试图发送另外的命令写IC_DATA_CMD寄存器时被置位

  TX_EMPTY   当发送缓冲器等于或者低于IC_TX_TL寄存器中规定的阈值时被置位;当数据高于阈值时标志位将被自动清除

  TX_ABRT    当i2c模块无法完成处理器下达的命令时被置位,有如下几种原因:

                          * 发送地址字节后没有从机应答

                          * 地址识别成功后主机发送的数据从机没有应答

                          * 当i2c模块只能作为从机时试图发送主机命令

                          * 当模块的RESTART功能被关闭,而处理试图完成的功能必须要RESTART功能开启才能完成

                          * 高速模块主机代码被应答

                          * START BYTE被应答

                          * 模块仲裁失败

                          无论标志位什么时候被置位,发送缓冲器和接收缓冲器的内容都会被刷新 

  ACTIVITY   表明i2c模块正在活动,这个标志位将会一直保持直到用以下4种方式清除:

                          * 关闭i2c

                          * 读取IC_CLR_ACTIVITY寄存器

                          * 读取IC_CLR_INTR寄存器

                          * 系统重启

                          即使i2c模块是空闲的,这个标志仍然需要被置位直到被清除,因为这表明i2c总线上有数据正在传输

 

需要用到的:

 

  RD_REQ     当i2c模块作为从机时并且另外的主机试图从本模块读取数据时被置位  

  RX_DONE    当i2c模块作为从机发送数据时,如果主机没有应答则置位;这种情况发生在i2c模块发送最后一个字节数据时,表明传输结束

  STOP_DET   表明i2c总线上产生了STOP信号,无论模块作为主机还是从机

  START_DET  表明i2c总线上产生了START信号,无论模块作为主机还是从机

 

2、IIC从机中断收发函数

 

// 从机收发函数处理

void I2C1_EV_IRQHandler(void)

{

  __IO uint16_t SR1Register =0;

  __IO uint16_t SR2Register =0;

 

 

  SR1Register = I2C1->SR1;           // 通过读取 SR1/2 获取 IIC 状态

  SR2Register = I2C1->SR2;

 

 

  // 从机发送

  // 判断IIC是从机模式 - 最低位(MSL = 0)

  if((SR2Register & 0x0001) != 0x0001)

  {

    // ADDR:根据状态判断获取从机IIC地址成功

    if((SR1Register & 0x0002) == 0x0002)

    {

      // 清除标志,准备接收数据

      SR1Register = 0;

      SR2Register = 0;

 TrCount= 0;

    }

 

 

//TxE:根据状态标志可以发送数据

if((SR1Register & 0x0080) == 0x0080)

{

 SR1Register = 0;

      SR2Register = 0;

 I2C1->DR =TrCount ++;

}

 

//STOPF:监测停止标志

if((SR1Register & 0x0010) == 0x0010)

{

 I2C1->CR1 |= CR1_PE_Set;

      SR1Register = 0;

      SR2Register = 0;

 TrCount= 5;

}

 

//TIME_OUT

if((SR1Register & 0x4000) == 0x4000)

{

 I2C1->CR1 |= CR1_PE_Set;

 SR1Register = 0;

      SR2Register = 0;

}

  }  

  

  // IIC从机接收

  // 判断IIC是从机模式 - 最低位(MSL = 0)

  if((SR2Register &0x0001) != 0x0001)

  {

    // 收到主机发送的地址:(ADDR = 1: EV1) 

    if((SR1Register & 0x0002) == 0x0002)

    {

      // 清除标志,准备接受数据

      SR1Register = 0;

      SR2Register = 0;

      Rx_Idx = 0;

    }

    

    // 接收数据 (RXNE = 1: EV2)

    if((SR1Register & 0x0040) == 0x0040)

    {

      Buffer_Rx[Rx_Idx++] = I2C1->DR;

      SR1Register = 0;

      SR2Register = 0;

    }

    

    // 监测停止条件 (STOPF =1: EV4) 

    if(( SR1Register & 0x0010) == 0x0010)

    {

      I2C1->CR1 |= CR1_PE_Set;

      SR1Register = 0;

      SR2Register = 0;

      Flag_RcvOK = 1;                         

    }

  }

}

 

 

 

3、代码参考实例

 

//stm32f10x_it.c

 

#include "stm32f10x_it.h"

#include "stdio.h"

 

extern u32 BufferSize ;

extern u8 I2C1_ADDRESS ;

extern u8 I2C2_ADDRESS ;

extern vu8 I2C1_Buffer_Tx[];

extern vu8 I2C2_Buffer_Rx[];

vu32 Tx_Counter = 0;

vu32 Rx_Counter = 0;

vu32 show_counter1 = 0;

vu32 show_counter2 = 0;

 

// I2C1 作为主机,用于中断接收从机数据

void I2C1_EV_IRQHandler(void)

{

  show_counter1++;

  if(show_counter1 > 1000000)

  {

    show_counter1 = 0;

    printf("rn The I2C1 LastEvent is %x rn", I2C_GetLastEvent(I2C1));

  }

  switch(I2C_GetLastEvent(I2C1))

  {

    case I2C_EVENT_MASTER_MODE_SELECT: // 已发送启始条件

    {

 // 七位地址发送

      I2C_Send7bitAddress(I2C1, I2C2_ADDRESS, I2C_Direction_Receiver);

      printf("rn The I2C1 is ready rn");

      break;

    }

    case I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED: // 已发送从机地址

    {

      printf("rn The slave address is %x rn", I2C_ReceiveData(I2C1));

      break;

    }

    case (I2C_EVENT_MASTER_BYTE_RECEIVED | (I2C_FLAG_BTF & 0x0f)): // 第一个数据已接收

    {

      // 要接收最后一个字节前先关总线,不然总线锁死

      I2C_GenerateSTOP(I2C1,ENABLE);

      printf("rn The I2C1 has received data2 %x rn", I2C_ReceiveData(I2C1));

      printf("rn The I2C1 is finish rn");

      break;

    }

    case 0x40:

    {

      // 接收了两个同样的数据,没有这个释放不了 RXNE

      I2C_ReceiveData(I2C1);

    }

default: {break;}

  }

}

 

 

// I2C2 用于从机发送数据到主机

void I2C2_EV_IRQHandler(void)

{

  show_counter2++;

  if(show_counter2 > 100000)

  {

    show_counter2 = 0;

    printf("rn The I2C2 LastEvent is %x rn", I2C_GetLastEvent(I2C2));

  }

  switch(I2C_GetLastEvent(I2C2))

  {

    // 收到匹配的地址数据

    case I2C_EVENT_SLAVE_TRANSMITTER_ADDRESS_MATCHED: 

    {

      printf("rn The I2C2 is ready rn");

      I2C_GenerateSTOP(I2C2, DISABLE);

      break;

    }

    case I2C_EVENT_SLAVE_BYTE_TRANSMITTING: //发送数据

    {

      printf("rn The I2C2 transmits is transmitting rn");

      I2C_SendData(I2C2, 0xb6 + Rx_Counter); 

      break;

 

    }

 

   // 发送数据,要发送,不然锁死,不过 master 没收到

 

    case I2C_EVENT_SLAVE_BYTE_TRANSMITTED:

    {

 

      printf("rn The I2C2 transmits one byte rn");

 

     I2C_SendData(I2C2, 0xb6 + (Rx_Counter++));

 

      break;

    }

    case I2C_EVENT_SLAVE_STOP_DETECTED: //收到结束条件

    {

      printf("rn The I2C2 is finish rn");

      I2C_ClearFlag(I2C2,I2C_FLAG_STOPF);

      I2C_GenerateSTOP(I2C2, ENABLE);

      break;

    }

    default: {break;}

  }

}

 

/*----------------------------------------------------------------------------------------------------

名称: I2C 测试 24C02 测试

编写: mingzhang.zhao

内容:测试 stm32f103vct6 的硬件 I2C 实现中断收发数据

注意事项:

1.USART1: PA9 为 TX, PA10 为 RX

I2C1: PB6 为 SCL, PB7 为 SDA

I2C2: PB10 为 SCL, PB11 为 SDA

----------------------------------------------------------------------------------------------------*/

#include "stm32f10x.h"

#include "stdio.h"

#define PRINTF_ON 1

void RCC_Configuration(void);void GPIO_Configuration(void);

void USART_Configuration(void);

void I2C_Configuration(void);

void NVIC_Configuration(void);

void Delay(__IO uint32_t t);

u8 I2C1_ADDRESS = 0x30; //7 位 I2C 地址

u8 I2C2_ADDRESS = 0x31;

#define Size 4

vu8 I2C1_Buffer_Tx[Size] = {1,2,3,4};

vu8 I2C2_Buffer_Rx[Size] = {0};

u32 BufferSize = Size ;

 

int main(void)

{

  RCC_Configuration();

  GPIO_Configuration();

  USART_Configuration();

  I2C_Configuration();

  NVIC_Configuration();

  I2C_GenerateSTART(I2C1,ENABLE);

  while(1)

  {

    Delay(1000);

    I2C_GenerateSTART(I2C1,ENABLE); //I2C1 循环读取数据

  }

}

 

// 初始化和配置相关

void I2C_Configuration(void)

{

  I2C_InitTypeDef I2C_InitStructure;

  I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;

  I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;

  I2C_InitStructure.I2C_OwnAddress1 = I2C1_ADDRESS;

  I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;

  I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;

  I2C_InitStructure.I2C_ClockSpeed = 200000;I2C_Init(I2C1,&I2C_InitStructure);

  I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;

  I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;

  I2C_InitStructure.I2C_OwnAddress1 = I2C2_ADDRESS;

  I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;

  I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;

  I2C_InitStructure.I2C_ClockSpeed = 200000;

  I2C_Init(I2C2,&I2C_InitStructure);

  I2C_ITConfig(I2C1,I2C_IT_EVT|I2C_IT_BUF,ENABLE);

  I2C_ITConfig(I2C2,I2C_IT_EVT|I2C_IT_BUF,ENABLE);

  I2C_Cmd(I2C1,ENABLE);

  I2C_Cmd(I2C2,ENABLE);

}

 

void NVIC_Configuration(void)

{

  NVIC_InitTypeDef NVIC_InitStructure;

  NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);

  NVIC_InitStructure.NVIC_IRQChannel = I2C1_EV_IRQn;

  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;

  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;

  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;

  NVIC_Init(&NVIC_InitStructure);

  NVIC_InitStructure.NVIC_IRQChannel = I2C2_EV_IRQn;

  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;

  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;

  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;

  NVIC_Init(&NVIC_InitStructure);

}

 

void GPIO_Configuration(void)

{

  GPIO_InitTypeDef GPIO_InitStructure;

  //初始化 I2C1GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6|GPIO_Pin_7;

  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;

  GPIO_Init(GPIOB , &GPIO_InitStructure);

  //初始化 I2C2

  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10|GPIO_Pin_11;

  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;

  GPIO_Init(GPIOB , &GPIO_InitStructure);

  //初始化 USART1

  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;

  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;

  GPIO_Init(GPIOA , &GPIO_InitStructure);

  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;

  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;

  GPIO_Init(GPIOA , &GPIO_InitStructure);

}

 

void RCC_Configuration(void)

{

  /* 定义枚举类型变量 HSEStartUpStatus */

  ErrorStatus HSEStartUpStatus;

  /* 复位系统时钟设置*/

  RCC_DeInit();

  /* 开启 HSE*/

  RCC_HSEConfig(RCC_HSE_ON);

  /* 等待 HSE 起振并稳定*/

  HSEStartUpStatus = RCC_WaitForHSEStartUp();

  /* 判断 HSE 起是否振成功,是则进入 if()内部 */

  if(HSEStartUpStatus == SUCCESS)

  {

  /* 选择 HCLK(AHB)时钟源为 SYSCLK 1 分频 */

  RCC_HCLKConfig(RCC_SYSCLK_Div1);

  /* 选择 PCLK2 时钟源为 HCLK(AHB) 1 分频 */

  RCC_PCLK2Config(RCC_HCLK_Div1);

  /* 选择 PCLK1 时钟源为 HCLK(AHB) 2 分频 */RCC_PCLK1Config(RCC_HCLK_Div2);

  /* 设置 FLASH 延时周期数为 2 */

  FLASH_SetLatency(FLASH_Latency_2);

  /* 使能 FLASH 预取缓存 */

  FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);

  /* 选择锁相环(PLL)时钟源为 HSE 1 分频, 倍频数为 9,则 PLL 输出频率为 8MHz

  * 9 = 72MHz */

  RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9);

  /* 使能 PLL */

  RCC_PLLCmd(ENABLE);

  /* 等待 PLL 输出稳定 */

  while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET);

  /* 选择 SYSCLK 时钟源为 PLL */

  RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);

  /* 等待 PLL 成为 SYSCLK 时钟源 */

  while(RCC_GetSYSCLKSource() != 0x08);

  }

  /* 打开 APB2 总线上的 GPIOA 时钟*/

  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOB|RCC_APB

  2Periph_USART1, ENABLE);

  //RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);

  RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1|RCC_APB1Periph_I2C2,ENABLE);

  //RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR|RCC_APB1Periph_BKP|RCC_APB1Pe

  riph_WWDG|RCC_APB1Periph_SPI2, ENABLE);

}

 

 

void USART_Configuration(void)

{

  USART_InitTypeDef USART_InitStructure;

  USART_ClockInitTypeDef USART_ClockInitStructure;USART_ClockInitStructure.USART_Clock = USART_Clock_Disable;

  USART_ClockInitStructure.USART_CPOL = USART_CPOL_Low;

  USART_ClockInitStructure.USART_CPHA = USART_CPHA_2Edge;

  USART_ClockInitStructure.USART_LastBit = USART_LastBit_Disable;

  USART_ClockInit(USART1 , &USART_ClockInitStructure);

  USART_InitStructure.USART_BaudRate = 9600;

  USART_InitStructure.USART_WordLength = USART_WordLength_8b;

  USART_InitStructure.USART_StopBits = USART_StopBits_1;

  USART_InitStructure.USART_Parity = USART_Parity_No;

  USART_InitStructure.USART_HardwareFlowControl =

  USART_HardwareFlowControl_None;

  USART_InitStructure.USART_Mode = USART_Mode_Rx|USART_Mode_Tx;

  USART_Init(USART1,&USART_InitStructure);

  USART_Cmd(USART1,ENABLE);

}

 

void Delay(__IO uint32_t t)

{

  while(t--);

}

#if PRINTF_ON

int fputc(int ch,FILE *f)

{

  USART_SendData(USART1,(u8) ch);

  while(USART_GetFlagStatus(USART1,USART_FLAG_TC) == RESET);

  return ch;

}

#endif

  • 3
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
stm8si2c程序,调试通过 INTERRUPT_HANDLER(I2C_IRQHandler, 19) { /* In order to detect unexpected events during development, it is recommended to set a breakpoint on the following instruction. */ struct SCB_T *system=&system_process; unsigned char i,i2c_sr1,i2c_sr2,i2c_event,i2c__status=0,temp,sr1_analysis_int_resource[8],sr2_analysis_int_resource[8]; char i2c_interrupt_type=0,p;//在一次I2中断中,I2C中断中的中断标志位个数; disableInterrupts();//关总中断 i2c_sr1=I2C->SR1; p=I2C->SR3; i2c_sr2=I2C->SR2; //temp=I2C->SR3; //analysis interrupt resource in i2c->sr1 register sr1_analysis_int_resource[0]=i2c_sr1&I2C_SR1_SB; sr1_analysis_int_resource[1]=i2c_sr1&I2C_SR1_ADDR; sr1_analysis_int_resource[2]=i2c_sr1&I2C_SR1_BTF; sr1_analysis_int_resource[3]=i2c_sr1&I2C_SR1_ADD10; sr1_analysis_int_resource[4]=i2c_sr1&I2C_SR1_STOPF; // sr1_i2c__state[5]=i2c_state&((u8)I2C_SR1_BIT6); sr1_analysis_int_resource[6]=i2c_sr1&I2C_SR1_RXNE; sr1_analysis_int_resource[7]=i2c_sr1&I2C_SR1_TXE; //analysis interrupt resource in i2c->sr2 register sr2_analysis_int_resource[0]=i2c_sr2&I2C_SR2_BERR; sr2_analysis_int_resource[1]=i2c_sr2&I2C_SR2_ARLO; sr2_analysis_int_resource[2]=i2c_sr2&I2C_SR2_AF; sr2_analysis_int_resource[3]=i2c_sr2&I2C_SR2_OVR; sr2_analysis_int_resource[5]=i2c_sr2&I2C_SR2_WUFH; if(sr1_analysis_int_resource[0]==I2C_SR1_SB) {i2c__status=0x01;i2c_interrupt_type++;} if(sr1_analysis_int_resource[1]==I2C_SR1_ADDR) {i2c__status=0x02;i2c_interrupt_type++;} if(sr1_analysis_int_resource[2]==I2C_SR1_BTF) {i2c__status=0x03;i2c_interrupt_type++;} if(sr1_analysis_int_resource[3]==I2C_SR1_ADD10) {i2c__status=0x04;i2c_interrupt_type++;} if(sr1_analysis_int_resource[4]==I2C_SR1_STOPF) {i2c__status=0x05;i2c_interrupt_type++;} if(sr1_analysis_int_resource[6]==I2C_SR1_RXNE) {i2c__status=0x06;i2c_interrupt_type++;} if(sr1_analysis_int_resource[7]==I2C_SR1_TXE) {i2c__status=0x07;i2c_interrupt_type++;} if(sr2_analysis_int_resource[0]==I2C_SR2_BERR) {i2c__status=0x08;i2c_interrupt_type++;} if(sr2_analysis_int_resource[1]==I2C_SR2_ARLO) {i2c__status=0x09;i2c_interrupt_type++;} if(sr2_analysis_int_resource[2]==I2C_SR2_AF) {i2c__status=0x0a;i2c_interrupt_type++;} if(sr2_analysis_int_resource[3]==I2C_SR2_OVR) {i2c__status=0x0b;i2c_interrupt_type++;} if(sr2_analysis_int_resource[5]==I2C_SR2_WUFH) {i2c__status=0x0c;i2c_interrupt_type++;} if(i2c_interrupt_type>=2) /*there are more than one interrupt resource in the time*/ { if(i2c_interrupt_type==2) { if((sr1_analysis_int_resource[1]==I2C_SR1_ADDR)&&(sr1_analysis_int_resource[7]==I2C_SR1_TXE)) { I2C->DR=system->i2c.send_frame.data[system->i2c.send_frame.proc]; system->i2c.send_frame.proc++; system->i2c.debug.reserve[system->i2c.int_debug_count].type=0x62; } else if((sr1_analysis_int_resource[7]==I2C_SR1_TXE)&&(sr1_analysis_int_resource[2]==I2C_SR1_BTF)) { system->i2c.send_frame.terminate=0; //set I2C transfer terminate bit; system->i2c.send_frame.mod=0; system->i2c.send_frame.write=0; system->i2c.debug.reserve[system->i2c.int_debug_count].type=0x64; } else if((sr1_analysis_int_resource[7]==I2C_SR1_TXE)&&(sr2_analysis_int_resource[2]==I2C_SR2_AF)) { I2C->CR2|=I2C_CR2_STOP; I2C->SR2&=(~I2C_SR2_AF);//clear AF bit; system->i2c.error=1; system->i2c.debug.reserve[system->i2c.int_debug_count].type=0x64; } else { system->i2c.error=1; I2C_ITConfig(I2C_IT_EVT, DISABLE); system->i2c.debug.reserve[system->i2c.int_debug_count].type=0x37; } } else { system->i2c.error=1; I2C_ITConfig(I2C_IT_EVT, DISABLE); system->i2c.debug.reserve[system->i2c.int_debug_count].type=0x37; } } else { switch(i2c__status) { case I2C_SR1_SB_proc: //如果是发送模式 if(system->i2c.send_frame.mod==1)//说明本次中断之前是从模式,说明这是在从模式下发的起始位; { //EV5 p=I2C->SR1; I2C->DR=system->i2c.send_frame.add__L; //自动清除I2C_SR1_SB标志 system->i2c.debug.reserve[system->i2c.int_debug_count].type=0x38; } else { if(system->i2c.rev_frame.mod==1) //说明本次中断之间是主模式,这次发的是重复起始位; { //EV6如果是接收模式 p=I2C->SR1; I2C->DR=system->i2c.rev_frame.add__L;//自动清除I2C_SR1_SB标志; system->i2c.debug.reserve[system->i2c.int_debug_count].type=0x51; } else { system->i2c.error=1; system->i2c.debug.reserve[system->i2c.int_debug_count].type=0x36; } } break; case I2C_SR1_ADDR_proc: p=I2C->SR1; temp=I2C->SR3;//软件读取SR1寄存器后,对SR3寄存器的读操作将清除该位 temp&=(u8)I2C_SR3_TRA; I2C->CR2|=(u8)I2C_CR2_ACK;// 使能应答位 I2C->CR2&=(u8)(~I2C_CR2_POS);//设置接受到当字节应答 //如果是发送模式 if(system->i2c.send_frame.mod==1) { if(temp==(u8)I2C_SR3_TRA) {; } else { system->i2c.error=1; } } else { if(system->i2c.rev_frame.mod==1) { if(temp==0)//machine at a master-receive mod { system->i2c.rev_frame.proc=0; } else { system->i2c.error=1; } } else { system->i2c.error=1; } } system->i2c.debug.reserve[system->i2c.int_debug_count].type=0x52; break; case I2C_SR1_RXNE_proc: if(system->i2c.rev_frame.proci2c.rev_frame.num-3)) { system->i2c.rev_frame.data[system->i2c.rev_frame.proc]=I2C->DR; system->i2c.rev_frame.proc++; system->i2c.debug.reserve[system->i2c.int_debug_count].type=0x57; } else if(system->i2c.rev_frame.proc==(u8)(system->i2c.rev_frame.num-2)) { system->i2c.rev_frame.data[system->i2c.rev_frame.proc]=I2C->DR; system->i2c.rev_frame.proc++; system->i2c.debug.reserve[system->i2c.int_debug_count].type=0x58; I2C->CR2&=(u8)(~I2C_CR2_ACK);//不返回应答 I2C->CR2|=I2C_CR2_STOP; //发停止位结束这次数据接收; } else if(system->i2c.rev_frame.proc>=(u8)(system->i2c.rev_frame.num-1)) { system->i2c.rev_frame.data[system->i2c.rev_frame.proc]=I2C->DR; system->i2c.rev_frame.proc++; system->i2c.debug.reserve[system->i2c.int_debug_count].type=0x59; system->i2c.rev_frame.terminate=0; //set I2C transfer terminate bit; system->i2c.rev_frame.mod=0; system->i2c.rev_frame.read=0; } else { system->i2c.error=1; system->i2c.debug.reserve[system->i2c.int_debug_count].type=0xfb; } break; case I2C_SR1_TXE_proc: if(system->i2c.send_frame.proci2c.send_frame.num-1)) { I2C->DR=system->i2c.send_frame.data[system->i2c.send_frame.proc]; system->i2c.send_frame.proc++; system->i2c.debug.reserve[system->i2c.int_debug_count].type=0x61; } else if(system->i2c.send_frame.proc=(u8)(system->i2c.send_frame.num)) { I2C->CR2|=I2C_CR2_STOP; // 发停止位结束 这次数据接收; I2C_ITConfig(I2C_IT_BUF, DISABLE); system->i2c.debug.reserve[system->i2c.int_debug_count].type=0x60; } else { system->i2c.error=1; system->i2c.debug.reserve[system->i2c.int_debug_count].type=0xfc; } break; case I2C_SR2_AF_proc: I2C->CR2|=I2C_CR2_STOP; I2C->SR2&=(~I2C_SR2_AF);//clear AF bit; system->i2c.error=1; system->i2c.debug.reserve[system->i2c.int_debug_count].type=0x63; break; default: system->i2c.error=1; system->i2c.debug.reserve[system->i2c.int_debug_count].type=0xfd; break; } } system->i2c.int_debug_count++; enableInterrupts();//开总中断 }
以下是一个简单的C语言代码示例,用于在STM32上实现I2C从机。该示例使用了STM32CubeMX和HAL库。 ```c #include "stm32f4xx_hal.h" #define I2C_ADDRESS 0x68 // I2C从机地址 I2C_HandleTypeDef hi2c1; void SystemClock_Config(void); static void MX_GPIO_Init(void); static void MX_I2C1_Init(void); int main(void) { HAL_Init(); SystemClock_Config(); MX_GPIO_Init(); MX_I2C1_Init(); uint8_t buffer[10]; // 用于存储接收到的数据 uint8_t dataToSend = 0xAA; // 要发送的数据 while (1) { HAL_I2C_Slave_Receive(&hi2c1, buffer, sizeof(buffer), HAL_MAX_DELAY); // 从主机接收数据 HAL_I2C_Slave_Transmit(&hi2c1, &dataToSend, 1, HAL_MAX_DELAY); // 向主机发送数据 } } void SystemClock_Config(void) { RCC_OscInitTypeDef RCC_OscInitStruct = {0}; RCC_ClkInitTypeDef RCC_ClkInitStruct = {0}; RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI; RCC_OscInitStruct.HSIState = RCC_HSI_ON; RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT; RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE; if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) { Error_Handler(); } RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2; RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSI; RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1; RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1; if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0) != HAL_OK) { Error_Handler(); } } static void MX_I2C1_Init(void) { hi2c1.Instance = I2C1; hi2c1.Init.ClockSpeed = 100000; hi2c1.Init.DutyCycle = I2C_DUTYCYCLE_2; hi2c1.Init.OwnAddress1 = I2C_ADDRESS; hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT; hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE; hi2c1.Init.OwnAddress2 = 0; hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE; hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE; if (HAL_I2C_Init(&hi2c1) != HAL_OK) { Error_Handler(); } if (HAL_I2C_EnableListen_IT(&hi2c1) != HAL_OK) { Error_Handler(); } } void HAL_I2C_SlaveRxCpltCallback(I2C_HandleTypeDef *hi2c) { // 接收完成回调函数 } void HAL_I2C_SlaveTxCpltCallback(I2C_HandleTypeDef *hi2c) { // 发送完成回调函数 } void HAL_I2C_ListenCpltCallback(I2C_HandleTypeDef *hi2c) { HAL_I2C_EnableListen_IT(hi2c); // 重新启用监听模式 } void Error_Handler(void) { while (1) { } } ``` 代码中首先定义了I2C从机的地址为0x68。然后在`MX_I2C1_Init`函数中初始化了I2C1,并启用了从机模式和中断监听模式。在while循环中,我们使用HAL库提供的`HAL_I2C_Slave_Receive`函数从主机接收数据,并使用`HAL_I2C_Slave_Transmit`函数向主机发送数据。 当接收完成或发送完成时,将调用`HAL_I2C_SlaveRxCpltCallback`或`HAL_I2C_SlaveTxCpltCallback`函数。当监听完成时,将调用`HAL_I2C_ListenCpltCallback`函数,我们在该函数中重新启用监听模式以继续接收数据。 请注意,这仅是一个简单的示例代码,并且可能需要根据您的具体应用程序进行修改。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值