Skip to content

예제 pwm_ccp_dimming

irmusy edited this page Oct 7, 2013 · 1 revision

개요

본 예제는 가변저항의 값을 읽고, 그 결과 만큼 LED 밝기를 제어합니다. 가변저항의 값을 읽기 위해 ADC를 이용하고, LED 밝기를 제어하기 위해 PWM을 이용합니다. 이때 이용하는 PWM은 PWM 장치를 이용한 것이 아닌 타이머의 CCP(Capture, Compare, PWM)를 이용한 간이 PWM입니다.

가변저항과 LED를 아래 회로와 같이 연결합니다.

pwm_ccp_dimming 회로도

회로도는 PDF 파일로 다운로드 받으실 수도 있습니다.

[myMCU-EXP rev.B](myMCU-EXP rev.B) 보드를 사용하는 경우 내장된 가변저항과 LED CR2를 그대로 사용하게 되므로 간편하게 실험하실 수 있습니다.

관련 Peripheral

  • SysCtl
  • GPIO
  • Timer
  • ADC

소스 살펴보기

33 line:

#define PWM_FREQUENCY 25000
#define PWM_MAX_DUTY 1000

타이머를 이용해 생성 할 PWM의 주기를 25kHz로 잡았습니다. 그리고 PWM 듀티는 0~1000 까지 값을 사용합니다.

61 line:

    //
    // Initialize Timer CCP module for PWM
    //
    PWM_Init();
    PWM_Disable();

    PWM_SetDuty(750);   // 25% duty
    PWM_Enable();

PWM을 초기화 합니다. 각 함수 설명에서 자세히 설명합니다.

70 line:

    VR_Init();

가변저항 값을 읽기 위해 ADC를 초기화합니다.

82 line:

static void VR_Init()
{
    //
    // Configure ADC
    //
    SysCtlPeripheralEnable(SYSCTL_PERIPH_ADC);
    SysCtlADCSpeedSet(SYSCTL_ADCSPEED_500KSPS);

    // ADC sequence #0 - setup with 1 conversions
    ADCSequenceDisable(ADC_BASE, 0);
    ADCSequenceConfigure(ADC_BASE, 0, ADC_TRIGGER_TIMER, 0);
    ADCIntRegister(ADC_BASE, 0, ADCIntHandler);
    ADCIntEnable(ADC_BASE, 0);

    // sequence step 0 - channel 0
    ADCSequenceStepConfigure(ADC_BASE, 0, 0, ADC_CTL_CH0 | ADC_CTL_IE | ADC_CTL_END);

    ADCSequenceEnable(ADC_BASE, 0);

    //
    // Configure Timer to trigger ADC
    //
    SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER1);
    TimerConfigure( TIMER1_BASE, TIMER_CFG_32_BIT_PER );
    TimerControlTrigger(TIMER1_BASE, TIMER_A, true);
    TimerLoadSet( TIMER1_BASE, TIMER_A, SysCtlClockGet() / 100 );     // 100Hz control loop
    TimerEnable( TIMER1_BASE, TIMER_A );

}

ADC를 설정하고, 주기적으로 ADC를 수행하기 위해 타이머를 설정합니다. 제어 주기 100Hz입니다. ADC와 타이머 설정에 관한 보다 자세한 설명은 [adc_2ch 예제](예제 adc_2ch)를 참고하시기 바랍니다.

113 line:

static void ADCIntHandler(void)
{
    long cnt;
    unsigned long adc_result[16];
    unsigned short duty;

    ADCIntClear(ADC_BASE, 0);

    cnt = ADCSequenceDataGet(ADC_BASE, 0, adc_result);  // read ADC result
    if (cnt == 1)
    {
        duty = adc_result[0] * PWM_MAX_DUTY / 1023;        // calculate duty ratio

        PWM_SetDuty(duty);                              // Set PWM duty
    }
}

ADC 변환 완료 인터럽트 핸들러입니다. 100Hz로 설정한 Timer1에 의해 ADC가 자동으로 변환을 시작하고, 변환이 완료되면 ADC 인터럽트가 발생하여 본 인터럽트 핸들러가 호출됩니다. ADC 인터럽트 핸들러에서는 ADC 결과를 읽어 VR의 값을 읽고 이를 이용해 PWM 듀티를 설정합니다.

130 line:

/*
 * Configure Timer0-A for PWM generation.
 * Timer0-A is connected to PD4/CCP0 pin.
 */
static void PWM_Init(void)
{
    SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER0);
    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOD);
    GPIOPinTypeTimer(GPIO_PORTD_BASE, GPIO_PIN_4);
    TimerConfigure(TIMER0_BASE, TIMER_CFG_16_BIT_PAIR | TIMER_CFG_A_PWM);
    TimerLoadSet(TIMER0_BASE, TIMER_A, SysCtlClockGet() / PWM_FREQUENCY);

    PWM_SetDuty(PWM_MAX_DUTY / 2);
}

타이머의 CCP 기능을 이용해 PWM을 생성하기 위한 초기화 과정입니다. Timer0를 이용해 PWM을 생성합니다. Timer0의 TIMER_A를 이용해 생성된 PWM은 PD4/CCP0 핀을 이용해 출력됩니다.

145 line:

/*
 * Sets PWM output duty cycle.
 * PWM duty cycle is allowed between 0~PWM_MAX_DUTY
 */
static void PWM_SetDuty(unsigned short duty)
{
    unsigned long d;

    if (duty > PWM_MAX_DUTY)
        duty = PWM_MAX_DUTY;
    else if (duty == 0)
        duty = 1;

    d = SysCtlClockGet() / PWM_FREQUENCY * (PWM_MAX_DUTY - duty) / PWM_MAX_DUTY;

    TimerMatchSet(TIMER0_BASE, TIMER_A, d);
}

PWM 듀티를 설정합니다. 본 예제에서는 듀티 값을 0~1000의 범위를 가지는 정수로 사용하고 있습니다.

163 line:

static void PWM_Enable(void)
{
    TimerEnable(TIMER0_BASE, TIMER_A);
}

static void PWM_Disable(void)
{
    TimerDisable(TIMER0_BASE, TIMER_A);
}

PWM 출력을 enable/disable 시키는 함수입니다.

실행 방법 안내

  1. 펌웨어를 빌드한 후 다운로드 하고, 보드의 리셋 버튼을 1회 누릅니다.
  2. 가변저항을 노브를 돌려가면서 LED의 밝기가 변경되는지 확인합니다.