忙了一陣這個PWM,玩着玩着終於發現了些規律。Nordic 也挺會坑爹的。app
nRF51822 是沒有硬件 PWM 的,只能靠一系列難以理解的 PPI /GPIOTE/TIMER來實現,其實我想說,我醉了。函數
幸虧SDK有這個的demo,否則真的很醉。這裏說的是SDK9.0.0。ui
即使是有SDK,相信不少人都像我同樣,看下去會以爲暈頭轉向的,不過知道幾個函數的應用就能夠了。spa
先記下怎麼開始用一個PWM。這裏我要用2路極性相反的PWM。code
先來初始化兩個個PWM實例,名字是PWM一、PWM2,用硬件Timer1/Timer2做爲基礎,千萬要切記Timer1/Timer2沒被佔用,而後記得打開Timer1/Timer2的宏。blog
#define TIMER1_ENABLED 1
#define TIMER2_ENABLED 1
APP_PWM_INSTANCE(PWM1,1);
APP_PWM_INSTANCE(PWM1,1);
而後初始化一個PWM。it
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 。這就是我想要說的重點。io
這個函數是能夠反覆使用以修改 PWM的頻率的,在再次使用時,先uninit它,以下:class
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)); }
就是這兩個怪事。記下來。