TI F28P65 使用 ePWM 模块模拟 SPI 时钟的详细方法

引言

在嵌入式开发中,当芯片自带的硬件SPI接口数量不足,或者需要适配非标准时钟极性与相位的SPI从设备时,利用TI C2000系列芯片(如F28P65x)强大的ePWM(增强型脉宽调制)模块来模拟SPI时钟是一种高效且灵活的替代方案。本文将详细介绍如何将ePWM配置为一个可精确控制频率和占空比的方波发生器,从而生成SPI从设备所需的串行时钟(SCLK),并提供完整的代码示例与调试建议。

为什么需要模拟?

应用场景分析

场景 说明
SPI模块资源不足 F28P65x最多提供4个高速(50MHz)SPI端口,若外接从设备超过此数量,可用ePWM扩展
非标准时序要求 某些SPI从设备需要特定的时钟极性与相位,通过ePWM可完全由软件自定义
节约外设资源 将硬件SPI保留给高速/关键设备,ePWM模拟用于低速或非关键设备

核心原理

ePWM模块内部包含时基(TB)计数比较(CC)、**动作限定(AQ)**等子模块。一个完整的PWM周期包含一个高电平和低电平,对应一个完整的SPI时钟周期。因此:

SPI比特率(SCLK频率)= ePWM开关频率

通过配置TBPRD(周期寄存器)和CMPA(比较寄存器),可生成50%占空比的方波,直接作为SPI时钟信号。

三步生成SPI时钟

第一步:计算频率

公式:

复制代码
TBPRD = f_EPWMCLK / (2 * f_SPI_CLK)

参数说明:

  • TBPRD:ePWM时基周期寄存器值
  • f_EPWMCLK:ePWM模块输入时钟频率(例如100MHz)
  • f_SPI_CLK:目标SPI时钟频率

计算示例:

复制代码
f_EPWMCLK = 100 MHz
f_SPI_CLK = 5 MHz
TBPRD = 100,000,000 / (2 * 5,000,000) = 10

第二步:生成波形

在向上计数模式下,设置 CMPA = TBPRD / 2 得到50%占空比。通过AQ子模块配置:

  • 计数值等于CMPA → 引脚输出高电平
  • 计数值等于TBPRD → 引脚输出低电平

生成的方波即为SPI_SCLK。

第三步:精确使能控制(使用TZ模块)

SPI从设备通常需要仅在数据传输期间有时钟 ,其余时间时钟应为空闲状态。利用ePWM的TZ(Trip Zone) 模块,结合外部使能信号(如GPIO或片选信号),可精确控制时钟的输出与关闭。

配置思路:

  1. 将TZ模块的DCAEVT1DCBEVT1事件配置为高电平有效
  2. 当使能信号为高时,触发TZ动作,将ePWM输出强制拉低(时钟停止)
  3. 通过反相逻辑或外部反相器,可实现"使能高有效→输出时钟"的正逻辑

简化方案: 若片选信号低有效,可直接配置TZ为低电平有效触发,使片选拉低时关闭时钟。

示例代码(基于DriverLib)

以下代码以F28P65x为例,配置ePWM1生成5MHz的SPI时钟,并演示TZ模块的基本使能控制(使用GPIO作为使能信号,高电平时关闭时钟)。

复制代码
#include "driverlib.h"
#include "device.h"

void initEPWM_SPIClock(void)
{
    // 1. 使能ePWM1模块时钟
    SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_EPWM1);

    // 2. 配置GPIO0为ePWM1A输出
    GPIO_setPinConfig(GPIO_0_EPWM1A);
    GPIO_setDirectionMode(0, GPIO_DIR_MODE_OUT);

    // 3. 时基配置:向上计数,周期TBPRD=10(100MHz / (2*5MHz))
    EPWM_setTimeBasePeriod(EPWM1_BASE, 10);
    EPWM_setTimeBaseCounterMode(EPWM1_BASE, EPWM_COUNTER_MODE_UP);
    EPWM_setTimeBaseClockDiv(EPWM1_BASE, EPWM_CLOCK_DIVIDER_1);

    // 4. 比较值配置:CMPA = TBPRD/2 = 5
    EPWM_setCounterCompareValue(EPWM1_BASE, EPWM_COUNTER_COMPARE_A, 5);

    // 5. 动作配置:CMPA匹配时置高,PRD匹配时置低
    EPWM_setActionQualifierAction(EPWM1_BASE,
                                  EPWM_AQ_OUTPUT_A,
                                  EPWM_AQ_OUTPUT_HIGH,
                                  EPWM_AQ_OUTPUT_ON_TIMEBASE_UP_CMPA);
    EPWM_setActionQualifierAction(EPWM1_BASE,
                                  EPWM_AQ_OUTPUT_A,
                                  EPWM_AQ_OUTPUT_LOW,
                                  EPWM_AQ_OUTPUT_ON_TIMEBASE_PERIOD);

    // 6. TZ模块配置:使能DCAEVT1事件,高电平时强制拉低输出(即关闭时钟)
    EPWM_disableTripZone(EPWM1_BASE);                     // 先清零配置
    EPWM_setTripZoneAction(EPWM1_BASE,
                           EPWM_TZ_ACTION_EVENT_DCAEVT1,
                           EPWM_TZ_ACTION_LOW);           // 事件触发时拉低
    EPWM_setDigitalCompareEventTrigger(EPWM1_BASE,
                                       EPWM_DC_TYPE_DCAEVT1,
                                       EPWM_DC_EVT_TRIG_HIGH); // 高电平有效

    // 7. 启动ePWM
    EPWM_setTimeBaseCounter(EPWM1_BASE, 0);
    EPWM_enableADCTrigger(EPWM1_BASE, EPWM_SOC_A);        // 可选,用于同步
}

注意: 上述示例中使能信号高电平时关闭时钟,如需反逻辑(使能高电平时输出时钟),可简单地将使能信号先反相输入到TZ引脚,或在软件中配置TZ事件极性(查阅具体芯片TRM)。

调试与验证

1. 示波器/逻辑分析仪

将探头连接到模拟时钟的GPIO引脚,观察波形:

  • 频率是否等于目标SPI时钟
  • 占空比是否为50%(或符合从设备要求)
  • 使能信号控制下时钟是否正确启停

2. 代码级检查

  • 确认ePWM模块时钟已使能:SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_EPWM1)
  • 检查GPIO复用配置是否正确
  • 在调试器中查看TBPRDCMPATZ相关寄存器值是否符合预期

3. 常见问题排查

现象 可能原因 解决办法
无输出波形 GPIO未配置为ePWM功能 检查GPIO_setPinConfig
频率不正确 TBPRD计算错误或时钟分频设置不对 核对ePWM输入时钟频率及分频系数
使能无法关闭时钟 TZ事件极性配置错误 检查DCAEVT1触发条件及动作设置

扩展技巧

同步多路SPI时钟

若同一ePWM模块的A、B两路输出需作为两路独立SPI时钟,可将B通道配置为A通道的从同步模式,并设置相位偏移来控制两路时钟的延迟。

使用CLB(可配置逻辑模块)

对于极其复杂的时序要求(如带死区的时钟、多相时钟等),可考虑使用F28P65x内部的可配置逻辑块(CLB),实现更灵活的定制逻辑。

总结

方案对比

方案 优点 缺点
硬件SPI 速度快、CPU负载低 数量有限、时序固定
ePWM模拟 灵活、可扩展、节省外设 需占用ePWM资源、CPU参与数据收发

应用价值

使用ePWM模拟SPI时钟在资源紧张或需要高度定制时序的场景下极具价值。通过上述方法,您可以轻松生成精确的SPI时钟,并结合TZ模块实现精确的使能控制。配合GPIO模拟MOSI/MISO数据线,即可完整实现一个"软SPI"主机。

希望本文能帮助您在C2000平台上灵活应对SPI扩展需求。如有疑问,欢迎交流!


参考文献

  • TI TMS320F28P65x Technical Reference Manual (TRM), Chapter: Enhanced Pulse Width Modulator (ePWM)
  • TI C2000Ware DriverLib API Guide

========================================================================

明白了!您的实际需求是:SSI协议 (通常用于绝对编码器,如BISS、SSI),它没有片选信号,需要主机精确产生固定数量(32个)的时钟脉冲,然后停止,等待100μs后再产生下一组32个脉冲。即:帧周期100μs(10kHz),每帧32个时钟脉冲。

这比单纯的连续时钟复杂,核心挑战是如何让ePWM精确输出指定数量的脉冲后自动停止,并能周期性重启

🎯 解决方案概览

方案 原理 优点 缺点
方案一:ePWM单次触发 + 中断计数 用ePWM输出连续时钟,在中断中计数,达到32个后关闭ePWM;再用定时器重启 实现简单,灵活 中断响应有延迟,高速时可能丢脉冲
方案二:ePWM的"单发模式"+ 软件重触发 利用ePWM的EPWM_TB_COUNT_MODE_UP_ONESHOT模式(仅向上计数一次) 硬件自动停止,精确控制脉冲数 F28P65是否支持需要确认(C2000部分型号支持)
方案三:ePWM + 事件触发计数器(ECAP/PCNT) ePWM输出始终使能,但用外部计数器(或芯片内部ECAP)计数脉冲,达到32个后触发TZ关闭ePWM 纯硬件,零CPU干预 需要额外资源
方案四:使用CLB(可配置逻辑块) 用CLB搭建一个32脉冲计数器,自动门控时钟 最灵活,硬件自动 开发复杂

推荐方案一(中断计数+定时器重启):实现简单,在中等时钟频率(如2~5MHz)下完全可行,100μs的间隔足够CPU处理中断。


🔧 详细实现步骤(方案一)

整体思路

  1. 配置ePWM输出连续SPI时钟(例如5MHz)。
  2. 使能ePWM的周期中断比较中断,每输出一个时钟脉冲产生一次中断。
  3. 在中断服务函数中累计脉冲个数,当达到32个时,禁用ePWM模块的输出(或直接关闭时钟)。
  4. 配置一个CPU定时器(TIMER0/1/2) ,周期为100μs,定时器中断中重新使能ePWM输出并重置计数器,开始下一帧。

注意事项

  • 中断优先级:定时器中断应高于ePWM中断,以确保帧周期精确。
  • 关闭ePWM输出:可以用EPWM_setOutputEnable()或直接禁止ePWM时钟。
  • 为避免ePWM重新启动时相位不连续,可以同步重置时基计数器。

💻 代码示例(基于DriverLib)

以下代码实现:ePWM1输出5MHz连续时钟,每输出32个脉冲后自动停止,每隔100μs重新输出32个脉冲。

c 复制代码
#include "driverlib.h"
#include "device.h"

// 全局变量
volatile uint16_t pulseCount = 0;
volatile uint16_t targetPulse = 32;
volatile uint8_t  frameActive = 0;   // 当前帧是否正在输出时钟

// 定时器中断周期 100us
#define TIMER_PERIOD_US 100

// 函数声明
void initEPWM_Continuous(void);
void initTimerForFrame(void);
__interrupt void epwm1ISR(void);
__interrupt void timer0ISR(void);

void main(void)
{
    Device_init();
    Device_initGPIO();
    Interrupt_initModule();
    Interrupt_initVectorTable();

    initEPWM_Continuous();
    initTimerForFrame();

    // 使能中断
    Interrupt_enable(INT_EPWM1);
    Interrupt_enable(INT_TIMER0);

    // 先启动第一帧:使能ePWM输出
    EPWM_setOutputEnable(EPWM1_BASE, EPWM_OUT_A, true);
    frameActive = 1;

    while(1)
    {
        // 主循环可做其他事
    }
}

// 配置ePWM1为连续5MHz时钟,使能周期中断(每个周期产生一次中断 = 一个时钟脉冲)
void initEPWM_Continuous(void)
{
    SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_EPWM1);

    // GPIO0 -> ePWM1A
    GPIO_setPinConfig(GPIO_0_EPWM1A);
    GPIO_setDirectionMode(0, GPIO_DIR_MODE_OUT);

    // 100MHz EPWMCLK -> 5MHz PWM -> TBPRD = 10
    EPWM_setTimeBasePeriod(EPWM1_BASE, 10);
    EPWM_setTimeBaseCounterMode(EPWM1_BASE, EPWM_COUNTER_MODE_UP);
    EPWM_setTimeBaseClockDiv(EPWM1_BASE, EPWM_CLOCK_DIVIDER_1);

    EPWM_setCounterCompareValue(EPWM1_BASE, EPWM_COUNTER_COMPARE_A, 5);

    // 动作:CMPA高,PRD低 -> 50%占空比
    EPWM_setActionQualifierAction(EPWM1_BASE,
                                  EPWM_AQ_OUTPUT_A,
                                  EPWM_AQ_OUTPUT_HIGH,
                                  EPWM_AQ_OUTPUT_ON_TIMEBASE_UP_CMPA);
    EPWM_setActionQualifierAction(EPWM1_BASE,
                                  EPWM_AQ_OUTPUT_A,
                                  EPWM_AQ_OUTPUT_LOW,
                                  EPWM_AQ_OUTPUT_ON_TIMEBASE_PERIOD);

    // 使能周期中断(每个PWM周期触发一次 = 一个时钟脉冲)
    EPWM_enablePeriodInt(EPWM1_BASE);
    EPWM_setInterruptSource(EPWM1_BASE, EPWM_INT_TBCTR_U_PERIOD);
    EPWM_setInterruptEventCount(EPWM1_BASE, 1);  // 每次周期事件都触发中断

    // 先禁止输出(由定时器启动)
    EPWM_setOutputEnable(EPWM1_BASE, EPWM_OUT_A, false);

    // 注册中断
    Interrupt_register(INT_EPWM1, &epwm1ISR);
    Interrupt_enable(INT_EPWM1);

    // 启动ePWM时基(但无输出)
    EPWM_setTimeBaseCounter(EPWM1_BASE, 0);
}

// 配置CPU定时器0,周期100us
void initTimerForFrame(void)
{
    // 定时器时钟通常为 SYSCLK (200MHz 或 100MHz)
    uint32_t timerClk = SysCtl_getClock(SYSCTL_DEVICE_OSCSRC) /
                        SYSCTL_SYSCLK_DIV_1;
    uint32_t periodCycles = (timerClk / 1000000) * TIMER_PERIOD_US; // 100us
    CPUTimer_setPeriod(CPUTIMER0_BASE, periodCycles);
    CPUTimer_setPreScaler(CPUTIMER0_BASE, 0);  // 1分频
    CPUTimer_enableInt(CPUTIMER0_BASE);
    CPUTimer_enable(CPUTIMER0_BASE);

    Interrupt_register(INT_TIMER0, &timer0ISR);
    Interrupt_enable(INT_TIMER0);
}

// ePWM中断:每输出一个时钟脉冲调用一次
__interrupt void epwm1ISR(void)
{
    EPWM_clearEventTriggers(EPWM1_BASE);
    EPWM_clearPeriodInt(EPWM1_BASE);

    if(frameActive)
    {
        pulseCount++;
        if(pulseCount >= targetPulse)
        {
            // 已经输出32个脉冲,立即关闭输出
            EPWM_setOutputEnable(EPWM1_BASE, EPWM_OUT_A, false);
            frameActive = 0;
            pulseCount = 0;
        }
    }
    else
    {
        // 未激活帧时,忽略多余中断(通常不会发生)
    }
    Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP3);
}

// 定时器0中断:每100us触发一次,开始新的一帧
__interrupt void timer0ISR(void)
{
    CPUTimer_clearInt(CPUTIMER0_BASE);

    // 确保上一帧已关闭
    EPWM_setOutputEnable(EPWM1_BASE, EPWM_OUT_A, false);

    // 重置脉冲计数和状态
    pulseCount = 0;
    frameActive = 1;

    // 可选:同步ePWM时基计数器,使每帧起始相位一致
    EPWM_setTimeBaseCounter(EPWM1_BASE, 0);

    // 使能输出,开始新帧
    EPWM_setOutputEnable(EPWM1_BASE, EPWM_OUT_A, true);

    Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP1);
}

⚠️ 注意事项

  1. 中断延迟 :ePWM中断频率 = 5MHz = 每200ns一次中断!这对于CPU来说是极高的负载,且无法保证在下一个脉冲到来前完成中断处理。所以上述代码在高频时钟下不可行
    ➡️ 改进 :不要在每个时钟脉冲都进中断,而是利用ePWM的比较器在输出第32个脉冲时产生中断(例如设置CMPB = 32,然后使用"计数事件"触发中断)。但ePWM本身没有脉冲计数器,所以需要更巧妙的硬件方案。

🚀 更适合SSI的高效方案:使用ePWM的"单次触发"模式 + 硬件定时器

核心思路

利用ePWM的向上计数模式 + 软件强制同步 ,结合一个辅助定时器产生100μs的帧触发。但要求ePWM能输出恰好N个脉冲,最好的办法是:

使用ePWM的"单次触发"模式(One-shot mode) ,配置时基为向上计数,但设置TBCTL[FREE_SOFT] = 0,并在达到目标脉冲数后通过EPWM_forceSync()重新启动。不过F28P65的ePWM是否支持硬件单次触发,需要查阅TRM。

如果硬件不支持,可以用ePWM + ECAP的组合:

  • ePWM始终输出连续时钟。
  • ECAP模块捕获ePWM输出信号,配置为计数模式(捕捉每个上升沿),当计数值达到32时,产生中断,在中断中关闭ePWM输出。
  • 定时器100μs中断中重置ECAP计数器并重新使能ePWM。

这样ePWM中断频率仍然是5MHz,但ECAP中断只在每32个脉冲后触发一次,大大降低CPU负载。


🧩 推荐最终方案:ePWM + ECAP 硬件计数

原理框图

复制代码
定时器0 (100us) -> 清除ECAP计数值 -> 使能ePWM输出
ePWM输出 -> ECAP输入通道 -> ECAP计数模式 (上升沿) -> 计数值==32 -> ECAP中断 -> 关闭ePWM输出

关键配置

  1. ePWM:连续输出5MHz时钟(或您需要的任何频率),输出引脚同时连接到ECAP输入引脚(可通过内部连接或外部跳线)。
  2. ECAP :配置为绝对计数模式 (Capture mode),捕获上升沿,每次捕获后计数器加1,并可与预设值比较。或简单使用ECAP的"APWM模式"下的周期中断,但更简单的是:ECAP每次捕获产生中断,在中断中计数,达到32后关闭ePWM。这样仍然有中断,但频率降低为5MHz/32 ≈ 156kHz,仍较高。
    更好的方法是:利用ECAP的多捕获模式,设置连续捕获32个事件后触发中断。查阅F28P65 TRM,ECAP支持"连续/单次捕获模式",可以设定捕获次数(如32),当达到设定次数后产生中断。这样中断频率 = 帧率10kHz,非常理想。

📝 最终代码框架(ECAP中断 + 定时器重启)

c 复制代码
// 全局变量
volatile uint8_t frameActive = 0;

void initEPWM_5MHz(void)
{
    // 同之前配置连续时钟,但不要使能ePWM中断
    // 输出到GPIO,同时该GPIO也作为ECAP输入(内部路由)
}

void initECAP_PulseCounter(void)
{
    SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_ECAP1);
    // 将ePWM1A映射到ECAP1输入(通过GPIO输入交叉开关或直接内部连接,取决于芯片)
    // 对于F28P65,可以使用Input X-BAR将GPIO0连接到ECAP1
    InputXBAR_setInputPin(INPUT_XBAR_ECAP1, 0);  // GPIO0

    ECAP_enable(ECAP1_BASE);
    ECAP_setCaptureMode(ECAP1_BASE, ECAP_ABSOLUTE_MODE);
    // 配置为连续捕获32个事件后产生中断
    ECAP_setCaptureEdge(ECAP1_BASE, ECAP_EVENT_1, ECAP_EDGE_RISING);
    // ... 需查阅TRM设置捕获事件数量为32
    ECAP_enableInterrupt(ECAP1_BASE, ECAP_INT_CEVT1);  // 达到捕获次数中断
}

void initTimer_100us(void)
{
    // 同前,定时器中断中重置ECAP计数器并启用ePWM
}

__interrupt void ecap1ISR(void)
{
    ECAP_clearInterrupt(ECAP1_BASE, ECAP_INT_CEVT1);
    // 已捕获32个脉冲,关闭ePWM输出
    EPWM_setOutputEnable(EPWM1_BASE, EPWM_OUT_A, false);
    frameActive = 0;
    // 清除ECAP计数器,准备下一帧
    ECAP_setCounter(ECAP1_BASE, 0);
}

__interrupt void timer0ISR(void)
{
    // 开始新帧
    ECAP_setCounter(ECAP1_BASE, 0);
    EPWM_setOutputEnable(EPWM1_BASE, EPWM_OUT_A, true);
    frameActive = 1;
    // 清除定时器中断
}

✅ 总结

步骤 工具 作用
1 ePWM 产生连续的高频SPI时钟
2 ECAP 硬件计数时钟脉冲个数,达到32个后中断
3 CPU定时器 每100μs启动新的一帧

这种方案将脉冲计数完全交给硬件(ECAP),CPU只需处理10kHz的帧中断和32脉冲完成中断,负载极低,且能精确控制32个时钟。

如需更具体的ECAP配置细节(如如何设置捕获32个事件),请查阅TMS320F28P65x TRM中"Enhanced Capture (ECAP)"章节的"连续捕获模式"说明。

🔧 详细实现步骤(方案三)

方案三:ePWM + 事件触发计数器(ECAP/PCNT)

除了用中断让CPU去关,利用eCAP直接输出硬件触发信号是更高效的选择。在F28P65x上,主要有两种不需要中断参与的硬件方法:利用eCAP的TRIP_OUT信号将eCAP配置为APWM模式进行匹配触发

⚙️ 方法一:利用eCAP的TRIP_OUT信号

这是最直接的硬件触发方式。eCAP模块内部有一个信号监控单元(Signal Monitoring Unit) ,专门用于检测输入信号的异常。你可以把它配置成一个计数器,当它检测到预设数量的脉冲后,就会输出一个TRIP_OUT信号。然后,只需在芯片内部通过X-BAR将TRIP_OUT连接到ePWM的TZ(Trip Zone)输入引脚,即可实现TZ硬件联动。

  • 关键配置 :eCAP的TRIP_OUT默认是使能的,你需要在X-BAR中选择正确的连接路径。这个方法优点是完全硬件实现,CPU零负载,触发延迟极低,非常适合对时序要求严苛的场景。
  • 补充说明TRIP_OUT是eCAP Type 1模块的新功能,由信号监控单元产生,相关文档建议在使用TRIP_OUT时,禁止ePWM的TRIPOUT反馈信号,避免可能发生的误触发。

⚙️ 方法二:配置为APWM模式,使用计数器匹配触发

这是方法一的变体。将eCAP模块配置为辅助PWM(APWM)模式。在这种模式下,它的行为就像一个简化的PWM发生器,内部有一个计数器,你可以设置一个比较值(Compare Value)。当计数器值等于这个比较值时,它会自动产生一个触发事件。如果把这个计数器"喂"上你想要的时钟信号(例如,配置eCAP去捕获你的SPI时钟),那么当它数到预设值时,就会触发动作。

  • 注意事项 :此模式在eCAP作为捕获模式时不可用。而且,该触发事件通常还是需要中断来"响应",并非纯粹的硬件触发。

📊 两种硬件方案对比

下面表格清晰地展示了这两种硬件方案的区别:

对比维度 eCAP的TRIP_OUT信号 APWM模式计数器匹配
触发方式 硬件信号直接触发ePWM的TZ 内部计数器匹配产生触发事件
是否需要中断 不需要 通常需要中断
触发源 eCAP内部监控单元 APWM模式下的计数器比较器
主要优点 完全硬件控制,CPU零负载,延迟低 配置相对简单
主要挑战 需要理解信号监控单元的配置 触发后仍需中断服务程序处理
适用场景 对实时性要求极高,希望完全解放CPU的SSI脉冲计数 更通用的触发场景,或eCAP未用于捕获时

💎 总结

  • 首选方案 :追求最优解的话,方法一(使用eCAP的TRIP_OUT信号)是更彻底、更优雅的纯硬件解决方案,能实现完全的硬件自动化,最低的延迟和零CPU负载。
  • 后备方案 :如果需要快速实现,可以评估APWM模式的可行性。但其"触发后仍需中断"的特性,意味着最终可能还是要回到你最初想避免的中断方案。
相关推荐
LinuxRos10 小时前
I2C子系统与驱动开发:从协议到实战
linux·人工智能·驱动开发·嵌入式硬件·物联网
冷凝雨12 小时前
复旦微FM33 MCU 底层开发指南——UART
stm32·单片机·串口·uart·fm33lc0·复旦微电子
白掰虾12 小时前
STM32CubeMX2教程——STM32C5 UART
stm32·单片机·嵌入式硬件·mcu·usart·stm32cubemx2·stm32c542
lzx1864884370212 小时前
AH1008:一款宽输入10-55V,输出5V/5A的高效同步整流降压DC-DC转换器
嵌入式硬件·集成测试·硬件工程·ic
清风66666613 小时前
基于单片机的无线遥控车库门控制
单片机·嵌入式硬件·毕业设计·课程设计·期末大作业
我不是程序猿儿13 小时前
【嵌入式】面向 STM32 的 ADC 与 DMA 学习路线
linux·stm32·单片机·嵌入式硬件·学习
fei_sun13 小时前
HDLBits-Verilog Practice
fpga开发
一支闲人13 小时前
研究STM32库函数 如何操作寄存器
stm32·单片机
Aaron158814 小时前
RFSOC+VU13P中在线部分可重构技术的应用分析
人工智能·算法·matlab·fpga开发·重构·信息与通信·信号处理