IIC--主从机的中断收发
一,简介:
I2C(IIC)属于两线式串行总线,由飞利浦公司开发用于微控制器(单片机)和外围设备 (从设备)进行通信的一种总线,属于一主多从(一个主设备 (主设备),
多个从设备 (从设备))的总线结构,总线上的每个设备都有一个特定的设备地址,以区分同一12C总线上的其他设备。
物理I2C接口有两根双向线,串行时钟线 (SCL)和串行数据线 (SDA)组成,可用于发送和接收数据,但是通信都是由主设备发起,从设备被动响应,实现数据的传输。
本节主要介绍IIC的主发,主收,从发,从收。由于基本收发例程均存在,所以本节全部采用中断的方式实现!
二,I2C主设备与从设备的一般通信过程:
主设备给从设备发送/写入数据
1.主设备发送起始(START) 信号
2.主设备发送设备地址到从设备
3.等待从设备响应(ACK)
4.主设备发送数据到从设备,一般发送的每个字节数据后会跟着等待接收来自从设备的响应(ACK)
5.数据发送完毕,主设备发送停止(STOP)信号终止传输
主设备从从设备接收/读取数据
1.设备发送起始 (START) 信号
2.主设备发送设备地址到从设备
3.等待从设备响应(ACK)
4.主设备接收来自从设备的数据,一般接收的每个字节数据后会跟着向从设备发送一个响应(ACK)
5.一般接收到最后一个数据后会发送一个无效响应(NACK),然后主设备发送停止(STOP)信号终止传输
三,代码实现
1,主发从收
( IIC初始化基础配置参考我们IIC例程即可 )
1.1主中断发:
中断前主机需要先产生起始位:
I2C_GenerateSTART(I2C1, ENABLE);
中断配置:
void iic_int() { NVIC_InitTypeDef NVIC_InitStructure; /* 中断分组初始化 */ NVIC_InitStructure.NVIC_IRQChannel = I2C1_EV_IRQn; //中断 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2; //抢占优先级 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; //子优先级 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init( &NVIC_InitStructure ); I2C_ITConfig( I2C1, I2C_IT_BUF, ENABLE ); //使能中断 I2C_ITConfig( I2C1, I2C_IT_EVT, ENABLE ); //使能中断 }
中断服务函数:
void I2C1_EV_IRQHandler(void) __attribute__((interrupt("WCH-Interrupt-fast")));
void I2C1_EV_IRQHandler(void ) { if( I2C_GetITStatus( I2C1, I2C_IT_SB ) != RESET )//起始位发送标志位 { I2C_Send7bitAddress( I2C1, 0x02, I2C_Direction_Transmitter ); ((void)(I2C1->STAR1)); ((void)(I2C1->STAR2)); } if( I2C_GetITStatus( I2C1, I2C_IT_ADDR ) != RESET )//地址匹配 { ((void)(I2C1->STAR1)); ((void)(I2C1->STAR2)); } if( I2C_GetITStatus( I2C1, I2C_IT_TXE ) != RESET ) { if(master_send_len<6){ I2C_SendData( I2C1, TxData[master_send_len] ); master_send_len++; } else{ I2C_GenerateSTOP(I2C1, ENABLE);//再次进入TX中断后产生停止位,结束通信 } ((void)(I2C1->STAR1)); ((void)(I2C1->STAR2)); } }
1.2从中断收:
中断配置:和上面主机相同。
中断服务函数:
void I2C1_EV_IRQHandler(void) __attribute__((interrupt("WCH-Interrupt-fast"))); void I2C1_EV_IRQHandler(void ) { if( I2C_GetITStatus( I2C1, I2C_IT_ADDR ) != RESET ) { printf( "ADDR\r\n" ); ((void)(I2C1->STAR1)); ((void)(I2C1->STAR2)); } else if( I2C_GetITStatus( I2C1, I2C_IT_RXNE ) != RESET ) { RxData[slave_recv_len] = I2C1->DATAR; slave_recv_len++; if (slave_recv_len==6) { slave_recv_len=0; } ((void)(I2C1->STAR1)); ((void)(I2C1->STAR2)); } else if( I2C_GetITStatus( I2C1, I2C_IT_STOPF ) != RESET ) { slave_state = 0xff; I2C1->CTLR1 &= I2C1->CTLR1; ((void)(I2C1->STAR1)); //读SR1寄存器 } }
2,主收从发
2.1主中断收:
中断配置:和上面相同
中断服务函数:
void I2C1_EV_IRQHandler(void) __attribute__((interrupt("WCH-Interrupt-fast"))); void I2C1_EV_IRQHandler(void ) { if( I2C_GetITStatus( I2C1, I2C_IT_SB ) != RESET )//起始位发送标志位 { I2C_Send7bitAddress( I2C1, 0x02, I2C_Direction_Receiver );//置主机为接收状态 ((void)(I2C1->STAR1)); ((void)(I2C1->STAR2)); } if( I2C_GetITStatus( I2C1, I2C_IT_ADDR ) != RESET )//地址匹配 { ((void)(I2C1->STAR1)); ((void)(I2C1->STAR2)); } if( I2C_GetITStatus( I2C1, I2C_IT_BTF ) != RESET ) { I2C_ReadRegister( I2C1, I2C_Register_STAR1); ((void)I2C1->DATAR); } if( I2C_GetITStatus( I2C1, I2C_IT_RXNE ) != RESET ) { if(master_recv_len<6){ mastr_RxData[master_recv_len] = I2C1->DATAR; master_recv_len++; } if (master_recv_len==5) {//发六个数据要在第五位时就要发停止位,也就是需要提前停止 I2C_GenerateSTOP( I2C1, ENABLE ); //产生停止条件 I2C_NACKPositionConfig(I2C1, I2C_NACKPosition_Next); } if(master_recv_len==6){ master_sate=0xff; } ((void)(I2C1->STAR1)); ((void)(I2C1->STAR2)); } }
2.2从中断发:
中断使能:和上面相同
中断服务函数:
void I2C1_EV_IRQHandler(void) __attribute__((interrupt("WCH-Interrupt-fast")));
void I2C1_EV_IRQHandler(void ) { if( I2C_GetITStatus( I2C1, I2C_IT_ADDR ) != RESET ) { ((void)(I2C1->STAR1)); ((void)(I2C1->STAR2)); } else if( I2C_GetITStatus( I2C1, I2C_IT_BTF ) != RESET ) { I2C_ReadRegister( I2C1, I2C_Register_STAR1); ((void)I2C1->DATAR); } else if( I2C_GetITStatus( I2C1, I2C_IT_TXE ) != RESET ) { I2C_SendData( I2C1, TxData[slave_send_len] ); slave_send_len++; if (slave_send_len==7) {//会进七次中断,虽然收六个数据,但也是要再第七次再清零 slave_send_len=0; } ((void)(I2C1->STAR1)); ((void)(I2C1->STAR2)); } else if( I2C_GetITStatus( I2C1, I2C_IT_STOPF ) != RESET ) { I2C1->CTLR1 &= I2C1->CTLR1; ((void)(I2C1->STAR1)); //读SR1寄存器 } }
如果移植测试不成功,可留言留下你的邮箱,将源码发你这边!