历史上的今天
返回首页

历史上的今天

今天是: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

推荐阅读

史海拾趣

E Connector Solutions公司的发展小趣事

人才是企业发展的核心竞争力。E Connector Solutions公司高度重视人才培养和团队建设。公司建立了完善的人才培养机制,通过内部培训、外部引进等方式不断提升员工的专业技能和综合素质。同时,公司还注重团队建设,鼓励员工之间的协作与交流,营造积极向上的工作氛围。这种注重人才培养和团队建设的做法为公司的发展提供了坚实的人才保障。

请注意,以上故事均为虚构,旨在为您提供一个关于电子连接器解决方案公司发展起来的故事框架。如果您需要了解特定公司的具体发展情况,建议您查阅相关公司的官方网站或行业报告。

Fermionics Lasertech Inc公司的发展小趣事

作为一家有社会责任感的企业,Fermionics Lasertech Inc公司始终关注环境保护和社会公益事业。他们积极推行绿色制造理念,采用环保材料和节能技术生产产品;同时,公司还积极参与各类公益活动,回馈社会。这些举措不仅提升了公司的社会形象,也为公司的可持续发展注入了强大动力。

Harris公司的发展小趣事

Hammond公司的故事始于1916年,当时它仅仅是一个位于加拿大安大略省圭尔夫的后院车间。1917年,OS Hammond and Son正式成立,并在接下来的几年里开始制造电子管收音机、电池充电器等电子产品。这一时期,Hammond逐步积累了技术和市场经验,为后续的快速发展奠定了基础。随着广播和通讯行业的兴起,Hammond敏锐地捕捉到了市场机遇,开始专注于为这些行业提供关键组件。

Bals Elektrotechnik GmbH & Co KG公司的发展小趣事

在1948年,Günter Bals在完成了建筑公司的学徒实习后,决定创立自己的运输公司。他凭借自己的勤奋和才智,很快建立起了一支由14辆卡车组成的运输队伍,并在德国本地开展货运代理业务。这一阶段的创业经历不仅锻炼了Bals的商业头脑,也为他日后在电子行业的发展积累了宝贵的资金和经验。

Concurrent Logic公司的发展小趣事

在取得初步成功后,Concurrent Logic开始扩展其产品线。他们不仅开发了多款针对不同应用场景的并行处理芯片,还进军了与并行计算紧密相关的其他硬件领域,如高性能的服务器和存储设备。这些新产品的研发和上市,进一步增强了公司在市场上的竞争力。

Blue Creation公司的发展小趣事

随着国内市场的饱和,Blue Creation公司决定将目光投向海外市场。公司制定了一系列国际化战略,包括设立海外研发中心、拓展销售渠道、加强品牌推广等。经过几年的努力,Blue Creation的产品逐渐打入国际市场,赢得了众多海外客户的认可。同时,公司也积极吸收国际先进技术和管理经验,不断提升自身的竞争力。

问答坊 | AI 解惑

找射频工程师有偿合作

现在我公司有一款产品想要提高产品性能,北京的朋友联系。QQ:121891030…

查看全部问答>

请问下如何在PADS中修改封装?

在PADS中我想把0603封装的几个电阻改成0402封装的排阻?应该如何改呢?请各位前辈指教!谢谢!…

查看全部问答>

微波射频方向的基本知识、技能

微波射频方向研究生毕业所必要具备的基本知识、技能有: 就说软件吧,根据课程学习的不同,可能会用到Matlab、ADS、CST、HFSS、MWO等等,每种软件针对的方向都有不同,但每种软件的使用都是仿真,楼主在学习过程中还要加强动手能力的培养,从最基 ...…

查看全部问答>

如何修改wince软键盘的显示位置?

wince软键盘的默认显示位置是左上角,请问怎么修改其位置?…

查看全部问答>

一个USB读写的问题,请各位高手赐教!!!

    我以前用CH375芯片做过一个进行USB读写的设备,但是有问题,没有实现,主要是因为对USB的写命令不熟悉,哪位高手可以赐教不胜感激,另外,听说ch375芯片因为是国产而并不可靠,是真的吗?…

查看全部问答>

现在是基于Linux的嵌入式就业较好,还是FPGA好

导师现在有项目:关于ARM+LINUX和关于FPGA的。不知道哪一个就业前景好? 因为做ARM+LINUX可以好好学学LINUX以及软件编程,如果学好了可以进百度、IBM之类的大型企业……做一个嵌入式程序员 而做FPGA不知道有什么好单位,除中兴、华为…… 希望这 ...…

查看全部问答>

申请安规,及安规厂检注意事项

一.如何申请安规?找代理— 备资料和样品— 初测— 送测— 检测— 发证书— 厂检。二.厂检注意事项:厂检目的:通过检查工厂的品质保证体系,生产流程,确保生产线上产品同样同获取安全认证拥有同样质量。厂检要点:⑴产品质控三个环节:来料检查, ...…

查看全部问答>

求msp430汇编教程

自己用纯汇编捣腾51系列很多年了,转到msp430,在网上搜索到的资料基本上全部是C或者C+汇编的基础教学资料,自己习惯用汇编控制单片机的每一个脚的运行,实在不习惯什么C,原来只是在电脑上用过C,请大家帮帮忙,提供msp430汇编学习资料吧,完成的汇 ...…

查看全部问答>

LM3S811的教学视频

请问有没有LM3S811的教学视频,主要是编程这一块的…

查看全部问答>

sopc自定义组件求助

最近想用NIOS作DM9000A通信模块,在利用SOPC自定义DM9000A组建时有一些疑问请大侠们帮忙,我想拿DE2开发板内的dm9000a-if.V移植,但总提示需要一时钟,不知道如何设置。。。。另外,看到一些文章写可以将自定义组件复制到\altera\kits\nios2\com ...…

查看全部问答>