stm32专题⼗六:IIC(三)stm32IIC固件库函数分析因为I2C通讯⾮常重要,因此要详细的分析每⼀个库函数
IIC初始化结构体
/**
* @brief I2C Init structure definition
*/
typedef struct
{
// 指定时钟频率,这个值不能超过400kHz
uint32_t I2C_ClockSpeed; /*!< Specifies the clock frequency.
This parameter must be set to a value lower than 400kHz */
// IIC模式:可以有3种选择:I2C_Mode_I2C I2C_Mode_SMBusDevice I2C_Mode_SMBusHost
uint16_t I2C_Mode; /*!< Specifies the I2C mode.
This parameter can be a value of @ref I2C_mode */
// 占空⽐ I2C_DutyCycle_2 I2C_DutyCycle_16_9
uint16_t I2C_DutyCycle; /*!< Specifies the I2C fast mode duty cycle.
This parameter can be a value of @ref I2C_duty_cycle_in_fast_mode */
// ⾃⾝地址,这个可以任意给⼀个与其他IIC从机设备不同的地址,如0X0A
uint16_t I2C_OwnAddress1; /*!< Specifies the first device own address.
This parameter can be a 7-bit or 10-bit address. */
// 应答Ack使能 I2C_Ack_Enable I2C_Ack_Disable
uint16_t I2C_Ack; /*!< Enables or disables the acknowledgement.
This parameter can be a value of @ref I2C_acknowledgement */
/
/ IIC应答地址,⼀般7位 I2C_AcknowledgedAddress_7bit I2C_AcknowledgedAddress_10bit
uint16_t I2C_AcknowledgedAddress; /*!< Specifies if 7-bit or 10-bit address is acknowledged.
This parameter can be a value of @ref I2C_acknowledged_address */
}I2C_InitTypeDef;
IIC初始化函数,这⾥有⼀些值得注意的地⽅:
1 IIC模块时钟频率
2 分频系数
/**
* @brief Initializes the I2Cx peripheral according to the specified
* parameters in the I2C_InitStruct.
* @param I2Cx: where x can be 1 or 2 to select the I2C peripheral.
* @param I2C_InitStruct: pointer to a I2C_InitTypeDef structure that
* contains the configuration information for the specified I2C peripheral.
* @retval None
*/
void I2C_Init(I2C_TypeDef* I2Cx, I2C_InitTypeDef* I2C_InitStruct)
{
uint16_t tmpreg = 0, freqrange = 0;
uint16_t result = 0x04;
uint32_t pclk1 = 8000000; // 只是初始化时给的值,没有意义,给0也可以
RCC_ClocksTypeDef rcc_clocks;
/*---------------------------- I2Cx CR2 Configuration ------------------------*/
// 配置IIC模块输⼊时钟频率,标准模式⾄少为2MHz,快速模式⾄少为4MHz,最⼤为36MHz /* Get the I2Cx CR2 value */
// 先暂存CR2,只处理FREQ[5:0]位,其他位不变
tmpreg = I2Cx->CR2;
/* Clear frequency FREQ[5:0] bits */
// 清除FREQ[5:0]位
tmpreg &= CR2_FREQ_Reset;
/* Get pclk1 frequency value */
RCC_GetClocksFreq(&rcc_clocks);
// 获得APB1总线的时钟频率(36MHz)
pclk1 = rcc_clocks.PCLK1_Frequency;
/* Set frequency bits depending on pclk1 value */
// 计算FREQ[5:0]位写⼊值(36,已经是最⼤值)
freqrange = (uint16_t)(pclk1 / 1000000);
tmpreg |= freqrange;
/* Write to I2Cx CR2 */
// 写⼊到CR2寄存器
I2Cx->CR2 = tmpreg;
/*---------------------------- I2Cx CCR Configuration ------------------------*/
// 配置CCR寄存器(设置标准/快速模式、占空⽐、时钟控制分频系数等)
/* Disable the selected I2C peripheral to configure TRISE */
I2Cx->CR1 &= CR1_PE_Reset;
/* Reset tmpreg value */
/* Clear F/S, DUTY and CCR[11:0] bits */
tmpreg = 0;
/* Configure speed in standard mode */
// I2C_ClockSpeed <= 100k时,配置为标准模式
if (I2C_InitStruct->I2C_ClockSpeed <= 100000)
{
/* Standard mode speed calculate */
// APB1总线时钟/2/I2C_ClockSpeed = 分频系数
result = (uint16_t)(pclk1 / (I2C_InitStruct->I2C_ClockSpeed << 1));
// 允许设定的最⼩值为0x04,在快速DUTY模式下允许的最⼩值为0x01;
/* Test if CCR value is under 0x4*/
if (result < 0x04)
{
/* Set minimum allowed value */
result = 0x04;
}
/* Set speed value for standard mode */
tmpreg |= result;
/* Set Maximum Rise Time for standard mode */
I2Cx->TRISE = freqrange + 1;
}
/* Configure speed in fast mode */
// 快速模式下,分频系数的计算
else /*(I2C_InitStruct->I2C_ClockSpeed <= 400000)*/
{
if (I2C_InitStruct->I2C_DutyCycle == I2C_DutyCycle_2)
{
/* Fast mode speed calculate: Tlow/Thigh = 2 */
result = (uint16_t)(pclk1 / (I2C_InitStruct->I2C_ClockSpeed * 3));
}
else /*I2C_InitStruct->I2C_DutyCycle == I2C_DutyCycle_16_9*/
{
/* Fast mode speed calculate: Tlow/Thigh = 16/9 */
result = (uint16_t)(pclk1 / (I2C_InitStruct->I2C_ClockSpeed * 25));
/
* Set DUTY bit */
result |= I2C_DutyCycle_16_9;
}
/* Test if CCR value is under 0x1*/
if ((result & CCR_CCR_Set) == 0)
{
/* Set minimum allowed value */
result |= (uint16_t)0x0001;
}
/* Set speed value and set F/S bit for fast mode */
tmpreg |= (uint16_t)(result | CCR_FS_Set);
/
* Set Maximum Rise Time for fast mode */
I2Cx->TRISE = (uint16_t)(((freqrange * (uint16_t)300) / (uint16_t)1000) + (uint16_t)1); }
/* Write to I2Cx CCR */
// 写⼊到CCR寄存器,并使能IIC
I2Cx->CCR = tmpreg;
/* Enable the selected I2C peripheral */
I2Cx->CR1 |= CR1_PE_Set;
/*---------------------------- I2Cx CR1 Configuration ------------------------*/
// 配置IIC模式、应答
/* Get the I2Cx CR1 value */
tmpreg = I2Cx->CR1;
/
* Clear ACK, SMBTYPE and SMBUS bits */
tmpreg &= CR1_CLEAR_Mask;
/* Configure I2Cx: mode and acknowledgement */
/* Set SMBTYPE and SMBUS bits according to I2C_Mode value */
/* Set ACK bit according to I2C_Ack value */
tmpreg |= (uint16_t)((uint32_t)I2C_InitStruct->I2C_Mode | I2C_InitStruct->I2C_Ack);
/* Write to I2Cx CR1 */
I2Cx->CR1 = tmpreg;
/*---------------------------- I2Cx OAR1 Configuration -----------------------*/
// 配置IIC应答地址位数
/* Set I2Cx Own Address1 and acknowledged address */
I2Cx->OAR1 = (I2C_InitStruct->I2C_AcknowledgedAddress | I2C_InitStruct->I2C_OwnAddress1);
}
在上⼀节中提到,IIC发送/接收过程会产⽣相应的事件,我们通过检测事件来判断当前运⾏的状态,以下是检测函数ErrorStatus I2C_CheckEvent(I2C_TypeDef* I2Cx, uint32_t I2C_EVENT);
/**
* @brief Checks whether the last I2Cx Event is equal to the one passed
* as parameter.
* @param I2Cx: where x can be 1 or 2 to select the I2C peripheral.
* @param I2C_EVENT: specifies the event to be checked.
* This parameter can be one of the following values:
* @arg I2C_EVENT_SLAVE_TRANSMITTER_ADDRESS_MATCHED : EV1
* @arg I2C_EVENT_SLAVE_RECEIVER_ADDRESS_MATCHED : EV1
* @arg I2C_EVENT_SLAVE_TRANSMITTER_SECONDADDRESS_MATCHED : EV1
* @arg I2C_EVENT_SLAVE_RECEIVER_SECONDADDRESS_MATCHED : EV1
* @arg I2C_EVENT_SLAVE_GENERALCALLADDRESS_MATCHED : EV1
* @arg I2C_EVENT_SLAVE_BYTE_RECEIVED : EV2
* @arg (I2C_EVENT_SLAVE_BYTE_RECEIVED | I2C_FLAG_DUALF) : EV2
* @arg (I2C_EVENT_SLAVE_BYTE_RECEIVED | I2C_FLAG_GENCALL) : EV2
* @arg I2C_EVENT_SLAVE_BYTE_TRANSMITTED : EV3
* @arg (I2C_EVENT_SLAVE_BYTE_TRANSMITTED | I2C_FLAG_DUALF) : EV3
* @arg (I2C_EVENT_SLAVE_BYTE_TRANSMITTED | I2C_FLAG_GENCALL) : EV3
* @arg I2C_EVENT_SLAVE_ACK_FAILURE : EV3_2
* @arg I2C_EVENT_SLAVE_STOP_DETECTED : EV4
* @arg I2C_EVENT_MASTER_MODE_SELECT : EV5
* @arg I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED : EV6
* @arg I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED : EV6
* @arg I2C_EVENT_MASTER_BYTE_RECEIVED : EV7
* @arg I2C_EVENT_MASTER_BYTE_TRANSMITTING : EV8
* @arg I2C_EVENT_MASTER_BYTE_TRANSMITTED : EV8_2
* @arg I2C_EVENT_MASTER_MODE_ADDRESS10 : EV9
*
* @note: For detailed description of Events, please refer to section
* I2C_Events in stm32f10x_i2c.h file.
*
* @retval An ErrorStatus enumeration value:
* - SUCCESS: Last event is equal to the I2C_EVENT
* - ERROR: Last event is different from the I2C_EVENT
*/
ErrorStatus I2C_CheckEvent(I2C_TypeDef* I2Cx, uint32_t I2C_EVENT)
{
uint32_t lastevent = 0;
uint32_t flag1 = 0, flag2 = 0;
ErrorStatus status = ERROR;
/* Check the parameters */
assert_param(IS_I2C_ALL_PERIPH(I2Cx));
assert_param(IS_I2C_EVENT(I2C_EVENT));
/* Read the I2Cx status register */
// 分别读取SR1 SR2两个状态寄存器(16位),然后把状态合并到32位数据中
flag1 = I2Cx->SR1;
flag2 = I2Cx->SR2;
flag2 = flag2 << 16;
/* Get the last event value from I2C status register */
lastevent = (flag1 | flag2) & FLAG_Mask;
/* Check whether the last event contains the I2C_EVENT */
if ((lastevent & I2C_EVENT) == I2C_EVENT)
{
/
/ 判断事件是否正确发⽣
/* SUCCESS: last event is equal to I2C_EVENT */
status = SUCCESS;
}
else
{
/* ERROR: last event is different from I2C_EVENT */
status = ERROR;
}
/* Return status */
return status;
}
检测标志位的函数,其实也是读取SR1 SR2的相应位
FlagStatus I2C_GetFlagStatus(I2C_TypeDef* I2Cx, uint32_t I2C_FLAG);
/**
* @brief Checks whether the specified I2C flag is set or not.
* @param I2Cx: where x can be 1 or 2 to select the I2C peripheral.
* @param I2C_FLAG: specifies the flag to check.
* This parameter can be one of the following values:
* @arg I2C_FLAG_DUALF: Dual flag (Slave mode)
* @arg I2C_FLAG_SMBHOST: SMBus host header (Slave mode)
* @arg I2C_FLAG_SMBDEFAULT: SMBus default header (Slave mode) * @arg I2C_FLAG_GE
NCALL: General call header flag (Slave mode) * @arg I2C_FLAG_TRA: Transmitter/Receiver flag
* @arg I2C_FLAG_BUSY: Bus busy flag
* @arg I2C_FLAG_MSL: Master/Slave flag
* @arg I2C_FLAG_SMBALERT: SMBus Alert flag
* @arg I2C_FLAG_TIMEOUT: Timeout or Tlow error flag
* @arg I2C_FLAG_PECERR: PEC error in reception flag
* @arg I2C_FLAG_OVR: Overrun/Underrun flag (Slave mode)
* @arg I2C_FLAG_AF: Acknowledge failure flag
* @arg I2C_FLAG_ARLO: Arbitration lost flag (Master mode)
configuredclockspeed是什么意思* @arg I2C_FLAG_BERR: Bus error flag
* @arg I2C_FLAG_TXE: Data register empty flag (Transmitter)
* @arg I2C_FLAG_RXNE: Data register not empty (Receiver) flag
* @arg I2C_FLAG_STOPF: Stop detection flag (Slave mode)
* @arg I2C_FLAG_ADD10: 10-bit header sent flag (Master mode)
* @arg I2C_FLAG_BTF: Byte transfer finished flag
* @arg I2C_FLAG_ADDR: Address sent flag (Master mode) "ADSL"
* Address matched flag (Slave mode)"ENDA"
* @arg I2C_FLAG_SB: Start bit flag (Master mode)
* @retval The new state of I2C_FLAG (SET or RESET).
*/
FlagStatus I2C_GetFlagStatus(I2C_TypeDef* I2Cx, uint32_t I2C_FLAG)
{
FlagStatus bitstatus = RESET;
__IO uint32_t i2creg = 0, i2cxbase = 0;
/* Check the parameters */
assert_param(IS_I2C_ALL_PERIPH(I2Cx));
assert_param(IS_I2C_GET_FLAG(I2C_FLAG));
/* Get the I2Cx peripheral base address */
i2cxbase = (uint32_t)I2Cx;
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论