-
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
...
결과
'부산IT학원 > 스마트컨트롤러' 카테고리의 다른 글
20141031 (C++ Template 분할 컴파일, ARM PWM) (0) 2014.10.31 20141030 (C++ string class, Template) (0) 2014.10.30 20141029 (C++ ()연산자와 Functor(펑터), ARM SAM-BA) (0) 2014.10.30 20141028 (C++ new, delete, *, -> 연산자 오버로딩, ARM 소스변환) (0) 2014.10.28 20141027 (C++ 객체 초기화, 대입연산자, 배열 연산자, ARM ADS) (0) 2014.10.27