使用nRF52系列PWM驱动实现6秒周期正弦PWM波的问题
nRF52生成6秒周期正弦PWM波的周期不符问题解决
问题核心
基于nRF52系列MCU,使用SDK v15.3.0配置250kHz PWM基础时钟、TOP值4167,用360个数据点存储正弦占空比,理论周期应为(4167/250000)*360≈6秒,但实际检测仅约1.2秒。
错误原因分析
- 序列类型与加载模式不匹配:
配置的load_mode = NRF_PWM_LOAD_INDIVIDUAL(单通道独立加载模式),但序列却错误使用了p_wave_form指针(对应NRF_PWM_LOAD_COMMON模式的波形结构体数组),而非p_individual指针(对应INDIVIDUAL模式的单通道占空比数组)。这种类型不匹配导致PWM模块错误解析内存数据,有效序列长度远小于预期的360个。 - 无效TOP值覆盖:
代码中定义的seq_values_wave_form结构体未被使用,但错误赋值后,PWM会读取到其中的counter_top=4095,覆盖了你配置的top_value=4167,单个PWM周期变为4095/250000≈0.01638秒。再加上类型不匹配导致有效数据点仅72个(360/5),总周期就变成了72*0.01638≈1.18秒,与实测结果吻合。
修正方案
1. 匹配序列类型与加载模式
将序列的values指针改为p_individual,对应INDIVIDUAL加载模式:
// 原错误代码 // seq_wave_form.values.p_wave_form = data; // 改为 seq_wave_form.values.p_individual = data;
2. 删除无用代码
移除未使用的波形结构体定义,避免混淆:
// 删除该行 // nrf_pwm_values_wave_form_t seq_values_wave_form = {.channel_0 = 0, .counter_top = 4095};
3. 修正占空比缩放逻辑(可选)
原代码中data数组最大值为16368,远大于TOP值4167,会导致正弦波顶部被削平。调整缩放逻辑匹配TOP值:
// 原缩放代码 // uint16_t scaled_value = (uint16_t)((sin_value + 1) * 0x03FF); // data[i] = scaled_value << 4; // 改为 uint16_t scaled_value = (uint16_t)((sin_value + 1) * (4167 / 2.0)); // 归一化到0~4167范围 data[i] = scaled_value;
修正后的关键代码片段
uint16_t data[360]; uint16_t duty_cycle; nrf_pwm_clk_t base_clock; const nrf_drv_pwm_t m_pwm0 = NRF_DRV_PWM_INSTANCE(0); // 移除无用的波形结构体定义 nrf_pwm_values_t seq_pwm_values; nrf_pwm_sequence_t seq_wave_form; void pwm_init_config() { uint8_t prescaler_setting = 0; switch (prescaler_setting) { case 0: base_clock = NRF_PWM_CLK_250kHz; break; // 32MHz / 128 } nrf_drv_pwm_config_t const config0 = { .output_pins = { LED_1, NRF_DRV_PWM_PIN_NOT_USED, NRF_DRV_PWM_PIN_NOT_USED, NRF_DRV_PWM_PIN_NOT_USED, }, .irq_priority = APP_IRQ_PRIORITY_LOWEST, .base_clock = base_clock, .count_mode = NRF_PWM_MODE_UP, .top_value = 4167, .load_mode = NRF_PWM_LOAD_INDIVIDUAL, .step_mode = NRF_PWM_STEP_AUTO}; APP_ERROR_CHECK(nrf_drv_pwm_init(&m_pwm0, &config0, NULL)); } void initialize_basic_data() { int size = sizeof(data) / sizeof(data[0]); for (int i = 0; i < size; i++) { double radian = i * (M_PI / 180); double sin_value = sin(radian); // 修正缩放逻辑匹配TOP值 uint16_t scaled_value = (uint16_t)((sin_value + 1) * (4167 / 2.0)); data[i] = scaled_value; } // 使用p_individual指针匹配加载模式 seq_wave_form.values.p_individual = data; seq_wave_form.length = NRF_PWM_VALUES_LENGTH(data); seq_wave_form.repeats = 0; seq_wave_form.end_delay = 0; } void wave_effect() { initialize_basic_data(); nrf_drv_pwm_simple_playback(&m_pwm0, &seq_wave_form, 1, NRF_DRV_PWM_FLAG_LOOP); }
验证逻辑
修正后,每个数据点对应一个PWM周期,总周期为360*(4167/250000)=360*0.016668≈6秒,与理论值一致。
内容的提问来源于stack exchange,提问作者Flavio Andrade
相关产品推荐
相关产品推荐

