你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

STM32f401的硬件I2C

[复制链接]
强仔00001 发布时间:2014-7-21 22:48
         这两个星期都在调试stm32f4的硬件i2c,在这过程中遇到了各种蛋疼的问题,经过参考大量的例程和资料,今天终于把硬件的I2C调通了,我使用定时器310ms的中断,然后再10ms的中断里读取GY86MPU6050HMC5883L的数据,再经经过4元数法算出3个角。有人说stm32I2C用起来很难,但其实也不是很难的,我就是直接用官方的库函数实现的。下面来直入主题。
  硬件平台: UNCLEO-F401RE
 
首先是I2CIOI2C的配置的配置,这个至关重要,一旦初始化不正确,I2C就会出现各种状况。
下面贴上代码:
void I2C_Congiguration(void)
{
         /****IO口的配置*******/
         GPIO_InitTypeDef  GPIO_InitStructure;
  I2C_InitTypeDef  I2C_InitStructure;
        
         RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB | RCC_AHB1Periph_GPIOB,ENABLE);
        
         RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1,ENABLE);
        
         GPIO_PinAFConfig(GPIOB, GPIO_PinSource7, GPIO_AF_I2C1);
         GPIO_PinAFConfig(GPIOB, GPIO_PinSource6, GPIO_AF_I2C1);
 
         GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7; //GPIO_Pin_6 | GPIO_Pin_7
         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
         GPIO_InitStructure.GPIO_OType = GPIO_OType_OD;
         GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
         GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
 
         GPIO_Init(GPIOB, &GPIO_InitStructure);
        
        
           /* I2C1 的配置 */
         I2C_DeInit(I2C1);
  I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;
 // I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;
 // I2C_InitStructure.I2C_OwnAddress1 = 0xd0;
  I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;
  I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
  I2C_InitStructure.I2C_ClockSpeed = I2C_Speed;
 
  /*使能 I2C1 */
  I2C_Cmd(I2C1, ENABLE);
 
  /* I2C1 初始化*/
  I2C_Init(I2C1, &I2C_InitStructure);
 
         允许1字节1应答模式*/
         I2C_AcknowledgeConfig(I2C1, ENABLE);
        
}
        
}
 
在用stm32F4的库函数前,我要补充一下stm32F1stm32F4的区别。
第一个,在F 1 里边你可以使用这样的方式配置时钟复用
R C C _ A P B 2 P e r i p h C l o c k C m d ( R C C _ A P B 2 P e r i p h _ G P I O A | R C C _ A P B 2 P e r i p h _ G P I O B | R C C _ A P B 2 P e r i p h _ A F I O | R C C _ A P B 2 P e r i p h _ U S A R T 1 , E N A B L E ) ; / /
打开复用时
但是。。。在F 4 里边这个就不管用了。因为F 4 的变了,以前的那些变量不再爱你了。库里边根本就没有了这个变量R C C _ A P B 2 P e r i p h _ A F I O
第二,G P I O 的输入输出模式也变了。这样的用法:G P I O _ I n i t S t r u c t u r e . G P I O _ M o d e = G P I O _ M o d e _ I N _ F L O A T I N G ; 。已经不行了。原因同上,
G P I O _ M o d e _ I N _ F L O A T I N G 这种模式已经不存在了。
F 4 的库里边只有这个模式:G P I O _ M o d e _ A F 。所有使用复用功能的引脚都应设置成这种模式。
这样比F 1 方便多了。你不用考虑这个引脚应该设置成浮空输入还是推挽输出. . . . 因为引脚设置错误基本可以消失。
}
引脚的复用功能要用GPIO_PinAFConfig();这个函数了。配置完这些后,就是I2C的协议程序了。代码我就不贴上了,大家就下载附件来看吧。
然后就是定时器的配置;代码如下:
void TIM_Init()
{        
          TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
                  
    //Tim_Nvic_Init();
 
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);      //    TIM3 clock enable
 
 
    TIM_TimeBaseStructure.TIM_Period = 99;
    TIM_TimeBaseStructure.TIM_Prescaler = 7199;
    TIM_TimeBaseStructure.TIM_ClockDivision = 0;
    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
   
    TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);
   
 
                    
                   TIM_ITConfig(TIM3,TIM_IT_Update, ENABLE);
   
    /* TIM3 enable counter */
    TIM_Cmd(TIM3, ENABLE);
                   TIM_ClearFlag(TIM3,TIM_FLAG_Update);
 
}
 
我这个板子使用外部晶振的,我用的是12M,经过PLL后得出72M的时钟频率。
void Sysclock_Init()
{
        
  RCC->CR |= ((uint32_t)RCC_CR_HSEON);                      /* 使能HSE                       */
  while ((RCC->CR & RCC_CR_HSERDY) == 0);                   /* 等待HSE               */
 
  RCC->CFGR = RCC_CFGR_SW_HSE; 
         while ((RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_HSE);
        
         FLASH->ACR  = FLASH_ACR_PRFTEN;                           /* Enable Prefetch Buffer            */
  FLASH->ACR |= FLASH_ACR_ICEN;                             /* Instruction cache enable          */
  FLASH->ACR |= FLASH_ACR_DCEN;                             /* Data cache enable                 */
  FLASH->ACR |= FLASH_ACR_LATENCY_5WS;                     
        
         RCC->CFGR |= RCC_CFGR_HPRE_DIV1;                          /* HCLK = SYSCLK                     */
  RCC->CFGR |= RCC_CFGR_PPRE1_DIV1;                         /* APB1 = HCLK                     */
  RCC->CFGR |= RCC_CFGR_PPRE2_DIV1; 
        
          RCC->CR &= ~RCC_CR_PLLON;
        
  RCC-&gtLLCFGR = ( 20ul                   |                 /* PLL_M =  20                       */
                 (240ul CFGR |=  RCC_CFGR_SW_PLL;
 
  while ((RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_PLL);  
 
 
}
 
关于系统时钟的设置可以参考stm32f401参考手册第99页。
计算的公式是 SystemCoreClock = HSx*PLL_N/PLL_M))/PLL_P;
如下图:
系统时钟配置1.png
 
HSx可以选择外部高速晶振HSE和内部高速震荡器HSI,注意内部的高速震荡器是16M的,这个是经过本人用定时器开PWM算出来是正确的,注意系统时钟不能设得太高,否则就会起不了振的。
顺便说一下PLL_Q是用来给USB等外设的。
这一PLL_NPLL_M,PLL_Q是有范围的,如手册就表明了范围了。
系统时钟配置.png
 
 如果你没有外部晶振,就把上面的HSE全都替换成HSI         ,这是你就要注意是按16M来算的了。如果你用多少M的外部晶振,要修改头文件里的HSE_VALUE的数值,头文件是默认25M的,我外部是12M的,所以就改成#define HSE_VALUE    ((uint32_t)12000000)
系统时钟配置2.png
 
说了这么多,现在说回时钟的配置吧。
设置完时钟后,就要设置中断的优先级了。
void Tim_Nvic_Init(void)
{         
    NVIC_InitTypeDef NVIC_InitStructure;
   
           NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
        
    /* Enable the TIM3 gloabal Interrupt */
    NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);
}
当中断多的时候,这里就有很大的学问了,想了解的可以上去百度或google一下。我这里就不多说了。
中断的里的程序:
void TIM3_IRQHandler(void)
{
         if(TIM_GetITStatus(TIM3,TIM_IT_Update) != RESET)
         {                                   
                   TIM_ClearITPendingBit(TIM3,TIM_IT_Update);
                   Read_Filter_MPU6050();
                   //Read_HMC5883L();
                   Get_Attitude();
                   //ACC_ANGLE();               
         }
}
关键的主程序部分了
int main()
{
        
        
         uint8_t counter;
         short value;              
         Sysclock_Init();
         Tim_Nvic_Init();
         delay_init(72);
         I2C_Congiguration();
         MPU6050_Init();
         HMC5883L_Init();

         TIM_Init();
         while (1)
         {
         }
                  
}
注意时钟的配置要放到最后,否则会影响I2C会卡死的
现在已经运行了3个小时一起良好:
这是我用示波器下看的I2C时序
IMG_20140721_195147.jpg
 
转载请注!!                                    强仔00001 2014-7-21
TIM.zip (342.99 KB, 下载次数: 438)
IMG_20140721_211408.jpg
收藏 1 评论6 发布时间:2014-7-21 22:48

举报

6个回答
aaa999kk 回答时间:2014-7-24 16:29:36

RE: STM32f401的硬件I2C

初始化参数写错, 是有很多麻烦
巅峰残狼 回答时间:2014-7-25 21:57:50

RE: STM32f401的硬件I2C

这明明是分享帖嘛,怎么放在求助帖里呢?不过感觉挺好的,学习了
霹雳之火 回答时间:2014-7-28 16:34:14

回复: STM32f401的硬件I2C

回复第 3 楼 于2014-07-25 21:57:50发表:
这明明是分享帖嘛,怎么放在求助帖里呢?不过感觉挺好的,学习了 

是的看完之后楼主自己解决的问题,是分享帖
feixiang20 回答时间:2014-7-29 01:50:12

RE: STM32f401的硬件I2C

红笔部分是不是有什么问题需要解释呢
zzzhxw 回答时间:2016-3-22 13:43:06
楼主   好东西啊
wdshuang09 回答时间:2016-11-20 15:11:08
最近用寄存器调STM32F103  的I2C,也调通了;确实STM32的I2C不好调呀

所属标签

STM32团队

意法半导体微控制器和微处理器拥有广泛的产品线,包含低成本的8位单片机和基于ARM® Cortex®-M0、M0+、M3、M4、M33、M7及A7内核并具备丰富外设选择的32位微控制器及微处理器


最新内容

相似技术帖

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
微信公众号二维码 微信公众号
手机版二维码 手机版