自己GPIO17 产生 1Mhz方波。
端接GPIO 16-》17引脚。
#include <Arduino.h>
#include <driver/pcnt.h>
#define PCNT_UNIT PCNT_UNIT_0
#define PCNT_INPUT_PIN 16 // 接收端:改用 GPIO 16 (板上标注通常为 RX2)
#define PWM_OUTPUT_PIN 17 // 发送端:改用 GPIO 17 (板上标注通常为 TX2)
volatile int16_t last_count = 0;
volatile bool data_ready = false;
hw_timer_t *timer = NULL;
void IRAM_ATTR onTimer() {
pcnt_get_counter_value(PCNT_UNIT, (int16_t*)&last_count);
pcnt_counter_clear(PCNT_UNIT);
data_ready = true;
}
void setup() {
Serial.begin(115200);
delay(1000);
// 1. 在 GPIO 17 上产生一个 1MHz, 50% 占空比的方波
ledcAttach(PWM_OUTPUT_PIN, 1000000, 1);
ledcWrite(PWM_OUTPUT_PIN, 1);
// 2. 配置 PCNT 硬件计数器(接收端 GPIO 16)
pcnt_config_t pcnt_config = {0};
pcnt_config.pulse_gpio_num = PCNT_INPUT_PIN;
pcnt_config.ctrl_gpio_num = -1;
pcnt_config.unit = PCNT_UNIT;
pcnt_config.channel = PCNT_CHANNEL_0;
pcnt_config.pos_mode = PCNT_COUNT_INC;
pcnt_config.neg_mode = PCNT_COUNT_DIS;
pcnt_config.lctrl_mode = PCNT_MODE_KEEP;
pcnt_config.hctrl_mode = PCNT_MODE_KEEP;
pcnt_config.counter_h_lim = 20000;
pcnt_config.counter_l_lim = -20000;
pcnt_unit_config(&pcnt_config);
// 3. 关闭滤波器
pcnt_filter_disable(PCNT_UNIT);
pcnt_counter_clear(PCNT_UNIT);
pcnt_counter_resume(PCNT_UNIT);
// 4. 配置定时器(10ms 采样)
timer = timerBegin(1000000);
timerAttachInterrupt(timer, &onTimer);
timerAlarm(timer, 10000, true, 0);
Serial.println("--- ESP32 1MHz PCNT 测试开始 ---");
Serial.println("请用一根杜邦线连接:G17 (TX2) <---> G16 (RX2)");
}
void loop() {
if (data_ready) {
data_ready = false;
int16_t count_10ms = last_count;
uint32_t frequency = count_10ms * 100;
Serial.print("10ms Count: ");
Serial.print(count_10ms);
Serial.print(" | Frequency: ");
Serial.print(frequency);
Serial.println(" Hz");
}
}
测量10Mhz
#include <Arduino.h>
#include <driver/pcnt.h>
#define PCNT_UNIT PCNT_UNIT_0
#define PCNT_INPUT_PIN 16 // 接收端:GPIO 16 (RX2)
#define PWM_OUTPUT_PIN 17 // 发送端:GPIO 17 (TX2)
volatile int16_t last_hw_count = 0;
volatile bool data_ready = false;
hw_timer_t *timer = NULL;
// 针对 100ms 刷新的滑动滤波缓冲区(10个样本组合成1秒的物理总量)
const int FILTER_SIZE = 10;
uint32_t freq_history[FILTER_SIZE] = {0};
int filter_index = 0;
// 定时器采样中断(每 100ms 触发一次,非常安全)
void IRAM_ATTR onTimer() {
// 直接读取硬件计数值(100KHz在100ms内只有10000个脉冲,绝不溢出)
pcnt_get_counter_value(PCNT_UNIT, (int16_t *)&last_hw_count);
// 清空计数器,准备下一轮
pcnt_counter_clear(PCNT_UNIT);
data_ready = true;
}
void setup() {
Serial.begin(115200);
delay(1000);
// 1. 发送端测试信号:生成一个 100 KHz (0.100 MHz) 的自测信号
#if ESP_ARDUINO_VERSION_MAJOR >= 3
ledcAttach(PWM_OUTPUT_PIN, 1000000, 10); // 100KHz
ledcWrite(PWM_OUTPUT_PIN, 512); // 50% 占空比
#else
ledcSetup(0, 100000, 10);
ledcAttachPin(PWM_OUTPUT_PIN, 0);
ledcWrite(0, 512);
#endif
// 2. 配置 PCNT 硬件计数器
pcnt_config_t pcnt_config = { 0 };
pcnt_config.pulse_gpio_num = PCNT_INPUT_PIN;
pcnt_config.ctrl_gpio_num = -1;
pcnt_config.unit = PCNT_UNIT;
pcnt_config.channel = PCNT_CHANNEL_0;
pcnt_config.pos_mode = PCNT_COUNT_INC;
pcnt_config.neg_mode = PCNT_COUNT_DIS;
pcnt_config.lctrl_mode = PCNT_MODE_KEEP;
pcnt_config.hctrl_mode = PCNT_MODE_KEEP;
// 100KHz测量的安全边界
pcnt_config.counter_h_lim = 32000;
pcnt_config.counter_l_lim = -32000;
pcnt_unit_config(&pcnt_config);
// 3. 100KHz 属于中低频,可以开启硬件滤波器滤除杂波(设为 100 个采样时钟周期)
pcnt_set_filter_value(PCNT_UNIT, 100);
pcnt_filter_enable(PCNT_UNIT);
pcnt_counter_clear(PCNT_UNIT);
pcnt_counter_resume(PCNT_UNIT);
// 4. 配置定时器(100ms 采样一次,兼顾响应速度与精度)
#if ESP_ARDUINO_VERSION_MAJOR >= 3
timer = timerBegin(1000000);
timerAttachInterrupt(timer, &onTimer);
timerAlarm(timer, 100000, true, 0); // 100000us = 100ms 采样窗口
#else
timer = timerBegin(0, 80, true);
timerAttachInterrupt(timer, &onTimer, true);
timerAlarmWrite(timer, 100000, true);
timerAlarmEnable(timer);
#endif
Serial.println("--- ESP32 100KHz 滤波优化版测试开始 ---");
}
int t = 0;
void loop() {
if (data_ready) {
data_ready = false;
// 100ms 内的硬件脉冲数,乘以 10 得到一秒的赫兹(Hz)基准
uint32_t current_hz = (uint32_t)last_hw_count * 10;
// 将新数据存入滑动窗口
freq_history[filter_index] = current_hz;
filter_index = (filter_index + 1) % FILTER_SIZE;
// 计算滑动平均值,平滑 1 KHz 级别的微小抖动
uint64_t sum_hz = 0;
for (int i = 0; i < FILTER_SIZE; i++) {
sum_hz += freq_history[i];
}
uint32_t final_hz = sum_hz / FILTER_SIZE;
if (final_hz > 0) {
t++;
// 将 Hz 转换为 MHz
double mhz = (double)final_hz / 1000.0;
Serial.print(t);
Serial.print(" freq: ");
// 完美输出类似 0.100 MHz 的格式
Serial.print(mhz, 3);
Serial.println(" kHz");
}
}
}

3241

被折叠的 条评论
为什么被折叠?



