STM32设置为I2C从机模式

news2024/9/25 23:13:37

STM32设置为I2C从机模式

目录

  • STM32设置为I2C从机模式
    • 前言
    • 1 硬件连接
    • 2 软件编程
    • 3 运行测试
      • 3.1 I2C连续写入
      • 3.1 I2C连续读取
      • 3.1 I2C单次读写测试
    • 4 总结

前言

STM32的I2C作为主机的情况相信很多同学都用过,网上也有很多教程,但是作为从设备使用的例子应该不多,本文通过硬件和软件的层面,介绍如何把STM32设置为一个I2C从机。

1 硬件连接

测试芯片:STM32F103ZET6
测试方法:用一个USB转I2C的工具接到STM32的I2C引脚上,通过上位机工具进行读写操作。如果没有这个工具,也可以用另外一个stm32或者其他设备测试通讯,同时也可以借助示波器或者逻辑分析仪来辅助调试。
硬件连接:
STM32这边使用硬件I2C1(PB6、PB7),并外接上拉电阻。
在这里插入图片描述
在这里插入图片描述

2 软件编程

根据STM32数据参考手册,I2C作为从设备时发送和接收的流程如下:
在这里插入图片描述
在这里插入图片描述

测试例程:定义一个256字节的buffer用来存放I2C从机的数据,默认赋初值0-255,然后通过中断的方式实现I2C数据读写。
示例代码如下:

#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连续写入

通过上位机工具写入:
请添加图片描述

通过逻辑分析仪抓取波形:
请添加图片描述

3.1 I2C连续读取

通过上位机工具连续读取256字节:
在这里插入图片描述

通过逻辑分析仪抓取波形:
在这里插入图片描述

在这里插入图片描述

3.1 I2C单次读写测试

通过上位机工具读取原值,再写入新值,最后再读取新值:
请添加图片描述

通过逻辑分析仪抓取波形:
请添加图片描述

4 总结

通过上位机工具的测试以及逻辑分析仪的解析,STM32的硬件I2C从机通信正常且稳定,读写速度测试了100k和400k,没有发现问题,至此测试完成。
好了,关于STM32如何设置从机模式就介绍到这里,如果你们有什么问题,欢迎评论区留言。

需要完整源码工程的同学可以自行下载:https://download.csdn.net/download/ShenZhen_zixian/87950363

如果这篇文章能够帮到你,就…懂的。
请添加图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/688862.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【C++ 程序设计】第 9 章:函数模板与类模板

目录 一、函数模板 &#xff08;1&#xff09;函数模板的概念 &#xff08;2&#xff09;函数模板的示例 &#xff08;3&#xff09;函数或函数模板调用语句的匹配顺序 二、类模板 &#xff08;1&#xff09;类模板概念 &#xff08;2&#xff09;类模板示例 &…

阵列模式综合第三部分:深度学习(附源码)

一、前言 这个例子展示了如何设计和训练卷积神经网络&#xff08;CNN&#xff09;来计算产生所需模式的元素权重。 二、介绍 模式合成是阵列处理中的一个重要课题。阵列权重有助于塑造传感器阵列的波束图案&#xff0c;以匹配所需图案。传统上&#xff0c;由于空间信号处理和频…

SSL工作原理

SSL 是一个安全协议&#xff0c;它提供使用 TCP/IP 的通信应用程序间的隐私与完整性。因特网的 超文本传输协议&#xff08;HTTP&#xff09;使用 SSL 来实现安全的通信。 在客户端与服务器间传输的数据是通过使用对称算法&#xff08;如 DES 或 RC4&#xff09;进行加密的。公…

使用ZenDAS进行Gompertz趋势分析

某项目做了18次测试&#xff0c;每次测试发现的缺陷个数如下表所示&#xff1a; 测试序号 发现缺陷数 1 60 2 96 3 157 4 191 5 155 6 106 7 64 8 335 9 92 10 196 11 109 12 133 13 166 14 129 15 16 16 30 17 19 18 5 对上述的数据在Z…

IPv6手工隧道配置与验证实验

IPv6手工隧道配置与验证实验 【实验目的】 熟悉IPv6手工隧道的概念。 掌握IPv6和IPv4共存的实现方法。 掌握IPv6手工隧道的配置。 验证配置。 【实验拓扑】 实验拓扑如下图所示。 实验拓扑 设备参数如表所示。 设备参数表 设备 接口 IPv6地址 子网掩码位数 默认网…

中间件-netty(1)

netty 前言篇 文章目录 一、IO基础篇1.概念1.1 阻塞(Block)和非阻塞(Non-Block)1.2 同步(Synchronization)和异步(Asynchronous)1.3 BIO 与 NIO 对比1.3.1 面向流与面向缓冲1.3.2 阻塞与非阻塞1.3.3 选择器的问世 2.NIO 和 BIO 如何影响应用程序的设计2.1 API调用2.2 数据处理2…

蓝桥杯专题-试题版-【操作格子】【查找整数】【分解质因数】【高精度加法】

点击跳转专栏>Unity3D特效百例点击跳转专栏>案例项目实战源码点击跳转专栏>游戏脚本-辅助自动化点击跳转专栏>Android控件全解手册点击跳转专栏>Scratch编程案例点击跳转>软考全系列点击跳转>蓝桥系列 &#x1f449;关于作者 专注于Android/Unity和各种游…

Spring FrameWork从入门到NB -三级缓存解决循环依赖内幕 (二)

开始用上一篇文章讲到的Spring依赖注入的步骤&#xff0c;用两个例子来推导一下整个过程&#xff0c;举例子有助于了解真相。 先用一个最简单的例子&#xff1a;没有依赖的单例bean的创建。 推导过程是需要上一篇文章的步骤的&#xff0c;要参照步骤一步一步来。 无依赖的单…

Linux内核代码60%都是驱动?驱动代码不会造成内核臃肿吗?

为什么内核中驱动占比最高 一、前言二、Linux中避免内核臃肿的措施2.1 交叉编译及SDK包的裁剪2.2 设备树2.3 模块化2.4 硬件抽象层 三、嵌入式Linux的裁剪四、总结 一、前言 今天逛知乎看到这么一个问题&#xff1a;为什么Linux内核代码60%都是驱动? 如果每支持新的设备就加入…

【设计模式】Java设计模式——模板方法模式(Template Pattern)

文章目录 1. 介绍1.1 定义1.2 作用 2. 模式结构2.1 UML类图2.2 模式组成 3. 代码实例3.1 背景3.2 应用 4. 优点5. 缺点6. 应用场景 1. 介绍 1.1 定义 模板方法模式(Template Pattern)&#xff0c;又叫模板模式&#xff0c;它属于行为型模式模板方法模式定义一个模板结构&…

Apikit 自学日记:版本管理

功能入口&#xff1a;API管理应用 / 选中某个项目 / 项目管理菜单 / 项目版本管理 项目版本管理功能模块提供对项目级别的版本管理&#xff0c;可新增、删除、对比项目级版本。在创建项目版本号的时候会对整个项目的部分模块数据进行快照保存。可用于每次迭代发布打全局版本号…

ESP32设备驱动-TMF8801激光测距传感器驱动

TMF8801激光测距传感器驱动 文章目录 TMF8801激光测距传感器驱动1、TMF8801介绍2、硬件准备3、软件准备4、驱动实现1、TMF8801介绍 TMF8801 是一款真正的直接飞行时间 (ToF) 传感器系统,采用单一模块化封装,通过亚纳秒光脉冲和抗锯齿“秒表”方法测量往返时间,提供高精度深度…

流量分析工具wireshark-学习笔记

&#xff08;一&#xff09;wireshark工具 1、wireshark工具简介 Wireshark是一种开源网络分析工具&#xff0c;它可以让你在计算机网络上捕获和查看数据包&#xff0c;并能帮助你深入了解网络的运行和协议的实现。它可以捕获不同类型的流量&#xff0c;包括以太网、Wi-Fi、TC…

【面试题】面试官问:如果有100个请求,你如何使用Promise控制并发?

大厂面试题分享 面试题库 前后端面试题库 &#xff08;面试必备&#xff09; 推荐&#xff1a;★★★★★ 地址&#xff1a;前端面试题库 web前端面试题库 VS java后端面试题库大全 开篇 在现代Web开发中&#xff0c;异步请求已经成为了必不可少的一部分。然而&#xff0c;…

ISP之图像降分辨率

1、图像缩放背景 图像的放大、缩小(简称缩放)是图像处理的一种处理方法。所谓图像缩放是指图像分辨率的改变&#xff0c;它在图像显示、传输、图像分析以及动画制作、电影合成、甚至医学图像处理中都有着相当广泛的应用。比如要在1024 X 768 分辨率的显示器上全屏显示800 X 60…

8.2 电压比较器(2)

五、集成电压比较器 1、集成电压比较器的主要特点和分类 电压比较器可将模拟信号转换成二值信号&#xff0c;即只有高电平和低电平两种状态的离散信号。因此&#xff0c;可用电压比较器作为模拟电路和数字电路的接口电路。集成电压比较器虽然比集成运放的开环增益低&#xff…

强化学习从基础到进阶-案例与实践[6]:演员-评论员算法(advantage actor-critic,A2C),异步A2C、与生成对抗网络的联系等详解

【强化学习原理项目专栏】必看系列&#xff1a;单智能体、多智能体算法原理项目实战、相关技巧&#xff08;调参、画图等、趣味项目实现、学术应用项目实现 专栏详细介绍&#xff1a;【强化学习原理项目专栏】必看系列&#xff1a;单智能体、多智能体算法原理项目实战、相关技巧…

Arcmap读取nc文件并导出为tif格式

Arcmap读取nc文件并导出为tif格式 前言操作步骤 前言 在使用某一降水数据的时候&#xff0c;发现直接把nc格式的数据拖进Arcmap&#xff0c;查看属性表的时候是空的&#xff0c;点击图上的信息也只会显示一个值&#xff0c;但这个nc数据应该是有很多个值的&#xff08;我的数据…

Kubernetes - adm搭建 · 保姆级教程

master&#xff08;2C/4G&#xff0c;cpu核心数要求大于2&#xff09; 192.168.179.25 docker、kubeadm、kubelet、kubectl、flannel node01&#xff08;2C/2G&#xff09; 192.168.179.26 docker、kubeadm、kubelet、kubectl…

【JavaScript】JavaScript中的nodeName、nodeType、nodeValue区别

文章目录 JavaScript中的nodeName、nodeType、nodeValue区别(一)nodeName(二)nodeValue(三)nodeType JS代码demo JavaScript中的nodeName、nodeType、nodeValue区别 (一)nodeName https://www.w3schools.cn/jsref/prop_node_nodename.html 元素节点的 nodeName是标签名称 属性…