忙了一阵这个PWM,玩着玩着终于发现了些规律。Nordic 也挺会坑爹的。
nRF51822 是没有硬件 PWM 的,只能靠一系列难以理解的 PPI /GPIOTE/TIMER来实现,其实我想说,我醉了。
幸好SDK有这个的demo,不然真的很醉。这里说的是SDK9.0.0。
即便是有SDK,相信很多人都像我一样,看下去会觉得晕头转向的,不过知道几个函数的应用就可以了。
先记下怎么开始用一个PWM。这里我要用2路极性相反的PWM。
先来初始化两个个PWM实例,名字是PWM1、PWM2,用硬件Timer1/Timer2作为基础,千万要切记Timer1/Timer2没被占用,然后记得打开Timer1/Timer2的宏。
#define TIMER1_ENABLED 1
#define TIMER2_ENABLED 1
APP_PWM_INSTANCE(PWM1,1);
APP_PWM_INSTANCE(PWM1,1);
然后初始化一个PWM。
void pwm_init(uint32_t freq) { static uint8_t flag=0; uint32_t period_us = 1000000UL/freq; /* 2-channel PWM, 200Hz, output on DK LED pins. */ app_pwm_config_t pwm_cfg = APP_PWM_DEFAULT_CONFIG_1CH(period_us, BEEF_PIN_E1); app_pwm_config_t pwm_cfg2 = APP_PWM_DEFAULT_CONFIG_1CH(period_us, BEEF_PIN_E2); // pwm_cfg2.pin_polarity[0] = APP_PWM_POLARITY_ACTIVE_HIGH; /* Switch the polarity of the second channel. */ // pwm_cfg.pin_polarity[0] = APP_PWM_POLARITY_ACTIVE_LOW; #if 1 if(flag) pwm_cfg2.pin_polarity[0] = APP_PWM_POLARITY_ACTIVE_LOW; else pwm_cfg2.pin_polarity[0] = APP_PWM_POLARITY_ACTIVE_HIGH; #endif flag = !flag; /* Initialize and enable PWM. */ ret_code_t err_code; err_code = app_pwm_init(&PWM1,&pwm_cfg,pwm_ready_callback); APP_ERROR_CHECK(err_code); err_code = app_pwm_init(&PWM2,&pwm_cfg2,pwm_ready_callback); APP_ERROR_CHECK(err_code); }
上面的代码你会注意到,我用了一个 flag 。这就是我想要说的重点。
这个函数是可以反复使用以修改 PWM的频率的,在再次使用时,先uninit它,如下:
void pwm_uninit(void) { app_pwm_uninit(&PWM1); app_pwm_uninit(&PWM2); }
我要说的重点是,第二次使用pwm_init()后然后enable_pwm,你就会发现这两路 的PWM的极性变成一样的了,所以我用一个flag,每次切换一下。解决了这个问题。
另外我发现修改占空比时,要等上一段时间才能修改完成,这点非常奇怪,懒得去追究原因了,所以才用了两个定时器来做这两路PWM。
void pwm_on(void) { app_pwm_enable(&PWM1); app_pwm_enable(&PWM2); app_pwm_channel_duty_set(&PWM1, 0, 50); app_pwm_channel_duty_set(&PWM2, 0, 50); // ready_flag = false; // while (app_pwm_channel_duty_set(&PWM1, 0, 50) == NRF_ERROR_BUSY); // while(!ready_flag); // APP_ERROR_CHECK(app_pwm_channel_duty_set(&PWM1, 1, 50)); }
就是这两个怪事。记下来。