想说的话:这一篇博客是自己作为笔记用的,仍然有一些问题没有解决,是按照我自己的需求写的。因为CubeMX自带的库函数烂的一批,然后我就自己根据手册写了,所以有很多是寄存器操作,不过应该还是有一定的参考意义。
尚存bug:1:没有加入超时机制
2:发送完成时,stopf位不能被置位,导致无法退出发送状态(尝试控制发送字节解决,嘻嘻我的协议是固定字节的)
我们中断里面写的处理函数,基本就是按照这里的流程来的。
这也是比较重要的一张表,中断之后,必须清空标志位后才能进行通讯。
原来数据手册内还有发送接收的时序图,但其实就是流程图的时序描写,本质上是同一个事物,这里就不粘了 ,有兴趣的朋友可以去参考下。
根据数据手册,我做出如下设计:每当收到主机发来的地址时,就触发中断,然后在中断里面判断读写,接着进入读写流程(参照上面流程图)
从机硬件初始化:
/* I2C3 init function */
static void MX_I2C3_Init(void)
{
hi2c3.Instance = I2C3;
hi2c3.Init.Timing = 0x10909CEC;
hi2c3.Init.OwnAddress1 = 0x60;//从机地址,注意和主机对应
hi2c3.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
hi2c3.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
hi2c3.Init.OwnAddress2 = 0;
hi2c3.Init.OwnAddress2Masks = I2C_OA2_NOMASK;
hi2c3.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
hi2c3.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
if (HAL_I2C_Init(&hi2c3) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
/**Configure Analogue filter
*/
if (HAL_I2CEx_ConfigAnalogFilter(&hi2c3, I2C_ANALOGFILTER_ENABLE) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
/**Configure Digital filter
*/
if (HAL_I2CEx_ConfigDigitalFilter(&hi2c3, 0) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
//I2C_Enable_IRQ(hi2c3,I2C_XFER_RX_IT|I2C_XFER_TX_IT);
// if (HAL_I2C_EnableListen_IT(&hi2c3) != HAL_OK)
// {
// _Error_Handler(__FILE__, __LINE__);
// }
I2C3->CR1|=0x08;//使能addr中断
//I2C3->CR1|=0x20000;
}
/* USER CODE BEGIN I2C3_MspInit 0 */
/* USER CODE END I2C3_MspInit 0 */
__HAL_RCC_I2C3_CLK_ENABLE();
/**I2C3 GPIO Configuration
PA7 ------> I2C3_SCL
PB4 (NJTRST) ------> I2C3_SDA
*/
GPIO_InitStruct.Pin = GPIO_PIN_7;
GPIO_InitStruct.Mode = GPIO_MODE_AF_OD;
GPIO_InitStruct.Pull = GPIO_PULLUP;//特别注意这里的上拉电阻,可以测试下,主机和从机应该都要能置0,1,一般主机提供会比较好
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF4_I2C3;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
GPIO_InitStruct.Pin = GPIO_PIN_4;
GPIO_InitStruct.Mode = GPIO_MODE_AF_OD;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF4_I2C3;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
/* Peripheral clock enable */
/* I2C3 interrupt Init */
HAL_NVIC_SetPriority(I2C3_EV_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(I2C3_EV_IRQn);
HAL_NVIC_SetPriority(I2C3_ER_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(I2C3_ER_IRQn);
/* USER CODE BEGIN I2C3_MspInit 1 */
void I2C3_EV_IRQHandler(void)
{
/* USER CODE BEGIN I2C3_EV_IRQn 0 */
/* USER CODE END I2C3_EV_IRQn 0 */
loop1:
HAL_I2C_EV_IRQHandler(&hi2c3);
/* USER CODE BEGIN I2C3_EV_IRQn 1 */
if((((I2C3->ISR)&0x08)>>3)==1)//判断是addr触发的中断
{
I2C3->ISR|=0x01;//TXE=1
I2C3->ICR|=0x08;//清除addr
}
//读写处理
{
if((((I2C3->ISR)&0x10000)>>16)==1)//dir
{
int i=0;
int j=0;
while(((((I2C3->ISR)&0x32)>>5)==0))//detect stop
{
if(((((I2C3->ISR)&0x10000)>>16)==0)||((((I2C3->ISR)&0x08)>>3)==1))//addr or read
goto loop1;
if(((((I2C3->ISR)&0x02)>>1)==1))TXIS
{
if(I2C3->RXDR==0x00)
I2C3->TXDR=ppp1[i];
if(I2C3->RXDR==0x12)
{
I2C3->TXDR=ppp2[i];
}
//[i]=I2C3->RXDR;
i++;
}
if(i==21)
{
//21个字节 退出
ppp2[0]++;
return;
}
}
//x=HAL_I2C_Slave_Receive(&hi2c3,ppp,2,5);
I2C3->ICR=(I2C3->ICR)|0x32;//clear stop
else//read
{
int i=0;
while(((((I2C3->ISR)&0x32)>>5)==0))//detect stop
{
if(((((I2C3->ISR)&0x10000)>>16)==1)||((((I2C3->ISR)&0x08)>>3)==1))
goto loop1;
if(((((I2C3->ISR)&0x04)>>2)==1))//RXNE
{
ppp[i]=I2C3->RXDR;
i++;
}
}
//x=HAL_I2C_Slave_Receive(&hi2c3,ppp,2,5);
I2C3->ICR=(I2C3->ICR)|0x32;
}
}
// I2C3->CR1|=0x08;
// /* USER CODE END I2C3_EV_IRQn 1 */
}
ISR:
|bit23…17|ADDCODE ----|主机地址----------|
|bit16…|DIR------------------|0读/1写------------|在addr=1时更新
|bit15…|BUSY---------------| ---------------------|起始信号=1,检测到stop=0
|bit5…|STOPF---------------|----------------------|检测到stop
|bit3…|ADDR----------------|----------------------|匹配到地址
|bit2…|RXNE----------------|----------------------|RXDR不为空
|bit1…|TXIS------------------|-------------------- -|发送标志
|bit0…|TXE------------------|-----------------------|TXDR为空