历史上的今天
今天是:2024年10月22日(星期二)
2021年10月22日 | stm32专题十六:IIC(三)stm32 IIC 固件库函数分析
2021-10-22 来源:eefocus
因为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
史海拾趣
|
微波射频方向研究生毕业所必要具备的基本知识、技能有: 就说软件吧,根据课程学习的不同,可能会用到Matlab、ADS、CST、HFSS、MWO等等,每种软件针对的方向都有不同,但每种软件的使用都是仿真,楼主在学习过程中还要加强动手能力的培养,从最基 ...… 查看全部问答> |
|
我以前用CH375芯片做过一个进行USB读写的设备,但是有问题,没有实现,主要是因为对USB的写命令不熟悉,哪位高手可以赐教不胜感激,另外,听说ch375芯片因为是国产而并不可靠,是真的吗?… 查看全部问答> |
|
导师现在有项目:关于ARM+LINUX和关于FPGA的。不知道哪一个就业前景好? 因为做ARM+LINUX可以好好学学LINUX以及软件编程,如果学好了可以进百度、IBM之类的大型企业……做一个嵌入式程序员 而做FPGA不知道有什么好单位,除中兴、华为…… 希望这 ...… 查看全部问答> |
|
一.如何申请安规?找代理— 备资料和样品— 初测— 送测— 检测— 发证书— 厂检。二.厂检注意事项:厂检目的:通过检查工厂的品质保证体系,生产流程,确保生产线上产品同样同获取安全认证拥有同样质量。厂检要点:⑴产品质控三个环节:来料检查, ...… 查看全部问答> |
|
自己用纯汇编捣腾51系列很多年了,转到msp430,在网上搜索到的资料基本上全部是C或者C+汇编的基础教学资料,自己习惯用汇编控制单片机的每一个脚的运行,实在不习惯什么C,原来只是在电脑上用过C,请大家帮帮忙,提供msp430汇编学习资料吧,完成的汇 ...… 查看全部问答> |
|
最近想用NIOS作DM9000A通信模块,在利用SOPC自定义DM9000A组建时有一些疑问请大侠们帮忙,我想拿DE2开发板内的dm9000a-if.V移植,但总提示需要一时钟,不知道如何设置。。。。另外,看到一些文章写可以将自定义组件复制到\altera\kits\nios2\com ...… 查看全部问答> |




