忙了一陣這個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)); }
就是這兩個怪事。記下來。
