/**************************************************************************//**
* [url=home.php?mod=space&uid=288409]@file[/url] main.c
* [url=home.php?mod=space&uid=895143]@version[/url] V1.00
* [url=home.php?mod=space&uid=247401]@brief[/url] This example code uses MS51 PWM to output 10 KHz waveform with 0~100% duty according to 0~3V ADC conversion.
*
* SPDX-License-Identifier: Apache-2.0
* [url=home.php?mod=space&uid=17282]@CopyRight[/url] (C) 2022 Nuvoton Technology Corp. All rights reserved.
*****************************************************************************/
#include "MS51_8K.h"
/*---------------------------------------------------------------------------------------------------------*/
/* Define */
/*---------------------------------------------------------------------------------------------------------*/
/* main-loop switch-case state */
#define IDLE_STATE 0
#define ADC_UPDATE_STATE 1
/**
* PWM frequency = FPWM / {(PWM0PH, PWM0PL) + 1}
* 10kHz = 24MHz / {(PWM0PH, PWM0PL) + 1}
* (PWM0PH, PWM0PL) = 2399(0x95F)
*/
#define PWM_FREQ 0x95F
#define ROUNDING(x) (2x-(int)(x))
/*---------------------------------------------------------------------------------------------------------*/
/* Global variables */
/*---------------------------------------------------------------------------------------------------------*/
bit g_bADC_Flag = 0;
unsigned int xdata u32_ADCdataAIN;
double i64_ADCdataConvert;
/*---------------------------------------------------------------------------------------------------------*/
/* Functions */
/*---------------------------------------------------------------------------------------------------------*/
/**
* @brief ADC interrupt service routine
*
* @param[in] None
*
* [url=home.php?mod=space&uid=266161]@return[/url] None
*
* [url=home.php?mod=space&uid=1543424]@Details[/url] Get ADC conversion result.
*/
void ADC_ISR(void) interrupt 11
{
_push_(SFRS);
clr_ADCCON0_ADCF;//Clear ADC interrupt flag
u32_ADCdataAIN = ADCRH << 4;
u32_ADCdataAIN |= ADCRL;
g_bADC_Flag = 1;
_pop_(SFRS);
}
/**
* @brief Initialize the PWM module with specified configurations. It could be clock source, PWM channel and frequency.
* The default duty cycle is 50%.
*
* @param[in] None
*
* @return None
*
* @details None
*/
void PWM0_Init(void)
{
/* Define PWM0 clock source and divider. */
PWM0_ClockSource(PWM_FSYS, 1);
/* Setting PWM0 channel 2 */
ENABLE_PWM0_CH2_P10_OUTPUT;
P10_PUSHPULL_MODE;
PWM0_ConfigOutputChannel(2, Independent, EdgeAligned, PWM_FREQ, 50);
PWM0_RUN();
}
/**
* @brief Update PWM duty cycle.
*
* @param[in] u16PWM0Duty Set PWM default duty cycle. The range is 0%~100%
*
* @return None
*
* @details The formula is:
* PWM duty cycle = PWM duty register / (PWM period register + 1)
* -> PWM duty register = PWM duty cycle * (PWM period register + 1)
*/
void PWM0_Reload(unsigned int u16PWM0Duty)
{
/* Reload PWM duty */
unsigned int u16PWM0DutyCycleTemp = 0;
u16PWM0DutyCycleTemp = ((PWM_FREQ + 1) / 100) * u16PWM0Duty;
PWM2H = u16PWM0DutyCycleTemp >> 8;
PWM2L = u16PWM0DutyCycleTemp;
set_PWMCON0_LOAD;
}
/**
* @brief Initialize the ADC module with specified configurations and start ADC convert.
*
* @param[in] None
*
* @return None
*
* @details None
*/
void ADC_Convert(void)
{
/*Enable channel 5 */
ENABLE_ADC_CH5;
ADCCON1 |= 0x30; /* clock divider */
ADCCON2 |= 0x0E; /* AQT time */
AUXR1 |= SET_BIT4; /* ADC clock low speed */
clr_ADCCON0_ADCF;
set_ADCCON0_ADCS;
/* Enable ADC interrupt */
set_IE_EADC;
}
void main(void)
{
unsigned char state = IDLE_STATE;
/* FSYS = 24MHz */
MODIFY_HIRC(HIRC_24);
PWM0_Init();
ENABLE_GLOBAL_INTERRUPT;
while (1)
{
switch (state)
{
case IDLE_STATE:
default:
/* Enable channel 5 */
ADC_Convert();
state = ADC_UPDATE_STATE;
break;
case ADC_UPDATE_STATE:
if (g_bADC_Flag == 1)
{
g_bADC_Flag = 0;
i64_ADCdataConvert = u32_ADCdataAIN;
i64_ADCdataConvert = i64_ADCdataConvert * 100 / 4095;
/* Integer value */
i64_ADCdataConvert = (2 * i64_ADCdataConvert - (int)(i64_ADCdataConvert));
PWM0_Reload((unsigned int)i64_ADCdataConvert);
DISABLE_ADC;
state = IDLE_STATE;
}
break;
}
}
}
代码主要包含以下几个部分:
定义和全局变量部分:定义了一些常量和全局变量,包括状态定义、PWM频率、ADC数据等。
ADC_ISR函数:这是ADC的中断服务函数,当ADC转换完成时会触发该中断,将转换结果存储在全局变量中。
PWM0_Init函数:用于初始化PWM模块,设置PWM时钟源、频率和输出通道。
PWM0_Reload函数:根据给定的占空比参数,重新加载PWM的占空比。
ADC_Convert函数:初始化ADC模块,并启动ADC转换。
main函数:主函数中包含一个状态机,通过状态机控制程序的执行流程。在IDLE_STATE下启动ADC转换,并切换到ADC_UPDATE_STATE状态。在ADC_UPDATE_STATE下,当ADC转换完成时,计算并转换ADC数据为占空比,然后重新加载PWM的占空比,并切换回IDLE_STATE状态。
总体来说,这段代码的作用是通过ADC输入控制PWM输出的占空比,实现根据模拟输入电压调节PWM波形的功能。
|