加入星計劃,您可以享受以下權(quán)益:

  • 創(chuàng)作內(nèi)容快速變現(xiàn)
  • 行業(yè)影響力擴散
  • 作品版權(quán)保護(hù)
  • 300W+ 專業(yè)用戶
  • 1.5W+ 優(yōu)質(zhì)創(chuàng)作者
  • 5000+ 長期合作伙伴
立即加入
  • 正文
    • 1 硬件連接
    • 2 軟件編程
    • 3 運行測試
  • 推薦器件
  • 相關(guān)推薦
  • 電子產(chǎn)業(yè)圖譜
申請入駐 產(chǎn)業(yè)圖譜

STM32設(shè)置為I2C從機模式

04/09 10:25
8099
閱讀需 16 分鐘
加入交流群
掃碼加入
獲取工程師必備禮包
參與熱點資訊討論

STM32的I2C作為主機的情況相信很多同學(xué)都用過,網(wǎng)上也有很多教程,但是作為從設(shè)備使用的例子應(yīng)該不多,本文通過硬件軟件的層面,介紹如何把STM32設(shè)置為一個I2C從機。

1 硬件連接

測試芯片STM32F103ZET6

測試方法:用一個USB轉(zhuǎn)I2C的工具接到STM32的I2C引腳上,通過上位機工具進(jìn)行讀寫操作。如果沒有這個工具,也可以用另外一個stm32或者其他設(shè)備測試通訊,同時也可以借助示波器或者邏輯分析儀來輔助調(diào)試。

硬件連接:

STM32這邊使用硬件I2C1(PB6、PB7),并外接上拉電阻

在這里插入圖片描述
在這里插入圖片描述

2 軟件編程

根據(jù)STM32數(shù)據(jù)參考手冊,I2C作為從設(shè)備時發(fā)送和接收的流程如下:

在這里插入圖片描述
在這里插入圖片描述

測試?yán)蹋憾x一個256字節(jié)的buffer用來存放I2C從機的數(shù)據(jù),默認(rèn)賦初值0-255,然后通過中斷的方式實現(xiàn)I2C數(shù)據(jù)讀寫。

示例代碼如下:

#include "stm32f10x.h"
#include "stm32f10x_gpio.h"
#include "stm32f10x_rcc.h"
#include "stm32f10x_i2c.h"
#include "misc.h"

#define I2CSLAVE_ADDR           0x40 << 1  // address is 0x40

#define I2C1_CLOCK_FRQ          100000     // I2C-Frq in Hz (100 kHz)
#define I2C1_RAM_SIZE           256        // RAM Size in Byte

#define I2C1_MODE_WAITING       0          // Waiting for commands
#define I2C1_MODE_SLAVE_ADR_WR  1          // Received slave address (writing)
#define I2C1_MODE_ADR_BYTE      2          // Received ADR byte
#define I2C1_MODE_DATA_BYTE_WR  3          // Data byte (writing)
#define I2C1_MODE_SLAVE_ADR_RD  4          // Received slave address (to read)
#define I2C1_MODE_DATA_BYTE_RD  5          // Data byte (to read)

uint8_t i2c1_mode = I2C1_MODE_WAITING;
uint8_t i2c1_ram_adr = 0;
uint8_t i2c1_ram[I2C1_RAM_SIZE];

uint8_t Get_I2C1_Ram(uint8_t adr) 
{
    return i2c1_ram[adr];
}

void Set_I2C1_Ram(uint8_t adr, uint8_t val) 
{
    i2c1_ram[adr] = val;
    return;
}

void I2C1_Ram_Init(void) 
{
    uint16_t i;
    for (i = 0; i < 256; i++)
    {
        Set_I2C1_Ram(i, i);
    }
}

void I2C1_Slave_Init(void) 
{
    GPIO_InitTypeDef  GPIO_InitStructure;
    NVIC_InitTypeDef NVIC_InitStructure;
    I2C_InitTypeDef  I2C_InitStructure;

    RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);

    /* Configure I2C_EE pins: SCL and SDA */
    GPIO_InitStructure.GPIO_Pin =  GPIO_Pin_6 | GPIO_Pin_7;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;
    GPIO_Init(GPIOB, &GPIO_InitStructure);

    /* Configure the I2C event priority */
    NVIC_InitStructure.NVIC_IRQChannel                   = I2C1_EV_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority        = 0;
    NVIC_InitStructure.NVIC_IRQChannelCmd                = ENABLE;
    NVIC_Init(&NVIC_InitStructure);

    /* Configure I2C error interrupt to have the higher priority */
    NVIC_InitStructure.NVIC_IRQChannel = I2C1_ER_IRQn;
    NVIC_Init(&NVIC_InitStructure);

    /* I2C configuration */
    I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;
    I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;
    I2C_InitStructure.I2C_OwnAddress1 = I2CSLAVE_ADDR;
    I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;
    I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
    I2C_InitStructure.I2C_ClockSpeed = I2C1_CLOCK_FRQ;

    /* I2C Peripheral Enable */
    I2C_Cmd(I2C1, ENABLE);

    /* Apply I2C configuration after enabling it */
    I2C_Init(I2C1, &I2C_InitStructure);

    I2C_ITConfig(I2C1, I2C_IT_EVT, ENABLE); //Part of the STM32 I2C driver
    I2C_ITConfig(I2C1, I2C_IT_BUF, ENABLE);
    I2C_ITConfig(I2C1, I2C_IT_ERR, ENABLE); //Part of the STM32 I2C driver

    I2C1_Ram_Init();
}

void I2C1_ClearFlag(void) 
{
    /* ADDR Flag clear */
    while((I2C1->SR1 & I2C_SR1_ADDR) == I2C_SR1_ADDR) 
    {
        I2C1->SR1;
        I2C1->SR2;
    }

    /* STOPF Flag clear */
    while((I2C1->SR1&I2C_SR1_STOPF) == I2C_SR1_STOPF) 
    {
        I2C1->SR1;
        I2C1->CR1 |= 0x1;
    }
}

void I2C1_EV_IRQHandler(void) 
{
    uint8_t wert;
    uint32_t event;

    /* Reading last event */
    event = I2C_GetLastEvent(I2C1);

    /* Event handle */
    if(event == I2C_EVENT_SLAVE_RECEIVER_ADDRESS_MATCHED) 
    {
        // Master has sent the slave address to send data to the slave
        i2c1_mode = I2C1_MODE_SLAVE_ADR_WR;
    }
    else if(event == I2C_EVENT_SLAVE_BYTE_RECEIVED) 
    {
        // Master has sent a byte to the slave
        wert = I2C_ReceiveData(I2C1);
        // Check address
        if(i2c1_mode == I2C1_MODE_SLAVE_ADR_WR) 
        {
            i2c1_mode = I2C1_MODE_ADR_BYTE;
            // Set current ram address
            i2c1_ram_adr = wert;
        }
        else 
        {
            i2c1_mode = I2C1_MODE_DATA_BYTE_WR;
            // Store data in RAM
            Set_I2C1_Ram(i2c1_ram_adr, wert);
            // Next ram adress
            i2c1_ram_adr++;
        }
    }
    else if(event == I2C_EVENT_SLAVE_TRANSMITTER_ADDRESS_MATCHED) 
    {
        // Master has sent the slave address to read data from the slave
        i2c1_mode = I2C1_MODE_SLAVE_ADR_RD;
        // Read data from RAM
        wert = Get_I2C1_Ram(i2c1_ram_adr);
        // Send data to the master
        I2C_SendData(I2C1, wert);
        // Next ram adress
        i2c1_ram_adr++;
    }
    else if(event == I2C_EVENT_SLAVE_BYTE_TRANSMITTED) 
    {
        // Master wants to read another byte of data from the slave
        i2c1_mode = I2C1_MODE_DATA_BYTE_RD;
        // Read data from RAM
        wert = Get_I2C1_Ram(i2c1_ram_adr);
        // Send data to the master
        I2C_SendData(I2C1, wert);
        // Next ram adress
        i2c1_ram_adr++;
    }
    else if(event == I2C_EVENT_SLAVE_STOP_DETECTED) 
    {
        // Master has STOP sent
        I2C1_ClearFlag();
        i2c1_mode = I2C1_MODE_WAITING;
    }
}

void I2C1_ER_IRQHandler(void) 
{
    if (I2C_GetITStatus(I2C1, I2C_IT_AF)) 
    {
        I2C_ClearITPendingBit(I2C1, I2C_IT_AF);
    }
}

3 運行測試

3.1 I2C連續(xù)寫入

通過上位機工具寫入:

請?zhí)砑訄D片描述

通過邏輯分析儀抓取波形:

請?zhí)砑訄D片描述

3.2 I2C連續(xù)讀取

通過上位機工具連續(xù)讀取256字節(jié):

在這里插入圖片描述

通過邏輯分析儀抓取波形:

在這里插入圖片描述

在這里插入圖片描述

3.3 I2C單次讀寫測試

通過上位機工具讀取原值,再寫入新值,最后再讀取新值:

請?zhí)砑訄D片描述

通過邏輯分析儀抓取波形:

請?zhí)砑訄D片描述

4 總結(jié)

通過上位機工具的測試以及邏輯分析儀的解析,STM32的硬件I2C從機通信正常且穩(wěn)定,讀寫速度測試了100k和400k,沒有發(fā)現(xiàn)問題,至此測試完成。

好了,關(guān)于STM32如何設(shè)置從機模式就介紹到這里,如果你們有什么問題,歡迎評論區(qū)留言。

需要完整源碼工程的同學(xué)可以自行下載:源碼下載地址 https://download.csdn.net/download/ShenZhen_zixian/87950363

另外還有一篇HAL庫版本的博客:STM32設(shè)置為I2C從機模式(HAL庫版本)

如果這篇文章能夠幫到你,就…懂的。

推薦器件

更多器件
器件型號 數(shù)量 器件廠商 器件描述 數(shù)據(jù)手冊 ECAD模型 風(fēng)險等級 參考價格 更多信息
XRCGB25M000F3A00R0 1 Murata Manufacturing Co Ltd Parallel - Fundamental Quartz Crystal, 25MHz Nom, ROHS AND REACH COMPLIANT, SMALL, SMD, 3 PIN

ECAD模型

下載ECAD模型
$0.34 查看
M25P05-AVMN6P 1 Rochester Electronics LLC 64KX8 FLASH 2.7V PROM, PDSO8, 0.150 INCH, ROHS COMPLIANT, PLASTIC, SOP-8
$0.79 查看
S29GL256P10FFI020 1 AMD Flash, 16MX16, 100ns, PBGA64,
$9.29 查看

相關(guān)推薦

電子產(chǎn)業(yè)圖譜