1、IC内部硬件原理
I2C由一个独立的时钟源计时,它允许I2C从PCLK频率独立地操作。
主从机模式只需要配置I2C_SDA和I2C_SCL和打开I2C APB clock(i2c_pclk)时钟;
2、初始化
3、通讯波形
Acknowledge(ACK)能软件启用或禁用。I2C接口的地址可以通过软件选择。
例如:I2C_InitStruct.OwnAddress1 = 0xA8;//接收地址
I2C_InitStruct.TypeAcknowledge = LL_I2C_ACK;//ACK在当前收到的字节之后发送
IIC初始化部分:
void MX_I2C2_Init(void)
{
LL_I2C_InitTypeDef I2C_InitStruct = {0};
LL_GPIO_InitTypeDef GPIO_InitStruct = {0};
LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOB);
/**I2C2 GPIO Configuration
PB10 ------> I2C2_SCL
PB11 ------> I2C2_SDA
*/
GPIO_InitStruct.Pin = LL_GPIO_PIN_10|LL_GPIO_PIN_11;
GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE;
GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_OPENDRAIN;
GPIO_InitStruct.Pull = LL_GPIO_PULL_UP;
GPIO_InitStruct.Alternate = LL_GPIO_AF_4;
LL_GPIO_Init(GPIOB, &GPIO_InitStruct);
/* Peripheral clock enable */
LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_I2C2);
/* I2C2 interrupt Init */
NVIC_SetPriority(I2C2_EV_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(),0, 0));
NVIC_EnableIRQ(I2C2_EV_IRQn);
NVIC_SetPriority(I2C2_ER_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(),0, 0));
NVIC_EnableIRQ(I2C2_ER_IRQn);
/** I2C Initialization
*/
LL_I2C_EnableAutoEndMode(I2C2);
LL_I2C_DisableOwnAddress2(I2C2);
LL_I2C_DisableGeneralCall(I2C2);
LL_I2C_EnableClockStretching(I2C2);
I2C_InitStruct.PeripheralMode = LL_I2C_MODE_I2C;//I2C主或者从机模式
I2C_InitStruct.Timing = 0x00731012;
I2C_InitStruct.AnalogFilter = LL_I2C_ANALOGFILTER_ENABLE; //模拟滤波器开启
I2C_InitStruct.DigitalFilter = 0;//数字滤波器
I2C_InitStruct.OwnAddress1 = 0xA8;//接收地址
I2C_InitStruct.TypeAcknowledge = LL_I2C_ACK;//ACK在当前收到的字节之后发送
I2C_InitStruct.OwnAddrSize = LL_I2C_OWNADDRESS1_7BIT;//7位地址
LL_I2C_Init(I2C2, &I2C_InitStruct);
LL_I2C_Enable(I2C2);//Enable I2C peripheral .
uint32_t temp = I2C_IT_STOPI |
I2C_IT_ADDRI |
I2C_IT_RXI |
I2C_IT_TXI;
I2C2->CR1 |= temp; //初始化IIC中断
}
IIC中断接收部分:
从机在接收和发送之前都要比配地址;
1、从机接收流程图
2、从机发送的流程图
/*IIC中断接收*/
void I2C2_EV_IRQHandler(void)
{
static uint8_t Instruct = 0;
static uint8_t Offset = 0;//接收的数据个数
static uint8_t TxBuff_num = 0;//发送的数据个数
static uint8_t MaxBytes = 0;
static uint8_t Addr_Bit=0;//因为接收和发送前都会I2C_ISR_ADDR,确保比配地址后接收和发送完成I2C_ISR_STOPF;
static uint8_t *TxBuff;
static uint8_t RxBuff[40] = { 0 };
uint8_t temp;
uint32_t status;
status = I2C2->ISR;//接收硬件自动发送过来的寄存器数据
// DBG_printf("I2C2->ISR: %08X \n\r", status);
if((status & I2C_ISR_ADDR)&&(!Addr_Bit))//判断是addr触发的中断 //0x00000008
{
I2C2->ISR|=I2C_ISR_TXE;//TXE=1
I2C2->ICR|=I2C_ISR_ADDR;//0x08;//清除addr
if(status & I2C_ISR_DIR) //0x00010000 //Transfer direction (slave mode)
{ // I2C2: slave enters transmitter mode.
if(Flag_Wakeup == 0xAA) Flag_Wakeup = 0;
}
else
{ // I2C1: slave enters receiver mode.
Instruct = 1;
}
Offset = 0;
TxBuff_num=0;
// DEBUG_I2C("I2C_ISR_ADDR =%d,%d,%08X \n\r", Instruct,Offset,status);
}
else if(status & I2C_ISR_RXNE)//从机接收内容
{
Addr_Bit=1;
I2C1->ISR |= I2C_ISR_TXE;
temp = LL_I2C_ReceiveData8(I2C2);
if(Instruct)
{ // Host Instruct
switch(temp)
{
case 0x00: // Get DevInfo
TxBuff = (uint8_t *)&tpDevInfo; // 24 bytes
MaxBytes = sizeof(tpDevInfo);
break;
case 0x18: // Get DevStatus//主机询问从机是否就绪
Addr_Bit=0; //
TxBuff = (uint8_t *)&tpDevStatus; // 8 bytes
MaxBytes = sizeof(tpDevStatus);
EventRelieved();
break;
default: break;
}
Instruct = 0;
}
if(Offset <= sizeof(MotorCtrlTab))
{
RxBuff[Offset] = temp;//保存接收的内容
// DEBUG_I2C("I2C_ISR_RXNE =%x,%d,%08X \n\r", RxBuff[Offset],Offset,status);
Offset++;
}
}
else if(status & I2C_ISR_TXIS)//0x00000002//从机发送命令
{
I2C2->ISR |= I2C_ISR_TXE;//清除I2C_ISR_TXE标志
if(Offset < MaxBytes)
{ //发送需要的数据给主机
LL_I2C_TransmitData8(I2C2, TxBuff[TxBuff_num++]);
}
else
{
// DEBUG_I2C("I2C_ISR_TXIS =ff,%d,%08X \n\r", TxBuff_num,status);
LL_I2C_TransmitData8(I2C2, 0xff);
}
}
else if(status & I2C_ISR_STOPF)//停止检测标志
{
Addr_Bit=0;
I2C2->ICR|=I2C_ISR_STOPF;//清除I2C_ISR_STOPF标志
DEBUG_I2C("STOPF =%x,%x,%d \n", RxBuff[0],RxBuff[1],Offset);
if((status & 0x10000) == 0)
{ // Instruction parsing from the Host
if(Offset == 2)//Offset接收的数据个数
{
switch(RxBuff[0])//取出接收的内容进行判断
{
case 0x31: // Set Heat pulse width
break;
case 0x32: // Set Motor speed
break;
case 0x33: // Set Motor direction
break;
default: return;
}
}
else if(Offset == 3)
{
}
else if(Offset == (1 + sizeof(tpDevControl)))
{
}
else if(Offset == (1 + sizeof(MotorCtrlTab)))
{
}
}
}
else
{
I2C2->ICR = 0x00003F38;//I2C_ClearITPendingBit(I2C2, 0x00003F38);
DBG_printf("I2C2 Unknown event occurs!\n\r");
}
/* USER CODE END I2C2_EV_IRQn 1 */
}