基于RT-Thread驱动EEPROM_AD24C02

基于RT-Thread驱动EEPROM_AD24C02

  • 前言
  • 一、硬件设计
  • 二、软件设计
  • 三、测试
    • 1、eeprom_test()测试
    • 2、基础操作字节实验
    • 3、多字节读写

前言

  1. 存储容量2048位,内部组织256x8(2K),即256个字节的存储单元;分为16页,每页16个字节
  2. 具有写保护,擦写寿命1,000,000次,数据保存期限100年
  3. 写操作可按字节写,也可按页写。
  4. I2C通信,器件从机写地址0x50, 从机读地址0x51
    在这里插入图片描述

一、硬件设计

  1. WP引脚上拉,这个引脚是写保护引脚,低电平解开保护,可以读写。高电平写保护,
    在这里插入图片描述
  2. 通过IIC即可与之通信。
    在这里插入图片描述

二、软件设计

  1. 创建工程
    在这里插入图片描述

  2. 打开RT-Thread Settings
    在这里插入图片描述

  3. 打开I2C设备驱动程序
    在这里插入图片描述

  4. 使能I2C模块
    在这里插入图片描述

  5. 进入board.h打开I2C1的的宏定义,SCL跟SDA引脚的绑定需要根据你实际硬件连接去修改
    在这里插入图片描述

  6. 主函数中这么写
    在这里插入图片描述

  7. 在applications文件夹下新建一个system_deal文件夹,然后再在system_deal文件夹下新建一个system_deal.csystem_deal.h文件,这个文件夹里我放一个给板子闪灯的程序,判断板子是否跑起来
    在这里插入图片描述

  8. system_deal.c文件里这么写

/** Copyright (c) 2006-2021, RT-Thread Development Team** SPDX-License-Identifier: Apache-2.0** Change Logs:* Date           Author       Notes* 2025-04-18     Administrator       the first version*/#include "system_deal.h"/*********************************************************************************************************** Function name:       SystemLedRun** Descriptions:        System Led Run** input parameters:    NONE** output parameters:   NONE** Returned value:      NONE*********************************************************************************************************/
static void SystemLedRun(void)
{static uint8_t l_ucmode = 0;if (l_ucmode == 0){rt_pin_write(SYS_LED, PIN_HIGH);l_ucmode = 1;}else if (l_ucmode == 1){rt_pin_write(SYS_LED, PIN_LOW);l_ucmode = 0;}
}/*********************************************************************************************************** Function name:       SysDeal_thread** Descriptions:        SysDeal thread** input parameters:    parameter** output parameters:   NONE** Returned value:      NONE*********************************************************************************************************/
static void SysDeal_thread(void* parameter)
{// set pinrt_pin_mode(SYS_LED, PIN_MODE_OUTPUT);rt_pin_write(SYS_LED, PIN_HIGH);while(1){SystemLedRun();   //闪个灯rt_thread_mdelay(500);}}/*********************************************************************************************************** Function name:       SystemDealTaskInit** Descriptions:        System Task Init** input parameters:    NONE** output parameters:   NONE** Returned value:      NONE*********************************************************************************************************/
void SystemDealTaskInit(void)
{rt_thread_t SysDeal_tid;SysDeal_tid = rt_thread_create("sys_ctl", SysDeal_thread, RT_NULL, SYS_THREAD_STACK, SYS_THREAD_PRO, SYS_THREAD_TICK);if (SysDeal_tid != RT_NULL){rt_thread_startup(SysDeal_tid);}else{
#if DEBUG_LOG_ENABLErt_kprintf("/--> SysDeal create failed!\n");
#endif}
}/*********************************************************************************************************** Function name:       SystemTaskInit** Descriptions:        System Task Init** input parameters:    NONE** output parameters:   NONE** Returned value:      NONE*********************************************************************************************************/
static void SystemTaskInit(void)
{SystemDealTaskInit();  // 15}/*********************************************************************************************************** Function name:       SystemStartInit** Descriptions:        System Start Init** input parameters:    NONE** output parameters:   NONE** Returned value:      NONE*********************************************************************************************************/
void SystemStartInit(void)
{SystemTaskInit();
}
  1. system_deal.h文件里这么写
/** Copyright (c) 2006-2021, RT-Thread Development Team** SPDX-License-Identifier: Apache-2.0** Change Logs:* Date           Author       Notes* 2025-04-18     Administrator       the first version*/
#ifndef APPLICATIONS_SYSTEM_DEAL_SYSTEM_DEAL_H_
#define APPLICATIONS_SYSTEM_DEAL_SYSTEM_DEAL_H_#include <rtdevice.h>
#include <rtthread.h>
#include "board.h"
#include "stdio.h"/* system io */
#define SYS_LED             GET_PIN(G, 13)/* thread information */
#define SYS_THREAD_STACK 1024
#define SYS_THREAD_PRO 15
#define SYS_THREAD_TICK 10extern void SystemStartInit(void);#endif /* APPLICATIONS_SYSTEM_DEAL_SYSTEM_DEAL_H_ */
  1. 在applications文件夹下新建drv_ad24c02文件夹,再在drv_ad24c02文件夹下新建drv_ad24c02.cdrv_ad24c02.h文件,这个文件夹里写的是ad24c02的驱动
    在这里插入图片描述
  2. drv_ad24c02.c文件里这么写
    在这里插入图片描述
/** Copyright (c) 2006-2021, RT-Thread Development Team** SPDX-License-Identifier: Apache-2.0** Change Logs:* Date           Author       Notes* 2025-04-18     Administrator       the first version*/
#include "drv_ad24c02.h"static struct rt_i2c_bus_device *i2c_bus = RT_NULL;
/*** eeprom write byte* @note This operation is write one bye to eeprom.** @param addr: the data address to write*        data: the data write to the address** @return >= 0: successful*           -1: error**/
rt_err_t eeprom_write_byte(uint8_t addr, uint8_t data)
{struct rt_i2c_msg msg;uint8_t buffer[2];buffer[0] = addr;buffer[1] = data;msg.addr  = EEPROM_I2C_ADDR;msg.flags = RT_I2C_WR;msg.buf = buffer;msg.len = 2;if(rt_i2c_transfer(i2c_bus, &msg, 1) != 1){rt_kprintf("eeprom i2c data write error.\n");return RT_ERROR;}rt_thread_mdelay(5);return RT_EOK;
}
/*** eeprom read byte* @note This operation is read one bye from eeprom.** @param addr: the data address to read** @return data: the data read from the address***/
uint8_t eeprom_read_byte(uint8_t addr)
{struct rt_i2c_msg msg;uint8_t buffer[2];uint8_t data;msg.addr = EEPROM_I2C_ADDR;msg.flags = RT_I2C_WR;buffer[0] = addr;msg.buf = buffer;msg.len = 1;rt_i2c_transfer(i2c_bus, &msg, 1);msg.flags = RT_I2C_RD;msg.buf = &data;rt_i2c_transfer(i2c_bus, &msg, 1);return data;
}
/*** eeprom check* @note This operation is check eeprom.** @param** @return >= 0: successful*           -1: error**/
static rt_err_t eeprom_check(uint8_t data)
{uint8_t temp;temp = eeprom_read_byte(EEPROM_SIZE - 1);if(temp != data){eeprom_write_byte(EEPROM_SIZE - 1, data);rt_thread_mdelay(5);temp = eeprom_read_byte(EEPROM_SIZE - 1);if(temp != data){
#if 1rt_kprintf("eeprom check data [0x%02X] not equal read data [0x%02X].\n", data, temp);
#endifreturn RT_ERROR;}rt_kprintf("eeprom check data [0x%02X] equal read data [0x%02X].\n", data, temp);}return RT_EOK;
}/*** eeprom init* @note This operation is eeprom init.** @param** @return >= 0: successful*           -1: error**/
rt_err_t eeprom_init(void)
{i2c_bus = (struct rt_i2c_bus_device *)rt_device_find(EEPROM_I2C_BUS_NAME);if (i2c_bus == RT_NULL){rt_kprintf("eeprom i2c bus find error.\n");return RT_ERROR;}rt_pin_mode(EEPROM_WP_PIN, PIN_MODE_OUTPUT);rt_pin_write(EEPROM_WP_PIN, PIN_LOW);if(eeprom_check(EEPROM_CHECK_VALUE) != RT_EOK){rt_kprintf("eeprom check error.\n");return RT_ERROR;}else {rt_kprintf("eeprom check success.\n");}return RT_EOK;
}/*** eeprom test* @note This operation is test eeprom.** @param** @return >= 0: successful*           -1: error**/
static int eeprom_test(void)
{rt_uint8_t *rw_buf = RT_NULL;rw_buf = (rt_uint8_t *)rt_malloc(EEPROM_SIZE);    //分配一个256字节大小的空间eeprom_init();//erase eepromfor(rt_uint16_t addr = 0; addr < EEPROM_SIZE; addr++){if(RT_EOK == eeprom_write_byte(addr, 0)){rt_kprintf("address [0x%02X] erase OK.\n", addr);}else{rt_kprintf("address [0x%02X] erase failed.\n", addr);}}rt_kprintf("\n");rt_thread_mdelay(1000);//read eepromfor(rt_uint16_t addr = 0; addr < EEPROM_SIZE; addr++){rw_buf[addr] = eeprom_read_byte(addr);rt_kprintf("address [0x%02X] data is [%d].\n", addr, rw_buf[addr]);}rt_kprintf("\n");rt_thread_mdelay(1000);//write eepromfor(rt_uint16_t addr = 0; addr < EEPROM_SIZE; addr++){if(RT_EOK == eeprom_write_byte(addr, 0XFF)){rt_kprintf("address [0x%02X] write OK.\n", addr);}else{rt_kprintf("address [0x%02X] write failed.\n", addr);}}rt_kprintf("\n");rt_thread_mdelay(1000);//read eepromfor(rt_uint16_t addr = 0; addr < EEPROM_SIZE; addr++){rw_buf[addr] = eeprom_read_byte(addr);rt_kprintf("address [0x%02X] data is [%d].\n", addr, rw_buf[addr]);}//freert_free(rw_buf);return RT_EOK;
}
MSH_CMD_EXPORT(eeprom_test, eeprom test);static void basic_test(int argc, char** argv)
{if (argc != 3){rt_kprintf("Usage: basic_test [addr(0-255)] [data(0-255)]\n");return;}uint8_t addr = atoi(argv[1]);uint8_t wr_data = atoi(argv[2]);// 写入并验证eeprom_write_byte(addr, wr_data);uint8_t rd_data = eeprom_read_byte(addr);rt_kprintf("Immediate read: Addr 0x%02X => Wr:0x%02X Rd:0x%02X %s \r\n",addr, wr_data, rd_data, (wr_data == rd_data) ? "OK" : "FAIL");// 重启后验证rt_kprintf("Power cycle device and run again to check persistence");
}
MSH_CMD_EXPORT(basic_test, basic single-byte test);static void read_test(int argc, char** argv)
{if(argc != 2){rt_kprintf("Usage: read_test [addr(0-255)]\n");return;}uint8_t addr = atoi(argv[1]);uint8_t rd_data = eeprom_read_byte(addr);rt_kprintf("Immediate read: Addr %d => Rd:%d \r\n",addr, rd_data);}
MSH_CMD_EXPORT(read_test, read single-byte test);
  1. drv_ad24c02.h文件里这么写
    在这里插入图片描述
/** Copyright (c) 2006-2021, RT-Thread Development Team** SPDX-License-Identifier: Apache-2.0** Change Logs:* Date           Author       Notes* 2025-04-18     Administrator       the first version*/
#ifndef APPLICATIONS_DRV_AD24C02_DEAL_DRV_AD24C02_H_
#define APPLICATIONS_DRV_AD24C02_DEAL_DRV_AD24C02_H_#include <rtdevice.h>
#include <rtthread.h>
#include "board.h"
#include "stdio.h"
#include "stdlib.h"#define EEPROM_I2C_BUS_NAME         "i2c1"
#define EEPROM_I2C_ADDR             0x50        //0xA0 << 1
#define EEPROM_SIZE                  256         //Byte
#define EEPROM_CHECK_VALUE           0x5A/*********************************eeprom**************************************************/
#define EEPROM_WP_PIN               GET_PIN(B, 4)extern rt_err_t eeprom_init(void);   //ad24c02初始化
#endif /* APPLICATIONS_DRV_AD24C02_DEAL_DRV_AD24C02_H_ */
  1. 包含头文件
    在这里插入图片描述
  2. 找个位置进行ad24c02初始化
    在这里插入图片描述
  3. 包含一下ad24c02驱动头文件
    在这里插入图片描述
  4. 编译通过
    在这里插入图片描述

三、测试

1、eeprom_test()测试

在MSH中使用命令行敲出eeprom_test进行测试。

  1. 先打help可以看到目前有什么指令,然后输入eeprom_test进行测试,按TAB键可以自动补齐。
    在这里插入图片描述

  2. 该测试函数首先会往eeprom的256个字节中写0,一个字节一个字节的写,每写成功一个都会返回erase OK
    在这里插入图片描述

  3. 写完后,又会再读出来,可以看到我们写进去是0,那读出来也是0
    在这里插入图片描述

  4. 然后又往这256个字节里面写,不过这回写的是0XFF
    在这里插入图片描述

  5. 然后再读,0XFF对应十进制就是255。
    在这里插入图片描述

  6. 检查打印,看是否都写成功,然后读出来是否是前面一次是0,后面这次是255。如果符合预期,说明咱的eeprom驱动写得没问题了。

2、基础操作字节实验

步骤:

  1. 在指定地址写入特定值
  2. 立即读取验证
  3. 断电重启再次读取验证持久性
    在MSH中敲出命令行,使用basic_test ,第一个参数写地址,第二个参数写数据
    在这里插入图片描述
    可以看到有返回,当然我们写进去的地址跟数据使用的是十进制,返回的使用的是十六进制,所以看起来不一样,自己换算一下可以发现是一样的。
    在这里插入图片描述
    我们再用read_test去读这个23地址,我们刚刚就在这个23地址中写入了66
    在这里插入图片描述
    可以发现读出来的是66
    在这里插入图片描述
    进行一次重启(即掉电),可以发现读出来的还是66,说明eeprom是起作用的
    在这里插入图片描述

3、多字节读写

新增这两个函数,这两个函数可以进行多字节读写

int16_t eeprom_write_params(uint8_t *buf, int16_t start_index, int16_t buf_len)
{static int write_count = 0;rt_kprintf("[EEPROM] write count : %d, write len : %d\n", ++write_count, buf_len);if (start_index + buf_len >= EEPROM_SIZE){rt_kprintf("EEPROM write params assert\n");return RT_ERROR;}// Write data to EEPROMfor (int16_t i = 0; i < buf_len; i++){if (eeprom_write_byte(start_index + i, buf[i]) != RT_EOK){rt_kprintf("EEPROM write error at address %d\n", start_index + i);return RT_ERROR;}}// Verify the written datauint8_t tmp_mem[buf_len];for (int16_t i = 0; i < buf_len; i++){tmp_mem[i] = eeprom_read_byte(start_index + i);if (tmp_mem[i] != buf[i]){rt_kprintf("EEPROM write verify failed at address %d\n", start_index + i);return RT_ERROR;}else{rt_kprintf("EEPROM write verify success at address %d\n", start_index + i);}}return RT_EOK;
}//eeprom read
int16_t eeprom_read_params(uint8_t *buf, int16_t start_index, int16_t buf_len)
{if (start_index + buf_len >= EEPROM_SIZE || buf == RT_NULL){rt_kprintf("EEPROM read params assert\n");return RT_ERROR;}// Read data from EEPROMfor (int16_t i = 0; i < buf_len; i++){buf[i] = eeprom_read_byte(start_index + i);}return RT_EOK;
}

再新加这个测试函数,用于验证

void eeprom_tes2(void)
{uint8_t write_buf[TEST_DATA_SIZE] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};uint8_t read_buf[TEST_DATA_SIZE] = {0};int16_t start_index = 0;// 初始化 EEPROMif (eeprom_init() != RT_EOK){rt_kprintf("EEPROM initialization failed\n");return;}// 向 EEPROM 写入数据if (eeprom_write_params(write_buf, start_index, TEST_DATA_SIZE) != RT_EOK){rt_kprintf("EEPROM write params failed\n");return;}rt_thread_mdelay(100); // 适当延时,确保写入完成// 从 EEPROM 读取数据if (eeprom_read_params(read_buf, start_index, TEST_DATA_SIZE) != RT_EOK){rt_kprintf("EEPROM read params failed\n");return;}// 验证写入和读取的数据是否一致for (int16_t i = 0; i < TEST_DATA_SIZE; i++){if (write_buf[i] != read_buf[i]){rt_kprintf("Data verification failed at index %d: write %d, read %d\n", i, write_buf[i], read_buf[i]);return;}}rt_kprintf("EEPROM read and write test passed\n");
}MSH_CMD_EXPORT(eeprom_tes2, EEPROM read and write test);

验证结果
在这里插入图片描述

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

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

相关文章

五、Hive表类型、分区及数据加载

在 Hive 中高效构建、管理和查询数据仓库&#xff0c;核心在于精准运用表类型&#xff08;内部/外部&#xff09;与分区策略&#xff08;静态/动态/多重&#xff09;。这不仅决定数据的生命周期归属&#xff0c;更是优化海量数据查询性能的关键手段。 一、表的身份权责&#x…

C++色彩博弈的史诗:红黑树

文章目录 1.红黑树的概念2.红黑树的结构3.红黑树的插入4.红黑树的删除5.红黑树与AVL树的比较6.红黑树的验证希望读者们多多三连支持小编会继续更新你们的鼓励就是我前进的动力&#xff01; 红黑树是一种自平衡二叉查找树&#xff0c;每个节点都带有颜色属性&#xff0c;颜色或为…

基于STM32、HAL库的CH342F USB转UART收发器 驱动程序设计

一、简介: CH342F是一款USB转串口芯片,由南京沁恒电子(WCH)生产,具有以下特点: 支持USB转UART、IrDA红外或SPI接口 内置时钟,无需外部晶振 支持5V和3.3V电源电压 最高支持3Mbps波特率 支持常用的MODEM联络信号 内置EEPROM,可配置设备VID/PID/序列号等 二、硬件接口: C…

项目功能-图片清理(上)

一、图片存储介绍 在实际开发中&#xff0c;我们会有很多处理不同功能的服务器。例如&#xff1a; 应用服务器&#xff1a;负责部署我们的应用 数据库服务器&#xff1a;运行我们的数据库 文件服务器&#xff1a;负责存储用户上传文件的服务器 分服务器处理的目的是让服务…

创建三个网络,分别使用RIP、OSPF、静态,并每个网络10个电脑。使用DHCP分配IP

DHCP 自动分配IP&#xff0c;集中管理&#xff0c;提高效率 在路由器中设置 Router>en Router#conf t Router(config)#ip dhcp pool ip30 //创建DHCP地址池 Router(dhcp-config)#network 192.168.30.0 255.255.255.0 // 配置网络地址和子网掩码 Router(dhcp-config)#defa…

如何使用 WMIC 命令在 Windows 11 或 10 上卸载软件

如果您正在寻找一个命令提示符或 PowerShell 命令来卸载 Windows 应用程序,那么使用 wmic(Windows Management Instrumentation Command-line)是一种强大的技术,尤其是在处理难以卸载的程序或自动化卸载过程时。在本教程中,我们将学习如何使用 wmic 来卸载软件。 先决条件…

FEKO许可证的安全与合规性

在电磁仿真领域&#xff0c;FEKO软件因其出类拔萃的性能和广泛的应用场景&#xff0c;赢得了全球用户的广泛赞誉。但在这背后&#xff0c;是什么让FEKO在众多竞争者中脱颖而出&#xff1f;答案是其许可证的安全与合规性。它们不仅为用户提供了坚固的保障&#xff0c;更确保了用…

ESP32开发入门(九):HTTP服务器开发实践

一、HTTP服务器基础 1.1 什么是HTTP服务器&#xff1f; HTTP服务器是能够处理HTTP请求并返回响应的网络服务程序。在物联网应用中&#xff0c;ESP32可以作为轻量级HTTP服务器&#xff0c;直接接收来自客户端(如浏览器、手机APP)的请求。 1.2 ESP32作为HTTP服务器的特点 轻量…

《棒球百科》MLB棒球公益课·棒球1号位

MLB&#xff08;美国职业棒球大联盟&#xff09;的棒球公益课通过推广棒球运动、普及体育教育&#xff0c;对全球多个地区产生了多层次的影响&#xff1a; 1. 体育文化推广 非传统棒球地区的普及&#xff1a;在棒球基础较弱的地区&#xff08;如中国、欧洲部分国家&#xff09…

Baumer工业相机堡盟工业相机的工业视觉是否可以在室外可以做视觉检测项目

Baumer工业相机堡盟工业相机的工业视觉是否可以在室外可以做视觉检测项目 Baumer工业相机​视觉检测项目为什么偏爱“室内环境”&#xff1f;​工业视觉中为什么倾向于室内环境**保障人员与设备安全**&#xff1a;室内环境可以提供更好的安全保障&#xff0c;避免检测设备和人员…

1. 使用 IntelliJ IDEA 创建 React 项目:创建 React 项目界面详解;配置 Yarn 为包管理器

1. 使用 IntelliJ IDEA 创建 React 项目&#xff1a;创建 React 项目界面详解&#xff1b;配置 Yarn 为包管理器 &#x1f9e9; 使用 IntelliJ IDEA 创建 React 项目&#xff08;附 Yarn 配置与 Vite 建议&#xff09;&#x1f4f7; 创建 React 项目界面详解1️⃣ Name&#xf…

C++GO语言微服务之用户信息处理②

目录 01 03-获取用户信息-上 02 04-获取用户信息-下 03 05-更新用户名实现 01 06-中间件简介和中间件类型 02 07-中间件测试和模型分析 03 08-中间件测试案例和小结 04 09-项目使用中间件 01 03-获取用户信息-上 ## Cookie操作 ### 设置Cookie go func (c *Context) …

QMK键盘固件开发全解析:QMK 固件开发的最新架构和规范(2025最新版)

QMK键盘固件开发全解析:QMK 固件开发的最新架构和规范(2025最新版) 📚 前言概述 QMK(Quantum Mechanical Keyboard)作为目前开源键盘固件领域的"扛把子",凭借其强大的功能和活跃的社区支持,已经成为众多DIY键盘爱好者的首选开发框架。无论是入门级玩家还是资…

极狐GitLab 容器镜像仓库功能介绍

极狐GitLab 是 GitLab 在中国的发行版&#xff0c;关于中文参考文档和资料有&#xff1a; 极狐GitLab 中文文档极狐GitLab 中文论坛极狐GitLab 官网 极狐GitLab 容器镜像库 (BASIC ALL) 您可以使用集成的容器镜像库&#xff0c;来存储每个极狐GitLab 项目的容器镜像。 要为您…

Umi+React+Xrender+Hsf项目开发总结

一、菜单路由配置 1.umirc.ts 中的路由配置 .umirc.ts 文件是 UmiJS 框架中的一个配置文件&#xff0c;用于配置应用的全局设置&#xff0c;包括但不限于路由、插件、样式等。 import { defineConfig } from umi; import config from ./def/config;export default defineCon…

【运维】基于Python打造分布式系统日志聚合与分析利器

《Python OpenCV从菜鸟到高手》带你进入图像处理与计算机视觉的大门! 解锁Python编程的无限可能:《奇妙的Python》带你漫游代码世界 在分布式系统中,日志数据分散在多个节点,管理和分析变得复杂。本文详细介绍如何基于Python开发一个日志聚合与分析工具,结合Logstash和F…

Python实战:海量获取京东商品信息

在数据驱动的商业时代&#xff0c;数据就是最宝贵的资源。对于电商从业者、市场分析师而言&#xff0c;从京东这类大型电商平台获取商品信息&#xff0c;能够为市场调研、竞品分析、销售策略制定提供重要依据。今天&#xff0c;就来分享如何用Python实现京东商品信息的海量获取…

聊一聊常见的超时问题:timeout

大家好&#xff0c;我是G探险者&#xff01; 在日常开发中&#xff0c;“超时&#xff08;Timeout&#xff09;”类错误是开发者们经常遇到的问题。无论是调用第三方服务、访问数据库&#xff0c;还是并发任务处理&#xff0c;都可能因超时而导致请求失败或系统异常。 本文将系…

创建型模式:工厂方法(Factory Method)模式

一、简介 工厂方法(Factory Method)模式是一种创建型设计模式,它定义了一个创建对象的接口,但让子类决定实例化哪一个类。工厂方法使一个类的实例化延迟到其子类。在 C# 中,工厂方法模式提供了一种更灵活的对象创建方式,将对象的创建和使用分离,提高了代码的可维护性和…

外网访问内网海康威视监控视频的方案:WebRTC + Coturn 搭建

外网访问内网海康威视监控视频的方案&#xff1a;WebRTC Coturn 需求背景 在仓库中有海康威视的监控摄像头&#xff0c;内网中是可以直接访问到监控摄像的画面&#xff0c;由于项目的需求&#xff0c;需要在外网中也能看到监控画面。 实现这个功能的意义在于远程操控设备的…