Android Camera2 与 Camera API技术探究和RAW数据采集
Android Camera2
Android Camera2 是 Android 系统中用于相机操作的一套高级应用程序接口(API),它取代了之前的 Camera API。以下是关于 Android Camera2 的一些主要信息:
- 主要特点:
- 强大的控制能力:提供对相机更深入的控制,允许开发者精确设置对焦模式、曝光模式、快门速度、白平衡、增益等各种拍摄参数,能够满足复杂的拍摄需求,例如专业摄影应用或对图像质量有较高要求的场景。
- 多流输出支持:单个相机设备可以同时输出多个流,每个流针对不同的使用场景进行了优化,如预览、拍照、视频录制或图像分析等。这使得开发者可以根据应用的具体需求灵活地获取和处理不同类型的图像数据。
- 高效的数据处理:支持高效的零复制连拍和视频流功能,能够快速地获取和处理连续的图像数据,提高了相机的响应速度和数据处理效率。
- 核心类与组件:
- CameraManager:用于管理系统中的相机设备,提供了获取相机设备列表、打开指定相机以及获取相机特性等方法。开发者可以通过它来检测系统中可用的相机,并获取相机的相关信息以进行后续的操作。
- CameraDevice:代表系统中的摄像头硬件设备,负责建立与相机的连接,并管理相机的状态。它可以创建 CaptureSession(捕获会话)以及 CaptureRequest(捕获请求),是与相机硬件进行交互的核心类。
- CameraCharacteristics:描述了特定相机设备所支持的各种特性,通过 CameraManager 获取。开发者可以根据这些特性来判断相机的能力,例如是否支持自动对焦、是否支持特定的分辨率等,以便在应用中进行相应的设置和处理。
- CameraCaptureSession:是应用程序与相机设备之间进行数据传输和交互的会话。当程序需要预览、拍照或录制视频时,都需要创建一个 CameraCaptureSession。它管理着 CaptureRequest 的队列,将开发者设置的拍摄参数传递给相机设备,并接收相机返回的图像数据。
- CaptureRequest 和 CaptureRequest.Builder:CaptureRequest 代表了一次捕获请求,用于描述捕获图片或视频的各种参数设置,如对焦模式、曝光模式、分辨率等。CaptureRequest.Builder 则负责生成 CaptureRequest 对象,方便开发者设置各种参数。
- 使用步骤:
- 获取 CameraManager:首先需要获取 CameraManager 对象,这是进行所有相机操作的前提。可以通过
Context.getSystemService(Context.CAMERA_SERVICE)方法来获取 CameraManager。 - 打开相机设备:使用 CameraManager 的
openCamera(String cameraId, CameraDevice.StateCallback callback, Handler handler)方法打开指定的摄像头。其中,cameraId是要打开的摄像头的标识符,callback用于监听摄像头的状态变化,handler表示执行回调的线程。 - 创建 CameraCaptureSession:当摄像头打开后,通过
CameraDevice.createCaptureSession(List<Surface> outputs, CameraCaptureSession.StateCallback callback, Handler handler)方法创建 CameraCaptureSession。outputs是一个包含所有需要从该摄像头获取图片的Surface的列表,callback用于监听会话的创建过程,handler表示执行回调的线程。 - 创建 CaptureRequest:调用
CameraDevice.createCaptureRequest(int templateType)方法创建CaptureRequest.Builder,其中templateType可以是TEMPLATE_PREVIEW(预览)、TEMPLATE_RECORD(拍摄视频)、TEMPLATE_STILL_CAPTURE(拍照)等。然后使用CaptureRequest.Builder设置拍照的各种参数。 - 开始预览或拍照:调用
CameraCaptureSession.setRepeatingRequest()方法开始预览,或调用capture()方法进行拍照。拍照的优先级比预览的优先级高,如果需要多次拍照,可以多次调用capture()方法。
- 获取 CameraManager:首先需要获取 CameraManager 对象,这是进行所有相机操作的前提。可以通过
- 支持的版本和兼容性:Android Camera2 从 Android 5.0(API 级别 21)开始支持。但需要注意的是,虽然 Android 5.0 及更高版本的设备支持 Camera2,但部分设备可能并不支持所有的 Camera2 功能。在实际开发中,需要根据设备的具体特性和支持情况进行适配和处理。
相比Camera API技术优势
Android Camera2 与 Camera API 相比,具有以下优势:
- 功能与控制方:
- 更多的手动控制选项:
- Camera2 提供了丰富的手动设置功能,如曝光时间、ISO 感光度、对焦模式、焦距等参数都可以由开发者手动设置和精确调整,能够满足专业摄影或对图像质量有较高要求的场景。而 Camera API 的手动控制功能非常有限,通常只能实现简单的自动调节拍摄。
- 例如,在光线复杂的环境中,使用 Camera2 可以根据实际需求手动调整曝光时间,以获得更准确的曝光效果,避免画面过亮或过暗;在拍摄特写镜头时,可以手动设置对焦模式和焦距,确保主体清晰。
- 支持 RAW 图像捕获:Camera2 支持 RAW 格式的图像捕获,RAW 格式的图像包含了更多的原始图像信息,为后期处理提供了更大的空间和更高的灵活性,可以让用户在后期对图像的色彩、对比度、锐度等进行更精细的调整。相比之下,Camera API 通常只能获取经过压缩和处理的图像格式,丢失了很多原始信息14。
- 高速连拍模式:Camera2 支持高速连拍功能,能够以更快的速度连续拍摄多张照片,这对于捕捉快速运动的物体或瞬间的精彩场景非常有帮助。而在 Camera API 中,实现连拍功能相对较为困难,且连拍速度和效果可能不尽如人意4。
- 更多的手动控制选项:
- 性能优化方面:
- 并行处理能力:Camera2 支持并行拍摄和预览,在同时进行多个操作时表现更好,可以在预览的同时进行拍照、录像等操作,并且不会相互干扰,提高了相机的使用效率和响应速度。而在 Camera API 中,切换不同的拍摄模式(如从预览模式切换到拍照模式)可能会比较耗时,影响用户体验1。
- 高效的数据处理:Camera2 采用了更高效的数据处理方式,能够快速地获取和处理图像数据,减少了数据传输和处理的延迟。例如,在拍摄视频时,Camera2 可以更流畅地获取和编码视频数据,降低了视频的卡顿现象5。
- 架构与兼容性方面:
- 更灵活的架构:Camera2 的架构更加灵活,将相机系统塑造为一个管道,该管道可按照 1:1 的基准将传入的帧捕获请求转化为帧,并将图像数据的缓冲区输出到设置的目的
Surface中。这种架构使得开发者可以更方便地定制和扩展相机的功能,实现各种复杂的拍摄需求。 - 更好的兼容性:虽然 Camera API 在早期的 Android 版本中广泛使用,但随着 Android 系统的不断升级,Camera2 逐渐成为了 Android 相机功能的主要 API。新的 Android 版本会对 Camera2 进行更好的优化和支持,而 Camera API 可能会逐渐被淘汰,使用 Camera2 可以更好地保证应用在不同 Android 版本上的兼容性3。
- 更灵活的架构:Camera2 的架构更加灵活,将相机系统塑造为一个管道,该管道可按照 1:1 的基准将传入的帧捕获请求转化为帧,并将图像数据的缓冲区输出到设置的目的
- 设备特性支持与检测方面:
- 设备能力检测:通过
CameraCharacteristics类,Camera2 可以方便地检查设备相机的各种特性和功能,开发者可以根据设备的支持情况来动态地调整相机的设置和功能,提高了应用的适应性和稳定性。例如,在应用启动时,可以先检测设备是否支持手动对焦功能,如果支持则开启手动对焦选项,否则隐藏该选项,避免出现功能不可用的情况。 - 支持更多新硬件特性:随着手机硬件的不断发展,新的相机硬件特性不断涌现,Camera2 能够更好地支持这些新特性,如更高的分辨率、更快的对焦速度、更好的低光性能等,为用户提供更好的拍摄体验。
- 设备能力检测:通过
Android Camera2 RAW图像捕获
要使用 Android Camera2 进行 RAW 图像捕获,你可以按照以下步骤进行操作:
- 检查设备支持:首先,确保你的设备支持 Camera2 API 并且支持 RAW 图像捕获。你可以通过查询设备的 CameraCharacteristics 来获取相关信息123。
- 获取 CameraManager:通过
Context.getSystemService(Context.CAMERA_SERVICE)获取 CameraManager 实例123。 - 打开相机设备:使用 CameraManager 的
openCamera(String cameraId, CameraDevice.StateCallback callback, Handler handler)方法打开相机设备。你需要指定要打开的相机 ID 以及相应的回调和处理程序123。 - 创建 CaptureRequest.Builder:创建一个 CaptureRequest.Builder 对象,并设置相关的参数,如对焦模式、曝光模式等。同时,将图像格式设置为
ImageFormat.RAW_SENSOR以指定捕获 RAW 图像1。 - 创建 CameraCaptureSession:使用 CameraDevice 的
createCaptureSession(List<Surface> outputs, CameraCaptureSession.StateCallback callback, Handler handler)方法创建一个 CameraCaptureSession。将包含 RAW 图像的 Surface 添加到输出列表中1。 - 开始捕获:调用 CameraCaptureSession 的
capture(CaptureRequest request, CameraCaptureSession.CaptureCallback callback, Handler handler)方法开始捕获 RAW 图像。你可以指定相应的回调来处理捕获结果1。 - 处理 RAW 图像数据:在 CaptureCallback 的
onCaptureCompleted方法中,你将接收到包含 RAW 图像数据的 CaptureResult 对象。你可以从 CaptureResult 中获取图像数据,并进行相应的处理或保存。
示例代码如下:
import android.content.Context;
import android.graphics.ImageFormat;
import android.hardware.camera2.CameraAccessException;
import android.hardware.camera2.CameraCaptureSession;
import android.hardware.camera2.CameraCharacteristics;
import android.hardware.camera2.CameraDevice;
import android.hardware.camera2.CameraManager;
import android.hardware.camera2.CaptureRequest;
import android.os.Handler;
import android.os.HandlerThread;
import android.util.Log;
import android.view.Surface;public class RawImageCapture {private CameraManager cameraManager;private String cameraId;private CameraDevice cameraDevice;private CameraCaptureSession cameraCaptureSession;private CaptureRequest.Builder captureRequestBuilder;public void startRawImageCapture(Context context) {// 获取CameraManagercameraManager = (CameraManager) context.getSystemService(Context.CAMERA_SERVICE);try {// 获取相机设备IDcameraId = cameraManager.getCameraIdList()[0];// 打开相机设备cameraManager.openCamera(cameraId, new CameraDevice.StateCallback() {@Overridepublic void onOpened(CameraDevice camera) {cameraDevice = camera;createCaptureSession();}@Overridepublic void onDisconnected(CameraDevice camera) {cameraDevice.close();}@Overridepublic void onError(CameraDevice camera, int error) {cameraDevice.close();}}, null);} catch (CameraAccessException e) {e.printStackTrace();}}private void createCaptureSession() {try {// 创建CaptureRequest.BuildercaptureRequestBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);captureRequestBuilder.addTarget(new Surface(ImageFormat.RAW_SENSOR));// 创建CameraCaptureSessioncameraDevice.createCaptureSession(Arrays.asList(new Surface(ImageFormat.RAW_SENSOR)), new CameraCaptureSession.StateCallback() {@Overridepublic void onConfigured(CameraCaptureSession session) {cameraCaptureSession = session;startCapture();}@Overridepublic void onConfigureFailed(CameraCaptureSession session) {}}, null);} catch (CameraAccessException e) {e.printStackTrace();}}private void startCapture() {try {cameraCaptureSession.capture(captureRequestBuilder.build(), new CameraCaptureSession.CaptureCallback() {@Overridepublic void onCaptureCompleted(CameraCaptureSession session, CaptureRequest request, TotalCaptureResult result) {// 处理RAW图像数据Log.d("RawImageCapture", "RAW image captured");}}, null);} catch (CameraAccessException e) {e.printStackTrace();}}
}
如何对接Android Camera2
大牛直播SDK前几年在做Android平台RTMP推送和轻量级RTSP服务的时候,实际上就已经支持了Camera2的采集和数据投递,考虑到,目前5.0以下版本的设备越来越少,后面的GB28181设备接入模块,更是以Camera2的demo为准。

Camera2数据回调并投递到底层jni示例代码如下:
/** Camera2MainActivity.java* Author:daniusdk.com* WeChat: xinsheng120*/
@Override
public void onCameraImageData(Image image) {Image.Plane[] planes = image.getPlanes();if (image.getFormat() != ImageFormat.YUV_420_888) {Log.i(TAG, "image format is not YUV_420_888, format:" + image.getFormat());return;} else {// Log.i(TAG, "image format is YUV_420_888, format:" + image.getFormat());}int w = image.getWidth(), h = image.getHeight();int y_offset = 0, u_offset = 0, v_offset = 0;Rect crop_rect = image.getCropRect();if (crop_rect != null && !crop_rect.isEmpty()) {w = crop_rect.width();h = crop_rect.height();y_offset += crop_rect.top * planes[0].getRowStride() + crop_rect.left * planes[0].getPixelStride();u_offset += (crop_rect.top / 2) * planes[1].getRowStride() + (crop_rect.left / 2) * planes[1].getPixelStride();v_offset += (crop_rect.top / 2) * planes[2].getRowStride() + (crop_rect.left / 2) * planes[2].getPixelStride();;// Log.i(TAG, "crop w:" + w + " h:" + h + " y_offset:"+ y_offset + " u_offset:" + u_offset + " v_offset:" + v_offset);}int scale_w = 0, scale_h = 0, scale_filter_mode = 0;scale_filter_mode = 3;int rotation_degree = cameraImageRotationDegree_;if (rotation_degree < 0) {Log.i(TAG, "onCameraImageData rotation_degree < 0, may need to set orientation_ to 0, 90, 180 or 270");return;}for (LibPublisherWrapper i : publisher_array_)i.PostLayerImageYUV420888ByteBuffer(0, 0, 0,planes[0].getBuffer(), y_offset, planes[0].getRowStride(),planes[1].getBuffer(), u_offset, planes[1].getRowStride(),planes[2].getBuffer(), v_offset, planes[2].getRowStride(), planes[1].getPixelStride(),w, h, 0, 0,scale_w, scale_h, scale_filter_mode, rotation_degree);}
总结
Android Camera2 API 是从 Android 5.0(Lollipop)开始引入的,相对Camera API,优势非常明显,如果需要通过Android平台采集视频数据,在设备支持的前提下,建议尽可能用Camera2做数据采集。
相关文章:
Android Camera2 与 Camera API技术探究和RAW数据采集
Android Camera2 Android Camera2 是 Android 系统中用于相机操作的一套高级应用程序接口(API),它取代了之前的 Camera API。以下是关于 Android Camera2 的一些主要信息: 主要特点: 强大的控制能力:提供…...
[python][pipenv]pipenv的使用
pipenv 是一个 Python 开发工作流程的工具,它旨在将 pip 的包管理和 virtualenv 的虚拟环境管理结合起来。以下是一些基本的 pipenv 使用方法: 安装 pipenv: 如果你还没有安装 pipenv,可以通过 pip 安装它: pip insta…...
SpringSession微服务
一.在linux中确保启动起来redis和nacos 依赖记得别放<dependencyManagement></dependencyManagement>这个标签去了 1.首先查看已经启动的服务 docker ps 查看有没有安装redis和nacos 2.启动redis和nacos 发现没有启动redis和nacos,我们先来启动它。,…...
强化学习:通过试错学习最优策略---示例:使用Q-Learning解决迷宫问题
强化学习(Reinforcement Learning, RL)是一种让智能体(agent)在与环境交互的过程中,通过最大化某种累积奖励来学习如何采取行动的学习方法。它适用于那些需要连续决策的问题,比如游戏、自动驾驶和机器人控制…...
OpenGL ES 纹理(7)
OpenGL ES 纹理(7) 简述 通过前面几章的学习,我们已经可以绘制渲染我们想要的逻辑图形了,但是如果我们想要渲染一张本地图片,这就需要纹理了。 纹理其实是一个可以用于采样的数据集,比较典型的就是图片了,我们知道我…...
【C#】CacheManager:高效的 .NET 缓存管理库
在现代应用开发中,缓存是提升性能和降低数据库负载的重要技术手段。无论是 Web 应用、桌面应用还是移动应用,缓存都能够帮助减少重复的数据查询和处理,从而提高系统的响应速度。然而,管理缓存并不简单,尤其是当你需要处…...
【数学分析笔记】第4章第2节 导数的意义和性质(2)
4. 微分 4.2 导数的意义与性质 4.2.3 单侧导数 f ′ ( x ) lim Δ x → 0 f ( x Δ x ) − f ( x ) Δ x lim x → x 0 f ( x ) − f ( x 0 ) x − x 0 f(x)\lim\limits_{\Delta x\to 0}\frac{f(x\Delta x)-f(x)}{\Delta x}\lim\limits_{x\to x_0}\frac{f(x)-f(x_0)…...
深度学习:迁移学习
目录 一、迁移学习 1.什么是迁移学习 2.迁移学习的步骤 1、选择预训练的模型和适当的层 2、冻结预训练模型的参数 3、在新数据集上训练新增加的层 4、微调预训练模型的层 5、评估和测试 二、迁移学习实例 1.导入模型 2.冻结模型参数 3.修改参数 4.创建类ÿ…...
Footprint Growthly Quest 工具:赋能 Telegram 社区实现 Web3 飞速增长
作者:Stella L (stellafootprint.network) 在 Web3 的快节奏世界里,社区互动是关键。而众多 Web3 社区之所以能够蓬勃发展,很大程度上得益于 Telegram 平台。正因如此,Footprint Analytics 精心打造了 Growthly —— 一款专为 Tel…...
进入xwindows后挂起键盘鼠标没有响应@FreeBSD
问题: 在升级pkg包后,系统无法进入xfce等xwindows,表现为黑屏和看见鼠标,左上角有一个白字符块,键盘鼠标没有反应,整个系统卡住。但是可以ssh登录,内部的服务一切正常。 表现 处理过程…...
CentOS7.9 snmptrapd更改162端口
端口更改前: 命令: netstat -an |grep 162 [root@kibana snmp]# netstat -an | grep 162 udp 0 0 0.0.0.0:162 0.0.0.0:* unix 3 [ ] STREAM CONNECTED 45162 /run/systemd/journal/stdout u…...
模糊测试SFuzz亮相第32届中国国际信息通信展览会
9月25日,被誉为“中国ICT市场的创新基地和风向标”的第32届中国国际信息通信展在北京盛大开幕,本次展会将在为期三天的时间内,为信息通信领域创新成果、尖端技术和产品提供国家级交流平台。开源网安携模糊测试产品及相关解决方案精彩亮相&…...
CMake学习
向大佬lyf学习,先把其8服务器中所授fine 文章目录 前言一、CMakeList.txt 命令1. 最外层CMakeLists1.1 cmake_minimum_required()1.2 project()1.3 set()1.4 add_subdirectory(&…...
书生·浦语大模型全链路开源开放体系
书生浦语大模型全链路开源开放体系 大模型应用生态的发展和繁荣是建立在模型基座强大的通用基础能力之上的。上海AI实验室联合团队研究认为,大模型各项性能提升的基础在于语言建模能力的增强,对于大模型的研究应回归语言建模本质,通过更高质量…...
PHP安装swoole扩展无效,如何将文件上传至Docker容器
目录 过程 操作方式 过程 在没有使用过云服务器以前,Docker这个平台一直都很神秘。在我申请了华为云服务器,并使用WordPress镜像去搭建自己的网站以后,我不得不去把Docker平台弄清楚,原因是我使用的一个主题需要安装swoole扩展,才能够正常启用。而要将swoole.so这个扩展…...
Web3.0 应用项目
Web3.0 是下一代互联网的概念,旨在去中心化、用户拥有数据控制权和通过区块链技术实现信任的网络。Web3.0的应用项目主要集中在区块链、加密货币、去中心化应用 (DApps)、去中心化金融 (DeFi)、NFT(非同质化代币)等领域。以下是一些典型的 We…...
Linux 学习笔记(十六)—— 重定向与缓冲区
一、文件重定向 矩阵的下标,也就是文件描述符的分配规则,是从0开始空的最小的文件描述符分配给进程新打开的文件;文件输出重定向的原理是,关掉1(输出),然后打开文件,这个新打开的文…...
828华为云征文|WordPress部署
目录 前言 一、环境准备 二、远程连接 三、WordPress简介 四、WordPress安装 1. 基础环境安装 编辑 2. WordPress下载与解压 3. 创建站点 4. 数据库配置 总结 前言 WordPress 是一个非常流行的开源内容管理系统(Content Management System, CMS…...
华为开源自研AI框架昇思MindSpore应用案例:计算高效的卷积模型ShuffleNet
如果你对MindSpore感兴趣,可以关注昇思MindSpore社区 ShuffleNet ShuffleNet网络介绍 ShuffleNetV1是旷视科技提出的一种计算高效的CNN模型,和MobileNet, SqueezeNet等一样主要应用在移动端,所以模型的设计目标就是利用有限的计算资源来达到…...
《C++ 小游戏:简易飞机大战游戏的实现》
文章目录 《C 游戏代码解析:简易飞机大战游戏的实现》一、游戏整体结构与功能概述二、各个类和函数的功能分析(一)BK类 - 背景类(二)hero_plane类 - 玩家飞机类(三)plane_bullet类 - 玩家飞机发…...
[2025CVPR]DeepVideo-R1:基于难度感知回归GRPO的视频强化微调框架详解
突破视频大语言模型推理瓶颈,在多个视频基准上实现SOTA性能 一、核心问题与创新亮点 1.1 GRPO在视频任务中的两大挑战 安全措施依赖问题 GRPO使用min和clip函数限制策略更新幅度,导致: 梯度抑制:当新旧策略差异过大时梯度消失收敛困难:策略无法充分优化# 传统GRPO的梯…...
rknn优化教程(二)
文章目录 1. 前述2. 三方库的封装2.1 xrepo中的库2.2 xrepo之外的库2.2.1 opencv2.2.2 rknnrt2.2.3 spdlog 3. rknn_engine库 1. 前述 OK,开始写第二篇的内容了。这篇博客主要能写一下: 如何给一些三方库按照xmake方式进行封装,供调用如何按…...
【Redis技术进阶之路】「原理分析系列开篇」分析客户端和服务端网络诵信交互实现(服务端执行命令请求的过程 - 初始化服务器)
服务端执行命令请求的过程 【专栏简介】【技术大纲】【专栏目标】【目标人群】1. Redis爱好者与社区成员2. 后端开发和系统架构师3. 计算机专业的本科生及研究生 初始化服务器1. 初始化服务器状态结构初始化RedisServer变量 2. 加载相关系统配置和用户配置参数定制化配置参数案…...
【解密LSTM、GRU如何解决传统RNN梯度消失问题】
解密LSTM与GRU:如何让RNN变得更聪明? 在深度学习的世界里,循环神经网络(RNN)以其卓越的序列数据处理能力广泛应用于自然语言处理、时间序列预测等领域。然而,传统RNN存在的一个严重问题——梯度消失&#…...
Auto-Coder使用GPT-4o完成:在用TabPFN这个模型构建一个预测未来3天涨跌的分类任务
通过akshare库,获取股票数据,并生成TabPFN这个模型 可以识别、处理的格式,写一个完整的预处理示例,并构建一个预测未来 3 天股价涨跌的分类任务 用TabPFN这个模型构建一个预测未来 3 天股价涨跌的分类任务,进行预测并输…...
376. Wiggle Subsequence
376. Wiggle Subsequence 代码 class Solution { public:int wiggleMaxLength(vector<int>& nums) {int n nums.size();int res 1;int prediff 0;int curdiff 0;for(int i 0;i < n-1;i){curdiff nums[i1] - nums[i];if( (prediff > 0 && curdif…...
AI编程--插件对比分析:CodeRider、GitHub Copilot及其他
AI编程插件对比分析:CodeRider、GitHub Copilot及其他 随着人工智能技术的快速发展,AI编程插件已成为提升开发者生产力的重要工具。CodeRider和GitHub Copilot作为市场上的领先者,分别以其独特的特性和生态系统吸引了大量开发者。本文将从功…...
【电力电子】基于STM32F103C8T6单片机双极性SPWM逆变(硬件篇)
本项目是基于 STM32F103C8T6 微控制器的 SPWM(正弦脉宽调制)电源模块,能够生成可调频率和幅值的正弦波交流电源输出。该项目适用于逆变器、UPS电源、变频器等应用场景。 供电电源 输入电压采集 上图为本设计的电源电路,图中 D1 为二极管, 其目的是防止正负极电源反接, …...
虚拟电厂发展三大趋势:市场化、技术主导、车网互联
市场化:从政策驱动到多元盈利 政策全面赋能 2025年4月,国家发改委、能源局发布《关于加快推进虚拟电厂发展的指导意见》,首次明确虚拟电厂为“独立市场主体”,提出硬性目标:2027年全国调节能力≥2000万千瓦࿰…...
STM32HAL库USART源代码解析及应用
STM32HAL库USART源代码解析 前言STM32CubeIDE配置串口USART和UART的选择使用模式参数设置GPIO配置DMA配置中断配置硬件流控制使能生成代码解析和使用方法串口初始化__UART_HandleTypeDef结构体浅析HAL库代码实际使用方法使用轮询方式发送使用轮询方式接收使用中断方式发送使用中…...
