STM32-15-DMA

news2024/11/25 10:01:21

STM32-01-认识单片机
STM32-02-基础知识
STM32-03-HAL库
STM32-04-时钟树
STM32-05-SYSTEM文件夹
STM32-06-GPIO
STM32-07-外部中断
STM32-08-串口
STM32-09-IWDG和WWDG
STM32-10-定时器
STM32-11-电容触摸按键
STM32-12-OLED模块
STM32-13-MPU
STM32-14-FSMC_LCD

文章目录

  • STM32-15-DMA
    • 1. DMA与中断的区别
      • 1. DMA
      • 2. 中断
    • 2. DMA介绍
    • 3. DMA结构框图
      • 1. DMA框图
      • 2. DMA处理过程
      • 3. DMA通道
    • 4. DMA相关寄存器
    • 5. DMA相关HAL库驱动
    • 6. 代码实现

STM32-15-DMA

1. DMA与中断的区别

DMADirect Memory Access,直接内存访问) 和中断是两种不同的机制,用于管理计算机系统中外围设备与处理器之间的数据传输和处理。

1. DMA

工作原理:

  • 独立传输:DMA允许外设直接与系统内存交换数据,而不需要通过处理器(CPU)。当需要大量数据传输时,DMA控制器接管传输任务,释放CPU去执行其他任务。
  • 传输过程:DMA传输数据时,CPU启动DMA传输,然后DMA控制器接管整个传输过程。传输完成后,DMA控制器通过中断通知CPU传输完成。

作用:

  • 提高效率:DMA减少了CPU在数据传输过程中的参与,使得CPU能够执行其他任务,从而提高系统的整体效率。
  • 减少延迟:由于DMA可以独立进行传输,因此数据传输的延迟更低,特别是在处理大块数据时。
  • 应用场景:DMA广泛应用于音频视频数据流网络数据包的传输存储设备的数据读写等场景。

对程序的影响:

  • 复杂度增加:引入DMA需要对DMA控制器进行配置,可能增加程序的复杂性。
  • 同步问题:在DMA传输过程中,程序需要处理好数据同步问题,避免数据不一致性问题。

2. 中断

工作原理:

  • 中断触发:中断是外设通过中断信号通知CPU某个事件发生,如输入设备有新数据可读取,定时器到期等。
  • 中断处理:CPU响应中断后,暂停当前任务,跳转到相应的中断处理程序(ISR)执行。当中断处理程序执行完毕后,CPU恢复先前任务的执行。

作用:

  • 实时响应:中断机制使CPU能够实时响应外设事件,保证系统对外部事件的快速反应。
  • 事件驱动:中断使得程序可以基于事件驱动,而不是定期轮询外设状态,从而节省CPU资源。
  • 应用场景键盘输入鼠标移动网络数据包到达定时器事件等。

对程序的影响:

  • 中断处理程序设计:中断处理程序需要尽可能简短、快速,避免长时间占用CPU。
  • 中断优先级管理:系统中可能有多个中断源,需要合理设计中断优先级,以确保关键中断能够及时响应。
  • 上下文切换开销:中断会引起上下文切换,带来一定的性能开销。

总结

  • DMA:适用于大量数据传输,降低CPU负载,提高系统效率。
  • 中断:适用于实时事件响应,保证系统对外部事件的快速处理。

两者结合使用,可以构建高效、实时的嵌入式系统。例如,DMA用于大数据块的传输,而中断用于触发DMA传输和处理传输完成事件。

2. DMA介绍

  • DMA: 即直接存储器访问。DMA传输方式无需CPU直接控制传输,也没有中断处理方式那样保留现场和恢复现场的过程,通过硬件为RAM与I/O设备开辟一条直接传送数据的通路,能使CPU的效率大为提高。
  • STM32F103内部有2个DMA控制器,DMA17个通道,DMA25个通道。每个通道专门用来管理来自于一个或多个外设对存储器访问的请求,还有一个仲裁器来协调各个DMA请求的优先权。
  • 特性:
    • 每个通道都直接连接专用的硬件DMA请求,每个通道都支持软件触发。这些功能通过软件来配置。
    • 在七个请求间的优先权可以通过软件编程设置,当软件相同时,由硬件决定。
    • 独立的源和目标数据区的传输宽度,模拟打包和拆包的过程。源和目标地址必须按数据传输宽度对齐。
    • 支持循环的缓冲器管理。
    • 每个通道都有3个事件标志,这3个事件标志逻辑或成为一个单独的中断请求。
    • 存储器和存储器间的传输。
    • 外设和存储器,存储器和外设的传输。
    • 闪存、SRAM、外设的SRAM、APB1、APB2和AHB外设均可作为访问的源和目标。
    • 可编程的数据传输数目最大为65535。

3. DMA结构框图

1. DMA框图

在这里插入图片描述

  • DMA请求

    如果外设想要通过DMA来传输数据,必须先给DMA控制器发送DMA请求,DMA收到请求信号之后,控制器会给外设一个应答信号,当外设应答后且DMA控制器收到应答信号之后,就会启动DMA的传输,直到传输完毕。

  • DMA通道

    DMA具有12个独立可编程的通道,其中DMA1有7个通道,DMA2有5个通道,每个通道对应不同的外设的DMA请求。虽然每个通道可以接收多个外设的请求,但是同一时间只能接收一个,不能同时接收多个。

  • DMA优先级

    当发生多个DMA通道请求时,就意味着有先后响应处理的顺序问题,这个就由仲裁器管理。仲裁器管理DMA通道请求分为两个阶段。第一阶段属于软件阶段,可以在DMA_CCRx寄存器中设置,有4个等级:非常高四个优先级。第二阶段属于硬件阶段,如果两个或以上的DMA通道请求设置的优先级一样,则他们优先级取决于通道编号,编号越低优先权越高,比如通道0高于通道1。在大容量产品和互联型产品中,DMA1控制器拥有高于DMA2控制器的优先级。

2. DMA处理过程

在这里插入图片描述

DMA(Direct Memory Access,直接内存访问)是一种允许外设直接与系统内存进行数据传输的机制,不需要CPU的直接干预。以下是DMA处理过程的详细描述:

DMA处理过程

  1. 配置DMA控制器
    • 源地址:设置数据传输的源地址(可以是外设寄存器地址或内存地址)。
    • 目标地址:设置数据传输的目标地址(可以是外设寄存器地址或内存地址)。
    • 传输方向:指定数据传输的方向,是从外设到内存,还是从内存到外设。
    • 数据长度:设置需要传输的数据长度(字节数)。
    • 传输模式:选择传输模式,可以是单次传输、块传输或连续传输模式。
  2. 启动DMA传输
    • 触发传输:在配置完成后,通过设置DMA控制器的启动位,开始数据传输。
    • 数据搬运:DMA控制器接管数据传输任务,将数据从源地址搬运到目标地址。这个过程中,DMA控制器直接与内存控制器和外设总线进行交互,不需要CPU干预。
  3. 中断通知
    • 传输完成中断:数据传输完成后,DMA控制器产生中断信号,通知CPU传输已经完成。CPU执行相应的中断服务程序(ISR)处理后续任务。
    • 错误处理:如果在传输过程中发生错误(如总线错误),DMA控制器也会产生中断,通知CPU进行错误处理。

3. DMA通道

DMA1通道与外设的对应关系
在这里插入图片描述

DMA2通道与外设的对应关系
在这里插入图片描述

4. DMA相关寄存器

寄存器名称作用
DMA_CCRxDMA通道x配置寄存器用于配置DMA(核心控制寄存器)
DMA_ISRDMA中断状态寄存器用于查询当前DMA传输状态
DMA_IFCRDMA中断标志清除寄存器用来清除DMA_ISR对应位
DMA_CNDTRxDMA通道x传输数量寄存器用于控制DMA通道x每次传输的数据量
DMA_CPARxDMA通道x外设地址寄存器用于存储STM32外设地址
DMA_CMARxDMA通道x存储器地址寄存器用于存放存储器的地址
USART_CR3USART控制寄存器3用于使能串口DMA发送
  • DMA通道x配置寄存器(DMA_CCRx
    在这里插入图片描述

  • DMA中断状态寄存器(DMA_ISR
    在这里插入图片描述

  • DMA 中断标志清除寄存器(DMA_IFCR
    在这里插入图片描述

  • DMA通道x传输数量寄存器(DMA_CNDTRx)
    在这里插入图片描述

    该寄存器控制着DMA通道x的每次传输所要传输的数据量。其设置范围为0~65535。并且该寄存器的值随着传输的进行而减少,当该寄存器的值为0的时候就代表此次数据传输己经全部发送完成。可以通过这个寄存器的值来获取当前DMA传输的进度

  • DMA通道x外设地址寄存器(DMA_CPARx
    在这里插入图片描述

    用来存储 STM32 外设的地址。

  • DMA通道x存储器地址寄存器(DMA_CMARx
    在这里插入图片描述

    用来存放存储器的地址。

5. DMA相关HAL库驱动

  1. 使能DMA时钟

    __HAL_RCC_DMA1_CLK_ENABLE();
    
  2. 初始化DMA

    HAL_StatusTypeDef HAL_DMA_Init(DMA_HandleTypeDef *hdma);
    
    typedef struct
    { 
     uint32_t Direction; /* 传输方向,例如存储器到外设 DMA_MEMORY_TO_PERIPH */
     uint32_t PeriphInc; /* 外设(非)增量模式,非增量模式 DMA_PINC_DISABLE */ 
     uint32_t MemInc; /* 存储器(非)增量模式,增量模式 DMA_MINC_ENABLE */ 
     uint32_t PeriphDataAlignment; /* 外设数据大小:8/16/32 位 */
     uint32_t MemDataAlignment; /* 存储器数据大小:8/16/32 位 */
     uint32_t Mode; /* 模式:循环模式/普通模式 */ 
     uint32_t Priority; /* DMA 优先级:低/中/高/非常高 */
    }DMA_InitTypeDef;
    
    __HAL_LINKDMA(&g_uart1_handler, hdmatx, g_dma_handle);
    
  3. 使能串口的DMA发送,启动传输

    HAL_UART_Transmit_DMA()
        
    HAL_StatusTypeDef HAL_UART_DMAStop(UART_HandleTypeDef *huart); /* 停止 */
    HAL_StatusTypeDef HAL_UART_DMAPause(UART_HandleTypeDef *huart); /* 暂停 */
    HAL_StatusTypeDef HAL_UART_DMAResume(UART_HandleTypeDef *huart); /* 恢复 */
    
  4. 查询DMA传输状态

    //查询DMA传输通道的状态
    __HAL_DMA_GET_FLAG(&g_dma_handle, DMA_FLAG_TC4);
    
    //获取当前传输剩余数据量
    __HAL_DMA_GET_COUNTER(&g_dma_handle);
    
    //设置对应的DMA数据流传输的数据量大小
    __HAL_DMA_SET_COUNTER (&g_dma_handle, 1000);
    
  5. DMA中断使用

    //通用中断处理函数
    void HAL_DMA_IRQHandler();
    
    //相关中断回调函数
    //发送完成回调函数
    void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart);
    //发送一半回调函数
    void HAL_UART_TxHalfCpltCallback(UART_HandleTypeDef *huart);
    //接收完成回调函数
    void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart);
    //接收一半回调函数
    void HAL_UART_RxHalfCpltCallback(UART_HandleTypeDef *huart);
    //传输出错回调函数
    void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart);
    

6. 代码实现

  • 功能

    每按下按键KEY0,串口1就会以DMA方式发送数据,同时在LCD上面显示传送进度。打开串口调试助手,可以收到DMA发送的内容。LED0闪烁用于提示程序正在运行。

  • DMA初始化函数

    void dma_init(DMA_Channel_TypeDef* DMAx_CHx)
    {
        if((uint32_t)DMAx_CHx > (uint32_t)DMA1_Channel7)
        {
            __HAL_RCC_DMA2_CLK_ENABLE();
        }
        else
        {
            __HAL_RCC_DMA2_CLK_ENABLE();
        }
        
        //将DMA与USART1连接起来
        __HAL_LINKDMA(&g_uart1_handle, hdmatx, g_dma_handle); 
        
        
        g_dma_handle.Instance = DMAx_CHx;                   //USART1_TX使用的DMA通道为DMA_Channel4
        g_dma_handle.Init.Direction = DMA_MEMORY_TO_PERIPH; //模式选择为从存储器到外设
        g_dma_handle.Init.PeriphInc = DMA_PINC_DISABLE;     //外设非增量模式
        g_dma_handle.Init.MemInc = DMA_MINC_ENABLE;         //存储器增量模式
        g_dma_handle.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE; //外设数据长度为8位
        g_dma_handle.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;    //存储器数据长度为8位
        g_dma_handle.Init.Priority = DMA_PRIORITY_MEDIUM;            //中等优先级
        
        HAL_DMA_Init(&g_dma_handle);
    }
    
  • 主函数

    int main(void)
    {
        uint16_t i, k;
        uint16_t len;
        uint8_t  mask = 0;
        float pro = 0;          /* 进度 */
    
        HAL_Init();                         /* 初始化HAL库 */
        sys_stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟, 72Mhz */
        delay_init(72);                     /* 延时初始化 */
        usart_init(115200);                 /* 串口初始化为115200 */
        led_init();                         /* 初始化LED */
        lcd_init();                         /* 初始化LCD */
        key_init();                         /* 初始化按键 */
        dma_init(DMA1_Channel4);            /* 初始化串口1 TX DMA */
    
        lcd_show_string(30, 50, 200, 16, 16, "STM32", RED);
        lcd_show_string(30, 70, 200, 16, 16, "DMA TEST", RED);
        lcd_show_string(30, 90, 200, 16, 16, "ATOM@ALIENTEK", RED);
        lcd_show_string(30, 110, 200, 16, 16, "KEY0:Start", RED);
    
        len = sizeof(TEXT_TO_SEND);
        k = 0;
        
        for (i = 0; i < SEND_BUF_SIZE; i++) /* 填充ASCII字符集数据 */
        {
            if (k >= len)   /* 入换行符 */
            {
                if (mask)
                {
                    g_sendbuf[i] = 0x0a;
                    k = 0;
                }
                else
                {
                    g_sendbuf[i] = 0x0d;
                    mask++;
                }
            }
            else     /* 复制TEXT_TO_SEND语句 */
            {
                mask = 0;
                g_sendbuf[i] = TEXT_TO_SEND[k];
                k++;
            }
        }
     
        i = 0;
    
        while (1)
        {
            if (key_scan(0) == 1)       /* KEY0按下 */
            {
                printf("\r\nDMA DATA:\r\n");
                lcd_show_string(30, 130, 200, 16, 16, "Start Transimit....", BLUE);
                lcd_show_string(30, 150, 200, 16, 16, "   %", BLUE);    /* 显示百分号 */
    
                HAL_UART_Transmit_DMA(&g_uart1_handle, g_sendbuf, SEND_BUF_SIZE);
                /* 等待DMA传输完成,此时我们来做另外一些事情,比如点灯  
                 * 实际应用中,传输数据期间,可以执行另外的任务 
                 */
                while (1)
                {
                    if ( __HAL_DMA_GET_FLAG(&g_dma_handle, DMA_FLAG_TC4))   /* 等待 DMA1_Channel4 传输完成 */
                    {
                        __HAL_DMA_CLEAR_FLAG(&g_dma_handle, DMA_FLAG_TC4);
                        HAL_UART_DMAStop(&g_uart1_handle);                  /* 传输完成以后关闭串口DMA */
                        break;
                    }
    
                    pro = DMA1_Channel4->CNDTR; /* 得到当前还剩余多少个数据 */
                    len = SEND_BUF_SIZE;        /* 总长度 */
                    pro = 1 - (pro / len);      /* 得到百分比 */
                    pro *= 100;                 /* 扩大100倍 */
                    lcd_show_num(30, 150, pro, 3, 16, BLUE);
                } 
                lcd_show_num(30, 150, 100, 3, 16, BLUE);    /* 显示100% */
                lcd_show_string(30, 130, 200, 16, 16, "Transimit Finished!", BLUE); /* 提示传送完成 */
            }
    
            i++;
            delay_ms(10);
    
            if (i == 20)
            {
                LED0_TOGGLE();  /* LED0闪烁,提示系统正在运行 */
                i = 0;
            }
        }
    }
    
  • 实验结果

    通过LCD屏可以看到数据传输的百分比,通过串口助手可以看到传输的数据

在这里插入图片描述

声明:资料来源(战舰STM32F103ZET6开发板资源包)

  1. Cortex-M3权威指南(中文).pdf
  2. STM32F10xxx参考手册_V10(中文版).pdf
  3. STM32F103 战舰开发指南V1.3.pdf
  4. STM32F103ZET6(中文版).pdf
  5. 战舰V4 硬件参考手册_V1.0.pdf

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

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

相关文章

【Java面试】十七、并发篇(上)

文章目录 1、synchronized关键字的底层原理&#xff1a;Monitor2、synchronized相关2.1 为什么说synchronized是重量级锁2.2 synchronized锁升级之偏向锁2.3 synchronized锁升级之轻量级锁 3、Java内存模型JMM4、CAS4.1 CAS流程4.2 CAS底层实现 5、volatile关键字的理解5.1 可见…

区块链(Blockchain)调查研究(一)

文章目录 1. 区块链是什么&#xff1f;2. 区块链分类和特点3. 区块链核心关键技术3.1 共识机制3.2 密码学技术3.4 分布式存储3.5 智能合约 4. 区块链未来发展趋势5. 区块链能做什么、不能做什么&#xff1f;5.1 第一部分5.2 第二部分5.3 第三部分&#xff08;结论&#xff09; …

八爪鱼现金流-019-个人对接支付,个人网站支付解决方案

背景&#xff1a; 随着用户量不断增加&#xff0c;服务器成本越来越大。想着实现会员制回点服务器成本。 业务场景分析&#xff1a; 用户在站点上付款 -----> 我监听到付款金额 -----> 给用户开通会员 调研&#xff1a; 支付宝和微信官方支付接口&#xff1a;基本都需…

MOS管十大品牌

MOS管十大品牌-场效应管品牌排行-MOS管品牌-Maigoo品牌榜

统计学研硕大数据统计练手11

统计学论文练手作业 题目AI绘图仅供欣赏 题目 2024年的《政府工作报告》中提出“深化大数据、人工智能等研发应用,开展“人工智能+”行动,打造具有国际竞争力的数字产业集群”,请同学们结合自己工作的所在行业或领域谈一谈大数据技术在人工智能时代下的应用现状、存在的问…

VSC++: 民意调查比例法

void 民意调查比例法() {//缘由https://bbs.csdn.net/topics/396521294?page1#post-411408461从题目描述看&#xff1a;902/3~300.7&#xff0c;1498/5~299.6也就是大约求2个数的公约数&#xff0c;并使得这个公约数尽量求出最小误差&#xff1f;且商小于某值。int a 0, aa …

JS(JavaScript)的引用方式介绍与代码演示

天行健&#xff0c;君子以自强不息&#xff1b;地势坤&#xff0c;君子以厚德载物。 每个人都有惰性&#xff0c;但不断学习是好好生活的根本&#xff0c;共勉&#xff01; 文章均为学习整理笔记&#xff0c;分享记录为主&#xff0c;如有错误请指正&#xff0c;共同学习进步。…

Mamba v2诞生:3 SMA与Mamba-2

大模型技术论文不断&#xff0c;每个月总会新增上千篇。本专栏精选论文重点解读&#xff0c;主题还是围绕着行业实践和工程量产。若在某个环节出现卡点&#xff0c;可以回到大模型必备腔调或者LLM背后的基础模型新阅读。而最新科技&#xff08;Mamba,xLSTM,KAN&#xff09;则提…

从品牌的角度看老字号五芳斋如何“粽”出年轻味?

端午划着龙舟的浆又来到了我们身边&#xff0c;咸鸭蛋和粽子已经裹上精美的包装在货架上等待着它们的“有缘人”&#xff0c;其实长期以来&#xff0c;说起吃粽子除了“甜咸口”的辩论赛&#xff0c;貌似在产品上却并没有太多的创新&#xff0c;但近几年随着消费市场的不断创新…

今日早报 每日精选15条新闻简报 每天一分钟 知晓天下事 6月9日,星期日

每天一分钟&#xff0c;知晓天下事&#xff01; 2024年6月9日 星期日 农历五月初四 1、 人社部&#xff1a;个人养老金开户人数已超6000万&#xff0c;其中31岁至40岁的中高收入人群是开户、缴费和购买产品的主力军。 2、 医保局刊文&#xff1a;研究显示集采仿制药替代原研药…

网关API(SpringCloudGateway)如何自定义Filter

1.前言 SpringCloud 虽然给我们提供了很多过滤器&#xff0c;但是这些过滤器功能都是固定的&#xff0c;无法满足用户的各式各样的需求。因此SpringCloud提供了过滤器的扩展功能自定过滤器。 开发者可以根据自己的业务需求自定义过滤器。 2. 自定义 GatewayFilter(局部过滤器)…

LangChain4j实战

基础 LangChain4j模型适配: Provider Native Image Sync Completion Streaming Completion Embedding Image Generation Scoring Function Calling OpenAI ✅ ✅ ✅ ✅ ✅ ✅ Azure OpenAI ✅ ✅ ✅ ✅ ✅ Hugging Face ✅ ✅ Amazon Bedrock ✅ ✅…

STM32中ADC在cubemx基础配置界面介绍

ADCx的引脚,对应的不同I/O口&#xff0c;可以复用。 Temperature :温度传感器通道。 Vrefint :内部参照电压。 Conversion Trigger: 转换触发器。 IN0 至 IN15,是1ADC1的16个外部通道。本示例中输出连接的是ADC2的IN5通道&#xff0c;所以只勾选IN5.Temperature Sensor Cha…

【C++】:模板初阶和STL简介

目录 一&#xff0c;泛型编程二&#xff0c;函数模板2.1 函数模板概念2.2 函数模板格式2.3 函数模板的原理2.4 函数模板的实例化2.5 模板参数的匹配原则 三&#xff0c;类模板3.1 类模板的定义格式3.2 类模板的实例化 四&#xff0c;STL简介&#xff08;了解&#xff09;4.1 什…

将字符串str1复制为字符串str2

定义两个字符数组str1和str2&#xff0c;再设两个指针变量p1和p2&#xff0c;分别指向两个字符数组中的有关字符&#xff0c;通过改变指针变量的值使它们指向字符串中的不同的字符&#xff0c;以实现字符的复制。编写程序&#xff1a; 运行程序&#xff1a; 程序分析&#xff1…

STM32H750启动和内存优化(分散加载修改)

前些日子有个朋友一直给我推荐STM32H750这款芯片&#xff0c;说它的性价比&#xff0c;说它多么多么好。于是乎&#xff0c;这两天试了试&#xff0c;嚯&#xff0c;真香&#xff01;我们先看看基本配置 这里简单总结下&#xff0c;cortex-m7内核&#xff0c;128k片内flash …

【Java面试】十六、并发篇:线程基础

文章目录 1、进程和线程的区别2、并行和并发的区别3、创建线程的四种方式3.1 Runnable和Callable创建线程的区别3.2 线程的run和start 4、线程的所有状态与生命周期5、新建T1、T2、T3&#xff0c;如何保证线程的执行顺序6、notify和notifyAll方法有什么区别7、wait方法和sleep方…

Django Forbidden (CSRF cookie not set.)解决办法

解决办法就是在setting.py文件中注释&#xff1a; django.middleware.csrf.CsrfViewMiddleware, 这个中间件是为了防止跨站请求伪造的&#xff0c;平时用网页表单请求时&#xff0c;post提交是没有问题的&#xff0c;但是用api调用时就会被禁止&#xff0c;为了能使用接口调用…

文件怎么去重?5个技巧,教你删除重复文件!

一般来说&#xff0c;在处理大量文件时&#xff0c;你可能会遇到重复的类似文件。这些文件占据了电脑上不必要的磁盘空间&#xff0c;导致系统性能下降。而这些文件可以是不同类型的&#xff0c;如照片、视频、音频、存档、文档等。正因如此&#xff0c;您需要通过文件去重来删…

(四)React组件、useState

1. 组件 1.1 组件是什么 概念&#xff1a;一个组件就是用户界面的一部分&#xff0c;它可以有自己的逻辑和外观&#xff0c;组件之间可以相互嵌套&#xff0c;也可以复用多次。 组件化开发可以让开发者像搭积木一样构建一个完整的庞大应用 1.2 React组件 在React中&#xf…