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

posted @ 2023-12-25 17:18  WCH_CH32  阅读(413)  评论(0编辑  收藏  举报