STM32DMA学习日记

news2024/11/18 14:23:39

STM32 DMA学习日记

写于2024/9/28晚

文章目录

  • STM32 DMA学习日记
    • 1. DMA简介
    • 2. I/O方式
      • 2.1 程序查询方式
      • 2.2 程序中断方式
      • 2.3 DMA方式
    • 3.DMA框图
    • 4. 相关寄存器
      • 4.1 DMA中断状态寄存器(DMA_ISR)
      • 4.2 DMA中断标志清除寄存器(DMA_IFCR)
      • 4.3 DMA通道x传输数量寄存器(DMA_CNDTRx)
      • 4.4 DMA通道x配置寄存器(DMA_CCRx)
      • 4.5 DMA通道x外设地址寄存器(DMA_CPARx)
      • 4.6 DMA通道x存储器地址寄存器(DMA_CMARx)
    • 5.例程解析
      • 5.1 DMA相关HAL库驱动介绍

1. DMA简介

DMA,全称为:Direct Memory Access,即直接存储器访问。DMA 传输方式无需 CPU 直接控制传输,也没有中断处理方式那样保留现场和恢复现场的过程,通过硬件为 RAM 与 I/O 设备开辟一条直接传送数据的通路,能使 CPU 的效率大为提高。是计算机的4种I/O方式中的一种。

2. I/O方式

输入/输出系统实现主机与I/O设备之间的数据传送,可以采用不同的控制方式,各种方式在代价、性能、解决问题的着重点等方面各不相同,常用的I/O方式有程序查询、程序中断、DMA和通道等,其中前两种方式更依赖于CPU中程序指令的执行。下面我们来简介一下计算机组成原理中的4中I/O方式中的前三种。

2.1 程序查询方式

信息交换的控制完全由CPU执行程序实现,程序查询方式接口中设置一个数据缓冲寄存器(数据端口)和一个设备状态寄存器(状态端口)。主机进行I/O操作时,先发出询问信号,读取设备的状态并根据设备状态决定下一步操作究竟是进行数据传送还是等待。
{5A3B2F5B-BA0A-4474-99E4-FE472847AD72}

程序查询方式的工作流程如下(见图7.2):

  • ①CPU执行初始化程序,并预置传送参数。
  • ②向I/O接口发出命令字,启动I/O设备。
  • ③从外设接口读取其状态信息。
  • ④CPU不断查询I/O设备状态,直到外设准备就绪。
  • ⑤传送一次数据。
  • ⑥修改地址和计数器参数。
  • ⑦判断传送是否结束,若未结束转第③步,直到计数器为0

在这种控制方式下,CPU一旦启动I/O,就必须停止现行程序的运行,并在现行程序中插入一段程序。程序查询方式的主要特点是CPU有“踏步”等待现象,CPU与I/O串行工作。这种方式的接口设计简单、设备量少,但CPU在信息传送过程中要花费很多时间来查询和等待,而且在一段时间内只能和一台外设交换信息,效率大大降低。

2.2 程序中断方式

程序中断方式的思想:CPU在程序中安排好在某个时机启动某台外设,然后CPU继续执行当前的程序,不需要像查询方式那样一直等待外设准备就绪。一旦外设完成数据传送的准备工作,就主动向CPU发出中断请求,请求CPU为自己服务。在可以响应中断的条件下,CPU暂时中止正在执行的程序,转去执行中断服务程序为外设服务,在中断服务程序中完成一次主机与外设之间的数据传送,传送完成后,CPU返回原来的程序,如图7.3所示。

{A0A27BD6-8E2C-47B8-B064-6174455FE4C6}

2.3 DMA方式

DMA方式是一种完全由硬件进行成组信息传送的控制方式,它具有程序中断方式的优点,即在数据准备阶段,CPU与外设并行工作。DMA方式在外设与内存之间开辟一条“直接数据通道”,信息传送不再经过CPU,降低了CPU在传送数据时的开销,因此称为直接存储器存取方式。

由于数据传送不经过CPU,也就不需要保护、恢复CPU现场等烦琐操作。

这种方式适用于磁盘、显卡、声卡、网卡等高速设备大批量数据的传送,它的硬件开销比较大。在DMA方式中,中断的作用仅限于故障和正常传送结束时的处理。

DMA控制器的组成
在DMA方式中,对数据传送过程进行控制的硬件称为DMA控制器(DMA接口)。当I/O设备需要进行数据传送时,通过DMA控制器向CPU提出DMA传送请求,CPU响应之后将让出系统总线,由DMA控制器接管总线进行数据传送。其主要功能如下:

  1. 接受外设发出的DMA请求,并向CPU发出总线请求。
  2. CPU响应并发出总线响应信号,DMA接管总线控制权,进入DMA操作周期。
  3. 确定传送数据的主存单元地址及长度,并自动修改主存地址计数和传送长度计数。
  4. 规定数据在主存和外设间的传送方向,发出读写等控制信号,执行数据传送操作。
  5. 向CPU报告DMA操作结束。

{243E987B-4BAA-4FD4-94B8-E566F38635D2}

DMA方式和中断方式的区别
DMA方式和中断方式的重要区别如下:
①中断方式是程序的切换,需要保护和恢复现场;而DMA方式不中断现行程序,无需保护现场,除了预处理和后处理,其他时候不占用任何CPU资源。
②对中断请求的响应只能发生在每条指令执行结束时(执行周期后);而对DMA请求的响应可以发生在任意一个机器周期结束时(取指、间址、执行周期后均可)。
③中断传送过程需要CPU的干预;而DMA传送过程不需要CPU的干预,因此数据传输率非常高,适合于高速外设的成组数据传送。④DMA请求的优先级高于中断请求。
⑤中断方式具有处理异常事件的能力,而DMA方式仅局限于大批数据的传送。
⑥从数据传送来看,中断方式靠程序传送,DMA方式靠硬件传送。

{18B39D76-9DB5-48FE-98C8-F24C90E0503E}

3.DMA框图

STM32F103ZET6 有两个 DMA 控制器,DMA1 和 DMA2,本章,我们仅针对 DMA1 进行介绍。

下面先来学习 DMA 控制器框图,通过学习 DMA 控制器框图会有一个很好的整体掌握,同时对之后的编程也会有一个清晰的思路。

在这里插入图片描述

图中,我们标记了 3 处位置,起作用分别是:

DMA 请求

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

STM32F103 共有 DMA1 和 DMA2 两个控制器,DMA1 有 7 个通道,DMA2 有 5 个通道,不同的 DMA 控制器的通道对应着不同的外设请求,这决定了我们在软件编程上该怎么设置,具体见表 29.1.1.1DMA 请求映像表。

{A9D5348C-6521-4BD8-9EFD-57C963995C81}

{8EF4040D-7D98-4D0A-8C12-D5751D22E327}

② 通道

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

③ 仲裁器

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

4. 相关寄存器

4.1 DMA中断状态寄存器(DMA_ISR)

{7039A4D7-705B-45CC-B3B4-9B0408D11909}

该寄存器是查询当前 DMA 传输的状态,我们常用的是 TCIFx 位,即通道 DMA 传输完成与否的标志。注意此寄存器为只读寄存器,所以在这些位被置位之后,只能通过其他的操作来清除。

4.2 DMA中断标志清除寄存器(DMA_IFCR)

{DDC9A71E-0464-418B-88BB-88782AC0B85D}

该寄存器是用来清除 DMA_ISR 的对应位的,通过写 0 清除。在 DMA_ISR 被置位后,我们必须通过向该寄存器对应的位写 1 来清除。

4.3 DMA通道x传输数量寄存器(DMA_CNDTRx)

{94303E5E-A1E8-4446-B36C-47929AC012A3}

4.4 DMA通道x配置寄存器(DMA_CCRx)

image-20240929114707514

该寄存器控制着 DMA 很多相关信息,包括数据宽度、外设及存储器宽度、通道优先级、增量模式、传输方向、中断允许、使能等,所以说 DMA_CCRx 是 DMA 传输的核心控制寄存器。

4.5 DMA通道x外设地址寄存器(DMA_CPARx)

image-20240929114804484

该寄存器是用来存储 STM32 外设的地址,比如我们平常使用串口 1,那么该寄存器必须写入 0x40013804(其实就是&USART1_DR)。其他外设就可以修改成其他对应外设地址就好了。

4.6 DMA通道x存储器地址寄存器(DMA_CMARx)

DMA通道x存储器地址寄存器用来存放存储器的地址,该寄存器和 DMA_CPARx差不多,所以就不列出来了。举个应用的例子,在程序中,我们使用到一个 g_sendbuf[5200]数组来做存储器,那么我们在 DMA_CMARx 中写入&g_sendbuf 即可。

5.例程解析

5.1 DMA相关HAL库驱动介绍

驱动函数关联寄存器功能描述
__HAL_RCC_DMAx_CLK_ENABLE(…)RCC_AHBENR使能DMAx时钟
HAL_DMA_Init(…)DMA_CCR初始化DMA
HAL_DMA_Start_IT(…)DMA_CCR/CPAR/CMAR/CNDTR开始DMA传输
__HAL_LINKDMA(…)用来连接DMA和外设句柄
HAL_UART_Transmit_DMA(…)CCR/CPAR/CMAR/CNDTR/USART_CR3使能DMA发送,启动传输
__HAL_DMA_GET_FLAG(…)DMA_ISR查询DMA传输通道的状态
__HAL_DMA_ENABLE(…)DMA_CCR(EN)使能DMA外设
__HAL_DMA_DISABLE(…)DMA_CCR(EN)失能DMA外设

DMA外设相关结构体:DMA_HandleTypeDef 和 DMA_InitTypeDef

typedef struct __DMA_HandleTypeDef
{
  DMA_Channel_TypeDef   *Instance;               /*!< Register base address 寄存器基地址 */
  
  DMA_InitTypeDef       Init;                     /*!< DMA communication parameters DMA参数 */ 

} DMA_HandleTypeDef;    
typedef struct
{
        uint32_t Direction				/* DMA传输方向 */
        uint32_t PeriphInc				/* 外设地址(非)增量 */
        uint32_t MemInc					/* 存储器地址(非)增量*/
        uint32_t PeriphDataAlignment	/* 外设数据宽度 */
        uint32_t MemDataAlignment		/* 存储器数据宽度 */
        uint32_t Mode					/* 操作模式 */
        uint32_t Priority				/* DMA通道优先级 */

} DMA_InitTypeDef;

以DMA方式传输串口数据配置步骤

  1. 使能DMA时钟:__HAL_RCC_DMA1_CLK_ENABLE
  2. 初始化DMA:HAL_DMA_Init函数初始化DMA相关参数 __HAL_LINKDMA函数连接DMA和外设
  3. 使能串口的DMA发送,启动传输:HAL_UART_Transmit_DMA
  4. 查询DMA传输状态:__HAL_DMA_GET_FLAG 查询通道传输状态 __ HAL_DMA_GET_COUNTER 获取当前传输剩余数据量
  5. DMA中断使用:HAL_NVIC_EnableIRQ HAL_NVIC_SetPriority编写中断服务函数 xxx_IRQHandler
DMA_HandleTypeDef  g_dma_handle;            /* DMA句柄 */
extern UART_HandleTypeDef g_uart1_handle;   /* UART句柄 */


/**
 * @brief       串口TX DMA初始化函数
 *   @note      这里的传输形式是固定的, 这点要根据不同的情况来修改
 *              从存储器 -> 外设模式/8位数据宽度/存储器增量模式
 *
 * @param       dmax_chy    : DMA的通道, DMA1_Channel1 ~ DMA1_Channel7, DMA2_Channel1 ~ DMA2_Channel5
 *                            某个外设对应哪个DMA, 哪个通道, 请参考<<STM32中文参考手册 V10>> 10.3.7节
 *                            必须设置正确的DMA及通道, 才能正常使用! 
 * @retval      无
 */
void dma_init(DMA_Channel_TypeDef* DMAx_CHx)
{
    if ((uint32_t)DMAx_CHx > (uint32_t)DMA1_Channel7)     /* 大于DMA1_Channel7, 则为DMA2的通道了 */
    {
        __HAL_RCC_DMA2_CLK_ENABLE();                      /* DMA2时钟使能 */
    }
    else 
    {
        __HAL_RCC_DMA1_CLK_ENABLE();                      /* DMA1时钟使能 */
    }
    
    __HAL_LINKDMA(&g_uart1_handle, hdmatx, g_dma_handle);           /* 将DMA与USART1联系起来(发送DMA) */
    
    /* Tx DMA配置 */
    g_dma_handle.Instance = DMAx_CHx;                               /* USART1_TX使用的DMA通道为: DMA1_Channel4 */
    g_dma_handle.Init.Direction = DMA_MEMORY_TO_PERIPH;             /* DIR = 1 , 存储器到外设模式 */
    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.Mode = DMA_NORMAL;                            /* 外设流控模式 */
    g_dma_handle.Init.Priority = DMA_PRIORITY_MEDIUM;               /* 中等优先级 */

    HAL_DMA_Init(&g_dma_handle);
}

main.c

#include "./SYSTEM/sys/sys.h"
#include "./SYSTEM/usart/usart.h"
#include "./SYSTEM/delay/delay.h"
#include "./USMART/usmart.h"
#include "./BSP/LED/led.h"
#include "./BSP/LCD/lcd.h"
#include "./BSP/KEY/key.h"
#include "./BSP/DMA/dma.h"


const uint8_t TEXT_TO_SEND[] = {"正点原子 STM32 DMA 串口实验"}; /* 要循环发送的字符串 */
#define SEND_BUF_SIZE       (sizeof(TEXT_TO_SEND) + 2) * 200    /* 发送数据长度, 等于sizeof(TEXT_TO_SEND) + 2的200倍. */

uint8_t g_sendbuf[SEND_BUF_SIZE];           /* 发送数据缓冲区 */
extern DMA_HandleTypeDef  g_dma_handle;     /* DMA句柄 */
extern UART_HandleTypeDef g_uart1_handle;   /* UART句柄 */

int main(void)
{
    uint8_t  key = 0;
    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)
    {
        key = key_scan(0);

        if (key == KEY0_PRES)       /* 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;
        }
    }
}

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

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

相关文章

3. 将GitHub上的开源项目导入(clone)到本地pycharm上——深度学习·科研实践·从0到1

目录 1. 在github上搜项目 (以OpenOcc为例&#xff09; 2. 转移到码云Gitee上 3. 下载整个项目到本地 4. 在pycharm中打开项目 1. 在github上搜项目 (以OpenOcc为例&#xff09; 把链接复制下来&#xff0c;转移到国内Gitee上&#xff0c;会更稳定 2. 转移到码云Gitee上 &…

IT基础监控范围和对象

监控易作为一款由美信时代独立自主研发的分布式一体化集中监控平台&#xff0c;其监控范围极为广泛&#xff0c;几乎涵盖了所有主流的IT基础设施以及相关的设备和系统。以下是对监控易监控范围的详细介绍&#xff1a; 一、IT基础资源监控 服务器硬件监控&#xff1a;监控易支…

【CAM350】使用总结 <二>{ 光绘Gerber 比较 }

一、 比较两份版本不同的光绘文件&#xff1a; //Analysis-Compare layers// 二、参数默认&#xff0c;比较完成给出结果 三、也可以直接在一份文件上选择“Draw on top” 四、对比差距直观可见

PageHelper - MyBatis 分页插件

如果你也在用 MyBatis&#xff0c;建议尝试该分页插件&#xff0c;这一定是最方便使用的分页插件。分页插件支持任何复杂的单表、多表分页。 学习任何知识都推荐查看它的官方文档&#xff1a;MyBatis 分页插件 PageHelper 文档里面介绍了很多&#xff0c;我这里谈一下我的理解&…

单细胞miloR分析(基于 KNN 图的细胞差异丰度分析方法)

通常情况下&#xff0c;对两组或多组样本进行了不同处理/干预之后&#xff0c;研究者首先会进行同种细胞亚群处理前后的细胞数量的比较&#xff0c;但在单细胞分辨率时代之后&#xff0c;即使是同一个亚群中的不同细胞也应当看成不同的样本。 那么问题就来了&#xff0c;既然应…

矩阵特征值估计

特征值的相关理论 矩阵的特征值与特征向量的定义由于是代数最基本的知识&#xff0c;在此暂且不介绍了&#xff0c;不太清楚的可以查询一下低阶代数课程。 一、矩阵特征值的估计1——矩阵特征值在复平面上的分布 定义 Gerschgorin圆盘&#xff1a;设 A(aij)nn 为实方阵&…

计算机变量内存分区

内存分区 堆区、栈区、全局区、文字常量区、代码区 1.堆区&#xff1a;malloc、calloc、realloc、free操作&#xff0c;可读可写&#xff1b;2.栈区&#xff1a;局部变量、函数形参、返回值 、可读可写3.全局区&#xff1a;全部变量、静态局部变量、静态全局变量 、可读可写&…

动手学深度学习(李沐)PyTorch 第 5 章 深度学习计算

5.1 层和块 为了实现这些复杂的网络&#xff0c;我们引入了神经网络块的概念。 块&#xff08;block&#xff09;可以描述单个层、由多个层组成的组件或整个模型本身。 使用块进行抽象的一个好处是可以将一些块组合成更大的组件&#xff0c; 这一过程通常是递归的&#xff0c;…

Matlab实现鲸鱼优化算法优化回声状态网络模型 (WOA-ESN)(附源码)

目录 1.内容介绍 2部分代码 3.实验结果 4.内容获取 1内容介绍 鲸鱼优化算法&#xff08;Whale Optimization Algorithm, WOA&#xff09;是一种基于座头鲸捕食行为的群智能优化算法。该算法通过模仿座头鲸使用螺旋形路径和包围猎物的策略来探索和开发解空间&#xff0c;以找到…

「Python入门」Pycharm的安装和运行

文章目录 Pycharm介绍文件介绍安装Pycharm打开pycharm配置python解释器运行代码新建文件 Pycharm介绍 PyCharm是由JetBrains打造的一款Python IDE&#xff08;Integrated Development Environment&#xff0c;集成开发环境&#xff09;&#xff0c;带有一整套可以帮助用户在使…

用manim实现有想法的Pi

这幅图展示了一个关于矩阵乘法的数学公式&#xff0c;背景为深绿色&#xff0c;给人一种简洁而专业的感觉。图中间是一个矩阵乘法的表达式&#xff0c;左侧是两个 2222 矩阵&#xff0c;分别为&#xff1a; 右侧则是它们的乘积&#xff0c;结果矩阵为&#xff1a; 整个公式被一…

Windows:win11旗舰版连接无线显示器,连接失败

摘要&#xff1a;win11系统通过 miracast 无线连接到长虹电视的时候&#xff0c;一直连接不上。查看电脑又是支持 miracast 协议&#xff0c;后续发现关闭防火墙即可正常连接。 一、问题现状 最近公司里新换了电视&#xff0c;打算把笔记本电脑投屏到电视上。由于 HDMI 插拔不…

电子信息工程职称评审流程有哪些?

电子信息工程职称评审流程有哪些&#xff1f; 2024年工程类职称评审6大步骤&#xff1a; 1.确认申报条件 2.准备评审材料 3.提交评审材料 4.组织专家评审 5.进入答辩环节 6.职称公示下证 哪些人可以评电子信息工程呢&#xff1f; 从事微电子、计算机与网络、信息与通信、…

媒体发稿:怎样写下有吸引力的文案共享-华媒舍

媒体发稿推广已成为企业、机构和个人宣传策划的重要方式之一。因为市场竞争激烈&#xff0c;怎样写下有吸引力的爆款文案成为了一个重要环节。这篇科谱详细介绍文章内容将为您分享一些对于如何写下爆款文案的机密手册。 1、关键词的风采 题目是文案的店面&#xff0c;取决于读…

头戴式耳机性价比排名有哪些?五大头戴式耳机排名推荐!

现在头戴式耳机凭借其优良的音质、舒适的佩戴体验和出色的隔音效果&#xff0c;成为了众多音乐爱好者和影音娱乐用户的首选。然而&#xff0c;面对市场上众多品牌和型号&#xff0c;如何选择一款性价比高、符合个人需求的耳机&#xff0c;头戴式耳机性价比排名有哪些&#xff1…

Android OpenGLES2.0开发(三):绘制一个三角形

我们总是对陌生人太客气&#xff0c;而对亲密的人太苛刻 上一篇文章中&#xff0c;我们已经将OpenGL ES环境搭建完成。接下来我们就可以开始我们的绘图之旅了。该篇我们讲解最基本图形三角形的绘制&#xff0c;这是一切绘制的基础。在OpenGL ES的世界里一切图形都可以由三角形拼…

Linux云计算 |【第四阶段】RDBMS1-DAY5

主要内容&#xff1a; 试图概述&#xff08;创建视图VIEW、修改、查看、删除&#xff09;、变量&#xff08;全局变量、会话变量、用户变量、局部变量&#xff09;、存储过程&#xff08;创建、调用、删除存储过程&#xff09;、流程控制结构&#xff08;分支结构&#xff1a;…

必备!8款热门网页制作工具大汇总

在过去&#xff0c;网站的构建主要依赖专业人员手动编写HTML、CSS和JavaScript等代码。然而&#xff0c;如今涌现出越来越多智能化的网页制作工具&#xff0c;使得任何人都能在零编码基础上轻松创建和设计网站。本文将向您介绍2022年热门的网页制作工具。选择合适的网页制作工具…

【WPF】桌面程序开发之窗口的用户控件详解

使用Visual Studio开发工具&#xff0c;我们可以编写在Windows系统上运行的桌面应用程序。其中&#xff0c;WPF&#xff08;Windows Presentation Foundation&#xff09;项目是一种常见的选择。然而&#xff0c;对于初学者来说&#xff0c;WPF项目中xaml页面的布局设计可能是一…

Naive UI 选择器 Select 的:render-label 怎么使用(Vue3 + TS)

项目场景&#xff1a; 在Naive UI 的 选择器 Select组件中 &#xff0c;如何实现下面的效果 &#xff0c;在下拉列表中&#xff0c;左边展示色块&#xff0c;右边展示文字。 Naive UI 的官网中提到过这个实现方法&#xff0c;有一个render-label的api&#xff0c;即&#xff…