当前位置: 首页 > article >正文

ESP32学习笔记之UART

第一部分UART 核心概念1. 什么是 UARTUART 中文常叫“通用异步收发器”“异步”意思是通信双方不共享时钟所以要提前约定好通信参数。 UART 本质上就是按约定好的速度把 0 和 1 一位一位串行发出去关键特点串行通信一位一位传节省引脚异步通信无时钟线靠约定波特率全双工可同时收发点对点通常两个设备直连更详细的UART知识https://blog.csdn.net/2301_81636338/article/details/157764671?spm1011.2124.3001.62092. 一帧数据的组成起始位1 位标志传输开始数据位5~9 位常用 8 位校验位可选奇校验 / 偶校验 / 无校验停止位1 或 2 位标志帧结束常见配置8N18 数据位无校验1 停止位1 起始 8 数据 1 停止 10 位 / 字节3. 波特率定义每秒传输的 bit 数例9600 波特 9600 bit/s ≈960 字节/秒因为 1 字节占 10 位4. 为什么需要起始位和停止位因为没有时钟线接收方需要通过起始位同步知道“数据开始了”按约定时间采样每位通过停止位知道“这一帧结束了”5. UART vs I2C vs SPI特性UARTI2CSPI同步/异步异步同步同步双工方式全双工半双工全双工线数2 (TX, RX) 地2 (SDA, SCL)4 (SCK, MOSI, MISO, CS)设备数点对点多设备地址一主多从片选第二部分UART 常见问题与排查参数不一致检查波特率、数据位、停止位、校验位是否匹配接线问题TX ↔ RX 交叉连接共地GND 必须相连软件问题缓冲区溢出接收处理不及时中断优先级、任务调度第三部分ESP32 UART 实践UART 初始化步骤配置参数结构体uart_config_t波特率、数据位、停止位、校验位等设置引脚uart_set_pin()安装驱动uart_driver_install()收发数据循环发送 Helloc #include stdio.h #include string.h #include freertos/FreeRTOS.h #include freertos/task.h #include driver/uart.h #include esp_err.h #define UART_PORT_NUM UART_NUM_1 #define UART_BAUD_RATE 115200 #define UART_TX_PIN 17 #define UART_RX_PIN 18 #define UART_BUF_SIZE 1024 void app_main(void) { uart_config_t uart_config { .baud_rate UART_BAUD_RATE, .data_bits UART_DATA_8_BITS, .parity UART_PARITY_DISABLE, .stop_bits UART_STOP_BITS_1, .flow_ctrl UART_HW_FLOWCTRL_DISABLE, .source_clk UART_SCLK_DEFAULT, }; ESP_ERROR_CHECK(uart_param_config(UART_PORT_NUM, uart_config)); ESP_ERROR_CHECK(uart_set_pin( UART_PORT_NUM, UART_TX_PIN, UART_RX_PIN, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE)); ESP_ERROR_CHECK(uart_driver_install( UART_PORT_NUM, UART_BUF_SIZE, UART_BUF_SIZE, 0, NULL, 0)); const char *msg Hello from ESP32-S3 UART1\r\n; while (1) { uart_write_bytes(UART_PORT_NUM, msg, strlen(msg)); printf(UART1 sent: %s, msg); vTaskDelay(pdMS_TO_TICKS(1000)); } }回显Echoc #include stdio.h #include string.h #include freertos/FreeRTOS.h #include freertos/task.h #include driver/uart.h #include esp_err.h #define UART_PORT_NUM UART_NUM_1 #define UART_BAUD_RATE 115200 #define UART_TX_PIN 17 #define UART_RX_PIN 16 #define UART_BUF_SIZE 1024 void app_main(void) { uart_config_t uart_config { .baud_rate UART_BAUD_RATE, .data_bits UART_DATA_8_BITS, .parity UART_PARITY_DISABLE, .stop_bits UART_STOP_BITS_1, .flow_ctrl UART_HW_FLOWCTRL_DISABLE, .source_clk UART_SCLK_DEFAULT, }; ESP_ERROR_CHECK(uart_param_config(UART_PORT_NUM, uart_config)); ESP_ERROR_CHECK(uart_set_pin( UART_PORT_NUM, UART_TX_PIN, UART_RX_PIN, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE)); ESP_ERROR_CHECK(uart_driver_install( UART_PORT_NUM, UART_BUF_SIZE, UART_BUF_SIZE, 0, NULL, 0)); uint8_t data[UART_BUF_SIZE]; while (1) { int len uart_read_bytes( UART_PORT_NUM, data, UART_BUF_SIZE - 1, pdMS_TO_TICKS(100)); if (len 0) { data[len] \0; printf(UART1 received: %s\n, (char *)data); uart_write_bytes(UART_PORT_NUM, (const char *)data, len); } } }中断方式事件队列使用队列接收 UART 事件数据到达、溢出、错误等适合需要高效处理、不丢数据的场景#include stdio.h #include string.h #include freertos/FreeRTOS.h #include freertos/task.h #include freertos/queue.h #include driver/uart.h #include esp_err.h #include esp_log.h #define UART_PORT_NUM UART_NUM_1 #define UART_BAUD_RATE 115200 #define UART_TX_PIN 17 #define UART_RX_PIN 16 #define UART_BUF_SIZE 1024 #define UART_QUEUE_SIZE 20 static const char *TAG uart1_intr; static QueueHandle_t uart_queue; static void uart_event_task(void *pvParameters) { uart_event_t event; uint8_t data[UART_BUF_SIZE]; while (1) { if (xQueueReceive(uart_queue, event, portMAX_DELAY)) { switch (event.type) { case UART_DATA: int len uart_read_bytes( UART_PORT_NUM, data, event.size UART_BUF_SIZE - 1 ? event.size : UART_BUF_SIZE - 1, 0); if (len 0) { data[len] \0; ESP_LOGI(TAG, recv: %s, (char *)data); uart_write_bytes(UART_PORT_NUM, (const char *)data, len); } break; case UART_FIFO_OVF: case UART_BUFFER_FULL: ESP_LOGW(TAG, overflow or buffer full); uart_flush_input(UART_PORT_NUM); xQueueReset(uart_queue); break; case UART_BREAK: case UART_PARITY_ERR: case UART_FRAME_ERR: ESP_LOGW(TAG, error event: %d, event.type); break; default: break; } } } } void app_main(void) { uart_config_t uart_config { .baud_rate UART_BAUD_RATE, .data_bits UART_DATA_8_BITS, .parity UART_PARITY_DISABLE, .stop_bits UART_STOP_BITS_1, .flow_ctrl UART_HW_FLOWCTRL_DISABLE, .source_clk UART_SCLK_DEFAULT, }; ESP_ERROR_CHECK(uart_param_config(UART_PORT_NUM, uart_config)); ESP_ERROR_CHECK(uart_set_pin( UART_PORT_NUM, UART_TX_PIN, UART_RX_PIN, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE)); ESP_ERROR_CHECK(uart_driver_install( UART_PORT_NUM, UART_BUF_SIZE, UART_BUF_SIZE, UART_QUEUE_SIZE, uart_queue, 0)); xTaskCreate(uart_event_task, uart_event_task, 4096, NULL, 12, NULL); ESP_LOGI(TAG, UART1 interrupt event echo started); }DMA 方式高性能#include stdio.h #include string.h #include freertos/FreeRTOS.h #include freertos/task.h #include driver/uart.h #include esp_attr.h #include esp_log.h #include esp_private/gdma.h #include esp_private/periph_ctrl.h #include hal/uhci_ll.h #include soc/lldesc.h #define UART_PORT_NUM UART_NUM_1 #define UART_BAUD_RATE 115200 #define UART_TX_PIN 17 #define UART_RX_PIN 16 #define DMA_RX_BUF_SIZE 1024 #define DMA_TX_BUF_SIZE 1024 #define DMA_DESC_NUM 1 #define UART_RX_TOUT_THRESH 10 #define TASK_STACK_SIZE 4096 #define RX_DONE_BIT (1U 0) #define TX_DONE_BIT (1U 1) static const char *TAG uart_dma_echo; static volatile uhci_dev_t *s_uhci_hw UHCI0; static gdma_channel_handle_t s_rx_channel; static gdma_channel_handle_t s_tx_channel; static TaskHandle_t s_dma_task_hdl; DMA_ATTR static uint8_t s_rx_buf[DMA_RX_BUF_SIZE]; DMA_ATTR static uint8_t s_tx_buf[DMA_TX_BUF_SIZE]; DMA_ATTR static lldesc_t s_rx_desc[DMA_DESC_NUM]; DMA_ATTR static lldesc_t s_tx_desc[DMA_DESC_NUM]; static bool IRAM_ATTR rx_eof_callback(gdma_channel_handle_t dma_chan, gdma_event_data_t *event_data, void *user_data) { BaseType_t high_task_wakeup pdFALSE; (void)dma_chan; (void)event_data; (void)user_data; xTaskNotifyFromISR(s_dma_task_hdl, RX_DONE_BIT, eSetBits, high_task_wakeup); return high_task_wakeup pdTRUE; } static bool IRAM_ATTR tx_eof_callback(gdma_channel_handle_t dma_chan, gdma_event_data_t *event_data, void *user_data) { BaseType_t high_task_wakeup pdFALSE; (void)dma_chan; (void)event_data; (void)user_data; xTaskNotifyFromISR(s_dma_task_hdl, TX_DONE_BIT, eSetBits, high_task_wakeup); return high_task_wakeup pdTRUE; } static void start_rx_dma(void) { memset(s_rx_buf, 0, sizeof(s_rx_buf)); memset(s_rx_desc, 0, sizeof(s_rx_desc)); lldesc_setup_link(s_rx_desc, s_rx_buf, DMA_RX_BUF_SIZE, true); ESP_ERROR_CHECK(gdma_reset(s_rx_channel)); ESP_ERROR_CHECK(gdma_start(s_rx_channel, (intptr_t)s_rx_desc[0])); } static void start_tx_dma(const uint8_t *data, size_t len) { if (len 0 || len DMA_TX_BUF_SIZE) { return; } memcpy(s_tx_buf, data, len); memset(s_tx_desc, 0, sizeof(s_tx_desc)); lldesc_setup_link(s_tx_desc, s_tx_buf, len, false); ESP_ERROR_CHECK(gdma_reset(s_tx_channel)); ESP_ERROR_CHECK(gdma_start(s_tx_channel, (intptr_t)s_tx_desc[0])); } static void uart_dma_init(void) { periph_module_enable(PERIPH_UHCI0_MODULE); periph_module_reset(PERIPH_UHCI0_MODULE); periph_module_enable(PERIPH_UART1_MODULE); periph_module_reset(PERIPH_UART1_MODULE); uart_config_t uart_config { .baud_rate UART_BAUD_RATE, .data_bits UART_DATA_8_BITS, .parity UART_PARITY_DISABLE, .stop_bits UART_STOP_BITS_1, .flow_ctrl UART_HW_FLOWCTRL_DISABLE, .source_clk UART_SCLK_DEFAULT, }; ESP_ERROR_CHECK(uart_param_config(UART_PORT_NUM, uart_config)); ESP_ERROR_CHECK(uart_set_pin(UART_PORT_NUM, UART_TX_PIN, UART_RX_PIN, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE)); // 设置 UART 空闲超时空闲一小段时间就认为一帧结束 ESP_ERROR_CHECK(uart_set_rx_timeout(UART_PORT_NUM, UART_RX_TOUT_THRESH)); gdma_channel_alloc_config_t tx_config { .direction GDMA_CHANNEL_DIRECTION_TX, .flags.reserve_sibling 1, }; ESP_ERROR_CHECK(gdma_new_channel(tx_config, s_tx_channel)); gdma_channel_alloc_config_t rx_config { .direction GDMA_CHANNEL_DIRECTION_RX, .sibling_chan s_tx_channel, }; ESP_ERROR_CHECK(gdma_new_channel(rx_config, s_rx_channel)); ESP_ERROR_CHECK(gdma_connect(s_tx_channel, GDMA_MAKE_TRIGGER(GDMA_TRIG_PERIPH_UHCI, 0))); ESP_ERROR_CHECK(gdma_connect(s_rx_channel, GDMA_MAKE_TRIGGER(GDMA_TRIG_PERIPH_UHCI, 0))); gdma_strategy_config_t strategy { .auto_update_desc false, .owner_check false, }; ESP_ERROR_CHECK(gdma_apply_strategy(s_tx_channel, strategy)); ESP_ERROR_CHECK(gdma_apply_strategy(s_rx_channel, strategy)); gdma_rx_event_callbacks_t rx_cbs { .on_recv_eof rx_eof_callback, }; ESP_ERROR_CHECK(gdma_register_rx_event_callbacks(s_rx_channel, rx_cbs, NULL)); gdma_tx_event_callbacks_t tx_cbs { .on_trans_eof tx_eof_callback, }; ESP_ERROR_CHECK(gdma_register_tx_event_callbacks(s_tx_channel, tx_cbs, NULL)); uhci_ll_init((uhci_dev_t *)s_uhci_hw); uhci_ll_set_eof_mode((uhci_dev_t *)s_uhci_hw, UHCI_RX_IDLE_EOF); s_uhci_hw-escape_conf.val 0; uhci_ll_attach_uart_port((uhci_dev_t *)s_uhci_hw, 1); } static void dma_echo_task(void *arg) { uint32_t notify_value 0; (void)arg; start_rx_dma(); while (1) { xTaskNotifyWait(0, UINT32_MAX, notify_value, portMAX_DELAY); if (notify_value RX_DONE_BIT) { int rx_len lldesc_get_received_len(s_rx_desc, NULL); if (rx_len 0 rx_len DMA_RX_BUF_SIZE) { ESP_LOGI(TAG, rx_len%d, rx_len); start_tx_dma(s_rx_buf, rx_len); } start_rx_dma(); } if (notify_value TX_DONE_BIT) { ESP_LOGI(TAG, tx done); } } } void app_main(void) { uart_dma_init(); xTaskCreate(dma_echo_task, dma_echo_task, TASK_STACK_SIZE, NULL, 12, s_dma_task_hdl); ESP_LOGI(TAG, UART1 DMA echo started); ESP_LOGI(TAG, TX%d RX%d baud%d, UART_TX_PIN, UART_RX_PIN, UART_BAUD_RATE); }代码较长核心要点初始化 GDMA 通道并连接到 UHCI使用lldesc_t链表管理内存通过中断回调通知任务处理数据

相关文章:

ESP32学习笔记之UART

第一部分:UART 核心概念 1. 什么是 UART? UART 中文常叫“通用异步收发器”,“异步”意思是通信双方不共享时钟,所以要提前约定好通信参数。 UART 本质上就是按约定好的速度,把 0 和 1 一位一位串行发出去 关键特点&…...

垃圾网站穷疯了,什么都要钱

垃圾。。。。。...

攻防世界 crypto题GFSJ0527-【easy_RSA】

1.工具:thonny2.解题:打开附件,看到如下在一次RSA密钥对生成中,假设p473398607161,q4511491,e17 求解出d*RSA加密算法:①算法原理:RSA是一种非对称加密算法;②CTF中的常见…...

sslyze使用教程

SSLyze 是 Kali Linux 中一款专业的 TLS/SSL 安全扫描工具,主要用于检测目标服务器的 TLS/SSL 配置安全性,包括协议版本支持、加密套件强度、证书有效性、常见漏洞(如 Heartbleed、ROBOT)等,广泛应用于渗透测试、服务器…...

java微信小程序的中小型企业员工电子档案借阅管理系统的设计与实现

目录需求分析与规划技术架构设计核心功能模块开发微信小程序集成测试与部署运维与迭代项目技术支持可定制开发之功能创新亮点源码获取详细视频演示 :文章底部获取博主联系方式!同行可合作需求分析与规划 明确系统核心功能:员工档案录入、借阅…...

Pixel Dimension Fissioner部署教程:Docker镜像开箱即用+Stable v1.0.0适配

Pixel Dimension Fissioner部署教程:Docker镜像开箱即用Stable v1.0.0适配 1. 工具概览 Pixel Dimension Fissioner(像素语言维度裂变器)是一款基于MT5-Zero-Shot-Augment核心引擎构建的文本改写与增强工具。它将传统AI文本处理功能重新包装…...

告别手动排班:智能排班系统助力HR实现高效管理

人力资源部门在企业运营中承担着员工排班的重要职责。 传统的手动排班方式需要HR人员投入大量的时间和精力,工作强度大且效率低下。 尤其在员工人数较多的企业,排班工作往往成为HR部门的日常难题。 每次排班都需要反复核对员工信息、班次需求和特殊情况&…...

Qwen3-ASR语音识别应用:会议记录、字幕生成实战案例

Qwen3-ASR语音识别应用:会议记录、字幕生成实战案例 1. 语音识别技术的新选择 在数字化办公和内容创作领域,语音识别技术正变得越来越重要。Qwen3-ASR作为新一代语音识别解决方案,凭借其强大的多语言支持和方言识别能力,正在改变…...

智能排班系统:企业人力资源管理的数字化革新

传统企业排班工作长期依赖Excel等电子表格工具手动完成。 这种模式不仅需要投入大量的时间成本,还极易出现人为错误。 尤其在员工数量众多、班次结构复杂的组织中,排班工作往往成为人力资源部门的沉重负担。 排班管理人员常常需要花费数小时甚至数天的时…...

【ASP.NET Web Pages】页面布局核心实战:从复用性到安全性,打造一致化网站界面

在Web开发中,网站的视觉一致性直接影响用户体验,而维护效率则决定了开发团队的迭代速度。ASP.NET Web Pages作为轻量级的Web开发框架,提供了极其便捷的方式来实现全站统一布局,核心围绕“复用”和“集中管理”两大原则&#xff0c…...

京聚全球智,算力观新程——视程空间赴2026北京国际人工智能应用与机器人创新博览会

春风拂京城,智潮涌东方。2026年3月,以“京聚全球智,AI创未来”为主题的北京国际人工智能应用与机器人创新博览会(AI SHOW)盛大启幕,这场汇聚全球AI前沿技术、机器人创新成果的行业盛会,成为洞察…...

2025论文阅读-TSCMamba如何用“多视角”和“探戈舞步”提升分类精度?

Ahamed和Cheng - 2025 - TSCMamba Mamba meets multi-view learning for time series classification 论文:https://www.sciencedirect.com/science/article/abs/pii/S1566253525001526 代码:https://github.com/Atik-Ahamed/TSCMamba 什么是时间序列…...

MySQL 事务的二阶段提交是什么?

两阶段提交(Two-Phase Commit, 2PC) 是分布式事务或跨存储引擎事务中,为了保证数据一致性(Atomicity)而采用的一种协议。 在 MySQL 中,2PC 最典型的应用场景是 InnoDB 存储引擎与 Redo Log(重做…...

信奥赛网课怎么选?2026高性价比机构实测对比

一、信奥赛:升学赛道升温,选对网课少走弯路在科技素养升学的大趋势下,信息学奥赛(信奥赛)早已成为小升初科技特长生、初升高自主招生、高考强基计划的重要加分项。从CSP-J/S入门认证,到NOIP、NOI等高阶赛事…...

腾讯云COS临时密钥避坑指南:SpringBoot权限配置的5个致命细节

腾讯云COS临时密钥安全实践:SpringBoot权限配置的五大核心策略 在云存储服务中,临时密钥(STS)作为替代永久密钥的安全方案,已成为企业级应用的标准配置。然而,许多开发团队在实施过程中往往低估了权限粒度的…...

Qwen3-14B常见问题解决:max_new_tokens参数设置详解

Qwen3-14B常见问题解决:max_new_tokens参数设置详解 1. 问题背景与重要性 在使用Qwen3-14B这类大型语言模型时,max_new_tokens参数的正确设置直接影响模型输出的完整性和系统稳定性。很多用户在实际部署中会遇到以下典型问题: 生成的文本在…...

ATmega32U4高精度PWM调光类Dimmer设计与实现

1. ATmega32U4 PWM调光器类(Dimmer Class)技术深度解析ATmega32U4作为一款集成USB控制器的高性能8位AVR微控制器,广泛应用于人机交互设备、USB HID外设及智能照明控制模块。其片上定时器资源丰富,支持多路高精度PWM输出&#xff0…...

别再为实体重叠头疼了!用PyTorch+Transformers复现Casrel模型搞定联合抽取

用PyTorchTransformers实战Casrel模型:破解实体重叠难题的工程指南 当处理"姚明在火箭队打球"这类文本时,"姚明"既是球员实体又与公众人物实体重叠——这正是知识图谱构建中最棘手的实体重叠问题。传统流水线方法(先抽实…...

Nanbeige 4.1-3B快速上手指南:支持<think>标签的像素化思考日志实操手册

Nanbeige 4.1-3B快速上手指南:支持标签的像素化思考日志实操手册1. 环境准备与快速部署 1.1 系统要求 操作系统:支持Windows 10/macOS 12/主流Linux发行版Python版本:3.8-3.10(推荐3.9)GPU配置:至少8GB显…...

qt项目总结

绘制圆弧 文字组合(仪表盘)void paintEvent(QPaintEvent* event){Q_UNUSED(event);QPainter painter(this);painter.setRenderHint(QPainter::Antialiasing, true);// 1. 绘制背景圆弧painter.save();painter.setPen(QPen(QColor(255, 255, 255), 4));p…...

wan2.1-vae镜像免配置部署:supervisorctl一键管理+日志排查+端口诊断全流程

wan2.1-vae镜像免配置部署:supervisorctl一键管理日志排查端口诊断全流程 1. 平台介绍 muse/wan2.1-vae是基于Qwen-Image-2512模型的AI图像生成平台,它能够将文字描述转化为高质量的视觉图像。这个平台特别适合需要快速生成创意图像的设计师、内容创作…...

嵌入式多核C调度器上线即崩溃?紧急修复方案:3行__DMB指令+2个编译属性+1次TLB flush(已在STM32H753量产验证)

第一章:嵌入式多核C调度器上线即崩溃的典型现象与根因定位嵌入式多核系统中,C语言实现的轻量级调度器在首次启动(boot-up)阶段即发生硬故障(Hard Fault)、非法指令异常(UsageFault)或…...

c# 特性

1.c# 特性在 C# 中,特性 (Attributes) 是一种强大的机制,允许你将元数据(Metadata)声明性地附加到代码元素上(如类、方法、属性、参数、程序集等)。这些元数据可以在运行时通过反射 (Reflection) 读取&…...

威纶通触摸屏模板,直接打开就可以用,可根据自己要求修改, 威纶通触摸屏,全部图库

威纶通触摸屏模板,直接打开就可以用,可根据自己要求修改, 威纶通触摸屏,全部图库。刚拿到威纶通触摸屏项目的时候,最头疼的就是从零开始画界面。直到我发现他们家的官方模板库,简直像打开了新世界——直接解…...

Odoo 19 库存模块之期初库存导入概述

Odoo 19 库存模块期初库存概述 有效的库存管理对任何企业都至关重要,因为它直接影响运营、现金流和客户满意度。 对于正在实施 Odoo 19 或开启新会计期间的企业而言,设置准确的期初库存是库存管理中最基础、最关键的一步。 期初库存是指企业在新期间开始…...

运维人中间危机,我转型网安的逆袭之路,别慌有出路

2023年春节后的第一个工作日,我攥着9K的薪资条站在茶水间,看着新来的95后运维同事,他本科毕业两年,薪资却比我高3K。领导找我谈话时那句"基础运维岗位竞争太激烈",像一记闷棍敲醒了我。 我每天要重复着服务…...

最近在研究基于扰动观测器的直流电机调速系统,发现这玩意儿挺有意思的。先不说那些复杂的理论,直接上点干货,看看怎么用代码和仿真模型来实现这个系统

基于扰动观测器的直流电机调速系统, 有计算公式,仿真模型,仿真结果,ad电路图,程序首先,我们得有个直流电机的模型。假设电机的状态方程是这样的: % 电机状态方程 A [0 1; -k/J -b/J]; B [0; 1…...

Hot100-验证二叉搜索树

错误代码:/*** Definition for a binary tree node.* public class TreeNode {* int val;* TreeNode left;* TreeNode right;* TreeNode() {}* TreeNode(int val) { this.val val; }* TreeNode(int val, TreeNode left, TreeNode right) {…...

MCP集成效率提升300%:基于VS Code 1.89+最新Extension API重构的轻量接入方案(仅需12行核心代码)

第一章:MCP集成效率提升300%:基于VS Code 1.89最新Extension API重构的轻量接入方案(仅需12行核心代码)VS Code 1.89 引入了全新的 vscode.mcp 模块与声明式注册机制,彻底替代了传统事件监听手动协议解析的冗余模式。开…...

JavaScript设计模式(一):单例模式实现与应用

先提出一个问题,为什么要学习设计模式? 难道是提出一个代码形容词,是为了让代码看起高大上 or 装逼? 先看下设计模式的定义:在面向对象软件设计过程中针对特定问题的简洁而优雅的解决方案。 我的个人理解就是&#xff…...