【STM32 CubeMX】DAC 输出正弦波

本篇实现效果, 预览:

目录

一、前言

二、正弦波频率公式

[三、CubeMX 配置](#三、CubeMX 配置)

[1、DAC 基础 配置](#1、DAC 基础 配置)

[2、DMA 传输 配置](#2、DMA 传输 配置)

[3、TIM 定时器 配置](#3、TIM 定时器 配置)

[四、代码实现 --- 正弦表数组法输出信号](#四、代码实现 --- 正弦表数组法输出信号)

1、波形样本数组

2、启动定时器、DAC的DMA传输

3、运行效果

五、进阶---频率调整实战

[1、 编写可调式波形函数](#1、 编写可调式波形函数)

2、实例一:输出100kHz正弦波(高频挑战)

3、实例二:输出500Hz正弦波(低频实现)


一、前言

使用 数模转换器 (DAC) 生成高精度模拟波形 是一项常见需求。

本文将示范一种高效、可靠的正弦波生成方案:

利用定时器 (TIM) 自动触发 DAC 转换,并由 DMA 直接搬运波形数据

该方案能最大限度地解放CPU资源,确保输出连续、精准的正弦波信号。

为帮助读者循序渐进地掌握,教程将分为两个核心部分:

  1. 基础实践:通过STM32CubeMX的图形化配置,快速实现一个预设频率(10kHz)正弦波的输出,了解完整操作流程。
  2. 进阶应用:深入讲解波形数据表的动态生成方法与频率计算公式,实现目标频率的正弦波输出。

本文所有示例及方法均提供开源程序以供验证与参考,如有疑问或建议,欢迎交流指正。

开源程序: 【STM32 CubeMX】 DAC 输出正弦波 (已设置0积分。如发现下载需要积分,请通知修改)

实验器材:

实验器材 备注说明 链接
STM32F407VE 开发板 F4系列DAC共两个通道(PA4, PA5) 【链接】
示波器 带宽50MHz、采样率1Gsa/s 【链接】
探头 使用1X档位 机配

二、正弦波频率公式

在开始操作之前,先看看正弦波频率的计算公式:

  • 正弦波频率 = TIM时钟频率 ÷ PSC ÷ ARR ÷ 波点数

|-------------|--------------------------|
| 正弦波频率 | 希望输出的正弦波频率(单位:Hz) |
| TIM时钟频率 | 触发DAC的定时器的时钟频率(单位:Hz) |
| PSC | 定时器时钟的预分频器值 |
| ARR | 定时器的自动重载值。多少个定时器脉冲触发一次事件 |
| 波点数 | 一个正弦波周期的采样点数(波形数据表的长度) |

实例计算:输出10kHz正弦波

为了让大家更直观地理解,以STM32F407为例,规划一组参数来实现 10kHz 的正弦波。

  • 正弦波频率: 10,000 Hz

  • **TIM 时钟频率:**本篇使用 TIM6 。通常,F103的TIM6是72MHz, F407的TIM6是84MHz。

  • **PSC 预分频器:**通常设置为1,即不分频,以方便计算,并获得最高的触发频率。

  • **ARR 周期值:**分频后的TIM时钟,产生N个脉冲数后,触发一次DAC转换。

  • 波点数:这里用128,即一个正弦波由128个样本点组成 。样本点数越多,波形越细腻。

现在,公式中的5个成员,仅剩 ARR 为未知数。

我们将数值代入公式进行计算 (正弦波频率 = TIM时钟频率 ÷ PSC ÷ ARR ÷ 波点数):

10000 = 84000000 ÷ 1 ÷ ARR ÷ 128

计算过程:ARR = 84000000 ÷ 1 ÷ 128 ÷ 10000 = 65.625

寄存器值必须是整数 ,取整 ARR = 66

因此,实际的波形频率将是:正弦波频率 = 84000000 ÷ 1 ÷ 66 ÷ 128 = 9943Hz

这与我们的目标10kHz存在微小误差,这是由于ARR必须为整数所致。

解释、提示

设计目标是输出 10,000 Hz 的正弦波,但根据最终参数计算出的实际频率约为 9,943 Hz

这不是错误,而是一个刻意展示的关键现象。

寄存器值必须是整数。当ARR的计算不能整除,取整后,将无法实现精准波形频率的输出!

不必担心,这种微小的误差(约0.57%)在绝大多数应用中是完全可以接受的。

下文也将详细示范如何通过联动调整样本点数(波点数)与 ARR,来寻找最优解,从而实现对特定目标频率的精准输出。


三、CubeMX 配置

本节基于一个已建立的CubeMX工程进行讲解。若需了解新建工程的基础操作,可参考:

以下将在现有工程基础上,添加正弦波生成所需的DAC、DMA 和 TIM 配置。

1、DAC 基础 配置

实现步骤:

  • 使能:打勾通道
  • Output Buffer:Disable 禁用
  • Trigger:Timmer 6 Trigger Out event

解释、 提示

1、输出通道 OUT1、OUT2

STM32系列的大部分型号,DAC通常包含两个独立通道:

  • OUT1 对应引脚 PA4
  • OUT2 对应引脚 PA5

勾选需要的通道后,CubeMX 会自动配置对应引脚的工作模式,无需手动设置

为演示方便,本示例同时启用了两个通道。

2、Output Buffer (输出缓冲器):Disable。

这个功能很有意思 。好些网上教程对此项的描述过于偏理论了。稍作解释。

把这个"输出缓冲器"理解为:在DAC核心与输出引脚之间,有一个片内集成运算放大器。

输出的信号是否启用 (经过) 这个 输出缓冲放大器,是影响输出性能的关键选择。

使能--输出缓冲 Enabled

  • 优势:提供更大的驱动电流,可直接驱动如耳机、小功率扬声器等负载;
  • 缺点:略有噪声、输出电压范围受限(约0.2V~3.1V)
  • 适用场景:长电缆驱动、耳机、功率器件等对驱动能力要求高而对精度要求不严的场合

禁用--输出缓冲 Disabled

  • 优势:噪声更低、线性度更好、输出电压范围更宽(接近0V~VDDA)
  • 缺点:驱动负载时需外接运放电路
  • 适用场景:高精度测量、传感器校准、示波器等需要满幅输出的应用

本篇是把信号直接输出至示波器探头,因此禁用输出缓冲器: Disabled。

3、Trigger (触发源): Timer 6 Trigger Out event。

为使DAC能自动、周期性地进行转换,需要为其配置一个硬件触发源。

此处选择 Timer 6 Trigger Out event。

触发源在项目中用得比较少,这里也稍作解释。

每当Timer的计数器达到设定值,产生"更新事件"(Update Event)时,通过内部的TRGO线路向外发送一个脉冲信号。DAC被连接至此脉冲信号后,每个脉冲都会自动启动一次DAC转换。

结合下面的DMA功能,CPU只需启动传输,即可由定时器"指挥"DMA将波形数据数组自动、同步地搬运给DAC,从而高效、精准地输出连续波形,无需CPU持续干预

2、DMA 传输 配置

实现步骤:

  • 点击Add: 添加DAC1、DAC2
  • Mode: Circular
  • Memory: 打勾
  • 数据宽度: HalfWord

注意!别漏了添加DAC2,不然PA5会没信号输出。

解释、 提示

1、Mode 传输模式

  • Circular 循环传输 --- 输出连续波形必需
  • 每当 DMA 传输完指定数量的数据后,会重新、从头开始传输。这是输出连续、周期性波形 (如正弦波)的必需设置

2、Increment Address 地址增量控制

  • Peripheral 外设地址:不勾选。DAC数据寄存器是硬件,地址是固定的。
  • Memory 内存地址:勾选 。波形数组地址自动递增。

3、Data Width 数据宽度

  • Half Word :**半字, 16位。**DAC 的数据寄存器是 12 位,用16 位即可对齐访问。
  • 程序中的波形样本数组,应定义为uint16_t类型,与此处设置保持一致

3、TIM 定时器 配置

实现步骤:

  • 使能 TIM6:勾选 Activated
  • PSC (预分频器值): 1-1 (TIM的分频从0起,0即1分频,即不分频)
  • ARR (周期脉冲数):66-1 (TIM计数从0起; 即66个脉冲为一周期)
  • Trigger Event Selection (触发事件):Update Event (更新事件)

解释、 提示

TIM的配置,目的是将定时器配置为一个精准的"节拍器",每个"节拍"(更新事件), 触发DAC进行一次转换。

1、为什么上图里用 n-1 的写法? 而不直接写 0、65?

因为定时器硬件的计数机制是从0开始的。

寄存器值 = 期望值 - 1 。

权威解释请参阅《STM32参考手册》中关于TIM寄存器 TIMx_PSCTIMx_ARR 的详细描述。

2、TIM 的使能方式

在CubeMX中,使能定时器的方式因TIM而异,常见有三种:

  • Activated 复选框:勾选即可使能(TIM6、TIM7等基础定时器)
  • Internal Clock 复选框:勾选即可使能内部时钟(部分通用定时器)
  • Clock Source 多选框:选择"Internal Clock"选项(多数高级定时器)

对于本篇使用的TIM6 ,只需勾选Activated复选框即可完成使能。

3、预分频器 ( Prescaler, PSC )

作用:对输入时钟进行分频,得到供给计数器CNT的计数时钟。

每接收 PSC (Prescaler+1)个时钟脉冲,才产生1个计数脉冲。

在使用 TIM 触发 DAC 转换的应用中,通常将 Prescaler设置为 0(PSC=0+1,1分频即不分频)

不分频的好处是简化计算,并允许定时器以最高频率运行。

4、自动重载值 (Period, ARR )

设定定时器的计数周期,是决定触发频率的关键参数。

工作原理

  1. 计数器CNT从0开始,每个脉冲加1
  2. 当CNT值达到ARR设定值时,定时器发生溢出
  3. CNT自动清零,并产生一个更新事件 (Update Event)
  4. 此过程周而复始,形成稳定周期。

数值关系:

  • CubeMX界面或代码里的Period项填写值:66-1
  • 实际寄存器值:65(第66个脉冲溢出触发更新事件)

5、 触发事件选择 ( Trigger Event Selection )

选择:Update Event 更新事件

解释:此配置将定时器内部的更新事件映射到其TRGO(Trigger Output) 引脚上。每次定时器溢出产生更新事件时,都会通过TRGO线路发送一个精准的脉冲信号,用于触发DAC进行数据转换。这些操作将由硬件自动完成。

信号路径

定时器计数溢出 → 产生更新事件 → TRGO输出脉冲 → 触发DAC转换

这种硬件级触发方式确保了转换时序的精确性和稳定性,无需CPU干预。

配置阶段已完成。

点击 "**GENERATE CODE"**按钮,令CubeMX 把 DAC、DMA 、TIM6 的初始化代码生成到工程中。

接下来,我们将进入 代码实现 部分。


四、代码实现 --- 正弦表数组法输出信号

在使用CubeMX完成DAC、DMA和TIM的配置后,用户需要编写的代码量极少。主要步骤为:

  1. 准备正弦波数据表(数组)
  2. 启动定时器(TIM)
  3. 启动DAC的DMA传输

1、波形样本数组

实现步骤:

  • /* USER CODE BEGIN PV *//* USER CODE END PV */之间,添加正弦波数据数组。
cpp 复制代码
#define WAVE_POINTS    128         // 正弦波一个周期的采样点数

/* 1、正弦波数据表 (12位DAC,数值范围0~4095)
 * 使用数组法的优点:减少每次启动时的计算时间,保证波形精度
 * 注意事项:若将数组定义在函数内部,建议使用static修饰,避免栈溢出
 */
static const uint16_t sineData[WAVE_POINTS] =     
{
    /* 0°~90° 上升段 (n=0~31) */
    2048, 2148, 2248, 2348, 2447, 2545, 2642, 2737,
    2831, 2923, 3013, 3100, 3185, 3267, 3346, 3423,
    3495, 3565, 3630, 3692, 3750, 3804, 3853, 3898,
    3939, 3975, 4007, 4034, 4056, 4073, 4085, 4093,

    /* 90°~180° 下降段 (n=32~63) */
    4095, 4093, 4085, 4073, 4056, 4034, 4007, 3975,
    3939, 3898, 3853, 3804, 3750, 3692, 3630, 3565,
    3495, 3423, 3346, 3267, 3185, 3100, 3013, 2923,
    2831, 2737, 2642, 2545, 2447, 2348, 2248, 2148,

    /* 180°~270° 下降段 (n=64~95) */
    2048, 1947, 1847, 1747, 1648, 1550, 1453, 1358,
    1264, 1172, 1082,  995,  910,  828,  749,  672,
     600,  530,  465,  403,  345,  291,  242,  197,
     156,  120,   88,   61,   39,   22,   10,    2,

    /* 270°~360° 上升段 (n=96~127) */
       0,    2,   10,   22,   39,   61,   88,  120,
     156,  197,  242,  291,  345,  403,  465,  530,
     600,  672,  749,  828,  910,  995, 1082, 1172,
    1264, 1358, 1453, 1550, 1648, 1747, 1847, 1947
};

复制添加后,位置如下图:

解释、提示

  • 数组sineData存储了一个完整正弦周期的128个采样点,对应12位DAC的数值范围(0~4095)。
  • 若将数组定义在函数内部,尽量使用static,否则数组会在栈上分配,当样本数组过大时可能导致栈溢出,并且每次函数调用都会重新初始化。
  • 如果想修改波点数,不能直接修改这里的宏定义,还需要波点数重新计算每一个样本值。下文中提供了计算函数。

2、启动定时器、DAC的DMA传输

实现步骤:

  • main函数的/* USER CODE BEGIN 2 *//* USER CODE END 2 */之间(即在while(1)循环之前),添加以下代码:
cpp 复制代码
/* 2、启动定时器 TIM6 */
HAL_TIM_Base_Start(&htim6);                                                                    // 启动TIM。每个更新事件(计数达到一周期),由硬件发出脉冲信号触发DAC转换一次

/* 3、启动DAC的DMA传输 */
HAL_DAC_Start_DMA(&hdac, DAC_CHANNEL_1, (uint32_t *)sine12bit, WAVE_POINTS, DAC_ALIGN_12B_R);  // 启动DAC通道1(对应PA4)的DMA传输
HAL_DAC_Start_DMA(&hdac, DAC_CHANNEL_2, (uint32_t *)sine12bit, WAVE_POINTS, DAC_ALIGN_12B_R);  // 启动DAC通道2(对应PA5)的DMA传输

编写后,位置如下图:

解释、提示

1、HAL_TIM_Base_Start(&htim6):启动定时器TIM6

定时器开始从0计数,当计数值达到ARR(即66)时产生更新事件 。

2、HAL_DAC_Start_DMA ( ):启动DAC的DMA传输。

参数依次为:

  • &hdac:DAC句柄
  • DAC_CHANNNEL_1:DAC通道1(对应PA4)
  • (uint32_t*)sineData:波形数据数组的首地址(需转换为uint32_t指针)
  • WAVE_POINTS:传输数据个数(即数组长度)
  • DAC_ALIGN_12B_R:数据右对齐,12位有效位(因为DAC数据寄存器是12位的)

注意:如果只使用一个通道(例如只使用PA4),则只需调用一次HAL_DAC_Start_DMA,并选择对应的通道。

3、运行效果

编译、烧录到STM32F407开发板,

使用示波器采集 PA5 引脚 (或PA4),即可观察到输出的10kHz正弦波。

效果如下:

解释、提示

真实频率应该是9.943KHz,不是10KHz。

上面截图显示10KHz,是因为示波器 Freq 值在小幅跳动,拍照时刚好卡点10K而已。

为什么真实频率是9.943,在上文中已有说明:

因为寄存器必须用整数,而计算结果 ARR=65.6,ARR取值66,因此无法达成10KHz。

可参考下文,通过联动调整样本点数(波点数)与 ARR,寻找最优解,实现精准输出。


五、进阶---频率调整实战

想输出其他频率,只需在核心公式中调整参数即可:

回顾公式:

  • 正弦波频率 = TIM时钟频率 ÷ PSC ÷ ARR ÷ 波点数

当使用相同TIM时钟且PSC=1时,调整原则如下:

  • 提高频率:减小ARR值,或 减小波点数
  • 降低频率:增大ARR值,或 增加波点数

下面通过 100kHz 和 500Hz 两个实例,演示具体操作及常见误区。

1、 编写可调式波形函数

为便于调试,我们将波形生成过程封装为函数,

并把启动TIM启动DAC的DMA传输这两条执行语句,也封装进去,以简化调试过程。

实现步骤:

  • 在 main.c 的 /* USER CODE BEGIN 0 */ 与 /* USER CODE END 0 */ 之间添加函数
cpp 复制代码
/******************************************************************************
 * 函数名 : DAC_SineStart
 * 功  能 : 启动DAC正弦波输出 (动态计算波形表) 
 * 备  注 : 1. 波点数可通过宏定义WAVE_POINTS灵活调整; 
 *          2. 波点数的取值,建议根据 TIM时钟频率即值,如84MHz时钟下,取值21、42、84、168等,能令公式整除,以达到精准的波形频率
 *          2. 输出幅值:[MIN_VALUE, MAX_VALUE](默认 0-4095)
 *          3. 直流偏置:OFFSET(默认 0)
 *          4. TIM6 更新事件触发,DMA 循环模式
 *          5. 上电重新计算表,调试方便;若需提速,可在调试成型后改用 const 静态表
 * 参  数 : 无 (由函数内宏定义控制)
 * 返回值 : 无
 ******************************************************************************/
#include "math.h"

void DAC_SineStart(void)
{
    /* 1、定义参数 */
    #define WAVE_POINTS     128                      // 正弦数据点数; 取值建议根据 TIM时钟频率即值,如84MHz时钟下,取值21、42、84、168等,能令公式整除,以达到精准的波形频率
    #define MIN_VALUE         0                      // 正弦数据最小值; 即,波底的DAC值; 取值范围:0~4095 (对应0V~3.3V); 用于适配不同设备的工作安全范围,减少硬件电路的设计修改;
    #define MAX_VALUE      4095                      // 正弦数据最大值; 即,波顶的DAC值; 取值范围:0~4095 (对应0V~3.3V); 用于适配不同设备的工作安全范围,减少硬件电路的设计修改;
    #define OFFSET            0                      // 偏移量; 控制波形的直流偏置 (垂直位置)
    #define SCALE ((MAX_VALUE - MIN_VALUE) / 2.0)    // 缩放系数; 控制波形的幅度 (振幅大小)
    
    /* 2、开辟缓存 */
    static uint16_t sineData[WAVE_POINTS] = { 0 };   // 存储正弦波点值

    /* 3、生成无缝正弦表
          计算法:上电实时算表
          优点:调试阶段可随时改 WAVE_POINTS / MIN / MAX,方便灵活调试出需要的波形、振幅
          缺点:每次上电运行都得跑一遍 sin(),启动时间随点数线性增加; 调试定型后建议改用 const 静态表,上电即用,零计算延时  
    */
    for (uint16_t i = 0; i < WAVE_POINTS; i++)
    {
        double x = (double)i * (2.0 * 3.14159265 / WAVE_POINTS);              // 周期内均匀采样; 将索引转换为0到2π之间的值
        double sinValue = sin(x);                                             // 计算正弦值
        sineData[i] = (uint16_t)(lround((sinValue + 1.0) * SCALE + OFFSET));  // 缩放和平移正弦值        
        
    }
 
    /* 4、启动 TIM */
    HAL_TIM_Base_Start(&htim6);                                               // 启动TIM。每个更新事件(计数达到一周期),由硬件发出脉冲信号触发DAC转换一次

    /* 5、启动DAC的DMA传输 */
    HAL_DAC_Start_DMA(&hdac, DAC_CHANNEL_1, (uint32_t *)sineData, WAVE_POINTS, DAC_ALIGN_12B_R);    // 启动DAC通道1的DMA传输,数据输出至PA4引脚
    HAL_DAC_Start_DMA(&hdac, DAC_CHANNEL_2, (uint32_t *)sineData, WAVE_POINTS, DAC_ALIGN_12B_R);    // 启动DAC通道2的DMA传输,数据输出至PA5引脚
}

解释、提示

  1. sin() 和 lround() 需要添加文件引用: #include "math.h"
  2. 波点样本数,为了示范,也用 128 个波点数。
  3. 其余几个参数用于限制振幅,以适用于不同的方案场景,本篇不述。
  4. 使用这种实时计算波点样本,可便于调试。定型后改为静态const数组能提升性能。

编写后,位置如下图:

实现步骤:

  • 在main函数的初始化后、while之前, 调用刚才编写的函数
cpp 复制代码
 DAC_SineStart();                 // 启动波形输出

编写完成后,位置如下:

2、实例一:输出100kHz正弦波(高频挑战)

初次尝试。

使用100KHz、128个样本点。

参数计算: (TIM6时钟=84MHz、PSC=1、波点数=128、波形频率=100000)

得到 ARR = 84000000 ÷ 1 ÷ 128 ÷ 100000 = 6.56

寄存器必须是整数,取整后 ARR = 7。

如何修改ARR的值呢?两种操作方法:

  • CubeMX修改:打开工程文件夹的ioc文件进入CubeMX,修改TIM的period值为 7-1,生成。
  • 代码修改:在keil里双击打开 tim.c 文件,找到MX_TIM6_Init()函数,修改 Period = 7-1

建议使用修改代码的方法,更省工夫。

操作步骤:

  • 打开tim.c文件,找到TIM的初始化函数:MX_TIM6_Init( )
  • 修改 TIM 初始化中的 htim6.Init.Period = 7-1

修改完成 。

编译、烧录,运行效果如下图:

示波器实测,只有46.7KHz, 远远达不到100Khz!

问题根源DAC转换时间不足!

在调试摸索中总结:F407 的 DAC 的转换时间需90ns

而当前的触发周期:7 ÷ 84MHz ≈ 83ns < 90ns

触发过快 导致了转换错误!

疑惑

这个转换时间的测试数据,与芯片手册中的理论转换时间,差距甚大。

若有朋友知道其中原因,望分享。

正确方案:减少采样点数、加大ARR值

将采样点由128减至42。

参数计算: (TIM6时钟=84MHz、PSC=1、波点数=42、波形频率=100000)

ARR = 84000000 ÷ 1 ÷ 42 ÷ 100000 = 20

操作步骤:

  • 修改 WAVE_POINTS 宏值 为 42
  • 修改 TIM 初始化中的 htim6.Init.Period = 20-1

编写完成后,如下图:

编译、烧录,实现效果如下图:

解释、提示

1、关于波点数、ARR的取值技巧

为了能精准地实现波形频率,关键在于公式中的 ARR 能被整除。

举例,如F4的TIM6,时钟频率是84MHz,波点数取 21、42、84、168等, ARR容易被整除。

2、关于波形频率的上限

细心的朋友应该发现,上图中,波顶和波底,没有达到满幅的3.3V、0V。

这是因为波点数太少了。增大波点数,如168,可令信号无限接近满幅。

但是,这又回到头痛的问题,增大波点数,需要减小ARR值。而当F407的168MHz时钟下,务必注意 ARR >= 8,即 触发时间 > 90ns,否则转换出错。

补充:有些朋友咨询,如何实现1M、4M的波形。不能!!上面100K已经不能满幅了!!

3、实例二:输出500Hz正弦波(低频实现)

高频应用关注转换速度极限,而低频实现则更侧重于波形精度与平滑度

下面以输出500Hz正弦波为例,展示不同采样点数对波形质量的影响及参数调整方法。

参数计算 :(TIM6时钟=84MHz、PSC=1、波点数=42个、波形频率=500Hz)

ARR = 84000000 ÷ 1 ÷ 42 ÷ 500 = 4000

实现步骤:

  • 修改 WAVE_POINTS 宏值为 42
  • 修改 TIM 初始化中的 htim6.Init.Period = 4000-1

编译、烧录运行后,波形效果如下图:

可生成500Hz正弦波,但波形呈明显阶梯状平滑度差

这是因为每个周期仅用42个点来描绘,样本点数过低,导致波形失真严重,无法满足大多数对质量有要求的应用。

改进:增加点数至168点的平滑实现

为提高波形质量,将采样点数增加至168点。

参数计算(TIM6时钟84MHz、PSC=1、波点数168个、波形频率500Hz):

得到 ARR = 84000000 ÷ 168 ÷ 500 = 1000

实现步骤:

  • 修改 WAVE_POINTS 宏值为 168
  • 修改 TIM 初始化中的 htim6.Init.Period = 1000-1

输出效果,如下图:

增加点数后重新运行,波形平滑度得到显著改善。虽然会略微增加内存占用,但对于低频应用,这是提升输出信号质量的必要代价。


至此,我们已完整演示了从固定数组动态计算 、从10kHz100kHz 高频挑战及500Hz 低频实现的全过程。通过调整采样点数(N)定时器周期(ARR) 的配比,即可灵活生成不同频率与精度的正弦波。

教程中的方法、公式及代码均通过实际硬件验证。如有任何疑问或发现错漏,欢迎指正与交流。

相关推荐
YouEmbedded4 小时前
解码STM32定时器:原理、配置与实战
stm32·定时器·pwm·sg90舵机
羊小猪~~4 小时前
【QT】-- QT基础类
开发语言·c++·后端·stm32·单片机·qt
Q_21932764555 小时前
基于STM32的智能家居安防系统设计
网络·stm32·智能家居
BreezeJuvenile6 小时前
STM32_存储器与寄存器详细介绍
stm32·存储器·寄存器
小尧嵌入式7 小时前
【基础学习七十】ffmpeg命令
c++·stm32·嵌入式硬件·ffmpeg
北京盟通科技官方账号7 小时前
Windows 平台 EtherCAT 实时控制:从抖动抑制到虚拟化架构解析
stm32·单片机·嵌入式硬件
foundbug9997 小时前
基于STM32F103单片机实现汽车OBD诊断仪的开发方案
stm32·单片机·汽车
一枝小雨7 小时前
【OTA专题】 20 上电立即跳转:加快MCU启动速度
stm32·单片机·嵌入式·ota·bootloader·加速启动
物联网牛七七8 小时前
2、stm32f407学习笔记-存储器和寄存器以及映射
笔记·stm32·学习