IIC-从机中断接收
使用 IIC 外设作为从机通过中断的方式进行接收时,应在 IIC 初始化完成后配置中断优先级并使能对应的中断。
这里将中断优先级的抢占位配置为 1,子优先配置为 0,使能了事件中断与缓冲器中断。
1 NVIC_InitTypeDef NVIC_InitStructure = {0}; 2 3 NVIC_InitStructure.NVIC_IRQChannel = I2C1_EV_IRQn; 4 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; 5 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; 6 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; 7 NVIC_Init( &NVIC_InitStructure ); 8 9 I2C_ITConfig( I2C1, I2C_IT_BUF, ENABLE ); 10 I2C_ITConfig( I2C1, I2C_IT_EVT, ENABLE );
在 CH32V 系列芯片的应用手册中,详细的描述了 IIC 外设作为从机时,如何使用中断完成数据的接收。在通过代码实现该功能的过程中,可以参考手册中从接收器的传送序列图,按图中的提示完成软件的编写。
1.从机接收到 7 位地址后,会产生事件 1,图中提示,通过先读 SR1(STAR1)寄存器再读 SR2(STAR2)消除该事件。
1 if (I2C_GetITStatus( I2C1, I2C_IT_ADDR ) != RESET) { 2 ((void)(I2C1->STAR1)); 3 ((void)(I2C1->STAR2)); 4 }
2.在一字节数据接收完成后,会产生事件 2,图中提示,通过读 DR(DATAR) 寄存器可消除该事件。DR 寄存器为 IIC 数据寄存器,读取该寄存器即为获取总线上接收到的数据。代码中 RxData 为数据接收的 Buffer,接收全部的数据后,清除计数,覆盖原有数据。
1 if (I2C_GetITStatus( I2C1, I2C_IT_RXNE ) != RESET) { 2 RxData[slave_recv_len] = I2C1->DATAR; 3 slave_recv_len++; 4 if (slave_recv_len == 6) { 5 slave_recv_len = 0; 6 } 7 }
3.从机接收到主机发送的停止信号后,会产生事件 4,图中提示,通过先读 SR1(STAR1)寄存器再写 CR1(CTLR1)寄存器消除该事件。slave_state 为接收完成标志位,当 IIC 完整接收了全部的字节后,标志位置位。
1 if (I2C_GetITStatus( I2C1, I2C_IT_STOPF ) != RESET) { 2 slave_state = 0xff; 3 ((void)(I2C1->STAR1)); 4 I2C1->CTLR1 &= I2C1->CTLR1; 5 }
完整的中断函数如下,要注意,使用 RISC-V 系列单片机时,务必对中断进行声明!
1 void I2C1_EV_IRQHandler(void) __attribute__((interrupt("WCH-Interrupt-fast"))); 2 void I2C1_EV_IRQHandler(void ) 3 { 4 if (I2C_GetITStatus( I2C1, I2C_IT_ADDR ) != RESET) { 5 ((void)(I2C1->STAR1)); 6 ((void)(I2C1->STAR2)); 7 } 8 if (I2C_GetITStatus( I2C1, I2C_IT_RXNE ) != RESET) { 9 RxData[slave_recv_len] = I2C1->DATAR; 10 slave_recv_len++; 11 if (slave_recv_len == 6) { 12 slave_recv_len = 0; 13 } 14 } 15 if (I2C_GetITStatus( I2C1, I2C_IT_STOPF ) != RESET) { 16 slave_state = 0xff; 17 ((void)(I2C1->STAR1)); 18 I2C1->CTLR1 &= I2C1->CTLR1; 19 } 20 }
在主函数中,通过查询 slave_state 标志位,当接收完成后进行串口的打印操作。
1 while(1){ 2 if(slave_state == 0xff) 3 { 4 slave_state = 0; 5 slave_recv_len = 0; 6 printf( "RxData:\r\n" ); 7 for( i = 0; i < 6; i++ ) 8 { 9 printf("%02x ", RxData[i]); 10 } 11 printf("\r\n"); 12 } 13 }
2023-12-25