해보기는 했어?

오늘 안됐다고 포기하지 말고 용기내서 내일 다시 해 보자.

MEGAWIN

MG82F6D Series TIM_T2_Mode4_PWM

롬돌이 2022. 12. 13. 09:33
반응형

1. 프로그램 개요

P22Green 0 LED, P24 Red LED, P26Green 1 LED가 연결되어 있다.

타이머 2의 모드 48-bit PWM 모드이다. 이를 이용해서 PWM 시그널을 T2CKO로 출력 시키는 것을 테스트 해 본다.

TH2RCAP2H8-bit 자동 재적재 카운터를 구성하고, PWM의 시간(주파수)을 결정한다.

TL2 PWM 비교 레지스터로서 PWM의 파형(듀티)을 만든다. TH2의 오버플로우는 TF2를 셋 시키고 RCAP2L의 값을 TL2, RCAP2HTH2에 재적재 시킨다.

PWM 신호는 T2CKO에 출력되고, 이 신호는 T2MOD레지스터의 T2OE로 제어된다.

 

2. 회로도

 

3. Code

main routine

 

void main()

{

InitSystem();                                                            // 시스템 초기화

LED_G_1=0;LED_R=0;                                                 // LEG_G_1, LED_R ON

           DelayXms(1000);                                                       // 1초 딜레이

          LED_G_1=1;LED_R=1;                                                 // LED_G_1, LED_R OFF

                                                    

          while(1)

          {                                                                         // #1

                     LED_R=0;                                                     // LED_R ON

                     LED_G_1=0;                                                  // LED_G_1 ON

                     TM_SetT2LowByte(T2_PWM_DUTY_0);                   // TL2, RCAP2LPWM Duty 0의 데이터 저장

                     TM_SetT2RLLowByte(T2_PWM_DUTY_0);

                     DelayXms(1);                                                 // 1ms 딜레이

                     TM_EnT2CKO();                                              // T2CKO 출력 Enable

                     LED_G_1=1;                                                  // LED_G_1 OF

                     DelayXms(2);                                                 // 2ms 딜레이

                                                                                     // #2

                     LED_G_1=0;                                                  // LED_G_1 ON

                     TM_SetT2RLLowByte(T2_PWM_DUTY_10);               // RCAP2L PWM Duty 10의 데이터 저장, 200us 10%20us

                     LED_G_1=1;                                                  // LED_G_1 OFF

                     DelayXms(2);                                                 // 2ms 딜레이

                                                                                     // #3

                     LED_G_1=0;                                                  // LED_G1_ON

                     TM_SetT2RLLowByte(T2_PWM_DUTY_30);               // RCAP2L PWM Duty 30의 데이터 저장

                     LED_G_1=1;                                                  // LED_G1_OFF

                     DelayXms(2);                                                 // 2ms 딜레이

                                                                                     // #4

                     LED_G_1=0;                                                  // LED_G_1 ON

                     TM_SetT2RLLowByte(T2_PWM_DUTY_60);               // RCAP2LPWM Duty 60의 데이터 저장

                     LED_G_1=1;                                                  // LED_G_1 OFF

                     DelayXms(2);                                                 // 2ms 딜레이

                                                                                     // #5

                     LED_G_1=0;                                                  // LED_G_1 ON

                     TM_SetT2RLLowByte(T2_PWM_DUTY_80);               // RCAP2LPWM Duty 80의 데이터 저장

                     LED_G_1=1;                                                  // LED_G_1 OFF

                     DelayXms(2);                                                 // 2ms 딜레이

                                                                                     // #6

                     LED_G_1=0;                                                  // LED_G_1 ON

                     TM_SetT2RLLowByte(0xFF);                                // RCAP2LPWM Duty 100의 데이터 저장

                     LED_G_1=1;                                                  // LED_G_1 OFF

                     DelayXms(2);                                                 // 2ms 딜레이

                      // Duty 100%                                               // #7

                     LED_G_1=0;                                                  // LED_G_1 ON

                     TM_DisT2CKO();                                             // T2CKO Disable

                     IO_T2_PWM_OUT=0;                                       // IO_T2_PWM_OUT clear(Low)

                     LED_G_1=1;                                                  // LED_G_1 OFF

                     DelayXms(2);                                                 // 2ms Delay

 

                     // Disable Output                                          // #8

                     LED_R=1;                                                     // LED_R OFF

                     LED_G_1=0;                                                  // LED_G_1 ON

                     TM_DisT2CKO();                                             // T2CKO Disable

                     IO_T2_PWM_OUT=1;                                       // IO_T2_PWM_OUT Set(high)

                     LED_G_1=1;                                                  // LED_G_1 Off

                     DelayXms(10);                                               // 10ms Delay

         

           }

}

- 위 프로그램을 그대로 동작시키면 출력 파형의 듀티를 확인할 수 없다. 따라서 #1~7까지의 코드 중 동작 시키고자 하는 것만 남겨두고 주석처리를 한다.

그리고, DelayXms루틴대신 while(1) 로 무한루프를 만들어 듀티를 확인한다. while 문 안의 내용을 아래와 같이 수정하고, 첫 번 째 #if~#endif 문은 항상 동작하도록 하고 그 아래의 내용들은 블록단위로 나누어서 각각의 듀티를 확인해 본다.

while(1)

{

          LED_R=0;

          LED_G_1=0;

          TM_SetT2LowByte(T2_PWM_DUTY_0);

#if 1               

          TM_SetT2RLLowByte(T2_PWM_DUTY_0);

          DelayXms(1);

          TM_EnT2CKO();

          LED_G_1=1;

          DelayXms(2);

#endif

                               

#if 0                         

          LED_G_1=0;

          TM_SetT2RLLowByte(T2_PWM_DUTY_10);     // 20us

          LED_G_1=1;

          //DelayXms(2);

while(1);

#endif

                               

#if 0                         

          LED_G_1=0;

          TM_SetT2RLLowByte(T2_PWM_DUTY_30);     // 60us

          LED_G_1=1;

      //DelayXms(2);

           while(1);

#endif

 

#if 0

          LED_G_1=0;

          TM_SetT2RLLowByte(T2_PWM_DUTY_60);     // 120us

          LED_G_1=1;

          //DelayXms(2);

           while(1);

#endif

#if 0

          LED_G_1=0;

          TM_SetT2RLLowByte(T2_PWM_DUTY_80);     // 160us

          LED_G_1=1;

          //DelayXms(2);

           while(1);

#endif

#if 0

          LED_G_1=0;

          TM_SetT2RLLowByte(0xFF);          // 199us

          LED_G_1=1;

          //DelayXms(2);

           while(1);

#endif

#if 0

          // Duty 100%                           // 200us

          LED_G_1=0;                            

           TM_DisT2CKO();            

           IO_T2_PWM_OUT=0;

          LED_G_1=1;

          //DelayXms(2);

           while(1);

#endif

#if 1

           // Disable Output

          LED_R=1;

          LED_G_1=0;

           TM_DisT2CKO();

           IO_T2_PWM_OUT=1;

          LED_G_1=1;

           //DelayXms(2);

           while(1);

#endif            

}

 

 

⑵ 시스템 초기화 루틴

/***********************************************************************************

*Function:   void InitSystem(void)

*Description:           Initialize MCU

*Input:  

*Output:    

*************************************************************************************/

void InitSystem(void)

{

           InitPort();

           InitClock();

          

           InitTimer2();                         

}

- 포트 설정을 수행한다.

- 클럭을 설정한다.

- 타이머 2를 초기화 시킨다.

 

 

 

Port 초기화

/***********************************************************************************

*Function:   void InitPort(void)

*Description:  Initialize IO Port

*Input:  

*Output:    

*************************************************************************************/

void InitPort(void)

{

           IO_T2_PWM_OUT=1;

è P10T2 PWM OUT 이란 이름으로 대체한다.( #define IO_T2_PWM_OUT       P10)

           PORT_SetP2PushPull(BIT2|BIT4|BIT6);                                                   // Set P22,P24,P26 as Push-Pull,For LED.

è P22, P24, P26 LED용으로 사용한다.

           PORT_SetP1PushPull(BIT0);                                                                  //  Set P10 as Push-Pull for T2 PWM ouptput

è P10 Push-Pull 타입의 핀으로 설정한다.

}

 

*** 사용된 매크로함수는 “API_Macro_MG82FG6D16.H”에서 찾아볼 수 있다.

\Megawin 8051\(EN)MG82F6D16_SampleCode_v1.20\MG82F6D16_GPIO_TIM_T2_Mode4\code\include

 

⑷ 클럭 초기화 루틴 è 시스템 클럭 및 내부 클럭을 설정한다.

프로그램의 루틴 자체는 복잡하게 많이 설정해 두었으나 그 구조는 아래와 같다.

MCU_SYSCLK의 값은 11059200, 12000000, 22118400, 24000000, 29491200, 32000000, 44236800, 48000000로 설정이 가능하며, 각각 프로그램 상단에

#define        MCU_SYSCLK          12000000

와 같이 선언해주었다. 그리고, 바로

#define        MCU_CPUCLK          (MCU_SYSCLK)

로 선언하여 System 클럭과 CPU 클럭을 동일하게 사용하기로 선언하였다. 물론 사용자의 선택에 따라 틀려질 수 있으므로 어플리케이션에 따라 선언하면 된다.

#if (MCU_SYSCLK==12000000)                        // System Clock12MHz로 선언되어 있으면

#if (MCU_CPUCLK==MCU_SYSCLK)                    // CPU ClockSystem Clock와 동일하면

         // SysClk=12MHz CpuClk=12MHz

         CLK_SetCKCON0(IHRCO_12MHz|CPUCLK_SYSCLK_DIV_1|SYSCLK_MCKDO_DIV_1);         // 이와 같이 설정하고

        

#else

         // SysClk=12MHz CpuClk=6MHz

         CLK_SetCKCON0(IHRCO_12MHz|CPUCLK_SYSCLK_DIV_2|SYSCLK_MCKDO_DIV_1);         // CPU clockSystem Clock와 같거나 1/2로 설정할

// 수 있다.

#endif

#endif

- CLK_SetCKCON0(IHRCO_12MHz|CPUCLK_SYSCLK_DIV_1|SYSCLK_MCKDO_DIV_1);

CKCON0 레지스터의 각 비트를 설정한다.

CKCON0.7 : AFS, Alternated Frequency Selection, 내부 클럭 IHRCO12MHz(AFS = 0), 또는 11.059MHz(AFS = 1)로 설정함

CKCON0.3 : CCKS, CPU Clock Select, 0:CPU CLOCK = System Clock, 1:CPU CLOCK = System Clock/2

CKCON0.0 ~ 2 : Programable System Clock Select. SYSCLK_MCKDO_DIV_1(System Clock = Master Clock Divider Output)

 

/***********************************************************************************

*Function:   void InitClock(void)

*Description: 

*                                  Initialize clock

*Input:  

*Output:    

*************************************************************************************/

void InitClock(void)

{

#if (MCU_SYSCLK==11059200)

#if (MCU_CPUCLK==MCU_SYSCLK)

         // SysClk=11.0592MHz CpuClk=11.0592MHz

         CLK_SetCKCON0(IHRCO_110592MHz|CPUCLK_SYSCLK_DIV_1|SYSCLK_MCKDO_DIV_1);

        

#else

         // SysClk=11.0592MHz CpuClk=5.5296MHz

         CLK_SetCKCON0(IHRCO_110592MHz|CPUCLK_SYSCLK_DIV_2|SYSCLK_MCKDO_DIV_1);

#endif

#endif

 

#if (MCU_SYSCLK==12000000)

#if (MCU_CPUCLK==MCU_SYSCLK)

         // SysClk=12MHz CpuClk=12MHz

         CLK_SetCKCON0(IHRCO_12MHz|CPUCLK_SYSCLK_DIV_1|SYSCLK_MCKDO_DIV_1);

        

#else

         // SysClk=12MHz CpuClk=6MHz

         CLK_SetCKCON0(IHRCO_12MHz|CPUCLK_SYSCLK_DIV_2|SYSCLK_MCKDO_DIV_1);

#endif

#endif

 

#if (MCU_SYSCLK==22118400)

#if (MCU_CPUCLK==MCU_SYSCLK)

         // SysClk=22.1184MHz CpuClk=22.1184MHz

         CLK_SetCKCON0(IHRCO_110592MHz|CPUCLK_SYSCLK_DIV_1|SYSCLK_MCKDO_DIV_1|ENABLE_CKM|CKM_OSCIN_DIV_2);

         DelayXus(100);

         // IHRCO, MCK=CKMIx4, OSCin=IHRCO

         CLK_SetCKCON2(ENABLE_IHRCO|MCK_CKMI_X4|OSCIn_IHRCO);

#else

         // SysClk=22.1184MHz CpuClk=11.0592MHz

         CLK_SetCKCON0(IHRCO_110592MHz|CPUCLK_SYSCLK_DIV_2|SYSCLK_MCKDO_DIV_1|ENABLE_CKM|CKM_OSCIN_DIV_2);

         DelayXus(100);

         // IHRCO, MCK=CKMIx4, OSCin=IHRCO

         CLK_SetCKCON2(ENABLE_IHRCO|MCK_CKMI_X4|OSCIn_IHRCO);

#endif

#endif

 

#if (MCU_SYSCLK==24000000)

#if (MCU_CPUCLK==MCU_SYSCLK)

         // SysClk=24MHz CpuClk=24MHz

         CLK_SetCKCON0(IHRCO_12MHz|CPUCLK_SYSCLK_DIV_1|SYSCLK_MCKDO_DIV_1|ENABLE_CKM|CKM_OSCIN_DIV_2);

         DelayXus(100);

         // IHRCO, MCK=CKMIx4, OSCin=IHRCO

         CLK_SetCKCON2(ENABLE_IHRCO|MCK_CKMI_X4|OSCIn_IHRCO);

#else

         // SysClk=24MHz CpuClk=12MHz

         CLK_SetCKCON0(IHRCO_12MHz|CPUCLK_SYSCLK_DIV_2|SYSCLK_MCKDO_DIV_1|ENABLE_CKM|CKM_OSCIN_DIV_2);

         DelayXus(100);

         // IHRCO, MCK=CKMIx4, OSCin=IHRCO

         CLK_SetCKCON2(ENABLE_IHRCO|MCK_CKMI_X4|OSCIn_IHRCO);

#endif

#endif

 

#if (MCU_SYSCLK==29491200)

#if (MCU_CPUCLK==MCU_SYSCLK)

         // Cpuclk high speed

         CLK_SetCpuCLK_HighSpeed();

         // SysClk=29.491200MHz CpuClk=29.491200MHz

         CLK_SetCKCON0(IHRCO_110592MHz|CPUCLK_SYSCLK_DIV_1|SYSCLK_MCKDO_DIV_1|ENABLE_CKM|CKM_OSCIN_DIV_2);

         DelayXus(100);

         // IHRCO, MCK=CKMIx5.33, OSCin=IHRCO

         CLK_SetCKCON2(ENABLE_IHRCO|MCK_CKMI_X533|OSCIn_IHRCO);

#else

         // SysClk=29.491200MHz CpuClk=14.7456MHz

         CLK_SetCKCON0(IHRCO_110592MHz|CPUCLK_SYSCLK_DIV_2|SYSCLK_MCKDO_DIV_1|ENABLE_CKM|CKM_OSCIN_DIV_2);

         DelayXus(100);

         // IHRCO, MCK=CKMIx5.33, OSCin=IHRCO

         CLK_SetCKCON2(ENABLE_IHRCO|MCK_CKMI_X533|OSCIn_IHRCO);

#endif

#endif

 

#if (MCU_SYSCLK==32000000)

#if (MCU_CPUCLK==MCU_SYSCLK)

         // Cpuclk high speed

         CLK_SetCpuCLK_HighSpeed();

         // SysClk=32MHz CpuClk=32MHz

         CLK_SetCKCON0(IHRCO_12MHz|CPUCLK_SYSCLK_DIV_1|SYSCLK_MCKDO_DIV_1|ENABLE_CKM|CKM_OSCIN_DIV_2);

         DelayXus(100);

         // IHRCO, MCK=CKMIx5.33, OSCin=IHRCO

         CLK_SetCKCON2(ENABLE_IHRCO|MCK_CKMI_X533|OSCIn_IHRCO);

#else

         // SysClk=32MHz CpuClk=16MHz

         CLK_SetCKCON0(IHRCO_12MHz|CPUCLK_SYSCLK_DIV_2|SYSCLK_MCKDO_DIV_1|ENABLE_CKM|CKM_OSCIN_DIV_2);

         DelayXus(100);

         // IHRCO, MCK=CKMIx5.33, OSCin=IHRCO

         CLK_SetCKCON2(ENABLE_IHRCO|MCK_CKMI_X533|OSCIn_IHRCO);

#endif

#endif

 

#if (MCU_SYSCLK==44236800)

         // SysClk=44.2368MHz CpuClk=22.1184MHz

         CLK_SetCKCON0(IHRCO_110592MHz|CPUCLK_SYSCLK_DIV_1|SYSCLK_MCKDO_DIV_1|ENABLE_CKM|CKM_OSCIN_DIV_2);

         DelayXus(100);

         // IHRCO, MCK=CKMIx8, OSCin=IHRCO

         CLK_SetCKCON2(ENABLE_IHRCO|MCK_CKMI_X8|OSCIn_IHRCO);

#endif

 

#if (MCU_SYSCLK==48000000)

         // SysClk=48MHz CpuClk=24MHz

         CLK_SetCKCON0(IHRCO_12MHz|CPUCLK_SYSCLK_DIV_2|SYSCLK_MCKDO_DIV_1|ENABLE_CKM|CKM_OSCIN_DIV_2);

         DelayXus(100);

         // IHRCO, MCK=CKMIx8, OSCin=IHRCO

         CLK_SetCKCON2(ENABLE_IHRCO|MCK_CKMI_X8|OSCIn_IHRCO);

#endif

 

         // P60 Output MCK/4

         //CLK_P60OC_MCKDiv4();

}

 

 

 

 

Timer 2 설정

/***********************************************************************************

*Function:   void InitTimer2(void)

*Description:   Initialize Timer2 for 8bit PWM

*Input:   

*Output:    

*************************************************************************************/

void InitTimer2(void)

{

           TM_SetT2Mode_8bitPWM();                                                                   // T2 mode: 8bit PWM  

           TM_SetT2Clock_SYSCLKDiv12();                                                 // T2 clock source: SYSCLK/12

          

           TM_SetT2LowByte(T2_PWM_DUTY_10);                                        // T2 low byte (duty)                                 

           TM_SetT2RLLowByte(T2_PWM_DUTY_10);                                    // T2 low byte reload  (duty)

          

           TM_SetT2HighByte(256-T2_PWM_STEP_MAX);                              // T2 high byte           (freq) 

           TM_SetT2RLHighByte(256-T2_PWM_STEP_MAX);                           // T2 high byte           reload (freq)

          

           TM_EnableT2();                                                                                              // Enable T2

 

           //TM_EnableT2CKO_Invert();

           TM_SetT2CKOT2EX_P10P11();                                                               // Set T2CKO output to P11

           TM_DisT2CKO();                                                                                             // disable T2CKO output

}

- Timer 2 8Bit PWM모드로 설정

#define TM_SetT2Mode_8bitPWM()

CP_RL2=0;T2MOD=T2MOD&(~T2MS0);T2MOD=T2MOD|(T2SPL);SFRPI=1;T2MOD1=T2MOD1|T2MS1;SFRPI=0

T2SPL, T2MS1, CP/RL2, T2MS0 비트들을 이용해서 Timer 2의 모드를 설정한다. 본 예제에서는 8-bit PWM Mode로 설정된다.

- Timer 2용 클럭 설정

#define TM_SetT2Clock_SYSCLKDiv12()                 C_T2=0;T2MOD=T2MOD&(~T2X12);SFRPI=1;T2MOD1=T2MOD1&(~T2CKS);SFRPI=0

T2CKS, T2X12, C/T2 비트를 이용해서 Timer 2의 클럭을 설정한다. 본 예제에서는 SYSCLK/12Timer 2의 클럭으로 설정한다.

SYSCLK12MHz이므로 Timer2의 클럭은 1MHz이다. 그러므로 Timer 21us마다 카운트 된다.

 

- TL2 데이터 적재

TL2에 초기 데이터를 저장한다.

 

- PWM Step Max = 200

PWM count의 최대 값은 200으로 정한다.

 

- Duty 10의 데이터

#define T2_PWM_DUTY_10    ((256-T2_PWM_STEP_MAX)+(10*T2_PWM_STEP_MAX)/100)

위의 설정에 따라서 Duty 10은 이와 같이 계산된다.

0x0100에서 200을 빼고, 10%로 계산된 값을 더해 준다. 10%에 해당하는 값은 20이된다.

 

- Duty 30의 데이터

#define T2_PWM_DUTY_30    ((256-T2_PWM_STEP_MAX)+(30*T2_PWM_STEP_MAX)/100)

위의 설정에 따라서 Duty 30은 이와 같이 계산된다.

0x0100에서 200을 빼고, 30%로 계산된 값을 더해 준다. 30%에 해당하는 값은 60이된다.

 

- Duty 60의 데이터

#define T2_PWM_DUTY_60    ((256-T2_PWM_STEP_MAX)+(60*T2_PWM_STEP_MAX)/100)

위의 설정에 따라서 Duty 60은 이와 같이 계산된다.

0x0100에서 200을 빼고, 60%로 계산된 값을 더해 준다. 60%에 해당하는 값은 120이된다.

 

- Duty 80의 데이터

#define T2_PWM_DUTY_80    ((256-T2_PWM_STEP_MAX)+(80*T2_PWM_STEP_MAX)/100)

위의 설정에 따라서 Duty 80은 이와 같이 계산된다.

0x0100에서 200을 빼고, 80%로 계산된 값을 더해 준다. 80%에 해당하는 값은 160이된다.

 

- 주파수 설정을 위한 TH2 값 설정

TH2 값은 PWM의 주파수를 설정하도록 한다.

본 예제에서는 (0x256 – 200)의 값을 저장했으며, 이는 주기 200us5kHz 펄스를 만든다.

 

- T2 동작

#define TM_EnableT2()                              TR2=1

TR2를 셋 시켜서 Timer 2를 시작 시킨다.

 

- T2CKO 핀 할당

#define TM_SetT2CKOT2EX_P10P11()                    SFRPI=1;AUXR4=AUXR4&(~(T2PS1|T2PS0));SFRPI=0

SFR Page 1에만 존쟂하는 AUXR4 레지스터의 T2PS1, T2PS0 비트를 00으로 만들어 T2/T2CKO P1.0, T2EX P11에 할당한다.

 

- T2CKO Disable

#define TM_DisT2CKO()                                                  T2MOD=T2MOD&(~T2OE)

시스템 동작에서 제어하기 위하여 T2CKO를 우선 Disable 시켜둔다.

 

4. 프로그램 실행

*** Keil compiler가 인스톨되어 있어야함 ***

해당 Example 폴더를 찾아가 KeilPrj폴더를 Open 한다.

\Megawin 8051\(EN)MG82F6D16_SampleCode_v1.20\ MG82F6D16_TIM_T2_Mode4_PWM

 

 

 

 

해당 폴더의 Keil project 파일을 더블 클릭하여 실행시킨다.(MG82F6D16_DEMO.uvproj)

 

 

 

Rebuild 아이콘을 클릭하여 프로젝트를 컴파일 한다.

 

Demo BoardUSB Connector를 연결하여 전원을 인가하고, 전원 스위치를 ON시키고, OCD ICE를 연결한 상태에서 위 이미지의 Start/Stop Debug Session(Ctrl+F5) 버튼을 눌러 컴파일된 프로젝트의 디버그 데이터를 다운로드 시킨다.(컴파일 시 에러가 발생하지 않아야함)

 

다운로드 후 Run(F5) 버튼을 클릭하면 프로그램이 동작한다.

 

5. 동작 영상

https://youtu.be/izznMaPA7ts

 

반응형

'MEGAWIN' 카테고리의 다른 글

MG82F6D Series IAP Sample  (0) 2022.12.16
MG82F6D Series IAP LOOP  (0) 2022.12.15
MG82F6D Series I2C Slave Int  (0) 2022.12.09
MG82F6D시리즈 GPIO MODE  (0) 2022.12.08
MG82F6D Series ADC ROLL  (0) 2022.12.07