Pico如何使用C/C++选择哪个I2C控制器,以及SDA和SCL针脚
本文一开始讲述了解决方案,后面是我做的笔记,用来讲述我的发现流程和探究的 Pico I2C 代码结构。
前提知识
首先要说明一点:Pico 有两个 I2C,也就是两套 SDA 和 SCL。这点你可以在针脚图中名字看出,比如下图的 Pin 4 和 Pin 5是 I2C1 的,而默认的 Pin 6 和 Pin 7 是 I2C0 的。
默认情况下是只开启了第一个 I2C,也就是只有 I2C0 的针脚是可以使用的。如果这种情况下,你哪怕修改了针脚,但不是 I2C0 的,也是不会正常运行的。
如何选择哪个I2C控制器,以及SDA和SCL针脚
在设置之前声明三个变量或宏来方便开发。建议使用宏,这比较符合树莓派的开发风格:
#define I2C i2c0
#define I2C_SDA_PIN 4
#define I2C_SCL_PIN 5
如果宏扩展出错,那么就使用变量。
然后初始化 I2C 的时候来设置使用哪个 I2C 控制器,以及哪个SDA和SCL针脚。下面是设置根据上面的设置,这里使用的是第一个 I2C 控制器,SDA 使用的是 GP4,SCL 使用的是 GP5,频率为1000000
:
i2c_init(I2C, 1000000);
gpio_set_function(I2C_SDA_PIN, GPIO_FUNC_I2C);
gpio_set_function(I2C_SCL_PIN, GPIO_FUNC_I2C);
gpio_pull_up(I2C_SDA_PIN);
gpio_pull_up(I2C_SCL_PIN);
由于有两个 I2C 控制器,那么可以同时使用两套SDA
和SCL
针脚,但是要注意必须是I2C0
和I2C1
的针脚,不能是同一个控制器的。
发现历程(选读)
这部分不一定要看。这里记录一下我是怎么知道是这样处理的,顺道了解了一下代码结构和信息传递的流程,万一以后需要就不用花时间翻来翻去了。
第一次尝试
首先分析一下:要定义针脚就要知道针脚这个值是如何被利用的,这样就可以知道如何传递处理这个值了。
一般是在初始化的时候设置使用哪个I2C控制器以及SDA和SCL针脚,代码一般如下:
i2c_init(i2c_default, CLK);
gpio_set_function(PICO_DEFAULT_I2C_SDA_PIN, GPIO_FUNC_I2C);
gpio_set_function(PICO_DEFAULT_I2C_SCL_PIN, GPIO_FUNC_I2C);
gpio_pull_up(PICO_DEFAULT_I2C_SDA_PIN);
gpio_pull_up(PICO_DEFAULT_I2C_SCL_PIN);
研究《用C/C++修改I2C默认的SDA和SCL针脚》的时候,我知道了默认针脚是在pico.h
中配置的的,相关值有三个:PICO_DEFAULT_I2C
、PICO_DEFAULT_I2C_SDA_PIN
和PICO_DEFAULT_I2C_SCL_PIN
,那么只要追溯这三个值就行。
但是这样不好找,引用太多了。所以我就尝试了从另一方面先入手:I2C 是通过i2c_init()
函数初始化的,如下:
i2c_init(i2c_default, SSD1306_I2C_CLK);
我需要的只有第一个参数i2c_default
,因为这个参数传递了一些信息,第二个参数uint baudrate
是传递速率的,和针脚无关。
那么i2c_init()
函数的内容是什么呢?知道这个才能知道i2c_default
的类型是什么结构,以及内部进行了什么处理。
i2c_init()
函数声明在pico-sdk/src/rp2_common/hardware_i2c/i2c.c
中,函数参数列表如下:
uint i2c_init(i2c_inst_t *i2c, uint baudrate) {i2c_reset(i2c);i2c_unreset(i2c);i2c->restart_on_next = false;i2c->hw->enable = 0;...// Re-sets i2c->hw->enable upon returning:return i2c_set_baudrate(i2c, baudrate);
}
那这个i2c_inst_t
是个什么数据类型呢?我就继续找它。
在pico-sdk/src/rp2_common/hardware_i2c/include/hardware/i2c.h
的第 52 行可以看到它是i2c_inst
结构体的重命名:
typedef struct i2c_inst i2c_inst_t;
那继续找结构体i2c_inst
,这个结构体就在同一个文件里的第 135 行:
struct i2c_inst {i2c_hw_t *hw;bool restart_on_next;
};
终点还是第一个变量i2c_hw_t *hw
,因为只有它可能会传递针脚的值,那就继续找i2c_hw_t
是什么数据类型。
这个数据类型的声明在pico-sdk/src/rp2040/hardware_structs/include/hardware/structs/i2c.h
中。换句话说,这个文件就是为i2c_hw_t
结构体所准备的:
这个结构体存储了很多 I2C 的信息,但还是没找到针脚的信息,那么我就回到一开始在进行寻找。
第二次尝试
最开始我是寻找了i2c_init()
的第一个参数的类型i2c_inst_t
,收获不大。但是它的值我还没寻找,所以这次从参数值出发i2c_default
,这个值是哪定义的呢?
在刚才发现i2c_inst_t
声明和定义的pico-sdk/src/rp2_common/hardware_i2c/include/hardware/i2c.h
头文件中发现了需要的东西(第 76 行):
#ifdef PICO_DEFAULT_I2C_INSTANCE
#define i2c_default PICO_DEFAULT_I2C_INSTANCE
#endif
这个PICO_DEFAULT_I2C_INSTANCE
是什么呢?往上一瞅就能看到:
#if !defined(PICO_DEFAULT_I2C_INSTANCE) && defined(PICO_DEFAULT_I2C)
#define PICO_DEFAULT_I2C_INSTANCE (__CONCAT(i2c,PICO_DEFAULT_I2C))
#endif
在这里终于看到一个需要的值:PICO_DEFAULT_I2C
,前文可知这个默认为0
。
这里的(__CONCAT(i2c,PICO_DEFAULT_I2C))
是将i2c
和PICO_DEFAULT_I2C
的值连接起来了,默认情况下也就是i2c0
。也就是说,参数i2c_default
就是i2c0
。
这个技巧很不错,但是有些编译器用不了,比如我用 Clang x86_64-apple-darwin21.6.0 就无法扩展
PICO_DEFAULT_I2C
。
再深入一些
但是这里的i2c0
是什么呢?这是个什么类型的数据呢?
还是在pico-sdk/src/rp2_common/hardware_i2c/include/hardware/i2c.h
头文件中(如上图)有这样一段:
#define i2c0 (&i2c0_inst) ///< Identifier for I2C HW Block 0
#define i2c1 (&i2c1_inst) ///< Identifier for I2C HW Block 1
可以看到i2c0
是i2c0_inst
的地址,注释说这是I2C HW Block 0
的标识符。从上面的
extern i2c_inst_t i2c0_inst;
extern i2c_inst_t i2c1_inst;
可以看到i2c0_inst
和i2c1_inst
是外部变量,类型是i2c_inst_t
,这个类型之前我看到了定义的结构体:
struct i2c_inst {i2c_hw_t *hw;bool restart_on_next;
};
那这个i2c0_inst
是在哪声明的?
这部分在pico-sdk/src/rp2_common/hardware_i2c/i2c.c
中声明的:
i2c_inst_t i2c0_inst = {i2c0_hw, false};
i2c_inst_t i2c1_inst = {i2c1_hw, false};
这个i2c0_hw
又是啥呢?在哪定义的呢?
这是在pico-sdk/src/rp2040/hardware_structs/include/hardware/structs/i2c.h
中:
#define i2c0_hw ((i2c_hw_t *)I2C0_BASE)
#define i2c1_hw ((i2c_hw_t *)I2C1_BASE)
i2c0_hw
表示((i2c_hw_t *)I2C0_BASE)
,意思是I2C0_BASE
是个指向i2c_hw_t
的指针,它的内容在pico-sdk/src/rp2040/hardware_regs/include/hardware/regs/addressmap.h
中:
#define I2C0_BASE _u(0x40044000)
#define I2C1_BASE _u(0x40048000)
也就是说I2C0_BASE
就是0x40044000
,而i2c0_hw
的地址就是0x40044000
。
补充一点,这里_()
是无符号整数的意思,定义在pico-sdk/src/rp2040/hardware_regs/include/hardware/platform_defs
:
#ifndef _u
#ifdef __ASSEMBLER__
#define _u(x) x
#else
#define _u(x) x ## u
#endif
#endif
了解了蛮多知识,也希望能帮到有需要的人~
相关文章:
Pico如何使用C/C++选择哪个I2C控制器,以及SDA和SCL针脚
本文一开始讲述了解决方案,后面是我做的笔记,用来讲述我的发现流程和探究的 Pico I2C 代码结构。 前提知识 首先要说明一点:Pico 有两个 I2C,也就是两套 SDA 和 SCL。这点你可以在针脚图中名字看出,比如下图的 Pin 4…...
求生之路2私人服务器开服搭建教程centos
求生之路2私人服务器开服搭建教程centos 大家好我是艾西,朋友想玩求生之路2(left4dead2)重回经典。Steam玩起来有时候没有那么得劲,于是问我有没有可能自己搭建一个玩玩。今天跟大家分享的就是求生之路2的自己用服务器搭建的一个心路历程。 ࿰…...
Redis7之介绍(一)
1. 是什么 Redis:REmote Dictionary Server(远程字典服务器) Remote Dictionary Server( 远程字典服务)是完全开源的,使用ANSIC语言编写遵守BSD协议,是一个高性能的Key-Value数据库提供了丰富的数据结构,例如String、Hash、List、…...
基于Python+djangoAI 农作物病虫害预警系统智能识别系统设计与实现(源码&教程)
1.背景 随着科技的发展,机器学习技术在各个领域中的应用越来越广泛。在农业领域,机器学习技术的应用有助于提高农作物的产量和质量,降低农业生产的成本。本文针对农作物健康识别问题,提出一种基于机器学习方法的农作健康识别系统&…...
Kotlin Flow 转换以及上下游处理
本片文章主要介绍Flow上下游处理,上游一个Flow使用map,上游两个Flow使用zip,上游三个Flow及以上使用combine 1、下面代码展示了upStreamFlow作为上游,downStreamFlow作为下游,通过对upStreamFlow使用map操作符函数将…...
深度学习3. 强化学习-Reinforcement learning | RL
强化学习是机器学习的一种学习方式,它跟监督学习、无监督学习是对应的。本文将详细介绍强化学习的基本概念、应用场景和主流的强化学习算法及分类。 目录 什么是强化学习? 强化学习的应用场景 强化学习的主流算法 强化学习(reinforcement learning) …...
TCP/IP网络江湖武艺传承:物理层与通信江湖的幕后
目录 〇、引言:进入现代通信技术的江湖 一、数字信号与模拟信号:传承与差异...
智慧能源管理系统助力某制造企业提高能源利用效率
随着全球能源需求不断增加和能源价格的上涨,企业和机构日益意识到能源管理的重要性。传统的能源管理方式不仅效率低下,还容易造成资源浪费和环境污染。因此,许多企业开始探索采用智慧能源管理系统来提高能源利用效率,降低能源成本…...
opencv/C++ 人脸检测
前言 本文使用的测试资源说明: opencv版本:opencv 4.6.0 人脸检测算法 Haar特征分类器 Haar特征分类器是一个XML文件,描述了人体各个部位的Haar特征值。包括:人脸、眼睛、鼻子、嘴等。 opencv 4.6.0自带的Haar特征分类器&…...
UE4/5的Custom节点:在VScode使用HLSL(新手入门用)
目录 custom节点 VSCode环境安装 将VSCode里面的代码放入Custom中 custom节点 可以看到这是一个简单的Custom节点: 而里面是可以填写代码的: 但是在这里面去写代码会发现十分的繁琐【按下enter后,不会换行,也不会自动缩进】 …...
小研究 - J2EE 应用服务器的软件老化测试研究
软件老化现象是影响软件可靠性的重要因素,长期运行的软件系统存在软件老化现象,这将影响整个业务系统的正常运行,给企事业单位带来无可估量的经济损失。软件老化出现的主要原因是操作系统资源消耗殆尽,导致应用系统的性能下降甚至…...
Tomcat和Servlet基础知识的讲解(JavaEE初阶系列16)
目录 前言: 1.Tomcat 1.1Tomcat是什么 1.2下载安装 2.Servlet 2.1什么是Servlet 2.2使用Servlet来编写一个“hello world” 1.2.1创建项目(Maven) 1.2.2引入依赖(Servlet) 1.2.3创建目录(webapp&a…...
开源在大数据和分析中的角色
🌷🍁 博主猫头虎 带您 Go to New World.✨🍁 🦄 博客首页——猫头虎的博客🎐 🐳《面试题大全专栏》 文章图文并茂🦕生动形象🦖简单易学!欢迎大家来踩踩~🌺 &a…...
C#,《小白学程序》第四课:数学计算
1 文本格式 /// <summary> /// 《小白学程序》第四课:数学计算 /// 这节课超级简单,就是计算成绩的平均值(平均分) /// 这个是老师们经常做的一件事。 /// </summary> /// <param name"sender"></…...
SparkML机器学习
SparkML 机器学习: 让机器学会人的学习行为, 通过算法和数据来模拟或实现人类的学习行为,使之不断改善自身性能。 机器学习的步骤: 加载数据特征工程 数据筛选: 选取适合训练的特征列, 例如用户id就不适合, 因为它特性太显著.数据转化: 将字符串的数据转化数据类型…...
vue Promise 对象 等待所有异步处理完成 再继续处理
1 定义数据集合 用来搜集所有数据 let promises []; // 用来存储所有的 Promise 对象 2 promise对象 异步 返回数据 同时添加数据到promises 列表 // 依次读取列表元素的表 for (let symbol of symbolList) {let promise new Promise((resolve, reject) > { // 将请求…...
【业务功能篇84】微服务SpringCloud-ElasticSearch-Kibanan-电商实例应用
一、商品上架功能 ElasticSearch实现商城系统中全文检索的流程。 1.商品ES模型 商品的映射关系 PUT product {"mappings": {"properties": {"skuId": {"type": "long"},"spuId": {"type": "ke…...
图像检索,目标检测map的实现
一、图像检索指标Rank1,map 参考:https://blog.csdn.net/weixin_41427758/article/details/81188164?spm1001.2014.3001.5506 1.Rank1: rank-k:算法返回的排序列表中,前k位为存在检索目标则称为rank-k命中。 常用的为rank1:首…...
Docker容器学习:Dockerfile制作Web应用系统nginx镜像
目录 编写Dockerfile 1.文件内容需求: 2.编写Dockerfile: 3.开始构建镜像 4.现在我们运行一个容器,查看我们的网页是否可访问 推送镜像到私有仓库 1.把要上传的镜像打上合适的标签 2.登录harbor仓库 3.上传镜像 编写Dockerfile 1.文…...
【vue3.0 引入Element Plus步骤与使用】
全局引入Element Plus 1. 安装 Element Plus2. 引入 Element Plus3. 使用 Element Plus 组件 Element Plus 是一个基于 Vue 3.0 的 UI 组件库,它是 Element UI 的升级版。Element Plus 的设计理念是简单、易用、高效,具有良好的可定制性和扩展性。下面是…...
金融客户敏感信息的“精细化管控”新范式
目 录 01 客户信息保护三箭齐发,金融IT亟需把握四个原则 02 制度制约阻碍信息保护的精细化管控 03 敏感信息精细化管控范式的6个关键设计 04 分阶段实施,形成敏感信息管控的长效运营的机制 05 未来,新挑战与新机遇并存 …...
Starrocks--数据插入方式
Starrocks 数据插入方式 Starrocks是一款快速、可伸缩的分布式OLAP数据库,支持多种数据插入方式。下面将详细介绍几种常用的数据插入方式,并提供选择建议。 1. 批量加载(Bulk Load) 批量加载是通过将本地文件或HDFS文件导入到S…...
Java学数据结构(3)——树Tree B树 红黑树 Java标准库中的集合Set与映射Map 使用多个映射Map的案例
目录 引出B树插入insert删除remove 红黑树(red black tree)自底向上的插入自顶向下红黑树自顶向下的删除 标准库中的集合Set与映射Map关于Set接口关于Map接口TreeSet类和TreeMap类的实现使用多个映射Map:一个词典的案例方案一:使用一个Map对象方案二&…...
Vue3.0极速入门 - 环境安装新建项目
Vue介绍 Vue.js 是什么 Vue (读音 /vjuː/,类似于 view) 是一套用于构建用户界面的渐进式框架。与其它大型框架不同的是,Vue 被设计为可以自底向上逐层应用。Vue 的核心库只关注视图层,不仅易于上手,还便于与第三方库或既有项目整…...
android 使用libyuv 图像转换
libyuv 是一个开源的图像处理库,它提供了一系列函数用于处理YUV格式的图像。在 JNI(Java Native Interface)中使用 libyuv,你需要先在你的 C 代码中包含 libyuv,然后编写 JNI 函数来调用 libyuv 的函数。 以下是一个简…...
奥比中光:进击具身智能,打造机器人之眼
大数据产业创新服务媒体 ——聚焦数据 改变商业 跨过奇点的生成式人工智能是一个缸中大脑,只有赋予形体,才能与物理世界产生互动。 在5月的ITF世界半导体大会上,英伟达创世人兼CEO黄仁勋说,人工智能的下一波浪潮将是具身智能。 8…...
微信小程序报错: SyntaxError: Cannot use import statement outside a module
微信小程序数据绑定,导包出现了: “SyntaxError: Cannot use import statement outside a module” 排查问题步骤记录,共勉 1.出现问题代码: import {createStoreBindings} from "mobx-miniprogram-bindings"import {store} from …...
Ruoyi微服务启动流程
1、执行sql 执行sql ry-quarty.sql ry_2023706.sql 到ry-cloud 数据库 2、下载nacos 修改配置文件 修改连接地址 启动nacos 看到下面的配置文件即为成功 修改配置文件里面的数据库连接信息 3、修改nacos 为单机启动 4、启动项目即可 nacos自取 链接: https://pan.baidu…...
Android scrollTo、scrollBy、以及scroller详解 自定义ViewPager
Scroller VelocityTracker VelocityTracker 是一个速度跟踪器,通过用户操作时(通常在 View 的 onTouchEvent 方法中)传进去一系列的 Event,该类就可以计算出用户手指滑动的速度,开发者可以方便地获取这些参数去做其他…...
Aidex 移动端快速开发框架# RuoYi-Uniapp项目,uniapp vue app项目跨域问题
参考地址: manifest.json官方配置文档:manifest.json 应用配置 | uni-app官网 Chrome 调试跨域问题解决方案之插件篇: uni-app H5跨域问题解决方案(CORS、Cross-Origin) - DCloud问答 其实uni-app官方有解决跨域的办…...
电商网站建设运城/推广软件免费
A 题意就是求两个字符串的缩写,具体规则就是两个字符串,每个字符串的缩写可以是0-字符串的长度的任意长,然后合并起来,求字母顺序最小的那个#include <iostream> #include <cstring> #include <cstdio> #includ…...
如何开发一个网站/刷评论网站推广
基本介绍 redis-shake是阿里开源的用于redis数据同步的工具,支持的迁移方式如下: 恢复restore:将RDB文件恢复到目的redis数据库。 备份dump:将源redis的全量数据通过RDB文件备份起来。 解析decode:对…...
wordpress资讯自媒体中文主题/营销推广费用方案
✿今日屋主✿户型:两室一厅面积:77㎡风格:北欧全部花费:40万屋主是一个美食博主,一位自称爷的姑娘,也是一个标准的“颜控”。为了满足自己梦想中的开放式的大厨房有自然光的餐厅(主要是要吃的开…...
静态网站提交表单怎么做/环球军事网最新军事新闻最新消息
默认使用sqllite数据库 修改为mysql数据库 创建数据库 在app models中编写创建数据库类 from django.db import models class Book(models.Model):#表明book django 会自动使用项目名我们自定义的表名# 如果没有自定义主键,django会自动添加一个主键,字段…...
网站集群建设方案/上海网站seo诊断
上一篇简单的讲了下Handler的使用,本篇就解析一下Andorid消息处理机制的内部实现,到底是如何为绑定的线程创建looper对象和消息队列的,又是怎么实现消息添加、消息遍历和消息分发的。 首先需要介绍几个非常重要的角色:Looper、Han…...
用织梦模板做网站/win7优化设置
1 Flume概述 Flume是一个Cloudera提供的分布式、高可用、高可靠的海量日志采集、聚合、传输的系统。 Flume的主要作用是:实时读取服务器本地磁盘的数据,将数据写入到HDFS。 1.1 Flume基本架构 ①Agent agent是一个jvm进程,以事件的形式将数…...