NRF51822自学笔记(二)PWM

来源:互联网 发布:python 量化分析 编辑:程序博客网 时间:2024/05/22 13:50

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

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

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



然后通过两个灯来实现一下两路pwm波……pin为20和21的LED_2和LED_3

先看main.c(非例程)
#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里

#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

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语句实现了配置……

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 = 100;            break;        case PWM_MODE_LED_255:   // 8-bit resolution, 122Hz PWM frequency, 32kHz timer frequency (prescaler 9)            PWM_TIMER->PRESCALER = 9;            pwm_max_value = 255;              break;        case PWM_MODE_LED_1000:  // 0-1000 resolution, 250Hz PWM frequency, 250kHz timer frequency (prescaler 6)            PWM_TIMER->PRESCALER = 6;            pwm_max_value = 1000;            break;        case PWM_MODE_MTR_100:   // 0-100 resolution, 20kHz PWM frequency, 2MHz timer frequency (prescaler 3)            PWM_TIMER->PRESCALER = 3;            pwm_max_value = 100;            break;        case PWM_MODE_MTR_255:    // 8-bit resolution, 31kHz PWM frequency, 8MHz timer frequency (prescaler 1)            PWM_TIMER->PRESCALER = 1;            pwm_max_value = 255;            break;        case PWM_MODE_BUZZER_255:  // 8-bit resolution, 62.5kHz PWM frequency, 16MHz timer frequency (prescaler 0)            PWM_TIMER->PRESCALER = 0;            pwm_max_value = 255;            break;        default:            return 0xFFFFFFFF;    }    pwm_cc_update_margin_ticks = pwm_cc_margin_by_prescaler[PWM_TIMER->PRESCALER];    pwm_num_channels = config->num_channels;    for(int i = 0; i < pwm_num_channels; i++)    {        pwm_io_ch[i] = (uint32_t)config->gpio_num[i];        nrf_gpio_cfg_output(pwm_io_ch[i]);        pwm_running[i] = 0;               pwm_gpiote_channel[i] = config->gpiote_channel[i];            }    PWM_TIMER->TASKS_CLEAR = 1;    PWM_TIMER->BITMODE = TIMER_BITMODE_BITMODE_16Bit;    PWM_TIMER->CC[2] = pwm_next_max_value = pwm_max_value;PWM_TIMER->MODE = TIMER_MODE_MODE_Timer;    PWM_TIMER->SHORTS = TIMER_SHORTS_COMPARE2_CLEAR_Msk;    PWM_TIMER->EVENTS_COMPARE[0] = PWM_TIMER->EVENTS_COMPARE[1] = PWM_TIMER->EVENTS_COMPARE[2] = PWM_TIMER->EVENTS_COMPARE[3] = 0;             if(pwm_num_channels > 2)    {        PWM_TIMER2->TASKS_CLEAR = 1;        PWM_TIMER2->BITMODE = TIMER_BITMODE_BITMODE_16Bit;        PWM_TIMER2->CC[2] = pwm_next_max_value = pwm_max_value;        PWM_TIMER2->MODE = TIMER_MODE_MODE_Timer;        PWM_TIMER2->SHORTS = TIMER_SHORTS_COMPARE2_CLEAR_Msk;        PWM_TIMER2->EVENTS_COMPARE[0] = PWM_TIMER2->EVENTS_COMPARE[1] = PWM_TIMER2->EVENTS_COMPARE[2] = PWM_TIMER2->EVENTS_COMPARE[3] = 0;                     PWM_TIMER2->PRESCALER = PWM_TIMER->PRESCALER;    }    for(int i = 0; i < pwm_num_channels && i < 2; i++)    {        ppi_enable_channel(config->ppi_channel[i*2],  &PWM_TIMER->EVENTS_COMPARE[i], &NRF_GPIOTE->TASKS_OUT[pwm_gpiote_channel[i]]);        ppi_enable_channel(config->ppi_channel[i*2+1],&PWM_TIMER->EVENTS_COMPARE[2], &NRF_GPIOTE->TASKS_OUT[pwm_gpiote_channel[i]]);          pwm_modified[i] = false;            }    for(int i = 2; i < pwm_num_channels; i++)    {        ppi_enable_channel(config->ppi_channel[i*2],  &PWM_TIMER2->EVENTS_COMPARE[i-2], &NRF_GPIOTE->TASKS_OUT[pwm_gpiote_channel[i]]);        ppi_enable_channel(config->ppi_channel[i*2+1],&PWM_TIMER2->EVENTS_COMPARE[2], &NRF_GPIOTE->TASKS_OUT[pwm_gpiote_channel[i]]);          pwm_modified[i] = false;            }#if(USE_WITH_SOFTDEVICE == 1)    sd_radio_session_open(nrf_radio_signal_callback);#else    NVIC_SetPriority(PWM_IRQn, 0);    NVIC_EnableIRQ(PWM_IRQn);#endif    apply_pan73_workaround(PWM_TIMER, true);    PWM_TIMER->TASKS_START = 1;    if(pwm_num_channels > 2)    {        apply_pan73_workaround(PWM_TIMER2, true);        PWM_TIMER2->TASKS_START = 1;    }    return 0;}
当通道数大于2时,就要使用TIMER2了。下面是设置占空比的

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
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}
这两个函数功能是一样的……区别在后者先设置好了一组数……

最后看看中断服务函数

void PWM_IRQHandler(void){    static uint32_t i, new_capture, old_capture;    PWM_TIMER->CC[2] = pwm_max_value = pwm_next_max_value;    if(pwm_num_channels > 2) PWM_TIMER2->CC[2] = pwm_max_value;    for(i = 0; i < pwm_num_channels; i++)    {        if(pwm_modified[i])        {            pwm_modified[i] = false;            if(pwm_next_value[i] == 0)            {                nrf_gpiote_unconfig(pwm_gpiote_channel[i]);                nrf_gpio_pin_write(pwm_io_ch[i], 0);                pwm_running[i] = 0;            }            else if (pwm_next_value[i] >= pwm_max_value)            {                nrf_gpiote_unconfig(pwm_gpiote_channel[i]);                nrf_gpio_pin_write(pwm_io_ch[i], 1);                 pwm_running[i] = 0;            }            else            {                if(i < 2)                {                    new_capture = pwm_next_value[i];                    old_capture = PWM_TIMER->CC[i];                    if(!pwm_running[i])                    {                        nrf_gpiote_task_config(pwm_gpiote_channel[i], pwm_io_ch[i], NRF_GPIOTE_POLARITY_TOGGLE, NRF_GPIOTE_INITIAL_VALUE_HIGH);                          pwm_running[i] = 1;                        PWM_TIMER->TASKS_CAPTURE[3] = 1;                        if(PWM_TIMER->CC[3] > new_capture) NRF_GPIOTE->TASKS_OUT[pwm_gpiote_channel[i]] = 1;                        PWM_TIMER->CC[i] = new_capture;                    }                    else                    {                        while(1)                        {                            PWM_TIMER->TASKS_CAPTURE[3] = 1;                            if(safe_margins_present(PWM_TIMER_CURRENT, old_capture) && safe_margins_present(PWM_TIMER_CURRENT, new_capture)) break;                        }                        if((PWM_TIMER_CURRENT >= old_capture && PWM_TIMER_CURRENT < new_capture) || (PWM_TIMER_CURRENT < old_capture && PWM_TIMER_CURRENT >= new_capture))                        {                            NRF_GPIOTE->TASKS_OUT[pwm_gpiote_channel[i]] = 1;                        }                        PWM_TIMER->CC[i] = new_capture;                    }                }                else                {                    new_capture = pwm_next_value[i];                    old_capture = PWM_TIMER2->CC[i-2];                    if(!pwm_running[i])                    {                        nrf_gpiote_task_config(pwm_gpiote_channel[i], pwm_io_ch[i], NRF_GPIOTE_POLARITY_TOGGLE, NRF_GPIOTE_INITIAL_VALUE_HIGH);                          pwm_running[i] = 1;                        PWM_TIMER2->TASKS_CAPTURE[3] = 1;                        if(PWM_TIMER2->CC[3] > new_capture) NRF_GPIOTE->TASKS_OUT[pwm_gpiote_channel[i]] = 1;                        PWM_TIMER2->CC[i-2] = new_capture;                    }                    else                    {                        while(1)                        {                            PWM_TIMER2->TASKS_CAPTURE[3] = 1;                            if(safe_margins_present(PWM_TIMER2_CURRENT, old_capture) && safe_margins_present(PWM_TIMER2_CURRENT, new_capture)) break;                        }                        if((PWM_TIMER2_CURRENT >= old_capture && PWM_TIMER2_CURRENT < new_capture) || (PWM_TIMER2_CURRENT < old_capture && PWM_TIMER2_CURRENT >= new_capture))                        {                            NRF_GPIOTE->TASKS_OUT[pwm_gpiote_channel[i]] = 1;                        }                        PWM_TIMER2->CC[i-2] = new_capture;                    }                                    }            }        }    }
然后运行一下~会看见占空比不同,两个led灯的亮度不同。占空比为255的LED_1要比占空比为20的LED_1亮




0 1