/**************************************************************************** * @file main.c * @version V3.0err * $Revision: 4 $ * $Date: 17/05/04 12:57p $ * @brief Perform A/D Conversion with ADC continuous scan mode. * @note * Copyright (C) 2016 Nuvoton Technology Corp. All rights reserved. * ******************************************************************************/ #include #include #include #include "M0564.h" #include "define.h" #define INTERRUPT // dead time unit = 1/72us // ex. dead time 72 = 1us, 36 = 0.5us, 18=0.25us // ex. dead time 2 = 2/72 us, 3 = 3/72us, 4=4/72us #define DEAD_ZONE_01 2 // unit=1/72us, PWM0.0 PWM0.1 Dead time #define DEAD_ZONE_23 3 // unit=1/72us, PWM0.2 PWM0.3 Dead time #define DEAD_ZONE_45 4 // unit=1/72us, PWM0.4 PWM0.5 Dead time int Sync = 0; volatile int Positve = -1, DetectPeriodP, DetectPeriodN; int StableCnt; volatile int err; // phase angle, pwm freq in KHZ const unsigned int FREQ_TBL[][2] = { {30, 60}, {50, 80}, {70, 100}, {90, 150}, {110, 150}, {130, 100}, {150, 80}, {180, 60}, {210, 60}, {230, 80}, {250, 100}, {270, 150}, {290, 150}, {310, 100}, {330, 80}, {360, 60}}; unsigned int Period_tbl[361]; /** * @brief ACMP01 IRQ * * @param None * * @return None * * @details The ACMP01 default IRQ, declared in startup_M0564.s. */ extern "C" { void ACMP01_IRQHandler(void) { if(ACMP_GET_INT_FLAG(ACMP01, 1)) { ACMP_CLR_INT_FLAG(ACMP01, 1); // clear interrupt flag int T = TIMER_GetCounter(TIMER0); // get timer0 counter if(TIMER0->CTL & TIMER_CTL_CNTEN_Msk) { if(T < NOISE) return; // noise. skip } else { //StableCnt = 0; //Positve = -1; } TIMER_Stop(TIMER0); // stop timer0 TIMER_ClearIntFlag(TIMER0); // clear timer0 flag TIMER0->CNT = 0; // set timer0 cnt to 0 TIMER_Start(TIMER0); // start timer0 if(HZ_50U < T || T < HZ_60L) { // not in range Positve = -1; StableCnt = 0; err = 1; } else { if(StableCnt < STABLE_CNT) { // wait until stable StableCnt++; } else { if(ACMP_GET_OUTPUT(ACMP01, 1)) { // N > L Positve = 1; // positve DetectPeriodN = T; // yes, Save period } else { // L <= N Positve = 0; // positve DetectPeriodP = T; // yes, Save period } } } } } void TMR2_IRQHandler(void) { TIMER_ClearIntFlag(TIMER2); // clear interrupt flag PWM_Func(); } } /*---------------------------------------------------------------------------------------------------------*/ /* Init TABLE */ /*---------------------------------------------------------------------------------------------------------*/ void TABLE_Init() { for(int i = 0, j = 0 ; i < 361 ; i++) { if(i > FREQ_TBL[j][0]) { j++; } Period_tbl[i] = (BASE_CLOCK/1000 + (FREQ_TBL[j][1]/2))/FREQ_TBL[j][1] - 1; } } /*---------------------------------------------------------------------------------------------------------*/ /* WM callback */ /*---------------------------------------------------------------------------------------------------------*/ void PWM_Func() { int currState, T, PeriodN, PeriodP; do { // Get Curr State, Period and time currState = Positve; T = TIMER_GetCounter(TIMER0); PeriodN = DetectPeriodN; PeriodP = DetectPeriodP; } while(currState != Positve); // ACMP interrupt occurs ? if(currState < 0) { // Unrecognized signal? ComplementaryPWM0(0, 0); // Turn off PWM ComplementaryPWM0(2, 0); // Turn off PWM ComplementaryPWM0(4, 0); // Turn off PWM } else if(TIMER_GetIntFlag(TIMER0)) { // Unrecognized signal? Positve = -1; StableCnt = 0; ComplementaryPWM0(0, 0); // Turn off PWM ComplementaryPWM0(2, 0); // Turn off PWM ComplementaryPWM0(4, 0); // Turn off PWM } else { Sync = SYNC_LOST_TIME; int Angle; if(currState == 0) { // negative wave if(T >= PeriodN) { // over 360? Angle = 359; } else { Angle = 180 + 180*T/PeriodN; // calculate angle } } else { if(T >= PeriodP) { // over 180? Angle = 179; } else { Angle = 180*T/PeriodP; // calculate angle } } #ifdef DEBUG_IO const int N = 13; if(Angle >= FREQ_TBL[N][0] && Angle <= FREQ_TBL[N+1][0]) { PC0 = 1; } else { PC0 = 0; } // set output pwm #else int T = Period_tbl[Angle]; // get output freq ComplementaryPWM0(0, T); // output pwm ComplementaryPWM0(2, T); // output pwm ComplementaryPWM0(4, T); // output pwm #endif } } /*---------------------------------------------------------------------------------------------------------*/ /* UART function */ /*---------------------------------------------------------------------------------------------------------*/ void UART_Func() { int P1, P2; int Func = UART_Command(P1, P2); if(Func) {// command is received? switch(Func) { case 'v': // read v print("%d\r\n", ADC_GET_CONVERSION_DATA(ADC, P1)); break; case 'f': // read f case 't': // read t break; case 'F': // write F PWM(P1, P2>>1, P2); break; case 'T': // write T case 'V': // write V case 'a': // left case 'w': // up case 'd': // right case 'x': // down case ' ': // space print("NA\r\n"); break; } } } /*---------------------------------------------------------------------------------------------------------*/ /* BUTTON function */ /*---------------------------------------------------------------------------------------------------------*/ void BUTTON_Func() { if(Sync) { Sync--; } static int t; if(++t >= BLINK_TIME) { t = 0; if(Sync) SEG_DP = 0; // if signal is valid, blink DP LED = 0; if(err) {// if signal is unrecognized, display number counting err = 0; static unsigned char disp_num; if(++disp_num < '0' || disp_num > '9') disp_num = '0'; Display(disp_num); } } else { SEG_DP = 1; LED = 1; } static unsigned int pressed = 0, deboounce_cnt; if(pressed) { if(!UP || !DOWN || !LEFT || !RIGHT) { // key is not released deboounce_cnt = DEBOUNCE_TIME; } else if(--deboounce_cnt == 0) { pressed = 0; } } else if(!UP) {// UP is pressed pressed = 1; deboounce_cnt = DEBOUNCE_TIME; } else if(!DOWN) {// DOWN is pressed pressed = 1; deboounce_cnt = DEBOUNCE_TIME; } else if(!LEFT) {// LEFT is pressed pressed = 1; deboounce_cnt = DEBOUNCE_TIME; } else if(!RIGHT) {// RIGHT is pressed pressed = 1; deboounce_cnt = DEBOUNCE_TIME; } } /*---------------------------------------------------------------------------------------------------------*/ /* MAIN function */ /*---------------------------------------------------------------------------------------------------------*/ int main(void) { /* Unlock protected registers */ SYS_UnlockReg(); /* Init System, IP clock and multi-function I/O */ SYS_Init(); /* Lock protected registers */ SYS_LockReg(); /* Init TABLE */ TABLE_Init(); // Display 8 Display('8'); /* Init TIMER0 */ TIMER0_Init(); /* Init TIMER1 */ TIMER1_Init(); /* Set Pwm mode as complementary mode */ PWM_ENABLE_COMPLEMENTARY_MODE(PWM0); // Initial PWM PWM_Init(); // Set PWM0.0 PWM0.1 Dead time SetPWM0DeadZone(0, DEAD_ZONE_01); // Set PWM0.2 PWM0.3 Dead time SetPWM0DeadZone(2, DEAD_ZONE_23); // Set PWM0.4 PWM0.5 Dead time SetPWM0DeadZone(4, DEAD_ZONE_45); // Initial ADC ADC_Init(); /* Init UART1 */ UART1_Init(); // Delay 0.5 sec TIMER1_Delay(500000); // Display 0 Display('0'); /* Init ACMP */ ACMP_Init(); /* Enable ACMP01 interrupt */ NVIC_EnableIRQ(ACMP01_IRQn); #ifdef INTERRUPT /* Init TIMER2 */ TIMER2_Init(); #endif while(1) { #ifndef INTERRUPT PWM_Func(); #endif UART_Func(); if(TIMER_GetIntFlag(TIMER1)) { // timer1 elapsed? TIMER_ClearIntFlag(TIMER1); // clear timer1 flags if(Shutdown == 0) { BUTTON_Func(); } if(SHUTDOWN_MODE_CHANGED() != 0) { if(Shutdown) { /* Enable TIMER2 interrupt */ NVIC_DisableIRQ(TMR2_IRQn); TIMER_ClearIntFlag(TIMER2); NVIC_DisableIRQ(ACMP01_IRQn); TIMER_Stop(TIMER0); // stop timer0 TIMER_ClearIntFlag(TIMER0); // clear timer0 flag Positve = -1; StableCnt = 0; ComplementaryPWM0(0, 0); // Turn off PWM ComplementaryPWM0(2, 0); // Turn off PWM ComplementaryPWM0(4, 0); // Turn off PWM Display('E'); } else { Display('0'); TIMER_Stop(TIMER0); // stop timer0 TIMER_ClearIntFlag(TIMER0); // clear timer0 flag NVIC_EnableIRQ(ACMP01_IRQn); TIMER_ClearIntFlag(TIMER2); /* Enable TIMER2 interrupt */ NVIC_EnableIRQ(TMR2_IRQn); } } } } } /*** (C) COPYRIGHT 2016 Nuvoton Technology Corp. ***/