日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

STM32F10x_模拟I2C读写EEPROM(2)(切换SDA方向 + 读ACK位 + 完整代码)

發布時間:2023/12/20 编程问答 33 豆豆
生活随笔 收集整理的這篇文章主要介紹了 STM32F10x_模拟I2C读写EEPROM(2)(切换SDA方向 + 读ACK位 + 完整代码) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

文章目錄

  • 前言
  • 一、宏定義
  • 二、I2C延時函數
    • 1. 注意
  • 三、起始 / 停止信號
    • 1. 時序圖
    • 2. 起始信號
    • 3. 停止信號
  • 四、切換SDA方向
    • 1. SDA配置為輸入模式
    • 2. SDA配置為輸出模式
  • 五、應答位信息
    • 1. 主機(MCU)讀取 應答位
    • 2. 主機(MCU)產生 應答位
  • 六、I2C讀 / 寫 一個字節
    • 1. 注意
    • 2. I2C寫一個字節
    • 3. I2C讀一個字節
  • 七、E2 頁寫 / 連續讀
    • 1. E2 頁寫
    • 2. E2 連續讀
  • 八、小結


前言

  • 關于此文一些名詞術語不太理解的,可以去看我這篇博文
    《STM32F10x_模擬I2C讀寫EEPROM(1)》

  • 讀寫E2函數(帶備份區+校驗和判斷),可以去看我這篇博文
    《STM32F10x_模擬I2C讀寫EEPROM(3)(讀寫E2備份區 + 校驗位 + 完整代碼 + 應用實例)》

  • E2的中文資料可以到我博客資源里下載,沒有積分下載的,可以評論Ding我o( ̄▽ ̄)ブ

一、宏定義

// I2C引腳#define PORT_I2C_SCL GPIOx#define PORT_I2C_SDA GPIOx#define PIN_I2C_SCL GPIO_Pin_x#define PIN_I2C_SDA GPIO_Pin_x// 控制 SDA / SCL 高低電平#define I2C_SCL_LOW (PORT_I2C_SCL->BRR = PIN_I2C_SCL)#define I2C_SCL_HIGH (PORT_I2C_SCL->BSRR = PIN_I2C_SCL)#define I2C_SDA_LOW (PORT_I2C_SDA->BRR = PIN_I2C_SDA)#define I2C_SDA_HIGH (PORT_I2C_SDA->BSRR = PIN_I2C_SDA)// 讀 SDA 電平狀態#define I2C_SDA_READ (PORT_I2C_SDA->IDR & PIN_I2C_SDA)// 應答位信息#define I2C_ACK 0 //應答#define I2C_NOACK 1 //非應答/*1、"地址長度"根據芯片型號不同略有不同8位: AT24C01、AT24C0216位: AT24C04、AT24C08、AT24C16、AT24C32、AT24C64、AT24C128、AT24C256、AT24C5122、"頁長度"根據芯片型號不同略有不同8字節: AT24C01、AT24C0216字節: AT24C04、AT24C08、AT24C1632字節: AT24C32、AT24C6464字節: AT24C128、AT24C256128字節: AT24C512*/// 此文的E2型號 - AT24C512#define EEPROM_WORD_ADDR_SIZE 16 //地址長度#define EEPROM_PAGE_SIZE 128 //頁長度#define EEPROM_DEV_ADDR 0xA0 //地址(設備地址:與A2、A1、A0有關)#define EEPROM_WR 0x00 //寫#define EEPROM_RD 0x01 //讀

二、I2C延時函數

  • 1. 注意

    • 此函數實現的是非標準延時,請根據MCU速度 調節大小 /************************************************ 函數名稱 : I2C_Delay 功 能 : I2C延時(非標準延時,請根據MCU速度 調節大小) 參 數 : 無 返 回 值 : 無 *************************************************/ static void I2C_Delay(void) {uint16_t cnt = 100;while(cnt--); }

三、起始 / 停止信號

  • 1. 時序圖

  • 2. 起始信號

    • 時鐘線 SCL 保持高電平期間 數據線 SDA 電平從高到低的跳變作為I2C總線的起始信號 /************************************************ 函數名稱 : I2C_Start 功 能 : I2C開始 參 數 : 無 返 回 值 : 無 *************************************************/ void I2C_Start(void) {I2C_SCL_HIGH; //SCL高I2C_Delay();I2C_SDA_HIGH; //SDA高I2C_Delay();I2C_SDA_LOW; //SDA低I2C_Delay();I2C_SCL_LOW; //SCL低I2C_Delay(); }

  • 3. 停止信號

    • 時鐘線 SCL 保持高電平期間 數據線SDA 電平從低到高的跳變作為I2C總線的停止信號 /************************************************ 函數名稱 : I2C_Stop 功 能 : I2C停止 參 數 : 無 返 回 值 : 無 *************************************************/ void I2C_Stop(void) {I2C_SDA_LOW; //SDA低I2C_Delay();I2C_SCL_HIGH; //SCL高I2C_Delay();I2C_SDA_HIGH; //SDA高I2C_Delay(); }

四、切換SDA方向

  • 1. SDA配置為輸入模式

    /************************************************ 函數名稱 : I2C_SDA_SetInput 功 能 : I2C_SDA設置為輸入 參 數 : 無 返 回 值 : 無 *************************************************/ void I2C_SDA_SetInput(void) {GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Pin = PIN_I2C_SDA;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; // I2C_SDA設置為 浮空輸入GPIO_Init(PORT_I2C_SDA, &GPIO_InitStructure); }

  • 2. SDA配置為輸出模式

    /************************************************ 函數名稱 : I2C_SDA_SetOutput 功 能 : I2C_SDA設置為輸出 參 數 : 無 返 回 值 : 無 *************************************************/ void I2C_SDA_SetOutput(void) {GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Pin = PIN_I2C_SDA;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD; // I2C_SDA設置為 開漏輸出GPIO_Init(PORT_I2C_SDA, &GPIO_InitStructure); }

五、應答位信息

  • 1. 主機(MCU)讀取 應答位

    • 主機(MCU)寫數據的時候,從機(E2)產生應答,主機讀取應答位進行檢測;
      /************************************************ 函數名稱 : I2C_GetAck 功 能 : I2C主機讀取應答(或非應答)位 參 數 : 無 返 回 值 : I2C_ACK ----- 應答I2C_NOACK --- 非應答 *************************************************/ uint8_t I2C_GetAck(void) {uint8_t ack;I2C_SCL_LOW; //SCL低(此時從機可變化SDA電平產生應答位信息)I2C_Delay();I2C_SDA_SetInput(); //SDA配置為輸入模式(切換SDA方向)I2C_SCL_HIGH; //SCL高(SCL上升沿時,從機發應答位信息到SDA線上)I2C_Delay();if(I2C_SDA_READ) //讀取從機應答位信息ack = I2C_NOACK; //非應答elseack = I2C_ACK; //應答I2C_SCL_LOW; //SCL低(防止誤操作起始 / 結束信號)I2C_Delay();I2C_SDA_SetOutput(); //SDA配置為輸出模式(切換SDA方向)return ack; //返回應答位 }

  • 2. 主機(MCU)產生 應答位

    • 主機(MCU)讀數據的時候,主機產生應答,從機(E2)讀取應答位進行檢測;

      /************************************************ 函數名稱 : I2C_PutAck 功 能 : I2C主機產生應答(或非應答)位 參 數 : I2C_ACK ----- 應答I2C_NOACK --- 非應答 返 回 值 : 無 *************************************************/ void I2C_PutAck(uint8_t Ack) {I2C_SCL_LOW; //SCL低(此時主機可變化SDA電平產生應答位信息)I2C_Delay();if(I2C_ACK == Ack)I2C_SDA_LOW; //主機產生 → 應答elseI2C_SDA_HIGH; //主機產生 → 非應答I2C_Delay();I2C_SCL_HIGH; //SCL高 (SCL上升沿時,主機發應答位信息到SDA線上)I2C_Delay();I2C_SCL_LOW; //SCL低(防止誤操作起始 / 結束信號)I2C_Delay(); }

六、I2C讀 / 寫 一個字節

  • 1. 注意

    • I2C讀 / 寫一字節不是 E2 讀 / 寫一字節(需要區分開來)。
  • 2. I2C寫一個字節

    • 主機每寫完一個字節后,讀取從機返回的應答位:

      • 應答位若為0,表示從機應答,能繼續下一步操作;
      • 應答位若為1,表示從機非應答,不能進行下一步操作。
      /************************************************ 函數名稱 : I2C_WriteByte 功 能 : I2C寫一字節 參 數 : Data -------- 數據 返 回 值 : I2C_ACK ----- 應答I2C_NOACK --- 非應答 *************************************************/ uint8_t I2C_WriteByte(uint8_t Data) {uint8_t cnt;// 發送一個字節(8位)for(cnt = 0; cnt < 8; cnt++){I2C_SCL_LOW; //SCL低(SCL為低電平時,主機變化SDA有效,產生SDA數據)I2C_Delay();if(Data & 0x80)I2C_SDA_HIGH; //SDA高elseI2C_SDA_LOW; //SDA低Data <<= 1;I2C_Delay();I2C_SCL_HIGH; //SCL高(SCL上升沿,主機發送數據出去)I2C_Delay();}I2C_SCL_LOW; //SCL低(防止誤操作起始 / 結束信號)I2C_Delay();return I2C_GetAck(); //主機讀取應答位 }
  • 3. I2C讀一個字節

    • 主機每讀到一個字節(8位)后,產生應答位給從機檢測:
      • 應答位若為0,表示主機應答,主機不繼續讀取數據了;
      • 應答位若為1,表示主機非應答,主機可繼續讀取數據。
      /************************************************ 函數名稱 : I2C_ReadByte 功 能 : I2C讀一字節 參 數 : ack --------- 產生應答(或者非應答)位 返 回 值 : data -------- 讀取的一字節數據 *************************************************/ uint8_t I2C_ReadByte(uint8_t ack) {uint8_t cnt;uint8_t data;I2C_SCL_LOW; //SCL低(此時從機可變化SDA電平產生數據)I2C_Delay();I2C_SDA_SetInput(); //SDA配置為輸入模式(切換SDA方向)for(cnt = 0; cnt < 8; cnt++){I2C_SCL_HIGH; //SCL高(SCL上升沿時,從機發數據到SDA線上)I2C_Delay();data <<= 1;if(I2C_SDA_READ) //SDA為高(數據有效)data |= 0x01; I2C_SCL_LOW; //SCL低(防止誤操作起始 / 結束信號)I2C_Delay();}I2C_SDA_SetOutput(); //SDA配置為輸出模式(切換SDA方向)I2C_PutAck(ack); //產生應答(或者非應答)位return data; //返回數據 }

七、E2 頁寫 / 連續讀

  • 1. E2 頁寫

    • 一次頁寫操作寫入的數據字節數最大值為E2的頁大小;

    • 不同型號的E2對應的頁大小可能不同(下面簡稱頁大小的值為 P ,舉例:AT24C512 → P = 128);

    • E2 頁寫時序說明:

      • 舉例說明:MCU寫n(n <= P)個字節數據進E2;
      • ① 主器件發送起始信號和從器件地址信息( R/W 位置零 )給從器件,主器件檢測返回應答位信息;
      • ② 主器件發送起始字節地址,主器件檢測返回應答位信息;
      • ③ 非發送最后一個字節時,主器件每發送完一個字節后,不產生停止信號,主器件檢測應答位信息。循環此步驟③ n - 1次,按順序發送數據;
      • ④ 主器件發送最后一個字節后,主器件檢測應答位信息,然后主器件產生停止信號;
      • ⑤ 從器件接收到停止信號后,從器件開始內部數據的擦寫,在擦寫過程中,從器件不再應答主器件的任何請求。
    • 注意:如果進行頁寫操作時,n > p,地址計數器將自動翻轉,先前寫入的數據會被覆蓋,所以要注意每次頁寫的字節數不能大于E2的頁大小P,否則會影響數據的正確性。

      /************************************************ 函數名稱 : EEPROM_WritePage 功 能 : EEPROM寫頁 參 數 : Addr ------ 地址pData ----- 數據Length -----長度(<=EEPROM_PAGE_SIZE) 返 回 值 : I2C_ACK ----應答I2C_NOACK - 非應答 *************************************************/ uint8_t EEPROM_WritePage(uint16_t Addr, uint8_t *Data, uint16_t Length) {uint8_t ack;uint8_t i;/* 1.開始信號 */I2C_Start();/* 2.設備地址/寫 */ack = I2C_WriteByte(EEPROM_DEV_ADDR | EEPROM_WR);if(I2C_NOACK == ack){I2C_Stop();return I2C_NOACK;}/* 3.數據地址 */#if(8 == EEPROM_WORD_ADDR_SIZE)ack = I2C_WriteByte((uint8_t)(Addr&0x00FF)); //數據地址(8位) if(I2C_NOACK == ack){I2C_Stop();return I2C_NOACK;}#elseack = I2C_WriteByte((uint8_t)(Addr>>8)); //數據地址(16位)if(I2C_NOACK == ack){I2C_Stop();return I2C_NOACK;}ack = I2C_WriteByte((uint8_t)(Addr&0x00FF)); if(I2C_NOACK == ack){I2C_Stop();return I2C_NOACK;}#endif/* 4.寫一字節數據(循環) */for(i = 0; i < Length; i++){ack = I2C_WriteByte(*(Data + i));if(I2C_NOACK == ack){I2C_Stop();return I2C_NOACK;}}/* 5.停止信號 */I2C_Stop();return I2C_ACK; }
  • 2. E2 連續讀

    • 從E2讀取數據是一個復合的I2C時序,它實際上包含一個寫過程和一個讀過程。
    • E2 連續讀時序說明:
      • 舉例說明:MCU連續讀E2里的n(n <= P)個字節數據;
      • ① 主器件發送起始信號和從器件地址信息( R/W 位置1 )給從器件,主器件檢測返回應答位信息;
      • ② 主器件發送數據起始字節地址,主器件檢測返回應答位信息;
      • ③ 主器件再次發送起始信號和從器件地址信息( R/W 位置0 )給從器件,主器件檢測返回應答位信息;
      • ③ E2會向主機返回從"數據起始字節地址"開始的數據,一個字節一個字節地傳輸,主器件每接收完一個字節后,不產生停止信號,主器件響應“應答信號ACK”給E2。只要主器件的響應為"應答信號ACK",E2就會一直傳輸下去,循環此步驟③ n - 1次;
      • ④ 主器件接收最后一個字節后,主器件響應“非應答信號NOACK”給E2,然后主器件產生停止信號;
      • ⑤ 從器件接收到停止信號后,從器件停止傳輸數據,E2 連續讀結束。
      /************************************************ 函數名稱 : EEPROM_ReadSequential 功 能 : EEPROM讀一字節 參 數 : Addr ------ 地址Data ------ 數據Length -----長度 返 回 值 : I2C_ACK --- 應答I2C_NOACK - 非應答 *************************************************/ uint8_t EEPROM_ReadSequential(uint16_t Addr, uint8_t *Data, uint16_t Length) {uint8_t ack;uint8_t i;/* 1.開始信號 */I2C_Start();/* 2.設備地址/寫 */ack = I2C_WriteByte(EEPROM_DEV_ADDR | EEPROM_WR);if(I2C_NOACK == ack){I2C_Stop();return I2C_NOACK;}/* 3.數據地址 */#if (8 == EEPROM_WORD_ADDR_SIZE)ack = I2C_WriteByte((uint8_t)(Addr&0x00FF)); //數據地址(8位)if(I2C_NOACK == ack){I2C_Stop();return I2C_NOACK;}#elseack = I2C_WriteByte((uint8_t)(Addr>>8)); //數據地址(16位)if(I2C_NOACK == ack){I2C_Stop();return I2C_NOACK;}ack = I2C_WriteByte((uint8_t)(Addr&0x00FF));if(I2C_NOACK == ack){I2C_Stop();return I2C_NOACK;}#endif/* 4.重新開始 */I2C_Start();/* 5.設備地址/讀 */ack = I2C_WriteByte(EEPROM_DEV_ADDR | EEPROM_RD);if(I2C_NOACK == ack){I2C_Stop();return I2C_NOACK;}/* 6.讀一字節數據 */for(i = 0; i < Length - 1; i++){*(Data + i) = I2C_ReadByte(I2C_ACK); //只讀取1字節(產生應答)}*(Data + i) = I2C_ReadByte(I2C_NOACK); //只讀取1字節(產生非應答)/* 7.停止信號 */I2C_Stop();return I2C_ACK; }

八、小結

  • 寫的著急,歡迎糾正
  • ☆⌒(*^-゜)v THX!!
  • 碼字不易,記得點小心心 ( ?? ω ?? )?

總結

以上是生活随笔為你收集整理的STM32F10x_模拟I2C读写EEPROM(2)(切换SDA方向 + 读ACK位 + 完整代码)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。