Nuvoton M031 ile
Sinyallerin RMS degerini hesaplama
RMS değeri, bir AC (alternatif akım) sinyalinin efektif değerini temsil eder. Alternatif akım, zaman içinde değişen bir sinyal olduğu için, genellikle pik değeri yerine RMS değeri kullanılır. RMS değeri, sinyalin gücünü temsil ettiği için, güç hesaplamalarında da önemli bir role sahiptir.
RMS hesaplamalarımızı, Nuvoton M031 mikrodenetleyicileri ile donatılmış olan Numaker-M031 geliştirme kartı kullanarak gerçekleştireceğiz. Nuvoton M031 mikrodenetleyicileri, Tayvan merkezli yarı iletken üreticisi Nuvoton Technology Corporation tarafından üretilmektedir ve ARM Cortex-M0 çekirdeğini içermektedir.
Videodaki RMS hesabı uygulamasında ADC interrupt 10kHz'de bir timer tarafından tetiklenmiştir. ADC interrupt içinde sürekli olarak bir adc okuması yapılıp okunan adc değerlerinin kareleri toplamı hesaplanmıştır. Okunan adc değerleri 200 adet olduğunda bir flag kaldırılarak main içinde RMS hesabına sokulmuştur.
Bu uygulamada 50 Hz'lik sinyaller için RMS değerlerinin hesaplandığı dikkate alınmalıdır.
Giriş sinyali Frekansı = Timer frekansı / Örneklem Sayısı
Giriş sinyali Frekansı = 10000 / 200
Giriş sinyali Frekansı = 50 Hz
Kodlardaki Önemli Kısımlar
Öncelikle Timer ile 10 kHz'de tetiklenen ADC interrupt frekansından emin olmak için PB5 pinini toggle edip osiloskopta gözlemledik.
Daha sonra her adc interrupt'a girdiğinde bir adc değeri okuduk ve okunan bu değerlerin karekök toplamlarını aldık. 200 örnekleme ulaştığımızda rmsFlag'i kaldırdık ve değerlerimizi işlemek için main içinde çağırılan RMS fonksiyonuna yolladık.
RMS fonksiyonu içinde adc interrupt'tan gelen adc değerlerinin kareleri toplamı alınan örneklem sayısına (200)' bölündükten sonra karekökü alınmıştır.
Arm Cortex M0 çekirdeği FPU içermediğinden dolayı karekök almak için fixed point ile 'sqrt_i32' fonksiyonu kullanılmıştır.
Ayrıca FPU olmadığından dolayı voltaj hesabında 3.3 yerine 330 kullanılmıştır. Seri mönitörde okunan değerler de bu ölçekte yorumlanmıştır.
Arm Cortex M0 ile gerçekleştirilen bu tarz uygulamalarda FPU olmadığı için fixed point aritmetiği kullanarak işlem yapmak hatayı en aza indirecektir. Bu uygulama için fixed point aritmetiği kullanılmamıştır.
Kodlar
#include #include "NuMicro.h" #include "fpsqrt.h" // var #define OFFSET 0 volatile uint32_t gAdcIntFlag = 0; volatile int32_t adcValue, adcCenterValue; uint8_t rmsFlag=0; long gsumOfProduct,gadcSampleCount,total,rms; // func proto void SYS_Init(); void TIMER0_Init(); void RMS_Value(); void UART0_Init(); void SYS_Init(){ SYS_UnlockReg(); //--------------------------Clock Config------------------------------------------ CLK_EnableXtalRC(CLK_PWRCTL_HIRCEN_Msk); CLK_WaitClockReady(CLK_STATUS_HIRCSTB_Msk); CLK_SetHCLK(CLK_CLKSEL0_HCLKSEL_HIRC, CLK_CLKDIV0_HCLK(1)); CLK->PCLKDIV = (CLK_PCLKDIV_APB0DIV_DIV2 | CLK_PCLKDIV_APB1DIV_DIV2); //-------------------------------------------------------------------------------- //--------------------------UART Clock Config------------------------------------------ CLK_SetModuleClock(UART0_MODULE, CLK_CLKSEL1_UART0SEL_HIRC, CLK_CLKDIV0_UART0(1)); CLK_EnableModuleClock(UART0_MODULE); //------------------------------------------------------------------------------------- //--------------------------ADC Clock Config------------------------------------------ CLK_EnableModuleClock(ADC_MODULE); CLK_SetModuleClock(ADC_MODULE, CLK_CLKSEL2_ADCSEL_PCLK1, CLK_CLKDIV0_ADC(1)); //-------------------------------------------------------------------------------- //--------------------------Timer Clock Config------------------------------------------ CLK_EnableModuleClock(TMR0_MODULE); CLK_SetModuleClock(TMR0_MODULE, CLK_CLKSEL1_TMR0SEL_HIRC, 0); //-------------------------------------------------------------------------------- SystemCoreClockUpdate(); //--------------------------GPIO Config------------------------------------------ SYS->GPB_MFPH = (SYS->GPB_MFPH & ~(SYS_GPB_MFPH_PB12MFP_Msk | SYS_GPB_MFPH_PB13MFP_Msk)) | (SYS_GPB_MFPH_PB12MFP_UART0_RXD | SYS_GPB_MFPH_PB13MFP_UART0_TXD); GPIO_SetMode(PB, BIT2|BIT3, GPIO_MODE_INPUT); GPIO_SetMode(PB, BIT5, GPIO_MODE_OUTPUT); SYS->GPB_MFPL = (SYS->GPB_MFPL & ~(SYS_GPB_MFPL_PB2MFP_Msk | SYS_GPB_MFPL_PB3MFP_Msk)) | (SYS_GPB_MFPL_PB2MFP_ADC0_CH2 | SYS_GPB_MFPL_PB3MFP_ADC0_CH3); GPIO_DISABLE_DIGITAL_PATH(PB, BIT2|BIT3); //-------------------------------------------------------------------------------- SYS_LockReg(); } void TIMER0_Init(){ TIMER_Open(TIMER0, TIMER_PERIODIC_MODE, 10000); // timer 0 -> 10kHz TIMER_SetTriggerSource(TIMER0, TIMER_TRGSRC_TIMEOUT_EVENT); // timer 0 trig-> adc_ch2 TIMER_SetTriggerTarget(TIMER0, TIMER_TRG_TO_ADC); } void RMS_Value(){ ADC_POWER_ON(ADC); while(1) { //--------------------------ADC INT Config------------------------------------------ ADC_Open(ADC, ADC_ADCR_DIFFEN_SINGLE_END, ADC_ADCR_ADMD_SINGLE, BIT2); ADC_EnableHWTrigger(ADC, ADC_ADCR_TRGS_TIMER, 0); ADC_CLR_INT_FLAG(ADC, ADC_ADF_INT); ADC_ENABLE_INT(ADC, ADC_ADF_INT); NVIC_EnableIRQ(ADC_IRQn); //-------------------------------------------------------------------------------- gAdcIntFlag = 0; TIMER_Start(TIMER0); while(1) { while(gAdcIntFlag == 0); // wait adc interrupt gAdcIntFlag = 0; printf(" adcValue : %d \n \t", adcValue); printf(" adcCenterValue : %d \n \t", adcCenterValue); if(rmsFlag == 1){ rmsFlag = 0; total = gsumOfProduct/ gadcSampleCount; rms = (sqrt_i32(total))*330>>12; printf(" gadcSampleCount : %d \n \t", gadcSampleCount); printf(" gsumOfProduct : %d \n \t", gsumOfProduct); printf(" rms : %ld \n \t", rms); gadcSampleCount =0; gsumOfProduct =0; total =0; rms=0; } } TIMER_Stop(TIMER0); ADC_DISABLE_INT(ADC, ADC_ADF_INT); } } void ADC_IRQHandler(void) { static long sumOfProduct; static uint32_t adcSampleCount; PB5^=1; // interrupt hiz kontrol adcValue = ADC_GET_CONVERSION_DATA(ADC,2); adcCenterValue = adcValue - OFFSET; sumOfProduct += adcCenterValue * adcCenterValue; adcSampleCount++; if(adcCenterValue >= 0 && adcSampleCount>=200){ rmsFlag = 1; gsumOfProduct = sumOfProduct; gadcSampleCount = adcSampleCount; adcSampleCount = 0; sumOfProduct=0; } ADC_CLR_INT_FLAG(ADC, ADC_ADF_INT); //clear adc int flag gAdcIntFlag = 1; } void UART0_Init(){ SYS_ResetModule(UART0_RST); UART_Open(UART0, 115200); } int32_t main(void){ SYS_Init(); UART0_Init(); TIMER0_Init(); printf("\nSystem clock rate: %d Hz", SystemCoreClock); RMS_Value(); CLK_DisableModuleClock(TMR0_MODULE); CLK_DisableModuleClock(ADC_MODULE); NVIC_DisableIRQ(ADC_IRQn); while(1); }