ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 20141103 (C++ Template 특수화, 부분 특수화, 인자, static, 예외처리, ARM PWM)
    부산IT학원/스마트컨트롤러 2014. 11. 3. 12:45

    171일차









    ----------

    C++

    ----------



    ------- Template 특수화, 부분 특수화


    템플릿을 특수화하면 템플릿을 구성하는 멤버를 다르게 행동하도록 할 수 있다.

    다음 예제 참고


    예제)

    #include <iostream>

    #include <cstring>

    using namespace std;


    template <typename T>

    class Point 

    {

    private:

    T xpos, ypos;

    public:

    Point(T x=0, T y=0): xpos(x), ypos(y)

    {  }

    void ShowPosition() const

    {

    cout<<'['<<xpos<<", "<<ypos<<']'<<endl; 

    }

    };


    template <typename T>

    class SimpleDataWrapper 

    {

    private:

    T mdata;

    public:

    SimpleDataWrapper(T data) : mdata(data)

    { }

    void ShowDataInfo(void)

    {

    cout<<"Data: "<<mdata<<endl;

    }

    };


    template<>

    class SimpleDataWrapper <char*>

    {

    private:

    char* mdata;

    public:

    SimpleDataWrapper(char* data)

    {

    mdata=new char[strlen(data)+1];

    strcpy(mdata, data);

    }

    void ShowDataInfo(void)

    {

    cout<<"String: "<<mdata<<endl;

    cout<<"Length: "<<strlen(mdata)<<endl;

    }

    ~SimpleDataWrapper()

    {

    delete []mdata;

    }

    };


    // Template 특수화

    template<>

    class SimpleDataWrapper <Point<int>>

    {

    private:

    Point<int> mdata;

    public:

    SimpleDataWrapper(int x, int y) : mdata(x, y)

    { }

    void ShowDataInfo(void)

    {

    mdata.ShowPosition();

    }

    };


    int main(void)

    {

    SimpleDataWrapper<int> iwrap(170);

    iwrap.ShowDataInfo();


    SimpleDataWrapper<char*> swrap("Class Template Specialization");

    swrap.ShowDataInfo();


    SimpleDataWrapper<Point<int>> poswrap(3, 7);

    poswrap.ShowDataInfo();

    return 0;

    }



    위의 예제에서 확인할 수 있듯이 템플릿을 하면 컴파일러에서 자동으로 다른 타입의

    함수를 생성해 주지만 특수한 경우는 따로 선언한 것을 사용하게 한 것을 특수화라 한다.





    --- Template 부분 특수화


    특수화와 같은데 쬐금 업그레이드(?) 된 것이다.


    예제)

    #include <iostream>

    using namespace std;


    template <typename T1, typename T2>

    class MySimple 

    public:

    void WhoAreYou()

    {

    cout<<"size of T1: "<<sizeof(T1)<<endl;

    cout<<"size of T2: "<<sizeof(T2)<<endl;

    cout<<"<typename T1, typename T2>"<<endl;

    }

    };


    template<>

    class MySimple<int, double>

    {

    public:

    void WhoAreYou()

    {

    cout<<"size of int: "<<sizeof(int)<<endl;

    cout<<"size of double: "<<sizeof(double)<<endl;

    cout<<"<int, double>"<<endl;

    }

    };



    template<typename T1>

    class MySimple<T1, double>

    {

    public:

    void WhoAreYou()

    {

    cout<<"size of T1: "<<sizeof(T1)<<endl;

    cout<<"size of double: "<<sizeof(double)<<endl;

    cout<<"<T1, double>"<<endl;

    }

    };



    int main(void)

    {

    MySimple<char, double> obj1;

    obj1.WhoAreYou();

    MySimple<int, long> obj2;

    obj2.WhoAreYou();

    MySimple<int, double> obj3;

    obj3.WhoAreYou();

    return 0;

    }

    결과














    ------- Template 인자


    템플릿 매개변수의 선언에 마치 함수처럼 변수의 선언을 할 수 있다.


    예제)

    #include <iostream>


    using namespace std;


    template <typename T, int len> // 인자 선언

    class SimpleArray

    {

    private:

    T arr[len]; // 인자만큼 배열 할당


    public:

    T& operator[] (int idx)

    {

    return arr[idx];

    }


    SimpleArray<T, len>& operator=(const SimpleArray<T, len>& ref)

    {

    for(int i = 0; i < len; ++i)

    {

    arr[i] = ref.arr[i];

    }

    return *this;

    }

    };


    int main()

    {

    SimpleArray<int, 5> i5arr1; // 객체에 int * 5 크기의 배열 멤버 할당

    for(int i = 0; i < 5; ++i)

    {

    i5arr1[i] = i * 10;

    }


    SimpleArray<int, 5> i5arr2; // 객체에 int * 5 크기의 배열 멤버 할당

    i5arr2 = i5arr1;

    for(int i = 0; i < 5; ++i)

    {

    cout << i5arr2[i] << ", ";

    }

    cout << endl;


    SimpleArray<int, 7> i7arr1; // 객체에 int * 7 크기의 배열 멤버 할당

    for(int i = 0; i < 7; ++i)

    {

    i7arr1[i] = i * 10;

    }


    SimpleArray<int, 7> i7arr2; // 객체에 int * 7 크기의 배열 멤버 할당

    i7arr2 = i7arr1;

    for(int i = 0; i < 7; ++i)

    {

    cout << i7arr2[i] << ", ";

    }

    cout << endl;


    return 0;

    }

    결과




    설마 생각한 그것도 가능하다.

    바로 인자에 디폴트 값 지정....


    예제)

    #include <iostream>


    using namespace std;


    template <typename T = int, int len = 7>

    class SimpleArray

    {

    private:

    T arr[len];

    public:

    T& operator[] (int idx)

    {

    return arr[idx];

    }

    T& operator=(const T&ref)

    {

    for(int i=0; i<len; i++)

    arr[i]=ref.arr[i];

    }

    };


    int main(void)

    {

    SimpleArray<> arr; // 아무 값도 안넣어 줬기 때문에 디폴트 값이 들어감.

    for(int i = 0; i < 7; i++)

    arr[i] = i + 1;

    for(int i = 0; i < 7; i++)

    cout << arr[i] << " ";

    cout << endl;


    return 0;

    }

    결과











    ------- Template과 static 멤버 변수


    다음 예제 참고


    예제)

    #include <iostream>


    using namespace std;


    template <typename T>

    class SimpleStaticMem

    {

    private:

    static T mem; // static 변수 선언. 같은 타입끼리 공유함.


    public:

    void AddMem(int num)

    {

    mem = mem + num;

    }


    void ShowMem()

    {

    cout<<mem<<endl;

    }

    } ;


    template <typename T> 

    T SimpleStaticMem<T>::mem = 0; // class 내에 static 멤버는 꼭 전역에서 초기화 필수!!



    int main(void)

    {

    SimpleStaticMem<int> obj1; // 같은 클래스 이기 때문에 mem을 공유함

    SimpleStaticMem<int> obj2; // 같은 클래스 이기 때문에 mem을 공유함

    obj1.AddMem(2); // 2 더함

    obj2.AddMem(3); // 3 더함

    obj1.ShowMem();


    SimpleStaticMem<long> obj3; // 같은 클래스 이기 때문에 mem을 공유함

    SimpleStaticMem<long> obj4; // 같은 클래스 이기 때문에 mem을 공유함

    obj3.AddMem(100); // obj3에 100 더함

    obj4.ShowMem(); // obj4에서 출력했지만 공유하기 때문에 100 출력


    return 0 ;

    }

    결과












    ------- 예외처리

     

    try, catch, throw 라는 것으로 예외 처리를 하면 가독성과 유지보수성을 높일 수 있다.


    예제)

    #include <iostream>


    using namespace std;


    int main()

    {

    int num1;

    int num2;


    cout << "두 개의 숫자 입력: ";

    cin >> num1 >> num2;


    try

    {

    if(num2 == 0)

    {

    throw num2;

    }

    cout << "나눗셈의 몫: " << num1/num2 << endl;

    cout << "나눗셈의 나머지: " << num1%num2 << endl;

    }

    catch(int expn) // throw num2 값을 expn이 받음

    {

    cout << "제수는 " << expn << "이 될 수 없습니다." << endl;

    cout << "프로그램을 다시 실행하세요." << endl;

    }


    cout << "end of main" << endl;


    return 0;

    }






















    ------------

    ARM

    ------------


    ------- PWM


    이번엔 TC device가 아닌 PWM device를 사용한다.






    - Clock 주파수 신호 종류

       총 13가지 이다. 이 중에 선택하여 사용함.




    - Timing도





    Timing도를 설명하자면









    예제 소스)

    /* 14번 Pin에 물린 LED가 점점 어두워짐. */

    #include "AT91SAM7S256.h"


    #define MAX_DUTY 800

    #define DFT_DUTY 100


    void PWM3_Init(void);

    void Delay_ms(unsigned int ms);

    void PWM3_Duty(unsigned int uiDuty);


    int main(void)

    {

    volatile unsigned int uiCnt;

    volatile unsigned int uiDuty;

    PWM3_Init();

    uiDuty = DFT_DUTY;

    while(1)

    {

    for(uiCnt = 0; 100000 > uiCnt; ++uiCnt); // 이 딜레이로 uiDuty의 값이

    PWM3_Duty(uiDuty); // 변하는 시간이 된다. 이 시간이 길수록

    // 바뀌는 시간도 느려진다.

    if(uiDuty < MAX_DUTY)

    {

    uiDuty = uiDuty + 10;

    }

    else

    {

    uiDuty = DFT_DUTY;

    }

    }

    return 0;

    }




    void PWM3_Init(void)

    {

    *AT91C_PMC_PCER = (1 << AT91C_ID_PWMC);  // PWM 전원 공급

    *AT91C_PIOA_PPUDR = AT91C_PA14_PWM3; // Pull-up off

    *AT91C_PIOA_BSR = AT91C_PA14_PWM3; // PWM3 output(Peripheral B모드 사용)

    *AT91C_PIOA_PDR = 0xFFFFFFFF; // 모든 PIO비활성화


    *AT91C_PWMC_MR = (0x00 << 24) | // PREB = MCK

    (0x06 << 8) | // PREA = MCK/64

    (0 << 16)  | // DIVB = Off

    (30 << 0); // DIVA = 30

    // 48Mhz / 64 = 750Khz

    // 750Khz / 30 = 25Khz


    *AT91C_PWMC_CH3_CMR = (0 << 8) | // CALG = 0, 톱니모양

    (0 << 9) | // CPOL = 0, Low로 시작

    (0 << 10)| // CPD = 0, duty

    (0x0B); // CPRE = CLKA


    *AT91C_PWMC_CH3_CDTYR = DFT_DUTY; // TC0 RA와 같은 기능

    *AT91C_PWMC_CH3_CPRDR = MAX_DUTY; // TC0 RC와 같은 기능

    *AT91C_PWMC_ENA = AT91C_PWMC_CHID3; // PWM Enable

    }




    void PWM3_Duty(unsigned int uiDuty)

    {

    if(MAX_DUTY < uiDuty)

    {

    uiDuty = MAX_DUTY;

    }

    *AT91C_PWMC_CH3_CUPDR = uiDuty;

    // 출력 주파수 조절하기 위해 CDTY Reg를 바로 건들면 오류가 난다.

    // CUPD Reg의 값을 바꾸면 다음 주기때 CDTY값이 바뀐다.

    }


    결과


    (결과에 불 깜빡임을 보면 부드럽게 꺼지는데, 실제로 볼 경우 제법 깜빡임이 있다.)








    위의 소스에서 아래와 같이 수정하면


    #define MAX_DUTY (18750 * 2) // 초당 주파수 값의 두배로 줌

    #define DFT_DUTY 18750 // 초당 주파수 값


    int main(void)

    ...

    while(1)

    {

    for(uiCnt = 0; 100000 > uiCnt; ++uiCnt); // 그냥 딜레이 걸어줌

    PWM3_Duty(uiDuty); // 값을 넣어주면

    // 1초씩 번갈아 가며 깜빡인다.

    }

    ...


    void PWM3_Init(void)

    ...

    *AT91C_PWMC_MR = (0x09 << 8) | // PREA = MCK/512

    (5 << 0); // DIVA = 5

    // 48 Mhz / 512 = 93750 hz

    // 93750 hz / 5 = 18750 hz

    ...


    결과







Designed by Tistory.