前言
STM32F7和STM32F1的IIC通讯调试,因为F7的环境是FREERTOS,故而选择硬件IIC的方式更不受系统影响。
初始化程序
F767(RTOS)从机
// An highlighted block
I2C_HandleTypeDef I2C_Handle; /* IIC句柄 */
/* 函数声明 */
/**
* @brief iic 初始化
* @param None
* @retval None
*/
void IIC_Init(void)
{
I2C_Handle.Instance = I2C1;
I2C_Handle.Init.Timing = 0x00000000; //1KHZ
I2C_Handle.Init.OwnAddress1 = I2C_ADDRESS; /* 此处设定从机地址1 */
I2C_Handle.Init.OwnAddress2 = 0xFE; /* 此处设定从机地址2 */
I2C_Handle.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT; /* 地址模式 */
I2C_Handle.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;/* 关闭双地址模式 */
I2C_Handle.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;/* */
I2C_Handle.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;/* 禁止延长 */
I2C_Handle.Init.OwnAddress2Masks = I2C_OA2_NOMASK;/* 无掩码 */
HAL_I2C_Init(&I2C_Handle);
if(HAL_I2C_EnableListen_IT(&I2C_Handle) != HAL_OK)/* Transfer error in reception process */
printf("初始化失败\r\n");
else
printf("IIC初始化成功\r\n");
}
HAL_I2C_EnableListen_IT()是使能监听中断,作为从机必须要开启该中断才能有效匹配地址。
/**
* Initializes the Global MSP.
*/
void HAL_I2C_MspInit(I2C_HandleTypeDef* hi2c)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_PeriphCLKInitTypeDef RCC_PeriphClkInit;
/*使能I2C时钟*/
__I2C1_CLK_ENABLE();
if(hi2c->Instance==I2C1)
{
/*使能I2C的IO口时钟*/
SCL_CLK_ENABLE();
SDA_CLK_ENABLE();
/*配置I2C的SCL口*/
GPIO_InitStructure.Pin = SCL_PIN;
GPIO_InitStructure.Mode = GPIO_MODE_AF_OD;
GPIO_InitStructure.Speed = GPIO_SPEED_HIGH;
GPIO_InitStructure.Pull = GPIO_NOPULL;
GPIO_InitStructure.Alternate = SCL_AF;
HAL_GPIO_Init(SCL_PORT, &GPIO_InitStructure);
/*配置I2C的SDA口*/
GPIO_InitStructure.Pin = SDA_PIN;
GPIO_InitStructure.Alternate = SDA_AF;
HAL_GPIO_Init(SDA_PORT, &GPIO_InitStructure);
/* Force the I2C peripheral clock reset */
__I2C1_FORCE_RESET();
/* Release the I2C peripheral clock reset */
__I2C1_RELEASE_RESET();
/* I2C1 interrupt Init */
HAL_NVIC_SetPriority(I2C1_EV_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(I2C1_EV_IRQn);
}
}
到这里从机初始化配置已经完成,下面是主机的初始化配置。
F103(裸机)主机
I2C_HandleTypeDef I2C_Handle;
HAL_StatusTypeDef I2C_MasterInit(void)
{
I2C_Handle.Instance = I2C1;
I2C_Handle.Init.ClockSpeed = 1000; //hz
I2C_Handle.Init.DutyCycle = I2C_DUTYCYCLE_2;
I2C_Handle.Init.OwnAddress1 = 0xF0;/* 主机地址 */
I2C_Handle.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
I2C_Handle.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
I2C_Handle.Init.OwnAddress2 = 0;
I2C_Handle.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
I2C_Handle.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
if (HAL_I2C_Init(&I2C_Handle) == HAL_OK)
return HAL_OK;
else
return HAL_ERROR;
}
void HAL_I2C_MspInit(I2C_HandleTypeDef* hi2c)
{
GPIO_InitTypeDef GPIO_InitStruct;
/* Peripheral clock enable */
__HAL_RCC_I2C1_CLK_ENABLE();
if(hi2c->Instance==I2C1)
{
__HAL_RCC_GPIOB_CLK_ENABLE();
/**I2C1 GPIO Configuration
PB6 ------> I2C1_SCL
PB7 ------> I2C1_SDA
*/
GPIO_InitStruct.Pin = GPIO_PIN_6|GPIO_PIN_7;
GPIO_InitStruct.Mode = GPIO_MODE_AF_OD;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
/* I2C1 interrupt Init */
HAL_NVIC_SetPriority(I2C1_EV_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(I2C1_EV_IRQn);
HAL_NVIC_SetPriority(I2C1_ER_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(I2C1_ER_IRQn);
/* USER CODE BEGIN I2C1_MspInit 1 */
/* Force the I2C peripheral clock reset */
__HAL_RCC_I2C1_FORCE_RESET();
/* Release the I2C peripheral clock reset */
__HAL_RCC_I2C1_RELEASE_RESET();
}
}
中断及传输函数
首先来讲一下IIC通讯的过程,
- 1、主机发送地址到总线上
- 2、从机触发地址匹配中断,成功后根据数据类型进行对应的操作
- 3、主机完成传输并产生stop
第1步,在主机使用传输函数,此处我们使用的是HAL_I2C_Master_Transmit 或者 HAL_I2C_Master_Receive,先以发送“写”为例。
第2步,从机会自动匹配地址,并产生中断,但后续需要我们在中断中处理:
uint8_t DebugReceData ;
/**
* @brief Slave Address Match callback.
* @param hi2c Pointer to a I2C_HandleTypeDef structure that contains
* the configuration information for the specified I2C.
* @param TransferDirection: Master request Transfer Direction (Write/Read), value of @ref I2C_XferOptions_definition
* @param AddrMatchCode: Address Match Code
* @retval None
*/
void HAL_I2C_AddrCallback(I2C_HandleTypeDef *hi2c, uint8_t TransferDirection, uint16_t AddrMatchCode)
{
if(AddrMatchCode == I2C_ADDRESS)
{
/* First of all, check the transfer direction to call the correct Slave Interface */
if(TransferDirection == I2C_DIRECTION_TRANSMIT) //写
{
HAL_I2C_Slave_Sequential_Receive_IT(&I2C_Handle, &DebugReceData, 1, I2C_FIRST_AND_LAST_FRAME);//重新开始中断,并接收随后的数据
}
else //读
{
HAL_I2C_Slave_Sequential_Transmit_IT(&I2C_Handle, &DebugReceData, 1, I2C_FIRST_AND_LAST_FRAME);//重新开始中断,并发送数据
}
}
else
{
/* Call Error Handler, Wrong Address Match Code */
Error_Handler();
}
}
地址匹配完成后,如果是写命令则会接收后续数据,可以在接收中断函数中处理。
HAL_I2C_SlaveRxCpltCallback();
HAL_I2C_MasterRxCpltCallback();
另外从机还需要增加监听中断的处理,需要重新开启监听功能。
/**
* @brief Listen Complete callback.
* @param hi2c Pointer to a I2C_HandleTypeDef structure that contains
* the configuration information for the specified I2C.
* @retval None
*/
void HAL_I2C_ListenCpltCallback(I2C_HandleTypeDef *hi2c)
{
/* 如果要进行丛机接收工作,丛机必须要重新开启监听中断 */
if(hi2c == &I2C_Handle)
{
HAL_I2C_EnableListen_IT(&I2C_Handle);
}
/* Communication is completed */
}
后续待更新…