【GD32】INA226电压电流功率检测模块

2.46 INA226电压电流功率检测模块

2.46.1 模块来源​

采购链接:​
INA226电压电流功率检测模块
资料下载:(基于该模块的资料,百度云链接等)​
链接:http://pan.baidu.com/s/1c0DbuXa 密码:3p2j​

​ 2.46.2 规格参数

工作电压:2.7 V -5.5 V
工作电流:典型值为 330μA
通信方式:I2C (时钟速率1k-2.94M)
引脚数量:10
(还有其他关于该模块的一些重要参数,例如温度传感器需要知道温度的检测范围,屏幕需要知道像素等等。)
1.感测的总线电压范围:
0V 至 36V (高侧或低侧感测)
2.高精度:
0.1% 增益误差(最大值)
10μV 偏移(最大值)
3.可配置的取平均值选项
4.16 个可编程地址

2.46.3 模块原理

INA226是一种高精度、低功耗的电流/电压监测芯片,它采用集成电流传感器和差分放大器电路,用于测量和监控电流和电压。INA226的工作原理如下:

  1. 电流测量:INA226内置了一个电流传感器,该传感器是基于霍尔效应或电阻的。当电流通过芯片的输入引脚时,传感器将产生一个与电流成正比的电压信号。
  2. 电压测量:INA226可以通过测量两个端口之间的电压差来实现电压测量。它采用差分放大器电路,将输入端口的电压与内部参考电压进行比较,并产生一个与输入电压差值成正比的电压信号。
  3. AD转换:INA226将电流和电压信号转换为数字信号。它包含一个内置的模数转换器(ADC),用于将模拟信号转换为数字形式。ADC将连续的模拟信号分割成离散的数字级别,并输出对应的数字值。
  4. 数据处理:转换后的数字信号被送入INA226的数字信号处理部分。在这里,它们经过放大、滤波和校准等处理,以产生准确的电流和电压测量结果。
  5. 数据输出:INA226通过接口(I2C)将测量结果输出给主控制器或其他外部设备。主控制器可以读取和解释这些测量结果,从而实现对电流和电压的监控和控制。
    总之,INA226通过集成电流传感器和差分放大器电路,以及内部的模数转换器和数字信号处理部分,实现对电流和电压的高精度测量和监控。

在这里插入图片描述

2.46.4 移植工程

讲解移植到立创梁山派的大致步骤,并基于该模块移植的代码实现什么功能。

2.46.4-1 引脚选择

如果是特殊引脚,例如使用串口时,需要讲解为什么使用该引脚,这个引脚是串口几等等。
接线按照以下模板进行编写。
在这里插入图片描述

2.46.4-2 移植步骤

将厂家提供的代码移植到立创·梁山派的步骤,图文并茂。如果没有厂家代码,请将实现功能的代码粘贴至此目录下,并进行关键代码注释。

   在本次INA226模块的测试中,使用的是贴片采样电阻R100,阻值为0.1欧姆。根据数据手册中的公式1和公式2进行计算。

在这里插入图片描述

首先,需要注意Shunt Voltage Register的值最大为0x7FFF,每个LSB对应2.5微伏,全量程范围为81.92毫伏。
由于分流电阻的阻值为0.1欧姆,因此最大电流为819.2毫安(注意避免超过此范围,以免导致错误测量结果)。
在假设Current_LSB为0.02毫安的情况下,满足最大电流不能超过819.2毫安的条件。根据公式1计算得到,Calibration Register的值为0x0A00。
因此,在配置INA226时,应将0x0A00写入Calibration Register中。
请确保在实际应用中选择适合您的应用的电流范围和分辨率,并避免超出设备的量程,以确保测量结果的准确性。

1.使用GPIO实现模拟I2C时序。
GPIO实现模拟I2C时序是一种在硬件资源有限的情况下的替代方法。虽然它具有灵活性和低硬件要求的优点,但也存在时序精度受限、速度较慢和资源占用较大等缺点。因此,在选择使用GPIO进行模拟I2C时序之前,需要权衡其优缺点,并根据具体应用的要求做出选择。
本代码封装了 I2C设备读写数据函数,方便其他I2C模块调用。

代码1  GPIO实现模拟I2C时序代码
/********************************************************************************
  * 测试硬件:立创·梁山派开发板GD32F470ZGT6    使用主频200Mhz    晶振25Mhz
  * 版 本 号: V1.0
  * 修改作者: LC
  * 修改日期: 2023年06月12日
  * 功能介绍:
  ******************************************************************************
  
*********************************************************************************/
#include <stdio.h>
#include "main.h"
#include "driver_i2c.h"
#include "systick.h"
// I2C引脚定义
#define SCL_PIN GPIO_SCL  // SCL引脚
#define SDA_PIN GPIO_SDA  // SDA引脚
#define I2C_PORT PORT_SDA
/******************************************************************
 * 函 数 名 称:I2C_GPIO_Init
 * 函 数 说 明:I2C的引脚初始化
 * 函 数 形 参:无
 * 函 数 返 回:无
 * 作       者:LC
 * 备       注:无
******************************************************************/
void i2c_gpio_init(void)
{
  /* 使能时钟 */
  rcu_periph_clock_enable(RCU_SCL);
  rcu_periph_clock_enable(RCU_SDA);

  /* 配置SCL为输出模式 */
  gpio_mode_set(PORT_SCL, GPIO_MODE_OUTPUT, GPIO_PUPD_PULLUP, GPIO_SCL);
  /* 配置为推挽输出 50MHZ */
  gpio_output_options_set(PORT_SCL, GPIO_OTYPE_OD, GPIO_OSPEED_50MHZ, GPIO_SCL);

  /* 配置SDA为输出模式 */
  gpio_mode_set(PORT_SDA, GPIO_MODE_OUTPUT, GPIO_PUPD_PULLUP, GPIO_SDA);
  /* 配置为推挽输出 50MHZ */
  gpio_output_options_set(PORT_SDA, GPIO_OTYPE_OD, GPIO_OSPEED_50MHZ, GPIO_SDA);

  gpio_bit_set(I2C_PORT, SDA_PIN);
  gpio_bit_set(I2C_PORT, SCL_PIN);

}



/*********************************************************
* 函数名称:i2c_delay
 * 函 数 说 明:I2C总线延时函数
* 函 数 形 参:无
 * 函 数 返 回:无
 * 作       者:LC
 * 备       注:无
*********************************************************/
void i2c_delay()
{
  uint32_t delay = 200;

  while (delay--)
  {
    __NOP();
  }
}
/*********************************************************

 * 函 数 名 称:i2c_start
 * 函 数 说 明:产生I2C起始信号
 * 函 数 形 参:无
 * 函 数 返 回:无
 * 作       者:LC
 * 备       注:无
*********************************************************/
static void i2c_start()
{
  gpio_bit_set(I2C_PORT, SDA_PIN); // 确保数据线为高电平
  gpio_bit_set(I2C_PORT, SCL_PIN); // 确保时钟线为高电平
  i2c_delay();
  gpio_bit_reset(I2C_PORT, SDA_PIN); // 拉低数据线,产生起始信号
  i2c_delay();
  gpio_bit_reset(I2C_PORT, SCL_PIN); // 拉低时钟线,准备发送数据
  i2c_delay();
}
/*********************************************************
 * 函 数 名 称:i2c_stop
 * 函 数 说 明:产生I2C停止信号
 * 函 数 形 参:无
 * 函 数 返 回:无
 * 作       者:LC
 * 备       注:无
*********************************************************/
static void i2c_stop()
{
  gpio_bit_reset(I2C_PORT, SDA_PIN); // 确保数据线为低电平
  gpio_bit_set(I2C_PORT, SCL_PIN); // 确保时钟线为高电平
  i2c_delay();
  gpio_bit_set(I2C_PORT, SDA_PIN); // 拉高数据线,产生停止信号
  i2c_delay();
}
/*********************************************************
 * 函 数 名 称:i2c_write_byte
 * 函 数 说 明:向I2C总线写入一个字节,并读取ACK信号
 * 函 数 形 参:data - 要写入的数据字节
 * 函 数 返 回:uint8_t - ACK信号,0表示收到ACK,1表示收到NACK
 * 作       者:LC
 * 备       注:无
*********************************************************/
static uint8_t i2c_write_byte(uint8_t data)
{
  uint8_t i, ack;

  for (i = 0; i < 8; i++)
  {
    if (data & 0x80) // 检查数据的最高位
    {
      gpio_bit_set(I2C_PORT, SDA_PIN); // 将数据线拉高,写入1
    }
    else
    {
      gpio_bit_reset(I2C_PORT, SDA_PIN); // 将数据线拉低,写入0
    }

    gpio_bit_set(I2C_PORT, SCL_PIN);  // 拉高时钟线,发送数据位
    i2c_delay();
    gpio_bit_reset(I2C_PORT, SCL_PIN);  // 拉低时钟线,准备发送下一位数据
    i2c_delay();
    data <<= 1;  // 左移一位,准备发送下一位数据
  }

  gpio_bit_set(I2C_PORT, SDA_PIN); // 拉高数据线,准备接收ACK信号
  gpio_bit_set(I2C_PORT, SCL_PIN); // 拉高时钟线
  i2c_delay();
  ack = gpio_input_bit_get(I2C_PORT, SDA_PIN); // 读取ACK信号
  gpio_bit_reset(I2C_PORT, SCL_PIN); // 拉低时钟线
  i2c_delay();
  return ack;
}


/*********************************************************
 * 函 数 名 称:i2c_read_byte
 * 函 数 说 明:从I2C总线读取一个字节,并发送ACK或NACK信号
 * 函 数 形 参:ack - ACK信号,0表示发送ACK,1表示发送NACK
 * 函 数 返 回:uint8_t - 读取到的数据字节
 * 作       者:LC
 * 备       注:无
*********************************************************/
static uint8_t i2c_read_byte(uint8_t ack)
{
  uint8_t i, data = 0;
  gpio_bit_set(I2C_PORT, SDA_PIN); // 确保数据线为高电平

  for (i = 0; i < 8; i++)
  {
    data <<= 1; // 左移一位,准备接收数据位
    gpio_bit_set(I2C_PORT, SCL_PIN); // 拉高时钟线,准备接收数据
    i2c_delay();


    if (gpio_input_bit_get(I2C_PORT, SDA_PIN))  // 检查数据线的状态
    {
      data |= 0x01;  // 如果数据线为高电平,将最低位设置为1
    }

    gpio_bit_reset(I2C_PORT, SCL_PIN);  // 拉低时钟线,准备接收下一位数据
    i2c_delay();
  }

  if (ack)
  {
    gpio_bit_reset(I2C_PORT, SDA_PIN); // 拉低数据线,发送NACK信号
  }
  else
  {
    gpio_bit_set(I2C_PORT, SDA_PIN); // 拉高数据线,发送ACK信号
  }

  gpio_bit_set(I2C_PORT, SCL_PIN); // 拉高时钟线,准备发送ACK或NACK信号
  i2c_delay();
  gpio_bit_reset(I2C_PORT, SCL_PIN); // 拉低时钟线
  i2c_delay();
  return data; // 返回读取到的数据字节
}


/*********************************************************
 * 函 数 名 称:i2c_write_data
 * 函 数 说 明:向I2C设备写入数据
 * 函 数 形 参:dev_addr - 设备地址
  reg_addr - 寄存器地址
  data - 要写入的数据数组指针
  len - 数据长度
 * 函 数 返 回:无
 * 作       者:LC
 * 备       注:无
*********************************************************/
void i2c_write_data(uint8_t dev_addr, uint8_t reg_addr, uint8_t *data, uint8_t len)
{
  i2c_start();
  i2c_write_byte((dev_addr << 1) & 0xFE);  // 写入设备地址
  i2c_write_byte(reg_addr);                // 写入寄存器地址

  for (uint8_t i = 0; i < len; i++)
  {
    i2c_write_byte(data[i]);              // 写入数据
  }

  i2c_stop();
}

/*********************************************************
 * 函 数 名 称:i2c_read_data
 * 函 数 说 明:从I2C设备读取数据
 * 函 数 形 参:dev_addr - 设备地址
  reg_addr - 寄存器地址
  data - 存储读取数据的数组指针
  len - 数据长度
 * 函 数 返 回:无
 * 作       者:LC
 * 备       注:无
*********************************************************/
void i2c_read_data(uint8_t dev_addr, uint8_t reg_addr, uint8_t *data, uint8_t len)
{
  i2c_start();
  i2c_write_byte((dev_addr << 1) & 0xFE);  // 写入设备地址
  i2c_write_byte(reg_addr);                // 写入寄存器地址
  i2c_start();
  i2c_write_byte((dev_addr << 1) | 0x01);  // 写入设备地址,读模式

  for (uint8_t i = 0; i < len; i++)
  {
    if (i == len - 1)
    {
      data[i] = i2c_read_byte(0);       // 读取最后一个字节,发送NACK
    }
    else
    {
      data[i] = i2c_read_byte(1);       // 读取字节,发送ACK
    }
  }

  i2c_stop();
}

2.INA226驱动主要包括以下功能
1.配置INA226:使用I2C接口发送配置命令和参数给INA226芯片。这些参数包括采样时间、测量范围等。
2.读取电压电流等数据:使用I2C接口从INA226芯片读取电流、电压和功率等数据。可以根据需要设置不同的读取频率和精度。
3.处理数据:根据实际的电路和采样电阻,需要选择合适的计算公式对从INA226读取的数据进行处理。可以使用公式和系数将原始数据转换为实际物理量。

代码2 INA226初始化、获取电压、电流、功率代码


/********************************************************************************
 * 测试硬件:立创·梁山派开发板GD32F470ZGT6    使用主频200Mhz    晶振25Mhz
 * 版 本 号: V1.0
 * 修改作者: LC
 * 修改日期: 2023年06月12日
 * 功能介绍:
 ******************************************************************************

*********************************************************************************/

#include "bsp_ina226.h"
#include "driver_i2c.h"

/************************************************
 * 函 数 名 称:ina226_init
 * 函 数 说 明:INA226初始化配置
 * 函 数 形 参:无
 * 函 数 返 回:无
 * 作       者:LC
 * 备       注:无
*************************************************/
void ina226_init()
{
  uint8_t config_data[2] = {0x80, 0x00}; 

  i2c_write_data(INA226Addr, 0x00, config_data, 2);  // 
  config_data[0] = 0x45;
  config_data[1] = 0x27;
  i2c_write_data(INA226Addr, 0x00, config_data, 2);  // 
  config_data[0] = 0x0A;
  config_data[1] = 0x00;
  i2c_write_data(INA226Addr, 0x05, config_data, 2);  // 
}

/************************************************
 * 函 数 名 称:ina226_get_voltage
 * 函 数 说 明:获取电压值
 * 函 数 形 参:无
 * 函 数 返 回:电压值(浮点数)
 * 作       者:LC
 * 备       注:无
*************************************************/
float ina226_get_voltage()
{
  uint8_t voltage_data[2];
  i2c_read_data(INA226Addr, 0x02, voltage_data, 2);  // 

  uint16_t data = (voltage_data[0] << 8) | voltage_data[1];
  float voltage = (float)data * 1.25 ; 
  return voltage;
}

/************************************************
 * 函 数 名 称:ina226_get_current
 * 函 数 说 明:获取电流值
 * 函 数 形 参:无
 * 函 数 返 回:电流值(浮点数)
 * 作       者:LC
 * 备       注:无
*************************************************/
float ina226_get_current()
{
  uint8_t current_data[2];
  i2c_read_data(INA226Addr, 0x04, current_data, 2);  // 
  int16_t data = (current_data[0] << 8) | current_data[1];
  float current = data * 0.02; 
  return current;
}

/************************************************
 * 函 数 名 称:ina226_get_power
 * 函 数 说 明:获取功率值
 * 函 数 形 参:无
 * 函 数 返 回:功率值(浮点数)
 * 作       者:LC
 * 备       注:无
*************************************************/
float ina226_get_power()
{
  uint8_t power_data[2];
  i2c_read_data(INA226Addr, 0x03, power_data, 2);  // 
  uint16_t data = (power_data[0] << 8) | power_data[1];
  float power = (float)data *  0.02 * 25; 
  return power;
}

2.46.5 移植验证

讲解代码移植成功后的现象,贴上完成该模块相关功能的图片或者视频。将代码上传飞书分享。
示例:
案例现象:
使用了120欧姆水泥电阻作为负载,并使用了万用表和INA226来分别测量电压数据。在正确连接电路之后,打开串口助手连接到立创·梁山派的串口,获取了电压、电流和功率数据。整个过程的现象如图所示。
正确连接电路后连接成功之后,立创·梁山派的串口向串口助手发送电压电流功率数据,现象如图所示。

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

成功示例文件

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

开源版中文和越南语贷款源码贷款平台下载 小额贷款系统 贷款源码运营版

后台 代理 前端均为vue源码&#xff0c;前端有中文和越南语 前端ui黄色大气&#xff0c;逻辑操作简单&#xff0c;注册可对接国际短信&#xff0c;可不对接 用户注册进去填写资料&#xff0c;后台审批&#xff0c;审批状态可自定义修改文字显示 源码免费下载地址抄笔记 (chaob…

Abstract Factory抽象工厂模式详解

模式定义 提供一个创建一系列相关或互相依赖对象的接口&#xff0c;而无需指定它们具体的类。 代码示例 public class AbstractFactoryTest {public static void main(String[] args) {IDatabaseUtils iDatabaseUtils new OracleDataBaseUtils();IConnection connection …

架构师系列-搜索引擎ElasticSearch(六)- 映射

映射配置 在创建索引时&#xff0c;可以预先定义字段的类型&#xff08;映射类型&#xff09;及相关属性。 数据库建表的时候&#xff0c;我们DDL依据一般都会指定每个字段的存储类型&#xff0c;例如&#xff1a;varchar、int、datetime等&#xff0c;目的很明确&#xff0c;就…

oarcle 19c ADG补丁升级(19.3-19.22)

一、备库操作 1.关闭备库数据库实例 sqlplus / as sysdba startup shutdown immediate # 查看oracle进程 ps -ef | grep sqlplus 2.关闭监听 lsnrctl start lsnrctl stop lsnrctl status 3.升级Opatch # 备份当前Opatch目录 su - oracle cd $ORACLE_HOME mv OPatch OPat…

康耐视visionpro-CogFindLineTool操作工具详细说明

◆CogFindeLineTool功能说明: 检测图像的直线边缘,实现边缘的定位、测量。 ◆CogFindeLineTool操作说明: ①.打开工具栏,双击或点击鼠标拖拽添加CogFindLineTool工具 ②.添加输入图像,点击鼠标右键“链接到”选择输入图像或以连线拖拽的方式选择相应输入图像 ③.所选空间…

Git-常规用法-含解决分支版本冲突解决方法

前置条件 已经创建了Gitee账号 创建一个远程仓库 个人主页-新建一个仓库-起好仓库名字-简介 远程仓库地址 Git的优点 Git是一个开源的分布式版本控制系统&#xff0c;可以有效、高速地处理从很小到非常大的项目版本管理。于2005年以GPL发布。采用了分布式版本库的做法&…

深入探索 RabbitMQ:功能丰富的消息中间件一

在现代分布式系统的构建中&#xff0c;消息中间件扮演着至关重要的角色。作为这一领域的佼佼者&#xff0c;RabbitMQ以其独特的特性和强大的功能&#xff0c;为应用程序提供了高效可靠的消息传递解决方案。以下是对RabbitMQ及其显著特点的更详细探讨。 什么是 RabbitMQ&#x…

考试酷基本功修炼课学习历程_FPGA成长篇

本文为明德扬原创文章&#xff0c;转载请注明出处&#xff01;作者&#xff1a;明德扬学员&#xff1a;考试酷账号&#xff1a;11167760 我是硬件工程师&#xff0c;日常工作中主要跟数字电路、模拟电路、嵌入式系统打交道&#xff0c;当然也会涉及到FPGA&#xff0c;但是苦于…

【Vue】新手一步一步安装 vue 语言开发环境

文章目录 1、下载node.js安装包 1、下载node.js安装包 1.打开node.js的官网下载地址&#xff1a;http://nodejs.cn/download/ 选择适合自己系统的安装包&#xff1a;winds、mac 2. 配置node.js和npm环境变量 安装好之后&#xff0c;对npm安装的全局模块所在路径以及缓存所在路…

05.MySQL索引事务

1. 索引 1.1 概念 索引是一种特殊的文件&#xff0c;包含着对数据表里所有记录的引用指针。 可以对表中的一列或多列创建索引&#xff0c;并指定索引的类型&#xff0c;各类索引有各自的数据结构实现 1.2 作用 数据库中的表、数据、索引之间的关系&#xff0c;类似于书架上的…

C++ - 面向对象(二)

一. 类的6个默认成员函数 在我们前面学习的类中&#xff0c;我们会定义成员变量和成员函数&#xff0c;这些我们自己定义的函数都是普通的成员函数&#xff0c;但是如若我们定义的类里什么也没有呢&#xff1f;是真的里面啥也没吗&#xff1f;如下 class Date {}; 如果一个类…

架构师系列-搜索引擎ElasticSearch(七)- 集群管理之分片

集群健康检查 Elasticsearch 的集群监控信息中包含了许多的统计数据&#xff0c;其中最为重要的一项就是集群健康&#xff0c;它在 status字段中展示为 green&#xff08;所有主分片和副本分片都正常&#xff09;、yellow&#xff08;所有数据可用&#xff0c;有些副本分片尚未…

EEG-GCNN 论文问题整理

auc是什么&#xff1f; AUC是指接收者操作特征曲线&#xff08;ROC曲线&#xff09;下的面积&#xff0c;用于评估分类模型的性能。AUC的取值范围在0到1之间&#xff0c;越接近1表示模型的性能越好&#xff0c;越接近0.5表示模型的性能越差。AUC的计算方法是通过计算ROC曲线下…

Kafka分布式数据处理平台

目录 一.消息队列基本介绍 1.为什么需要消息队列 2.使用消息队列的好处 2.1 解耦 耦合&#xff08;非解耦&#xff09; 解耦 2.2 可恢复性 2.3 缓冲 2.4 灵活性 & 峰值处理能力 2.5 异步通信 3.消息队列的两种模式 3.1 点对点模式 3.2 发布/订阅模式 二.Kafk…

【脚本】多功能Ubuntu临时授予用户sudo权限管理工具

转载请注明出处&#xff1a;小锋学长生活大爆炸[xfxuezhagn.cn] 设计原理和初衷可以看这里&#xff1a;【技巧】Ubuntu临时授予用户sudo权限&#xff0c;并在一定时间后自动撤销_ubuntu jianshao sudo-CSDN博客文章浏览阅读404次。非常实用_ubuntu jianshao sudohttps://blog.c…

# 达梦sql查询 Sql 优化

达梦sql查询 Sql 优化 文章目录 达梦sql查询 Sql 优化注意点测试数据单表查询 Sort 语句优化优化过程 多表关联SORT 优化函数索引的使用 注意点 关于优化过程中工具的选用&#xff0c;推荐使用自带的DM Manage&#xff0c;其它工具在查看执行计划等时候不明确在执行计划中命中…

Echarts简单的多表联动效果和添加水印和按钮切换数据效果

多表联动 多表联动效果指的是在多个表格之间建立一种交互关系&#xff0c;以便它们之间的操作或选择能够相互影响。通常情况下&#xff0c;多表联动效果可以通过以下方式之一实现&#xff1a; 数据关联&#xff1a; 当在一个表格中选择或操作某些数据时&#xff0c;另一个表格…

【opencv】示例-stiching.cpp 图像拼接

#include "opencv2/imgcodecs.hpp" // 导入opencv图像编码功能库 #include "opencv2/highgui.hpp" // 导入opencv高层用户界面功能库 #include "opencv2/stitching.hpp" // 导入opencv图像拼接功能库#include <iostream> // 导入输入输出…

Tool:VRAM的简介、查询电脑VRAM的常用方法

Tool&#xff1a;VRAM的简介、查询电脑VRAM的常用方法 目录 VRAM的简介 查询电脑VRAM的常用方法 1、对于Windows系统 T1、设置-系统-显示查询法 T2、使用 DirectX 诊断工具&#xff1a; T3、使用系统信息工具&#xff1a; 2、对于Linux系统 T1、使用nvidia-smi命令&…

IO流基本流

目录 什么是IO流 IO流的体系 字节流 FileOutputStream FileInputStream 字符集 字符流 FileReader FileWriter 字节流和字符流的使用场景 什么是IO流 内存不能永久化存储,程序停止,数据丢失,所以要添加一个存档功能,存储到硬盘的文件,我们要知道文件在哪里和如何传…