STM32CubeMX學(xué)習(xí)筆記(9)——I2C接口使用(讀寫EEPROM AT24C02)

一、I2C簡(jiǎn)介

I2C(Inter-Integrated Circuit ,內(nèi)部集成電路) 總線是一種由飛利浦 Philip 公司開(kāi)發(fā)的串行總線葛作。是兩條串行的總線闲延,它由一根數(shù)據(jù)線(SDA)和一根 時(shí)鐘線(SCL)組成姆涩。I2C 總線上可以接多個(gè) I2C 設(shè)備,每個(gè)器件都有一個(gè)唯一的地址識(shí)別志膀。同一時(shí)間只能有一個(gè)主設(shè)備,其他為從設(shè)備鳖擒。通常 MCU 作為主設(shè)備控制溉浙,外設(shè)作為從設(shè)備。

STM32 的 I2C 外設(shè)可用作通訊的主機(jī)及從機(jī)蒋荚,支持 100Kbit/s 和 400Kbit/s 的速率戳稽,支持 7 位、10 位設(shè)備地址期升,支持 DMA 數(shù)據(jù)傳輸惊奇,并具有數(shù)據(jù)校驗(yàn)功能。它的 I2C 外設(shè)還支持 SMBus2.0 協(xié)議播赁,SMBus 協(xié)議與 I2C 類似颂郎,主要應(yīng)用于筆記本電腦的電池管理中。

二容为、引腳分布

STM32 芯片有多個(gè) I2C 外設(shè)乓序,它們的 I2C 通訊信號(hào)引出到不同的 GPIO 引腳上,使用時(shí)必須配置到這些指定的引腳坎背。PB8 PB9 為重映射替劈。

三、EEPROM芯片

開(kāi)發(fā)板中的 EEPROM 芯片型號(hào):AT24C02得滤。AT24C 系列為美國(guó) ATMEL 公司推出的串行 COMS 型 EEPROM陨献。芯片型號(hào)后兩位表示芯片容量,例如 ATC24C02 為 2K耿戚。引腳圖中 A0湿故、A1、A2 為器件地址引腳膜蛔,GND為地坛猪,VCC為正電源,WP為寫保護(hù)皂股,SCL為串行時(shí)鐘線墅茉,SDA為串行數(shù)據(jù)線。

EEPROM 芯片中 WP 引腳具有寫保護(hù)功能,當(dāng)該引腳電平為高時(shí)就斤,禁止寫入數(shù)據(jù)悍募,當(dāng)引腳為低電平時(shí),可寫入數(shù)據(jù)洋机,我們直接接地坠宴,不使用寫保護(hù)功能。


AT24Cxx 設(shè)備地址為如下绷旗,前四位固定為 1010喜鼓,A2~A0為由管腳電平?jīng)Q定。AT24Cxx EEPROM Board模塊中默認(rèn)為接地衔肢。A2~A0000庄岖,最后一位 R/W 表示讀寫操作。所以由于 I2C 通訊時(shí)常常是地址跟讀寫方向連在一起構(gòu)成一個(gè) 8 位數(shù)角骤,且當(dāng) R/W 位為 0 時(shí)隅忿,表示寫方向,所以加上 7 位地址邦尊,其值為 0xA0背桐,常稱該值為 I2C 設(shè)備的“寫地址”;當(dāng) R/W 位為 1 時(shí)胳赌,表示讀方向牢撼,加上 7 位地址,其值為 0xA1疑苫,常稱該值為“讀地址”熏版。

四、新建工程

1. 打開(kāi) STM32CubeMX 軟件捍掺,點(diǎn)擊“新建工程”

2. 選擇 MCU 和封裝

3. 配置時(shí)鐘
RCC 設(shè)置撼短,選擇 HSE(外部高速時(shí)鐘) 為 Crystal/Ceramic Resonator(晶振/陶瓷諧振器)


選擇 Clock Configuration,配置系統(tǒng)時(shí)鐘 SYSCLK 為 72MHz
修改 HCLK 的值為 72 后挺勿,輸入回車曲横,軟件會(huì)自動(dòng)修改所有配置

4. 配置調(diào)試模式
非常重要的一步,否則會(huì)造成第一次燒錄程序后續(xù)無(wú)法識(shí)別調(diào)試器
SYS 設(shè)置不瓶,選擇 Debug 為 Serial Wire

五禾嫉、I2C1

5.1 參數(shù)配置

Connectivity 中選擇 I2C1 設(shè)置,并選擇 I2C 內(nèi)部集成電路


I2C 為默認(rèn)設(shè)置不作修改蚊丐。只需注意一下熙参,I2C 為標(biāo)準(zhǔn)模式,I2C 傳輸速率 (I2C Clock Speed) 為 100KHz麦备。

5.2 生成代碼

輸入項(xiàng)目名和項(xiàng)目路徑


選擇應(yīng)用的 IDE 開(kāi)發(fā)環(huán)境 MDK-ARM V5

每個(gè)外設(shè)生成獨(dú)立的 ’.c/.h’ 文件
不勾:所有初始化代碼都生成在 main.c
勾選:初始化代碼生成在對(duì)應(yīng)的外設(shè)文件孽椰。 如 GPIO 初始化代碼生成在 gpio.c 中昭娩。

點(diǎn)擊 GENERATE CODE 生成代碼

5.3 添加全局變量

在 main.c 頭部添加寫地址 0xA0,讀地址 0xA1黍匾,寫緩存區(qū) WriteBuffer栏渺,讀緩存區(qū) ReadBuffer

/* Private variables ---------------------------------------------------------*/
I2C_HandleTypeDef hi2c1;
UART_HandleTypeDef huart1;

/* USER CODE BEGIN PV */
#define ADDR_24LCxx_Write 0xA0
#define ADDR_24LCxx_Read 0xA1
#define BufferSize 256
uint8_t WriteBuffer[BufferSize] = {0};
uint8_t ReadBuffer[BufferSize] = {0};
/* USER CODE END PV */

5.4 添加寫入和讀取函數(shù)

/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{
  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_USART1_UART_Init();
  MX_I2C1_Init();
  /* USER CODE BEGIN 2 */
  printf("\r\n***************I2C Example*******************************\r\n");
  uint32_t i;
  uint8_t j;
  for(i = 0; i < 256; i++)
  {
    WriteBuffer[i] = i;    /* WriteBuffer init */
    printf("0x%02X ", WriteBuffer[i]);
    if(i % 16 == 15)
    {    
      printf("\n\r");
    }
  }
  /* wrinte date to EEPROM */
  for (j = 0; j < 32; j++)
  {
    if(HAL_I2C_Mem_Write(&hi2c1, ADDR_24LCxx_Write, 8*j, I2C_MEMADD_SIZE_8BIT, WriteBuffer+8*j, 8, 100) == HAL_OK)
    {
      printf("\r\n EEPROM 24C02 Write Test OK \r\n");
    }
    else
    {
      printf("\r\n EEPROM 24C02 Write Test False \r\n");
    }
  } 
  /* read date from EEPROM */
  HAL_I2C_Mem_Read(&hi2c1, ADDR_24LCxx_Read, 0, I2C_MEMADD_SIZE_8BIT, ReadBuffer, BufferSize, 1000);
  for(i = 0; i < 256; i++)
  {
    printf("0x%02X  ",ReadBuffer[i]);
    if(i%16 == 15)    
    {
      printf("\n\r");
    }
  }
    
  if(memcmp(WriteBuffer,ReadBuffer,BufferSize) == 0 ) /* check date */
  {
    printf("\r\n EEPROM 24C02 Read Test OK\r\n");
  }
  else
  {
    printf("\r\n EEPROM 24C02 Read Test False\r\n");
  }

  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

程序中先初始化寫數(shù)據(jù)緩存锐涯。然后調(diào)用 HAL_I2C_Mem_Write() 函數(shù)將數(shù)據(jù)寫入 EEPROM 中磕诊。根據(jù)函數(shù)返回值判斷寫操作是否正確。在 I2C 中可以找到內(nèi)存寫函數(shù)說(shuō)明纹腌。

  • 第一個(gè)參數(shù)為 I2C 操作句柄秀仲。
  • 第二個(gè)參數(shù)為 EEPROM 的寫操作設(shè)備地址。
  • 第三個(gè)參數(shù)為內(nèi)存地址壶笼。
  • 第四個(gè)參數(shù)為內(nèi)存地址長(zhǎng)度,EEPROM 內(nèi)存長(zhǎng)度為 8bit雁刷。
  • 第五個(gè)參數(shù)為數(shù)據(jù)緩存的起始地址覆劈。
  • 第六個(gè)參數(shù)為傳輸數(shù)據(jù)的大小。AT24C02 型號(hào)的芯片頁(yè)寫入時(shí)序最多可以一次 發(fā)送 8 個(gè)數(shù)據(jù)(即 n = 8 )沛励,該值也稱為頁(yè)大小责语,某些型號(hào)的芯片每個(gè)頁(yè)寫入時(shí)序最多可傳輸 16 個(gè)數(shù)據(jù)。
  • 第七個(gè)參數(shù)為操作超時(shí)時(shí)間目派。
/**
  * @brief  Write an amount of data in blocking mode to a specific memory address
  * @param  hi2c Pointer to a I2C_HandleTypeDef structure that contains
  *                the configuration information for the specified I2C.
  * @param  DevAddress Target device address: The device 7 bits address value
  *         in datasheet must be shifted to the left before calling the interface
  * @param  MemAddress Internal memory address
  * @param  MemAddSize Size of internal memory address
  * @param  pData Pointer to data buffer
  * @param  Size Amount of data to be sent
  * @param  Timeout Timeout duration
  * @retval HAL status
  */
HAL_StatusTypeDef HAL_I2C_Mem_Write(I2C_HandleTypeDef *hi2c, uint16_t DevAddress,
                                    uint16_t MemAddress, uint16_t MemAddSize,
                                    uint8_t *pData, uint16_t Size, uint32_t Timeout)


調(diào)用 HAL_I2C_Mem_Read() 函數(shù)讀取 EEPROM 中剛才寫入的數(shù)據(jù)坤候。HAL_I2C_Mem_Read() 函數(shù)描述如下。

  • 第一個(gè)參數(shù)為 I2C 操作句柄企蹭。
  • 第二個(gè)參數(shù)為 EEPROM 的讀操作設(shè)備地址白筹。
  • 第三個(gè)參數(shù)為內(nèi)存地址。
  • 第四個(gè)參數(shù)為內(nèi)存地址長(zhǎng)度谅摄。
  • 第五個(gè)參數(shù)為讀取數(shù)據(jù)存儲(chǔ)的起始地址徒河。
  • 第六個(gè)參數(shù)為傳輸數(shù)據(jù)的大小。
  • 第七個(gè)參數(shù)為操作超時(shí)時(shí)間送漠。
/**
  * @brief  Read an amount of data in blocking mode from a specific memory address
  * @param  hi2c Pointer to a I2C_HandleTypeDef structure that contains
  *                the configuration information for the specified I2C.
  * @param  DevAddress Target device address: The device 7 bits address value
  *         in datasheet must be shifted to the left before calling the interface
  * @param  MemAddress Internal memory address
  * @param  MemAddSize Size of internal memory address
  * @param  pData Pointer to data buffer
  * @param  Size Amount of data to be sent
  * @param  Timeout Timeout duration
  * @retval HAL status
  */
HAL_StatusTypeDef HAL_I2C_Mem_Read(I2C_HandleTypeDef *hi2c, uint16_t DevAddress,
                                  uint16_t MemAddress, uint16_t MemAddSize, 
                                  uint8_t *pData, uint16_t Size, uint32_t Timeout)

程序最后調(diào)用 memcmp() 函數(shù)判斷讀寫的兩個(gè)緩存的數(shù)據(jù)是否一致顽照。memcmp() 是比較內(nèi)存區(qū)域是否相等,標(biāo)準(zhǔn)庫(kù)里面的函數(shù)闽寡,在 main.c 前面添加 string.h 頭文件代兵。

5.5 查看打印

串口打印功能查看 STM32CubeMX學(xué)習(xí)筆記(6)——USART串口使用


5.6 HAL庫(kù)與標(biāo)準(zhǔn)庫(kù)代碼比較

STM32CubeMX 使用 HAL 庫(kù)生成的代碼:

/**
  * @brief I2C1 Initialization Function
  * @param None
  * @retval None
  */
static void MX_I2C1_Init(void)
{

  /* USER CODE BEGIN I2C1_Init 0 */

  /* USER CODE END I2C1_Init 0 */

  /* USER CODE BEGIN I2C1_Init 1 */

  /* USER CODE END I2C1_Init 1 */
  hi2c1.Instance = I2C1;
  hi2c1.Init.ClockSpeed = 100000;
  hi2c1.Init.DutyCycle = I2C_DUTYCYCLE_2;
  hi2c1.Init.OwnAddress1 = 0;
  hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
  hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
  hi2c1.Init.OwnAddress2 = 0;
  hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
  hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
  if (HAL_I2C_Init(&hi2c1) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN I2C1_Init 2 */

  /* USER CODE END I2C1_Init 2 */
}

HAL_StatusTypeDef HAL_I2C_Mem_Write(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint16_t MemAddress, uint16_t MemAddSize, uint8_t *pData, uint16_t Size, uint32_t Timeout);
HAL_StatusTypeDef HAL_I2C_Mem_Read(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint16_t MemAddress, uint16_t MemAddSize, uint8_t *pData, uint16_t Size, uint32_t Timeout);

使用 STM32 標(biāo)準(zhǔn)庫(kù)的代碼:

/**
  * @brief  I2C I/O配置
  * @param  無(wú)
  * @retval 無(wú)
  */
static void I2C_GPIO_Config(void)
{
  GPIO_InitTypeDef  GPIO_InitStructure; 

    /* 使能與 I2C 有關(guān)的時(shí)鐘 */
    EEPROM_I2C_APBxClock_FUN ( EEPROM_I2C_CLK, ENABLE );
    EEPROM_I2C_GPIO_APBxClock_FUN ( EEPROM_I2C_GPIO_CLK, ENABLE );
    
    
  /* I2C_SCL、I2C_SDA*/
  GPIO_InitStructure.GPIO_Pin = EEPROM_I2C_SCL_PIN;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;          // 開(kāi)漏輸出
  GPIO_Init(EEPROM_I2C_SCL_PORT, &GPIO_InitStructure);
    
  GPIO_InitStructure.GPIO_Pin = EEPROM_I2C_SDA_PIN;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;          // 開(kāi)漏輸出
  GPIO_Init(EEPROM_I2C_SDA_PORT, &GPIO_InitStructure);      
}

/**
  * @brief  I2C 工作模式配置
  * @param  無(wú)
  * @retval 無(wú)
  */
static void I2C_Mode_Config(void)
{
  I2C_InitTypeDef  I2C_InitStructure; 

  /* I2C 配置 */
  I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;
    
    /* 高電平數(shù)據(jù)穩(wěn)定爷狈,低電平數(shù)據(jù)變化 SCL 時(shí)鐘線的占空比 */
  I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;
    
  I2C_InitStructure.I2C_OwnAddress1 =I2Cx_OWN_ADDRESS7; 
  I2C_InitStructure.I2C_Ack = I2C_Ack_Enable ;
     
    /* I2C的尋址模式 */
  I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
    
    /* 通信速率 */
  I2C_InitStructure.I2C_ClockSpeed = I2C_Speed;
  
    /* I2C 初始化 */
  I2C_Init(EEPROM_I2Cx, &I2C_InitStructure);
  
    /* 使能 I2C */
  I2C_Cmd(EEPROM_I2Cx, ENABLE);   
}

void I2C_Send7bitAddress(I2C_TypeDef* I2Cx, uint8_t Address, uint8_t I2C_Direction);
void I2C_SendData(I2C_TypeDef* I2Cx, uint8_t Data);
uint8_t I2C_ReceiveData(I2C_TypeDef* I2Cx);

六植影、注意事項(xiàng)

用戶代碼要加在 USER CODE BEGIN NUSER CODE END N 之間,否則下次使用 STM32CubeMX 重新生成代碼后淆院,會(huì)被刪除何乎。


? 由 Leung 寫于 2021 年 1 月 26 日

? 參考:STM32CubeMX系列教程9:內(nèi)部集成電路(I2C)
    【STM32Cube_13】使用硬件I2C讀寫EEPROM(AT24C02)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末句惯,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子支救,更是在濱河造成了極大的恐慌抢野,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,729評(píng)論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件各墨,死亡現(xiàn)場(chǎng)離奇詭異指孤,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)贬堵,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,226評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門恃轩,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人黎做,你說(shuō)我怎么就攤上這事叉跛。” “怎么了蒸殿?”我有些...
    開(kāi)封第一講書人閱讀 169,461評(píng)論 0 362
  • 文/不壞的土叔 我叫張陵筷厘,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我宏所,道長(zhǎng)酥艳,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書人閱讀 60,135評(píng)論 1 300
  • 正文 為了忘掉前任爬骤,我火速辦了婚禮充石,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘霞玄。我一直安慰自己骤铃,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,130評(píng)論 6 398
  • 文/花漫 我一把揭開(kāi)白布坷剧。 她就那樣靜靜地躺著劲厌,像睡著了一般。 火紅的嫁衣襯著肌膚如雪听隐。 梳的紋絲不亂的頭發(fā)上补鼻,一...
    開(kāi)封第一講書人閱讀 52,736評(píng)論 1 312
  • 那天,我揣著相機(jī)與錄音雅任,去河邊找鬼风范。 笑死,一個(gè)胖子當(dāng)著我的面吹牛沪么,可吹牛的內(nèi)容都是我干的硼婿。 我是一名探鬼主播,決...
    沈念sama閱讀 41,179評(píng)論 3 422
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼禽车,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼寇漫!你這毒婦竟也來(lái)了刊殉?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書人閱讀 40,124評(píng)論 0 277
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤州胳,失蹤者是張志新(化名)和其女友劉穎记焊,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體栓撞,經(jīng)...
    沈念sama閱讀 46,657評(píng)論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡遍膜,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,723評(píng)論 3 342
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了瓤湘。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片瓢颅。...
    茶點(diǎn)故事閱讀 40,872評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖弛说,靈堂內(nèi)的尸體忽然破棺而出挽懦,到底是詐尸還是另有隱情,我是刑警寧澤木人,帶...
    沈念sama閱讀 36,533評(píng)論 5 351
  • 正文 年R本政府宣布巾兆,位于F島的核電站,受9級(jí)特大地震影響虎囚,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜蔫磨,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,213評(píng)論 3 336
  • 文/蒙蒙 一淘讥、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧堤如,春花似錦蒲列、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 32,700評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)诲宇。三九已至密浑,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間绑雄,已是汗流浹背唧取。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 33,819評(píng)論 1 274
  • 我被黑心中介騙來(lái)泰國(guó)打工铅鲤, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人枫弟。 一個(gè)月前我還...
    沈念sama閱讀 49,304評(píng)論 3 379
  • 正文 我出身青樓邢享,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親淡诗。 傳聞我的和親對(duì)象是個(gè)殘疾皇子骇塘,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,876評(píng)論 2 361

推薦閱讀更多精彩內(nèi)容