久久久久久久999_99精品久久精品一区二区爱城_成人欧美一区二区三区在线播放_国产精品日本一区二区不卡视频_国产午夜视频_欧美精品在线观看免费

 找回密碼
 立即注冊

QQ登錄

只需一步,快速開始

搜索
查看: 10331|回復(fù): 7
打印 上一主題 下一主題
收起左側(cè)

STM8L的I2C之MPU6050基本讀寫

[復(fù)制鏈接]
跳轉(zhuǎn)到指定樓層
樓主
ID:140343 發(fā)表于 2016-10-9 23:56 | 只看該作者 回帖獎勵 |倒序瀏覽 |閱讀模式
之前有寫過I2C的基本讀寫程序,但拿來驅(qū)動MPU6050時,還是遇到一些麻煩,搞了兩天終于把問題解決了.
這兩天遇到的最大的問題是,I2C的SCL頻率達不到設(shè)置的100KHz,只有8KHz,這相差也太遠了吧.
還好我手上有邏輯分析儀可以看到波形,第一行是SCL的波形.

從上面的波形可以看到,低電平明顯比高電平要長,上圖的數(shù)據(jù)是高電平是10us,低電平時間是100us,而數(shù)據(jù)手冊上說,在標準模式下,低電平和高電平應(yīng)該是1:1的關(guān)系.這里的高電平時間和程序里設(shè)置的是一樣的,就是低電平不正常.
因為低電平時間離奇的長,這樣就導(dǎo)致I2C讀寫速度很慢,讀或?qū)懸粋字節(jié)數(shù)據(jù)要用4ms,這根本就不能用.如果我用mpu6050來做平衡小車,這樣的速度根本就沒法控制小車平衡.為此我冥思苦想想,不斷修改程序,給mpu6050模塊焊拆電阻,折騰了好久,最終還是沒有解決.搞的我崩潰的想放棄了.

在群里發(fā)了這個求助,我自己群,也沒報太大希望能解決這個問題.就是想問一下,要把握憋壞了,悶聲我憋不出大招了.

直到群里的一位大神出現(xiàn),我才重拾信心,突發(fā)靈感找到問題所在.因為大神說,STM8L的I2C是可以達到100KHz的頻率的,之前都懷疑STM8L的硬件I2C能不能達到100KHz.

不知道,怎么就想到打開電路圖,看了下,發(fā)現(xiàn)了問題所在了.PC1這個引腳上接了個按鍵,最重要的是還接了阻容濾波的電路.PC1就是SCL引腳.
還好,ST聰明的工程師,在這里設(shè)計了一個跳線,用烙鐵,拆掉SB17這個零歐電阻跳線,就可以了.
拆掉后,果然看到的久違的波形了,感覺這波形很清爽,心情一下好了很多,愁眉舒展.

雖然只有95KHz,但我已經(jīng)很滿意了,肯定會有偏差的,畢竟用的是默認的內(nèi)部時鐘源,可能還有其他原因,導(dǎo)致頻率偏差。
總體感覺,這個邏輯分析儀的功能很強大,查看I2C讀寫數(shù)據(jù)很方便,不用人工去根據(jù)波形翻譯讀寫數(shù)據(jù)。老外這個邏輯分析儀做的不錯,對不住了,我用的是山寨的。
下面就是我用的這個邏輯分析儀,其實是一塊CY7C68013A最小系統(tǒng)板,我燒寫了開源的saleae邏輯分析儀固件,配合saleae的上位機軟件,就可以用了。這個在淘寶上,三十幾塊錢就可以買到。

這個其實我也能做的,如果大家需要,我可以親自畫板,做幾個,給大家,不要我墊錢就行了。

介紹一下本例程,之前的I2C例程,里面讀一個字節(jié)的函數(shù)有個問題,就是讀完一個字節(jié)后不會發(fā)送無應(yīng)答NACK時序,最終的時序是錯誤的。注:之前的文章會被刪掉,不用擔(dān)心找到的是錯誤的程序版本)本次進行了修正,在 I2C1_CR2_STOP=1語句前面加了I2C1_CR2_ACK=0。同時針對MPU6050增加了一個讀多個連續(xù)字節(jié)的函數(shù),下面貼出的例程,是正在測試這個讀多個字節(jié)的函數(shù)能否正常工作,例程已經(jīng)通過測試。讀出到數(shù)組中的數(shù)據(jù)和寫入的數(shù)據(jù)完全一致。

/*硬件連接*/
// PC0<--->SDA   PC1---->SCL
/****************************************************************************************
*開發(fā)環(huán)境:IAR for stm8 v6.5.3
*硬件平臺:STM8L-DISCOVERY
*功能說明:通過硬件I2C等待的方法,測試連續(xù)讀MPU6050寄存器函數(shù)是否正常
*作    者:茗風(fēng)
****************************************************************************************/
#include"iostm8l152c6.h"
#include"stdbool.h"
#include"stdint.h"

uint8_t ui8Read_mpu6050_buffer[14];
/******************************************************************************************************
*  名    稱:void delay_10ms(uint8_t x_ms)
*  功    能:延時10ms
*  入口參數(shù):無
*  出口參數(shù):無
*  說    明:
*  范    例:無
******************************************************************************************************/
void delay_100ms(void)
{
  uint8_t i,j;
  for(i=0;i<255;i++)//2*255個指令周期
    for(j=0;j<255;j++);//2*255個指令周期
  // delay_10ms共消耗 x_ms*2*255+2*x_ms個指令周期  
  // 255*2*255+2*255=130610us=130ms
  // 此延時函數(shù),延時時間為130ms
  // 16M/8/2=1M 一個指令周期為1us
}
/******************************************************************************************************
* 名 稱: uint8_t I2C_ReadOneByteDataFromSlave(uint8_t address)
* 功 能:從I2C從設(shè)備中讀取一字節(jié)的數(shù)據(jù)
* 入口參數(shù):address:讀取數(shù)據(jù)的寄存器地址
* 出口參數(shù):返回一個從I2C從設(shè)備指定地址讀到的數(shù)據(jù)
* 說 明:
* 范 例:無
******************************************************************************************************/
uint8_t I2C_ReadOneByteDataFromSlave(uint8_t address)
{
  volatile uint8_t t;
  //----------I2C起始信號--------------
  I2C1_CR2_START=1;//產(chǎn)生一個起始條件
  while(!(I2C1_SR1_SB==1));//讀SR1寄存器,清除SB標志位
//  _5NOPS;//根據(jù)數(shù)據(jù)手冊,檢測到標志位后,需插入5個NOP進行延時

  //-------發(fā)送寫I2C從器件地址---------
  I2C1_DR=0xD0;//發(fā)送從設(shè)備地址
  while(!(I2C1_SR1_ADDR==1));//讀SR1寄存器,清除ADDR標志位
// _5NOPS;//根據(jù)數(shù)據(jù)手冊,檢測到標志位后,需插入5個NOP進行延時
  if(I2C1_SR3_TRA==0)return 1;//讀SR3寄存器,清除ADDR標志位
  //  0: Data bytes received
  //  1: Data bytes transmitted

  //-----寫I2C從器件寄存器地址--------
  I2C1_DR=address;
  while(!(I2C1_SR1_BTF==1));//等待地址發(fā)送完成
//  _5NOPS;//根據(jù)數(shù)據(jù)手冊,檢測到標志位后,需插入5個NOP進行延時

  //--------I2C重復(fù)起始信號-----------
  I2C1_CR2_START=1;//重復(fù)產(chǎn)生一個起始條件
  while(!(I2C1_SR1_SB==1));//讀SR1寄存器,清除SB標志位
//  _5NOPS;//根據(jù)數(shù)據(jù)手冊,檢測到標志位后,需插入5個NOP進行延時

  //-------發(fā)送讀I2C從器件地址---------
  I2C1_DR=0xD1;//發(fā)送從設(shè)備地址
  while(!(I2C1_SR1_ADDR==1));//讀SR1寄存器,清除ADDR標志位
//  _5NOPS;//根據(jù)數(shù)據(jù)手冊,檢測到標志位后,需插入5個NOP進行延時
  if(I2C1_SR3_TRA==1)return 1;//讀SR3寄存器,清除ADDR標志位

  //-------------停止信號-------------
  I2C1_CR2_ACK=0;//ACK位控制著ACK信號,此位為0可以產(chǎn)生一個NOACK信號
  I2C1_CR2_STOP=1;

  //-------------等待接收到數(shù)據(jù)-------------
  while(!(I2C1_SR1_RXNE==1));//等待地址發(fā)送完成

  //-------------讀取數(shù)據(jù)-------------
  t=I2C1_DR;

  return t;
}
/******************************************************************************************************
* 名 稱:void I2C_WriteOneByteDataToSlave(uint8_t address,uint8_t dat)
* 功 能:寫入一字節(jié)的數(shù)據(jù)到I2C設(shè)備中
* 入口參數(shù):address:寫入的數(shù)據(jù)存儲地址    dat:待寫入的數(shù)據(jù)
* 出口參數(shù):無
* 說 明: 通過MSTM8L硬件寫入I2C設(shè)備一個字節(jié)的數(shù)據(jù)
* 范 例:無
******************************************************************************************************/
uint8_t I2C_WriteOneByteDataToSlave(uint8_t address,uint8_t dat)
{
  volatile uint8_t t;
  I2C1_CR2_ACK=1;
  //----------I2C起始信號--------------
  I2C1_CR2_START=1;//產(chǎn)生一個起始條件
  while(!(I2C1_SR1_SB==1));
// _5NOPS;//根據(jù)數(shù)據(jù)手冊,檢測到標志位后,需插入5個NOP進行延時
  I2C1_DR=0xD0;

  //--------寫I2C從器件地址-----------
  while(!(I2C1_SR1_ADDR==1));
//  _5NOPS;//根據(jù)數(shù)據(jù)手冊,檢測到標志位后,需插入5個NOP進行延時
  if(I2C1_SR3_TRA==0)return 1;//讀SR3寄存器,清除ADDR標志位

  //-----寫I2C從器件寄存器地址--------
  while(!(I2C1_SR1_TXE==1));
  I2C1_DR=address;

  //-------寫I2C數(shù)據(jù)到寄存器中--------
  while(!(I2C1_SR1_TXE==1));
  I2C1_DR=dat;
  while(!(I2C1_SR1_TXE==1));
  while(!(I2C1_SR1_BTF==1));
// _5NOPS;//根據(jù)數(shù)據(jù)手冊,檢測到標志位后,需插入5個NOP進行延時

  //-------------停止信號-------------
  I2C1_CR2_STOP=1;
  return 0;
}
/******************************************************************************************************
* 功    能:從I2C從設(shè)備讀取多個字節(jié)數(shù)據(jù)
* 入口函數(shù):
* 出口函數(shù):
* 說    明:
* 范    例:
* 日    期:
******************************************************************************************************/
uint8_t I2C_ReadMultiBytesFromSlave(uint8_t address,uint8_t *rxbuf,uint8_t len)
{
  volatile uint8_t i=0;

  if(len==0)return 1;//如果寫入字節(jié)長度為0退出

  I2C1_CR2_ACK=1;
  //----------I2C起始信號--------------
  I2C1_CR2_START=1;//產(chǎn)生一個起始條件
  while(!(I2C1_SR1_SB==1));//讀SR1寄存器,清除SB標志位

  //-------發(fā)送寫I2C從器件地址---------
  I2C1_DR=0xD0;//發(fā)送從設(shè)備地址
  while(!(I2C1_SR1_ADDR==1));//讀SR1寄存器,清除ADDR標志位
  if(I2C1_SR3_TRA==0)return 1;//讀SR3寄存器,清除ADDR標志位
  //  0: Data bytes received
  //  1: Data bytes transmitted

  //-----寫I2C從器件寄存器地址--------
  I2C1_DR=address;
  while(!(I2C1_SR1_BTF==1));//等待地址發(fā)送完成

  //--------I2C重復(fù)起始信號-----------
  I2C1_CR2_START=1;//重復(fù)產(chǎn)生一個起始條件
  while(!(I2C1_SR1_SB==1));//讀SR1寄存器,清除SB標志位

  //-------發(fā)送讀I2C從器件地址---------
  I2C1_DR=0xD1;//發(fā)送從設(shè)備地址
  while(!(I2C1_SR1_ADDR==1));//讀SR1寄存器,清除ADDR標志位
  if(I2C1_SR3_TRA==1)return 1;//讀SR3寄存器,清除ADDR標志位
  //-------------讀取數(shù)據(jù)-------------
  if(len>1)
  {
      for( i=len;i>1;i-- )
      {
        while(!(I2C1_SR1_RXNE==1));//等待I2C1_DR接收到數(shù)
        *rxbuf++ = I2C1_DR;  
      }
  }

  //-------------停止信號-------------
  I2C1_CR2_ACK=0;//ACK位控制著ACK信號,此位為0可以產(chǎn)生一個NOACK信號
  I2C1_CR2_STOP=1;

  while(!(I2C1_SR1_RXNE==1));//等待I2C1_DR接收到數(shù)
  *rxbuf++ = I2C1_DR;

  return 0;
}
/******************************************************************************************************
* 名 稱: IIC_init()
* 功 能:初始化IIC
* 入口參數(shù):無
* 出口參數(shù):無
* 說 明:PC0--SDA   PC1--SCL
* 范 例:無
******************************************************************************************************/
void I2C_Init(void)
{
  //----打開IIC外設(shè)時鐘----
  CLK_PCKENR1_PCKEN13=1;//
  I2C1_CR1_PE=0;
//  I2C1_CR2_SWRST=1;
  I2C1_CR2_ACK=1;

  //----I2C輸入時鐘頻率選擇----
  I2C1_FREQR_FREQ=0x02;//2MHz
  /*  The allowed range is between 1 MHz and 16 MHz
  000000: not allowed
  000001: 1 MHz
  000010: 2 MHz
  ...
  010000: 16 MHz                                 */

  //----配置時鐘控制寄存器----
  I2C1_CCRH=0;
//  I2C1_CCRH_F_S=0; //Standard mode I2C
//  I2C1_CCRH_DUTY=0;
  I2C1_CCRL=10;    //SCL高電平時間配置
  //I2C的SCK時鐘設(shè)置為100KHz,則SCK周期為10us
  //因為I2C1_FREQR_FREQ=0x02,即I2C輸入時鐘頻率為2M,周期為0.5us
  //CCR=10時,SCK的低電平時間為tlow=10*0.5us=5us,SCk高電平時間為thigh=10*0.5us=5us
  //所以CCR=10時,SCK輸出頻率為100KHz

  //----配置上升時間寄存器----
  I2C1_TRISER_TRISE=1;//in standard mode, the maximum allowed SCL rise time is 1000 ns.
  //1 us / 0.5 us = 2 + 1

  I2C1_CR1_PE=1;//

}
/******************************************************************************************************
* 功    能:MPU6050功能配置
* 入口函數(shù):
* 出口函數(shù):
* 說    明:
* 范    例:
* 日    期:
******************************************************************************************************/
void MPU6050_Config(void)
{
//  static uint8_t tmp=0;
//        I2C_WriteOneByteDataToSlave(0x6B,0x00);//電源管理
//        I2C_WriteOneByteDataToSlave(0x19,0x00);//陀螺儀采樣率,不分頻,8khz
//        I2C_WriteOneByteDataToSlave(0x1A,0x00);//不啟用低通濾波器
//        I2C_WriteOneByteDataToSlave(0x1B,0x18);//陀螺儀不自檢,2000deg/s
//        I2C_WriteOneByteDataToSlave(0x1C,0x1F);//加速度計不自檢,16g
        I2C_WriteOneByteDataToSlave(0x6B,0x00);//電源管理
        I2C_WriteOneByteDataToSlave(0x27,0x01);
        I2C_WriteOneByteDataToSlave(0x28,0x02);
        I2C_WriteOneByteDataToSlave(0x29,0x03);
        I2C_WriteOneByteDataToSlave(0x2A,0x04);
  I2C_WriteOneByteDataToSlave(0x2B,0x05);
        I2C_WriteOneByteDataToSlave(0x2C,0x06);
        I2C_WriteOneByteDataToSlave(0x2D,0x07);
        I2C_WriteOneByteDataToSlave(0x2E,0x08);
  I2C_WriteOneByteDataToSlave(0x2F,0x09);
}
void main(void)
{
  static uint8_t tmp=0;
  delay_100ms();
  I2C_Init();
  MPU6050_Config();
//  tmp=I2C_ReadOneByteDataFromSlave(0x1C);
  I2C_ReadMultiBytesFromSlave(0x27,ui8Read_mpu6050_buffer,9);
  while(1)
  {
//    asm("wfi");
  }
}

分享到:  QQ好友和群QQ好友和群 QQ空間QQ空間 騰訊微博騰訊微博 騰訊朋友騰訊朋友
收藏收藏1 分享淘帖 頂 踩
回復(fù)

使用道具 舉報

沙發(fā)
ID:164108 發(fā)表于 2017-2-18 21:16 | 只看該作者
你好樓主,能向你請教一下做那個邏輯分析儀的問題嘛?
回復(fù)

使用道具 舉報

板凳
ID:184406 發(fā)表于 2017-6-13 17:45 | 只看該作者
據(jù)說STM8的硬件IIC比較坑啊,不敢用
軟件IIC能達到100K嗎
回復(fù)

使用道具 舉報

地板
ID:215671 發(fā)表于 2017-6-29 08:03 來自手機 | 只看該作者
新入8L坑,學(xué)習(xí)下
回復(fù)

使用道具 舉報

5#
ID:76208 發(fā)表于 2017-7-7 16:55 | 只看該作者
樓主有沒有源代碼文件求助。1178225915@qq.com
回復(fù)

使用道具 舉報

6#
ID:227340 發(fā)表于 2017-8-12 22:33 | 只看該作者
樓至我想問下 我用的是stm8l051感覺也是很慢 怎么解決么
回復(fù)

使用道具 舉報

7#
ID:248120 發(fā)表于 2018-7-31 04:22 來自手機 | 只看該作者
樓主你好,硬件iic外面不需要接上拉電阻嗎?還有用不用中斷?可否發(fā)一下源代碼1107114564@qq.com謝謝
回復(fù)

使用道具 舉報

8#
ID:216226 發(fā)表于 2019-6-12 08:41 | 只看該作者
為什么不用庫函數(shù)呢,
回復(fù)

使用道具 舉報

您需要登錄后才可以回帖 登錄 | 立即注冊

本版積分規(guī)則

手機版|小黑屋|51黑電子論壇 |51黑電子論壇6群 QQ 管理員QQ:125739409;技術(shù)交流QQ群281945664

Powered by 單片機教程網(wǎng)

快速回復(fù) 返回頂部 返回列表
主站蜘蛛池模板: 在线观看国产 | 亚洲激情一级片 | 中文字幕一区二区三 | 网页av| 国产一区二区不卡 | 欧日韩不卡在线视频 | 九九热精品免费 | 噜噜噜噜狠狠狠7777视频 | 亚洲欧美在线观看 | 国产在线精品一区二区三区 | 成人午夜精品 | 91精品国产高清一区二区三区 | 亚洲第一免费播放区 | 欧美在线一区二区三区 | 亚洲 中文 欧美 | 96久久久久久 | www.99热 | 欧美一级久久 | 国产乱码精品一区二区三区中文 | 黄色av网站在线免费观看 | 精品日本久久久久久久久久 | 色婷婷久久久久swag精品 | 91精品国产综合久久香蕉麻豆 | 亚洲一区二区三区四区五区午夜 | 成人av一区 | 污片在线观看 | 伊人伊人 | 国产精品伦理一区二区三区 | 亚洲综合第一页 | 中文字幕在线播放不卡 | 久热免费在线 | 欧美寡妇偷汉性猛交 | 国产精品免费观看视频 | 亚洲综合色 | 337p日韩| 理论片87福利理论电影 | 精品国产91亚洲一区二区三区www | 欧美在线日韩 | 毛片在线视频 | com.色.www在线观看 | 狠狠操狠狠操 |