STM32CubeMX配置使用通用定时器产生PWM
一、定时器PWM功能简介
-
定时器,顾名思义,就是定时的功能,定时器在单片机中算是除GPIO外最基本的外设。在ST中,定时器分为几种,基础定时器,通用定时器,高级定时器和低功耗定时器。其中定时器除了用作定时外,还可以用作输入捕获、比较输出、PWM输出等功能。本文重点介绍PWM输出的功能配置。
-
脉宽调制(Pulse Width Modulation),简称PWM或P波,其实就是输出像方波一样的波型。其中PWM有几个比较重要的参数:频率(周期)、占空比、幅值。
- 基础定时器只有最简单的定时功能,而本文使用的PWM,基础定时器是无法满足的,只有通用定时器、高级定时器具备PWM功能,通用定时器结构框图如下所示:
- 这个框图比基础定时器要复杂一些,我们把它拆成四部分,基础定时、触发源、输入部分和输出部分。虽然框图这么划分,但实现基础定时、输入和输出的预分频、重装载值、计数值这部分是重叠的。输入和输出更是共用了捕获/比较的寄存器。
- 基础定时:这一块跟之前基础定时器的配置方式是一样的,可以参考那一篇文章STM32CubeMX-基础定时器配置。
- 触发源:用于触发启动定时器的功能。
- 输入部分:可用来配置输入捕获的功能,一般用作频率检测、电平翻转触发等。本文重点为PWM,所以输入部分在其他文章里再详细说明。
- 输出部分:可用来配置比较输出和PWM输出。
- 基础定时器只有最简单的定时功能,而本文使用的PWM,基础定时器是无法满足的,只有通用定时器、高级定时器具备PWM功能,通用定时器结构框图如下所示:
-
PWM相关的配置项
- PSC prescaler(预分频):用于将定时器的输入时钟分频使用,比如单片机当前芯片主频为48M,给到定时器的时钟也为48M,但由于功耗或实际应用场景等原因,并不需要定时器以这么高频率进行计数,那就可以使用预分频将频率降低。比如来个48分频,那实际定时器计数频率就是1MHz。需要注意的是,这个寄存器默认值为0,即一分频,所以想要设置48分频,应该设置寄存器的值为47,即设置值=预分频系数-1。
- CNT counter(计数值):这个就是定时器工作时的计数值,当定时器启动时,该寄存器每隔一个时钟周期会往上加1,直到计数值溢出(16位的定时器上溢值就是2的16次方,即65535)或在开启自动重装载功能时达到重装载值,则清0。
- Auto-reload register(重装载值):在开启了自动重装载功能后,当CNT计数值大于该设定值时,CNT计数值会自动清0重新计数。所以重装载值的设定值,一般也是需要设置目标值-1,也就是如果想要计10个数,那只要设置9即可。
- Capture/Compare x register(x通道的捕获/比较寄存器):当定时器某一通道配置为PWM功能时,该通道的此寄存器则作为比较寄存器。当CNT计数值大于该寄存器值时,输出电平翻转。
- Output control(输出控制器):这个用来总体控制输出的开关。
-
预分频系数和重装载值这两个就决定了PWM的频率。具体计算公式:PWM频率 = (系统时钟频率 / 预分频系数) / 重装载值
-
比较值和重装载值这两个就决定了PWM的占空比。具体计算公式:PWM占空比 = 比较值 / 重装载值
-
如下图所示:这个定时器是有4个独立通道的(TIMx_CH1~4),但4个通道共享一个分频系数和重装载值。所以当使用同一个定时器输出多个PWM通道时,其频率是共享的,只有占空比可以独立设置。如果真的需要不同通道设置不同的频率,那只能选择使用不同的定时器。
-
看下高级定时器,也有PWM的功能,甚至比通用定时器的PWM功能更丰富。从系统框图上最直观可以看到就是多了一路BKIN,一般是用在电机控制上紧急关闭输出的。
另外需要注意的是:高级定时器一般用在电机控制上,电机控制一般是需要 2~3 路 PWM 按一定的时序输出,所以使用PWM时,高级定时器比通用定时器需要多开一个总输出的寄存器。
二、定时器配置
- 这里我们实现一个呼吸灯。首先呼吸灯就是让LED的亮度从灭到亮无级过度,看起来就像是人呼吸一样顺畅。那怎么做到让LED亮度无级调节呢?最直接的方法就是调节控制LED灯的电压,前面知道了点亮一个LED灯是需要给一个3.3V的电压值,那如果我们给一个2V的电压值,那LED灯的亮度是不是就会比原本3.3V暗一些。但怎么调节给定的电压值呢?这里可以用PWM技术来处理。幅值为3.3V,占空比为50%的PWM,其平均电压为3.3*50%=1.65V。这里还有个问题,就是PWM的频率应该设置多少?这里只需要设置一个人眼看不出灯闪的频率即可,先初定一个2kHz。知道原理后,就可以开始对PWM进行设置了。
-
首先选择需要控制的IO口(需要确定该IO口是否具备定时器通道输出的功能),这里我们用的是开发板的PA5口,也就是LED灯的那个端口,选择TIM2_CH1。然后在左边的菜单框中选择Timers->TIM2,在弹出的菜单栏中,找到Clock Source,配置成Internal Clock,即使用内部时间作为时钟源。再配置Channel1为PWM Generation CH1,即PWM功能。
- Slave Mode(从机模式):可以在多种模式下与外部触发器同步,可配置为
- 重置模式:输入出现上升沿时复位定时器计数并更新寄存器值
- 门控模式:输入高电平时启动计数,输入低电平时停止计数,不重置寄存器
- 触发模式:输入出现上升沿时启动计数,不能控制停止
- Trigger Source(触发源):就上面框图里可用的ITR0~4等触发源,用来触发定时器工作,如果由软件启动,则不需要配置此项。
- Clock Source(时钟源):一般使用内部时钟源即可。
- Channel x(第x通道):可以配置每个通道的功能,比如PWM输出,比较输出,输入捕获等,当配置为PWM或比较输出时,还可以选配是否从端口输出,选择不输出的场景一般是把定时器仅用作计数器,当计数值达到某个设定阀值时,触发一个中断。
- One Pulse Mode(单脉冲模式):启用该功能时,当定时器计数值达到重装载值时停止计数。
- Slave Mode(从机模式):可以在多种模式下与外部触发器同步,可配置为
-
接下来配置PWM的相关参数
- Prescaler(预分频):用于将定时器的输入时钟分频使用,比如单片机当前芯片主频为48M,给到定时器的时钟也为48M,但由于功耗或实际应用场景等原因,并不需要定时器以这么高频率进行计数,那就可以使用预分频将频率降低。比如来个48分频,那实际定时器计数频率就是1MHz。需要注意的是,这个寄存器默认值为0,即一分频,所以想要设置48分频,应该设置寄存器的值为47,即设置值=预分频系数-1。
- Counter Mode(计数类型):可配置为向上计数和向下计数两种模式,向上计数则是定时器的计数正常向上累加,达到溢出值后清0,向下计数则是定时器的计数向下递减,减至0时将计数值恢复至最大值。
- Counter Period(重装载值-32位):在开启了自动重装载功能后,当CNT计数值大于该设定值时,CNT计数值会自动清0重新计数。所以重装载值的设定值,一般也是需要设置目标值-1,也就是如果想要计10个数,那只要设置9即可。
- Internal Clock Division(内部时钟分频):用于对内部时钟进行分频,可以配置为不分频、二分频和四分频。
- auto-reload preload(自动重装载):开启自动重装载功能后,如果配置的计数类型是向上计数时,当计数值大于重装载值时,定时器会自动将计数值清0重新开始计数;如果配置的计数类型是向下计数,则当计数值为0时,定时器自动将计数值设置为重装载值。这里开启即可。因为我们现在要实现的功能是呼吸灯,所以需要输出的PWM占空比是需要实时改变的,因此这里Pulse可配可不配,具体数值在代码里体现。
-
最后,配置PWM模式下PWM Generation Channel x的相关配置
- Mode(PWM的模式):有两种模式,分别是PWM1和PWM2
- 设置为PWM1时,如果设置为向上计数,则当计数值 < 比较值时,输出低电平;如果设置为向下计数,则当计数值 > 比较值时,输出低电平。
- PWM2则与之相反。
- Pulse(输出比较值):当计数值超过该设定值时,电平翻转,所以PWM的占空比即由该寄存器值 / 重装载值可得。
- Output compare preload(输出比较值预加载):当使能此功能时,设置Pulse输出比较值时,该值不会立即生效,而是会等到当前PWM完成一个周期的输出后才把当前值设置至Pulse输出比较值的寄存器中。这样可以实现设置的平滑切换。不使能则是立即生效。这里建议使能该功能。
- Fast Mode(快速模式):当需要输出高速PWM时则选配此功能。
- CH Polarity(通道极性):用来配置PWM输出的初始电平极性,当配置为High(高)时,默认为高电平;配置为low(低)时,则默认为低电平。
- Mode(PWM的模式):有两种模式,分别是PWM1和PWM2
三、代码实现
因为CubeMX已经配置好了PWM的频率,生成工程后,只需要调用启动PWM的接口即可。而要实现呼吸灯的效果,则需要循环修改定时器的比较值,也就是让PWM输出的占空比从0%到100%,再从100%到0%。每次设置时需要增加一个延时,防止呼吸过于急促。
HAL库代码实现
/**
* @brief The application entry point.
* @retval int
*/
int main(void)
{ /* USER CODE BEGIN 1 */ uint32_t duty = 0; uint32_t pre_d = 0; //保存当前定时器重装载值uint32_t comp_d = 0; //保存当前定时器比较值uint8_t dir = 0; //占空比增减方向标识/* USER CODE END 1 */ /*----------------------- MCU Configuration-----------------------------*/ /* Reset of all peripherals, Initializes the Flash interface and the Systick. */ HAL_Init(); /* USER CODE BEGIN Init */ /* USER CODE END Init */ /* Configure the system clock */ SystemClock_Config(); /* USER CODE BEGIN SysInit */ /* USER CODE END SysInit */ /* Initialize all configured peripherals */ MX_GPIO_Init(); MX_TIM2_Init(); /* USER CODE BEGIN 2 */ /* 开启定时器 */ HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_1); /* 获取当前定时器重装载值 */ pre_d = __HAL_TIM_GET_AUTORELOAD(&htim2); /* USER CODE END 2 */ /* Infinite loop */ /* USER CODE BEGIN WHILE */ while (1) { /* 占空比由0%到100%,再从100%到0%循环 */ if (dir == 0) { duty++; }else { duty--; } if (duty = 100) { dir = 1; }else if (duty == 0){ dir = 0; } /* 延个时,防止呼吸过快 */ HAL_Delay(10); /* 根据占空比计算比较值 */ comp_d = pre_d * (duty / 100); /* 设置比较值 */ if (__HAL_TIM_GET_COMPARE(&htim2, TIM_CHANNEL_1) != comp_d){ __HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_1, comp_d); }}/* USER CODE END WHILE */ /* USER CODE BEGIN 3 */ /* USER CODE END 3 */
}
LL库代码实现
- 同样的,仿照HAL库的实现方式,调用相应的LL库接口。首先是初始化部分,HAL库简化后核心逻辑如下,其实就只是使能当前通道后打开定时器而已,中间使能总输出只在高级定时器中才需要。
- 其他接口在LL库均能找到对应的接口,这里就直接上代码了。当然,使用LL库的时候,还是记得需要把生成代码库切成LL库。
/**
* @brief The application entry point.
* @retval int
*/
int main(void)
{ /* USER CODE BEGIN 1 */ uint32_t duty = 0; uint32_t pre_d, comp_d = 0; uint8_t dir = 0; /* USER CODE END 1 */ /* ------------------------------MCU Configuration--------------------------*/ /* Reset of all peripherals, Initializes the Flash interface and the Systick. */ LL_APB1_GRP2_EnableClock(LL_APB1_GRP2_PERIPH_SYSCFG); LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_PWR); /* SysTick_IRQn interrupt configuration */ NVIC_SetPriority(SysTick_IRQn, 3); /* USER CODE BEGIN Init */ /* USER CODE END Init */ /* Configure the system clock */ SystemClock_Config(); /* USER CODE BEGIN SysInit */ /* USER CODE END SysInit */ /* Initialize all configured peripherals */ MX_GPIO_Init(); MX_TIM2_Init(); /* USER CODE BEGIN 2 */ /* 使能通道 */ LL_TIM_CC_EnableChannel(TIM2, LL_TIM_CHANNEL_CH1); /* 使能总输出 */ LL_TIM_EnableAllOutputs(TIM2); /* 使能定时器 */ LL_TIM_EnableCounter(TIM2); /* 获取当前定时器重装载值 */ pre_d = LL_TIM_GetAutoReload(TIM2); /* USER CODE END 2 */ /* Infinite loop */ /* USER CODE BEGIN WHILE */ while (1) { /* 占空比由0~100再从100到0循环,单位% */ if (dir == 0){ duty++; } else { duty--; } if (duty >= 100){ dir = 1; } else if (duty == 0){ dir = 0; } /* 根据占空比计算比较值 */ comp_d = pre_d * duty / 100; /* 延个时,防止呼吸过快 */ LL_mDelay(10); /* 设置比较值 */ if (LL_TIM_OC_GetCompareCH1(TIM2) != comp_d){ LL_TIM_OC_SetCompareCH1(TIM2, comp_d); } /* USER CODE END WHILE */ /* USER CODE BEGIN 3 */ } /* USER CODE END 3 */
}
效果演示
烧录软件至开发板中,可以看到呼吸灯的效果。
三、注意事项
- 留意预分频系数和重装载值设置的时候都是要减1处理,也就是想要2分频,PSC需要设置为1,想要计数10次复位,则需要给重装载值设置9。
- 配置完生成的工程,并不会在初始化的时候就给打开计数,需要在使用过程中自行调用相关接口函数打开。
- 高级定时器实现PWM功能,会多一个总输出的控制,否则端口不会输出PWM。
看到呼吸灯的效果。
[外链图片转存中…(img-bLqNB56o-1748269147102)]
三、注意事项
- 留意预分频系数和重装载值设置的时候都是要减1处理,也就是想要2分频,PSC需要设置为1,想要计数10次复位,则需要给重装载值设置9。
- 配置完生成的工程,并不会在初始化的时候就给打开计数,需要在使用过程中自行调用相关接口函数打开。
- 高级定时器实现PWM功能,会多一个总输出的控制,否则端口不会输出PWM。
- 同个定时器的不同通道只能是相同的频率,需要输出不同频率的PWM波,需要使用不同的定时器。
【文章参考】https://baijiahao.baidu.com/s?id=1827395717468433105
相关文章:

STM32CubeMX配置使用通用定时器产生PWM
一、定时器PWM功能简介 定时器,顾名思义,就是定时的功能,定时器在单片机中算是除GPIO外最基本的外设。在ST中,定时器分为几种,基础定时器,通用定时器,高级定时器和低功耗定时器。其中定时器除了…...

WebSphere Application Server(WAS)8.5.5教程第十四讲:JPA
一、JPA 以下是对 JPA(Java Persistence API) 的深入详解,适用于具备一定 Java EE / Jakarta EE 背景的开发者,尤其是对数据持久化机制感兴趣的人员。 1、什么是 JPA? Java Persistence API(JPA…...

Linux系统调用深度剖析
Linux系统调用深度剖析与实践案例 目录 Linux系统调用深度剖析与实践案例 一、Linux系统调用概述 二、进程管理相关系统调用 1. fork():进程克隆与多任务处理 2. exec系列:程序加载与替换 3. wait/waitpid:进程状态同步 三、文件操作相关系统调用 1. 文件描述符操作…...

动态规划-918.环形子数组的最大和-力扣(LeetCode)
一、题目解析 听着有点复杂,这里一图流。 将环形问题转化为线性问题。 二、算法原理 1.状态表示 2.状态转移方程 详细可以移步另一篇博客,53. 最大子数组和 - 力扣(LeetCode) 3.初始化 由于计算中需要用到f[i-1]和g[i-1]的值&…...
Docker 镜像标签(Tag)规范与要求
Docker 镜像标签(Tag)规范与要求 背景 目前主流云厂商,如阿里云、百度云和腾讯云,均提供租户使用的镜像仓库服务。 各个厂商要求可能不太一样,比如华为:https://doc.hcs.huawei.com/zh-cn/usermanual/swr/swr_faq_0017.html 样…...

STM32:Modbus通信协议核心解析:关键通信技术
知识点1【 Modbus通信】 1、Modbus的概述 Modbus是OSI模型第七层的应用层报文传输协议 协议:说明有组包和解包的过程 2、通信机制 Modelbus是一个请求/应答协议 通信机制:主机轮询,从机应答的机制。每个从设备有唯一的地址,主…...

线程封装与互斥
目录 线程互斥 进程线程间的互斥相关背景概念 互斥量mutex 互斥量的接口 初始化互斥量有两种方法: 销毁互斥量 互斥量加锁和解锁 改进售票系统 互斥量实现原理探究 互斥量的封装 线程互斥 进程线程间的互斥相关背景概念 临界资源:多线程执行流共…...
鸿蒙OSUniApp 开发实时天气查询应用 —— 鸿蒙生态下的跨端实践#三方框架 #Uniapp
使用 UniApp 开发实时天气查询应用 —— 鸿蒙生态下的跨端实践 在移动互联网时代,天气应用几乎是每个人手机中的"标配"。无论是出行、旅游还是日常生活,实时获取天气信息都极为重要。本文将以"实时天气查询应用"为例,详…...
第十一天 5G切片技术在车联网中的应用
前言 在自动驾驶汽车每天产生4TB数据的时代,传统的移动网络已难以满足车联网的海量连接需求。中国移动2023年实测数据显示,某智能网联汽车示范区在传统5G网络下,紧急制动指令的传输延迟高达65ms,而5G网络切片技术将这个数值降低到…...

Spring AI 系列之一个很棒的 Spring AI 功能——Advisors
1. 概述 由AI驱动的应用程序已成为我们的现实。我们正在广泛地实现各种RAG应用程序、提示API,并利用大型语言模型(LLM)创建项目。借助 Spring AI,我们可以更快速地完成这些任务。 在本文中,我们将介绍一个非常有价值…...

Vue3 + TypeScript + el-input 实现人民币金额的输入和显示
输入人民币金额的参数要求: 输入要求: 通过键盘,只允许输入负号、小数点、数字、退格键、删除键、方向左键、方向右键、Home键、End键、Tab键;负号只能在开头;只保留第一个小数点;替换全角输入的小数点&a…...

2.1 C++之条件语句
学习目标: 理解程序的分支逻辑(根据不同条件执行不同代码)。掌握 if-else 和 switch 语句的用法。能编写简单的条件判断程序(如成绩评级、游戏选项等)。 1 条件语句的基本概念 什么是条件语句? 程序在执…...
ZYNQ实战:可编程差分晶振Si570的配置与动态频率切换
为什么需要可编程差分晶振? 在现代FPGA和嵌入式系统中,高速串行通信(如GTP/GTX收发器)对参考时钟的精度和灵活性要求极高。例如,1G以太网需要125MHz时钟,SATA协议需120MHz,而DisplayPort则需135MHz。传统固定频率晶振无法满足多协议动态切换需求,而Si570凭借其10MHz~8…...

Linux `ls` 命令深度解析与高阶应用指南
Linux `ls` 命令深度解析与高阶应用指南 一、核心功能解析1. 基本作用2. 与类似命令对比二、选项系统详解1. 常用基础选项2. 进阶筛选选项三、高阶应用技巧1. 组合过滤查询2. 格式化输出控制3. 元数据深度分析四、企业级应用场景1. 存储空间监控2. 安全审计3. 自动化运维五、特…...

【MPC控制 - 从ACC到自动驾驶】5. 融会贯通:MPC在ACC中的优势总结与知识体系构建
【MPC控制 - 从ACC到自动驾驶】融会贯通:MPC在ACC中的优势总结与知识体系构建 在过去的四天里,我们一起经历了一段奇妙的旅程: Day 1: 我们认识了自适应巡航ACC这位“智能领航员”,并初见了模型预测控制MPC这位“深谋远虑的棋手…...
Day3 记忆内容:map set 高频操作
以下是 第三天 的详细学习内容,聚焦 map和set的高效应用,重点突破查找类题型和去重逻辑,助你提升代码效率! 📚 Day3 记忆内容:map & set 高频操作 1. map 核心操作(手写3遍) /…...

初等数论--Garner‘s 算法
0. 介绍 主要通过混合积的表示来逐步求得同余方程的解。 对于同余方程 { x ≡ v 0 ( m o d m 0 ) x ≡ v 1 ( m o d m 1 ) ⋯ x ≡ v k − 1 ( m o d m k − 1 ) \begin{equation*} \begin{cases} x \equiv v_0 \quad (\ \bmod \ m_0)\\ x \equiv v_1 \quad (\ \bmod \ m_1)…...

NV211NV212美光科技颗粒NV219NV220
NV211NV212美光科技颗粒NV219NV220 技术架构解析:从颗粒到存储系统 近期美光科技发布的NV211、NV212、NV219、NV220系列固态颗粒,凭借其技术突破引发行业关注。这些颗粒基于176层QLC堆叠工艺,单Die容量预计在2026年可达1Tb,相当…...

SQL解析工具JSQLParser
目录 一、引言二、JSQLParser常见类2.1 Class Diagram2.2 Statement2.3 Expression2.4 Select2.5 Update2.6 Delete2.7 Insert2.8 PlainSelect2.9 SetOperationList2.10 ParenthesedSelect2.11 FromItem2.12 Table2.13 ParenthesedFromItem2.14 SelectItem2.15 BinaryExpressio…...

Wave Terminal + Cpolar:SSH远程访问的跨平台实战+内网穿透配置全解析
文章目录 前言1. Wave Terminal安装2. 简单使用演示3. 连接本地Linux服务器3.1 Ubuntu系统安装ssh服务3.2 远程ssh连接Ubuntu 4. 安装内网穿透工具4.1 创建公网地址4.2 使用公网地址远程ssh连接 5. 配置固定公网地址 前言 各位开发者朋友,今天为您介绍一款颠覆性操…...

html使用JS实现账号密码登录的简单案例
目录 案例需求 思路 错误案例及问题 修改思路 案例提供 所需要的组件 <input>标签,<button>标签,<script>标签 详情使用参考:HTML 教程 | 菜鸟教程 案例需求 编写一个程序,最多允许用户尝试登录 3 次。…...
sorted() 函数和sort()函数的区别
在Python中,sorted() 函数和列表的 sort() 方法都用于排序,但它们之间有一些关键的区别: 返回值: sorted():返回一个新的列表,包含所有排序后的元素,原始列表不会被修改。sort():对列…...
Solr搜索:比传统数据库强在哪?
Solr 是一个基于 Apache Lucene 的开源搜索平台,广泛用于全文检索和数据分析。与传统的关系型数据库查询相比,Solr 在某些方面具有明显的优势,特别是在处理大规模文本数据和复杂的搜索需求时。以下是 Solr 相对于传统数据库查询的主要优势&am…...

【数据集】基于ubESTARFM法的100m 地温LST数据集(澳大利亚)
目录 数据概述一、输入数据与处理二、融合算法1. ESTARFM(Enhanced STARFM)2. ubESTARFM(Unbiased ESTARFM)代码实现数据下载参考根据论文《Generating daily 100 m resolution land surface temperature estimates continentally using an unbiased spatiotemporal fusion…...

51c自动驾驶~合集55
我自己的原文哦~ https://blog.51cto.com/whaosoft/13935858 #Challenger 端到端碰撞率暴增!清华&吉利,框架:低成本自动生成复杂对抗性驾驶场景~ 自动驾驶系统在对抗性场景(Adversarial Scenarios)中的可靠性是安全落…...

【前端基础】Promise 详解
文章目录 什么是 Promise?为什么要使用 Promise?创建 Promise消费 Promise (使用 Promise)1. .then(onFulfilled, onRejected)2. .catch(onRejected)3. .finally(onFinally) Promise 链 (Promise Chaining)Promise 的静态方法1. Promise.resolve(value)2…...

高性能管线式HTTP请求
高性能管线式HTTP请求:原理、实现与实践 目录 高性能管线式HTTP请求:原理、实现与实践 1. HTTP管线化的原理与优势 1.1 HTTP管线化的基本概念 关键特性: 1.2 管线化的优势 1.3 管线化的挑战 2. 高性能管线式HTTP请求的实现方案 2.1 技术选型与工具 2.2 Java实现:…...
c/c++的opencv膨胀
使用 OpenCV (C) 进行图像膨胀操作详解 图像膨胀 (Dilation) 是形态学图像处理中的另一种基本操作,与腐蚀操作相对应。它通常用于填充图像中的小孔洞、连接断开的物体部分、以及加粗二值图像中的物体。本文将详细介绍膨胀的原理,并演示如何使用 C 和 Op…...
react native搭建项目
React Native 项目搭建指南 React Native 是一个使用 JavaScript 和 React 构建跨平台移动应用的框架。以下是搭建 React Native 项目的详细步骤: 1. 环境准备 安装 Node.js 下载并安装 Node.js (推荐 LTS 版本) 安装 Java Development Kit (JDK) 对于 Androi…...

【CSS】九宫格布局
CSS Grid布局(推荐) 实现代码: <!doctype html> <html lang"en"><head><meta charset"UTF-8" /><meta name"viewport" content"widthdevice-width, initial-scale1.0"…...