首页 > 代码库 > NRF51822自学笔记(二)PWM

NRF51822自学笔记(二)PWM

PWM这个东西我在32上用来电机调速过……通过改变高低电平占空比来实现一些功能。

keil的nrf51822目录下没有pwm.c..就在网上找了个pwm蜂鸣器的例程……看画风应该是官方的……吧……

例程的define为NRF51 SETUPA BOARD_PCA10028..修改一下,设置如下。

技术分享
技术分享
然后通过两个灯来实现一下两路pwm波……pin为20和21的LED_2和LED_3
 
先看main.c(非例程)
[cpp] view plain copy
 
print?技术分享技术分享
  1. #include <stdbool.h>  
  2. #include <stdint.h>  
  3. #include "nrf_delay.h"  
  4. #include "nrf_gpio.h"  
  5. #include "boards.h"  
  6. #include "nrf_pwm.h"  
  7.   
  8. /** 
  9.  * @brief Function for application main entry. 
  10.  */  
  11. int main(void)  
  12. {  
  13.     // Configure LED-pins as outputs  
  14.       nrf_gpio_cfg_output(20);  
  15.       nrf_gpio_cfg_output(21);  
  16.       
  17.       nrf_pwm_config_t pwm_config = PWM_DEFAULT_CONFIG;  
  18.       
  19.           pwm_config.mode             = PWM_MODE_LED_255;  
  20.           pwm_config.num_channels     = 2;  
  21.           pwm_config.gpio_num[0]      = 21;  
  22.           pwm_config.gpio_num[1]      = 20;  
  23.       nrf_pwm_init(&pwm_config);  
  24.       nrf_pwm_set_value(0,20);  
  25.       nrf_pwm_set_value(1,255);  
  26. }  
 
#include <stdbool.h>#include <stdint.h>#include "nrf_delay.h"#include "nrf_gpio.h"#include "boards.h"#include "nrf_pwm.h"/** * @brief Function for application main entry. */int main(void){    // Configure LED-pins as outputs	  nrf_gpio_cfg_output(20);	  nrf_gpio_cfg_output(21);		  nrf_pwm_config_t pwm_config = PWM_DEFAULT_CONFIG;              pwm_config.mode             = PWM_MODE_LED_255;          pwm_config.num_channels     = 2;          pwm_config.gpio_num[0]      = 21;          pwm_config.gpio_num[1]      = 20;	  nrf_pwm_init(&pwm_config);	  nrf_pwm_set_value(0,20);	  nrf_pwm_set_value(1,255);}

第一步把要操作的灯的pin配置一下,设置成outputs

第二步用一个结构体来设置一下PWM的一些参数。

          追踪一下PWM_DEFAULT_CONFIG,发现它在PWM.H里

 

[cpp] view plain copy
 
print?技术分享技术分享
  1. #define PWM_DEFAULT_CONFIG  {.num_channels   = 2,                \  
  2.                              .gpio_num       = {8,9,10,11},         \  
  3.                              .ppi_channel    = {0,1,2,3,4,5,6,7},    \  
  4.                              .gpiote_channel = {2,3,0,1},          \  
  5.                              .mode           = PWM_MODE_LED_100};  
 
#define PWM_DEFAULT_CONFIG  {.num_channels   = 2,                                             .gpio_num       = {8,9,10,11},                                      .ppi_channel    = {0,1,2,3,4,5,6,7},                                 .gpiote_channel = {2,3,0,1},                                       .mode           = PWM_MODE_LED_100};

然后配置mode为PWM_MODE_LED_255,两个通道,两个通道的pin为21和20。把结构体地址传给初始化函数,初始化之后调用nrf_pwm_set_value()来设置一下占空比。

 

追踪一下那个mode

 

[cpp] view plain copy
 
print?技术分享技术分享
  1. typedef enum  
  2. {  
  3.     PWM_MODE_LED_100,   // 0-100 resolution, 156Hz PWM frequency, 32kHz timer frequency (prescaler 9)  
  4.     PWM_MODE_LED_255,   // 8-bit resolution, 122Hz PWM frequency, 32kHz timer frequency (prescaler 9)  
  5.     PWM_MODE_LED_1000,  // 0-1000 resolution, 125Hz PWM frequency, 250kHz timer frequency (prescaler 6)  
  6.       
  7.     PWM_MODE_MTR_100,   // 0-100 resolution, 20kHz PWM frequency, 2MHz timer frequency (prescaler 3)  
  8.     PWM_MODE_MTR_255,   // 8-bit resolution, 31kHz PWM frequency, 8MHz timer frequency (prescaler 1)  
  9.       
  10.     PWM_MODE_BUZZER_255  // 8-bit resolution, 62.5kHz PWM frequency, 16MHz timer frequency (prescaler 0)  
  11. } nrf_pwm_mode_t;  
 
typedef enum{    PWM_MODE_LED_100,   // 0-100 resolution, 156Hz PWM frequency, 32kHz timer frequency (prescaler 9)    PWM_MODE_LED_255,   // 8-bit resolution, 122Hz PWM frequency, 32kHz timer frequency (prescaler 9)    PWM_MODE_LED_1000,  // 0-1000 resolution, 125Hz PWM frequency, 250kHz timer frequency (prescaler 6)        PWM_MODE_MTR_100,   // 0-100 resolution, 20kHz PWM frequency, 2MHz timer frequency (prescaler 3)    PWM_MODE_MTR_255,   // 8-bit resolution, 31kHz PWM frequency, 8MHz timer frequency (prescaler 1)        PWM_MODE_BUZZER_255  // 8-bit resolution, 62.5kHz PWM frequency, 16MHz timer frequency (prescaler 0)} nrf_pwm_mode_t;

= =一堆枚举常量,LED,蜂鸣器和MTR。在初始化函数里利用它们和switch语句实现了配置………

 

  1. uint32_t nrf_pwm_init(nrf_pwm_config_t *config)  
  2. {  
  3.     if(config->num_channels == 0 || config->num_channels > PWM_MAX_CHANNELS) return 0xFFFFFFFF;  
  4.       
  5.     switch(config->mode)  
  6.     {  
  7.         case PWM_MODE_LED_100:   // 0-100 resolution, 321Hz PWM frequency, 32kHz timer frequency (prescaler 9)  
  8.             PWM_TIMER->PRESCALER = 9;   
  9.             pwm_max_value = 100;  
  10.             break;  
  11.         case PWM_MODE_LED_255:   // 8-bit resolution, 122Hz PWM frequency, 32kHz timer frequency (prescaler 9)  
  12.             PWM_TIMER->PRESCALER = 9;  
  13.             pwm_max_value = 255;    
  14.             break;  
  15.         case PWM_MODE_LED_1000:  // 0-1000 resolution, 250Hz PWM frequency, 250kHz timer frequency (prescaler 6)  
  16.             PWM_TIMER->PRESCALER = 6;  
  17.             pwm_max_value = 1000;  
  18.             break;  
  19.         case PWM_MODE_MTR_100:   // 0-100 resolution, 20kHz PWM frequency, 2MHz timer frequency (prescaler 3)  
  20.             PWM_TIMER->PRESCALER = 3;  
  21.             pwm_max_value = 100;  
  22.             break;  
  23.         case PWM_MODE_MTR_255:    // 8-bit resolution, 31kHz PWM frequency, 8MHz timer frequency (prescaler 1)    
  24.             PWM_TIMER->PRESCALER = 1;  
  25.             pwm_max_value = 255;  
  26.             break;  
  27.         case PWM_MODE_BUZZER_255:  // 8-bit resolution, 62.5kHz PWM frequency, 16MHz timer frequency (prescaler 0)  
  28.             PWM_TIMER->PRESCALER = 0;  
  29.             pwm_max_value = 255;  
  30.             break;  
  31.         default:  
  32.             return 0xFFFFFFFF;  
  33.     }  
  34.     pwm_cc_update_margin_ticks = pwm_cc_margin_by_prescaler[PWM_TIMER->PRESCALER];  
  35.     pwm_num_channels = config->num_channels;  
  36.     for(int i = 0; i < pwm_num_channels; i++)  
  37.     {  
  38.         pwm_io_ch[i] = (uint32_t)config->gpio_num[i];  
  39.         nrf_gpio_cfg_output(pwm_io_ch[i]);  
  40.         pwm_running[i] = 0;         
  41.         pwm_gpiote_channel[i] = config->gpiote_channel[i];          
  42.     }  
  43.     PWM_TIMER->TASKS_CLEAR = 1;  
  44.     PWM_TIMER->BITMODE = TIMER_BITMODE_BITMODE_16Bit;  
  45.     PWM_TIMER->CC[2] = pwm_next_max_value = pwm_max_value;  
  46.     PWM_TIMER->MODE = TIMER_MODE_MODE_Timer;  
  47.     PWM_TIMER->SHORTS = TIMER_SHORTS_COMPARE2_CLEAR_Msk;  
  48.     PWM_TIMER->EVENTS_COMPARE[0] = PWM_TIMER->EVENTS_COMPARE[1] = PWM_TIMER->EVENTS_COMPARE[2] = PWM_TIMER->EVENTS_COMPARE[3] = 0;       
  49.       
  50.     if(pwm_num_channels > 2)  
  51.     {  
  52.         PWM_TIMER2->TASKS_CLEAR = 1;  
  53.         PWM_TIMER2->BITMODE = TIMER_BITMODE_BITMODE_16Bit;  
  54.         PWM_TIMER2->CC[2] = pwm_next_max_value = pwm_max_value;  
  55.         PWM_TIMER2->MODE = TIMER_MODE_MODE_Timer;  
  56.         PWM_TIMER2->SHORTS = TIMER_SHORTS_COMPARE2_CLEAR_Msk;  
  57.         PWM_TIMER2->EVENTS_COMPARE[0] = PWM_TIMER2->EVENTS_COMPARE[1] = PWM_TIMER2->EVENTS_COMPARE[2] = PWM_TIMER2->EVENTS_COMPARE[3] = 0;               
  58.         PWM_TIMER2->PRESCALER = PWM_TIMER->PRESCALER;  
  59.     }  
  60.   
  61.     for(int i = 0; i < pwm_num_channels && i < 2; i++)  
  62.     {  
  63.         ppi_enable_channel(config->ppi_channel[i*2],  &PWM_TIMER->EVENTS_COMPARE[i], &NRF_GPIOTE->TASKS_OUT[pwm_gpiote_channel[i]]);  
  64.         ppi_enable_channel(config->ppi_channel[i*2+1],&PWM_TIMER->EVENTS_COMPARE[2], &NRF_GPIOTE->TASKS_OUT[pwm_gpiote_channel[i]]);    
  65.         pwm_modified[i] = false;          
  66.     }  
  67.     for(int i = 2; i < pwm_num_channels; i++)  
  68.     {  
  69.         ppi_enable_channel(config->ppi_channel[i*2],  &PWM_TIMER2->EVENTS_COMPARE[i-2], &NRF_GPIOTE->TASKS_OUT[pwm_gpiote_channel[i]]);  
  70.         ppi_enable_channel(config->ppi_channel[i*2+1],&PWM_TIMER2->EVENTS_COMPARE[2], &NRF_GPIOTE->TASKS_OUT[pwm_gpiote_channel[i]]);    
  71.         pwm_modified[i] = false;          
  72.     }  
  73. #if(USE_WITH_SOFTDEVICE == 1)  
  74.     sd_radio_session_open(nrf_radio_signal_callback);  
  75. #else  
  76.     NVIC_SetPriority(PWM_IRQn, 0);  
  77.     NVIC_EnableIRQ(PWM_IRQn);  
  78. #endif  
  79.     apply_pan73_workaround(PWM_TIMER, true);  
  80.     PWM_TIMER->TASKS_START = 1;  
  81.     if(pwm_num_channels > 2)  
  82.     {  
  83.         apply_pan73_workaround(PWM_TIMER2, true);  
  84.         PWM_TIMER2->TASKS_START = 1;  
  85.     }  
  86.     return 0;  
uint32_t nrf_pwm_init(nrf_pwm_config_t *config){    if(config->num_channels == 0 || config->num_channels > PWM_MAX_CHANNELS) return 0xFFFFFFFF;        switch(config->mode)    {        case PWM_MODE_LED_100:   // 0-100 resolution, 321Hz PWM frequency, 32kHz timer frequency (prescaler 9)            PWM_TIMER->PRESCALER = 9;             pwm_max_value = http://www.mamicode.com/100;>

当通道数大于2时,就要使用TIMER2了。下面是设置占空比的

  1. void nrf_pwm_set_value(uint32_t pwm_channel, uint32_t pwm_value)  
  2. {  
  3.     pwm_next_value[pwm_channel] = pwm_value;  
  4.     pwm_modified[pwm_channel] = true;  
  5. #if(USE_WITH_SOFTDEVICE == 1)  
  6.     nrf_radio_request_t radio_request;  
  7.     radio_request.request_type = NRF_RADIO_REQ_TYPE_EARLIEST;  
  8.     radio_request.params.earliest.hfclk = NRF_RADIO_HFCLK_CFG_DEFAULT;  
  9.     radio_request.params.earliest.length_us = 250;  
  10.     radio_request.params.earliest.priority = NRF_RADIO_PRIORITY_HIGH;  
  11.     radio_request.params.earliest.timeout_us = 100000;  
  12.     sd_radio_request(&radio_request);  
  13. #else  
  14.     NVIC_SetPendingIRQ(PWM_IRQn);  
  15. #endif  
void nrf_pwm_set_value(uint32_t pwm_channel, uint32_t pwm_value){    pwm_next_value[pwm_channel] = pwm_value;    pwm_modified[pwm_channel] = true;#if(USE_WITH_SOFTDEVICE == 1)    nrf_radio_request_t radio_request;    radio_request.request_type = NRF_RADIO_REQ_TYPE_EARLIEST;    radio_request.params.earliest.hfclk = NRF_RADIO_HFCLK_CFG_DEFAULT;    radio_request.params.earliest.length_us = 250;    radio_request.params.earliest.priority = NRF_RADIO_PRIORITY_HIGH;    radio_request.params.earliest.timeout_us = 100000;    sd_radio_request(&radio_request);#else    NVIC_SetPendingIRQ(PWM_IRQn);#endif
  1. void nrf_pwm_set_values(uint32_t pwm_channel_num, uint32_t *pwm_values)  
  2. {  
  3.     for(int i = 0; i < pwm_channel_num; i++)  
  4.     {  
  5.         pwm_next_value[i] = pwm_values[i];  
  6.         pwm_modified[i] = true;  
  7.     }  
  8. #if(USE_WITH_SOFTDEVICE == 1)  
  9.     nrf_radio_request_t radio_request;  
  10.     radio_request.request_type = NRF_RADIO_REQ_TYPE_EARLIEST;  
  11.     radio_request.params.earliest.hfclk = NRF_RADIO_HFCLK_CFG_DEFAULT;  
  12.     radio_request.params.earliest.length_us = 250;  
  13.     radio_request.params.earliest.priority = NRF_RADIO_PRIORITY_HIGH;  
  14.     radio_request.params.earliest.timeout_us = 100000;  
  15.     sd_radio_request(&radio_request);  
  16. #else  
  17.     NVIC_SetPendingIRQ(PWM_IRQn);  
  18. #endif  
  19. }  
 
void nrf_pwm_set_values(uint32_t pwm_channel_num, uint32_t *pwm_values){    for(int i = 0; i < pwm_channel_num; i++)    {        pwm_next_value[i] = pwm_values[i];        pwm_modified[i] = true;    }#if(USE_WITH_SOFTDEVICE == 1)    nrf_radio_request_t radio_request;    radio_request.request_type = NRF_RADIO_REQ_TYPE_EARLIEST;    radio_request.params.earliest.hfclk = NRF_RADIO_HFCLK_CFG_DEFAULT;    radio_request.params.earliest.length_us = 250;    radio_request.params.earliest.priority = NRF_RADIO_PRIORITY_HIGH;    radio_request.params.earliest.timeout_us = 100000;    sd_radio_request(&radio_request);#else    NVIC_SetPendingIRQ(PWM_IRQn);#endif}

这两个函数功能是一样的……区别在后者先设置好了一组数……

 

最后看看中断服务函数

  1. void PWM_IRQHandler(void)  
  2. {  
  3.     static uint32_t i, new_capture, old_capture;  
  4.     PWM_TIMER->CC[2] = pwm_max_value = pwm_next_max_value;  
  5.     if(pwm_num_channels > 2) PWM_TIMER2->CC[2] = pwm_max_value;  
  6.     for(i = 0; i < pwm_num_channels; i++)  
  7.     {  
  8.         if(pwm_modified[i])  
  9.         {  
  10.             pwm_modified[i] = false;  
  11.             if(pwm_next_value[i] == 0)  
  12.             {  
  13.                 nrf_gpiote_unconfig(pwm_gpiote_channel[i]);  
  14.                 nrf_gpio_pin_write(pwm_io_ch[i], 0);  
  15.                 pwm_running[i] = 0;  
  16.             }  
  17.             else if (pwm_next_value[i] >= pwm_max_value)  
  18.             {  
  19.                 nrf_gpiote_unconfig(pwm_gpiote_channel[i]);  
  20.                 nrf_gpio_pin_write(pwm_io_ch[i], 1);   
  21.                 pwm_running[i] = 0;  
  22.             }  
  23.             else  
  24.             {  
  25.                 if(i < 2)  
  26.                 {  
  27.                     new_capture = pwm_next_value[i];  
  28.                     old_capture = PWM_TIMER->CC[i];  
  29.                     if(!pwm_running[i])  
  30.                     {  
  31.                         nrf_gpiote_task_config(pwm_gpiote_channel[i], pwm_io_ch[i], NRF_GPIOTE_POLARITY_TOGGLE, NRF_GPIOTE_INITIAL_VALUE_HIGH);    
  32.                         pwm_running[i] = 1;  
  33.                         PWM_TIMER->TASKS_CAPTURE[3] = 1;  
  34.                         if(PWM_TIMER->CC[3] > new_capture) NRF_GPIOTE->TASKS_OUT[pwm_gpiote_channel[i]] = 1;  
  35.                         PWM_TIMER->CC[i] = new_capture;  
  36.                     }  
  37.                     else  
  38.                     {  
  39.                         while(1)  
  40.                         {  
  41.                             PWM_TIMER->TASKS_CAPTURE[3] = 1;  
  42.                             if(safe_margins_present(PWM_TIMER_CURRENT, old_capture) && safe_margins_present(PWM_TIMER_CURRENT, new_capture)) break;  
  43.                         }  
  44.                         if((PWM_TIMER_CURRENT >= old_capture && PWM_TIMER_CURRENT < new_capture) || (PWM_TIMER_CURRENT < old_capture && PWM_TIMER_CURRENT >= new_capture))  
  45.                         {  
  46.                             NRF_GPIOTE->TASKS_OUT[pwm_gpiote_channel[i]] = 1;  
  47.                         }  
  48.                         PWM_TIMER->CC[i] = new_capture;  
  49.                     }  
  50.                 }  
  51.                 else  
  52.                 {  
  53.                     new_capture = pwm_next_value[i];  
  54.                     old_capture = PWM_TIMER2->CC[i-2];  
  55.                     if(!pwm_running[i])  
  56.                     {  
  57.                         nrf_gpiote_task_config(pwm_gpiote_channel[i], pwm_io_ch[i], NRF_GPIOTE_POLARITY_TOGGLE, NRF_GPIOTE_INITIAL_VALUE_HIGH);    
  58.                         pwm_running[i] = 1;  
  59.                         PWM_TIMER2->TASKS_CAPTURE[3] = 1;  
  60.                         if(PWM_TIMER2->CC[3] > new_capture) NRF_GPIOTE->TASKS_OUT[pwm_gpiote_channel[i]] = 1;  
  61.                         PWM_TIMER2->CC[i-2] = new_capture;  
  62.                     }  
  63.                     else  
  64.                     {  
  65.                         while(1)  
  66.                         {  
  67.                             PWM_TIMER2->TASKS_CAPTURE[3] = 1;  
  68.                             if(safe_margins_present(PWM_TIMER2_CURRENT, old_capture) && safe_margins_present(PWM_TIMER2_CURRENT, new_capture)) break;  
  69.                         }  
  70.                         if((PWM_TIMER2_CURRENT >= old_capture && PWM_TIMER2_CURRENT < new_capture) || (PWM_TIMER2_CURRENT < old_capture && PWM_TIMER2_CURRENT >= new_capture))  
  71.                         {  
  72.                             NRF_GPIOTE->TASKS_OUT[pwm_gpiote_channel[i]] = 1;  
  73.                         }  
  74.                         PWM_TIMER2->CC[i-2] = new_capture;  
  75.                     }                      
  76.                 }  
  77.             }  
  78.         }  
  79.     }  
 
void PWM_IRQHandler(void){    static uint32_t i, new_capture, old_capture;    PWM_TIMER->CC[2] = pwm_max_value = http://www.mamicode.com/pwm_next_max_value;>

然后运行一下~会看见占空比不同,两个led灯的亮度不同。占空比为255的LED_1要比占空比为20的LED_1亮

NRF51822自学笔记(二)PWM