目标

  1. 输出引脚:固定使用 GPIO25 输出信号
  2. 波形生成:支持正弦波、方波、三角波三种波形,输出频率范围 0.01Hz~55000Hz
  3. 交互方式:通过串口输入字符串 + 回车确认指令
  4. 直流电平输出:输入 dax(x 为 0~255),输出对应 0~3.3V 固定电平
  5. 参数独立性:波形类型设置与频率设置相互独立,互不影响

指令对照表

输入指令后回车确认生效

指令 功能说明 使用示例
s 切换为正弦波 输入s后回车
a 切换为三角波 输入a后回车
q 切换为方波 输入q后回车
数字 / 小数 设置输出频率 1002500.50.01
da+数值 输出直流固定电平(数值0~255) da128da 200

main.cpp

#include <Arduino.h>
#include "driver/dac.h"
#include "math.h"

// ================= DAC =================
#define DAC_CH DAC_CHANNEL_1

// ================= LUT =================
#define LUT_SIZE 256
uint8_t sine_lut[LUT_SIZE];
uint8_t tri_lut[LUT_SIZE];

//信号类型 正弦,三角,方波
enum WaveType { SINE, TRI, SQUARE };
//信号生成方式  DDS 生成 ,CW生成, 直流输出
enum Mode { MODE_DDS, MODE_CW, MODE_DC };

volatile WaveType wave = SINE;
volatile Mode mode = MODE_DDS;

volatile float current_freq = 1.0;

// ================= DC VALUE =================
volatile uint8_t dc_value = 0;

// ================= DDS =================
volatile uint32_t phase_acc = 0;
volatile uint32_t phase_inc = 0;

// ================= TIMER =================
hw_timer_t *timer = NULL;
bool timer_inited = false;

// ================= CW =================
// 定义DAC载波(CW)配置结构体变量cw_cfg
dac_cw_config_t cw_cfg = {
        .en_ch = DAC_CHANNEL_1,    // 选择输出通道:通道1(对应GPIO25)
        .scale = DAC_CW_SCALE_1,   // 输出幅度缩放:等级1(调节波形幅值大小)
        .phase = DAC_CW_PHASE_0,   // 波形初始相位:0°
        .freq = 1000,              // 波形输出频率:1000Hz(1kHz)
        .offset = 4                // 波形直流偏移量:4个DAC单位
};

// ================= ISR =================
void IRAM_ATTR onTimer() {

    if (mode != MODE_DDS) return;

    phase_acc += phase_inc;
    uint8_t idx = phase_acc >> 24;

    uint8_t out = 0;

    switch (wave) {
        case SINE:   out = sine_lut[idx]; break;
        case TRI:    out = tri_lut[idx];  break;
        case SQUARE: out = (phase_acc & 0x80000000) ? 255 : 0; break;
    }

    dac_output_voltage(DAC_CH, out);
}

// ================= LUT =================
void buildLUT() {
    for (int i = 0; i < LUT_SIZE; i++) {
        sine_lut[i] = (sin(2 * PI * i / LUT_SIZE) + 1.0) * 127.5;

        if (i < 128)
            tri_lut[i] = i * 2;
        else
            tri_lut[i] = 255 - (i - 128) * 2;
    }
}

// ================= TIMER =================
void initTimer() {
    if (timer_inited) return;

    timer = timerBegin(0, 80, true);
    timerAttachInterrupt(timer, &onTimer, true);
    timerAlarmWrite(timer, 125, true);
    timer_inited = true;
}

// ================= STOP =================
void stopAll() {
    dac_cw_generator_disable();
    if (timer_inited) timerAlarmDisable(timer);
}

// ================= ENGINE =================
void restartEngine() {

    stopAll();

    if (mode == MODE_DDS) {
        initTimer();
        timerAlarmEnable(timer);
    }
    else if (mode == MODE_CW) {
        dac_cw_generator_config(&cw_cfg);
        dac_cw_generator_enable();
    }
    else if (mode == MODE_DC) {
        dac_output_voltage(DAC_CH, dc_value);
    }
}

// ================= DDS =================
void startDDS(float f) {

    mode = MODE_DDS;

    phase_inc = (uint32_t)((f * 4294967296.0) / 8000.0);

    restartEngine();
}

// ================= CW =================
void startCW(float f) {

    mode = MODE_CW;

    cw_cfg.freq = (uint32_t)f;

    restartEngine();
}

// ================= DC =================
void startDC(uint8_t v) {

    mode = MODE_DC;
    dc_value = v;

    restartEngine();

    Serial.printf("[DC] output = %d\n", dc_value);
}

// ================= ROUTER =================
void setFreq(float f) {

    if (f < 0.01) f = 0.01;
    if (f > 55000) f = 55000;

    current_freq = f;

    if (f < 130.0) startDDS(f);
    else startCW(f);
}

// ================= WAVE =================
void setWave(char c) {

    if (c == 's') wave = SINE;
    else if (c == 'a') wave = TRI;
    else if (c == 'q') wave = SQUARE;

    if (current_freq < 130.0) {
        mode = MODE_DDS;
        restartEngine();
    }

    Serial.printf("[WAVE] %c | FREQ %.3f Hz\n", c, current_freq);
}

// ================= SERIAL PARSER =================
void handleInput(String s) {

    s.trim();

    //  DC 模式:DA 100 或 DA100
    if (s.startsWith("DA") || s.startsWith("da")) {

        s.remove(0, 2);
        s.trim();

        int v = s.toInt();
        if (v < 0) v = 0;
        if (v > 255) v = 255;

        startDC((uint8_t)v);
        return;
    }

    // 单字符波形
    if (s.length() == 1) {
        char c = s[0];
        if (c == 's' || c == 'a' || c == 'q') {
            setWave(c);
            return;
        }
    }

    // 频率
    float f = s.toFloat();
    if (f > 0) {
        setFreq(f);
        Serial.printf("[FREQ] %.3f Hz\n", f);
    }
}

// ================= SETUP =================
void setup() {

    Serial.begin(115200);
    dac_output_enable(DAC_CH);
    buildLUT();
    initTimer();
    setFreq(10);
    Serial.println("\n=== PRO FUNCTION GENERATOR ===");
    Serial.println("s/a/q = waveform");
    Serial.println("number = frequency");
    Serial.println("da 100 = DC output");
}

// ================= LOOP =================
void loop() {

    if (Serial.available()) {
        String s = Serial.readStringUntil('\n');
        handleInput(s);
    }
}
Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐