简介
PWM 是 Pulse Width Modulation 的缩写,它的中文名字是脉冲宽度调制,一种说法是它利用微处理器的数字输出来对模拟电路进行控制的一种有效的技术,其实就是使用数字信号达到一个模拟信号的效果。
本文使用输出比较模拟PWN输出。
具体实现
#include "hc32_ddl.h"
/* pwm Port/Pin definition */
#define KEY2_TRIGGER_EVENT (EVT_PORT_EIRQ3)
/* TIMERA unit and clock definition */
#define TIMERA_UNIT1 (M4_TMRA3)
#define TIMERA_UNIT1_CLOCK (PWC_FCG2_PERIPH_TIMA3)
#define TIMERA_UNIT1_OVERFLOW_INT (INT_TMRA3_OVF)
/* TIMERA channel 1 Port/Pin definition */
#define TIMERA_UNIT1_CH1 (TimeraCh1)
#define TIMERA_UNIT1_CH1_PORT (PortC)
#define TIMERA_UNIT1_CH1_PIN (Pin06)
#define TIMERA_UNIT1_CH1_FUNC (Func_Tima0)
#define TIMERA_COUNT_OVERFLOW (1953)
static void Port_Init(void)
{
uint8_t i;
stc_port_init_t stcPortInit;
/* configuration structure initialization */
MEM_ZERO_STRUCT(stcPortInit);
stcPortInit.enPinMode = Pin_Mode_Out;
stcPortInit.enPullUp = Disable;
stcPortInit.enExInt = Enable;
/* Initialize servo motor pin */
PORT_Init(PortC, Pin06, &stcPortInit);
PORT_ResetBits(PortC, Pin06);
}
static void TimeraUnit1_IrqCallback(void)
{
TIMERA_ClearFlag(TIMERA_UNIT1, TimeraFlagOverflow);
}
static void Tim_Config(void)
{
stc_timera_base_init_t stcTimeraInit;
stc_timera_compare_init_t stcTimerCompareInit;
stc_irq_regi_conf_t stcIrqRegiConf;
stc_timera_hw_startup_config_t stcTimeraHwConfig;
/* configuration structure initialization */
MEM_ZERO_STRUCT(stcTimeraInit);
MEM_ZERO_STRUCT(stcIrqRegiConf);
MEM_ZERO_STRUCT(stcTimerCompareInit);
MEM_ZERO_STRUCT(stcTimeraHwConfig);
/* Configuration peripheral clock */
PWC_Fcg2PeriphClockCmd(TIMERA_UNIT1_CLOCK, Enable);
/* Configuration TIMERA compare pin */
PORT_SetFunc(TIMERA_UNIT1_CH1_PORT, TIMERA_UNIT1_CH1_PIN, TIMERA_UNIT1_CH1_FUNC, Disable);
/* Configuration timera unit 1 base structure */
stcTimeraInit.enClkDiv = TimeraPclkDiv512; //100 000 000 /512
stcTimeraInit.enCntMode = TimeraCountModeTriangularWave;
stcTimeraInit.enCntDir = TimeraCountDirUp;
stcTimeraInit.enSyncStartupEn = Disable;
stcTimeraInit.u16PeriodVal = TIMERA_COUNT_OVERFLOW; // //freq: 50Hz -> 100 000 000 /512/50HZ/2 = 1953(period val)
TIMERA_BaseInit(TIMERA_UNIT1, &stcTimeraInit);
/* Configuration timera unit 1 compare structure */
stcTimerCompareInit.u16CompareVal = stcTimeraInit.u16PeriodVal/2; // 50%的占空比
stcTimerCompareInit.enStartCountOutput = TimeraCountStartOutputHigh;
stcTimerCompareInit.enStopCountOutput = TimeraCountStopOutputHigh;
stcTimerCompareInit.enCompareMatchOutput = TimeraCompareMatchOutputReverse;
stcTimerCompareInit.enPeriodMatchOutput = TimeraPeriodMatchOutputHigh;
stcTimerCompareInit.enSpecifyOutput = TimeraSpecifyOutputInvalid;
stcTimerCompareInit.enCacheEn = Disable;
stcTimerCompareInit.enTriangularTroughTransEn = Disable;
stcTimerCompareInit.enTriangularCrestTransEn = Disable;
stcTimerCompareInit.u16CompareCacheVal = stcTimerCompareInit.u16CompareVal;
/* Configure Channel 1 */
TIMERA_CompareInit(TIMERA_UNIT1, TIMERA_UNIT1_CH1, &stcTimerCompareInit);
TIMERA_CompareCmd(TIMERA_UNIT1, TIMERA_UNIT1_CH1, Enable);
/* Enable period count interrupt */
TIMERA_IrqCmd(TIMERA_UNIT1, TimeraIrqOverflow, Enable);
/* Interrupt of timera unit 1 */
stcIrqRegiConf.enIntSrc = TIMERA_UNIT1_OVERFLOW_INT;
stcIrqRegiConf.enIRQn = IRQ_INDEX_INT_TIMA_CH1;
stcIrqRegiConf.pfnCallback = &TimeraUnit1_IrqCallback;
enIrqRegistration(&stcIrqRegiConf);
NVIC_ClearPendingIRQ(stcIrqRegiConf.enIRQn);
NVIC_SetPriority(stcIrqRegiConf.enIRQn, DDL_IRQ_PRIORITY_DEFAULT);
NVIC_EnableIRQ(stcIrqRegiConf.enIRQn);
TIMERA_Cmd(TIMERA_UNIT1,Enable);
TIMERA_SetCompareValue( TIMERA_UNIT1,TIMERA_UNIT1_CH1, TIMERA_COUNT_OVERFLOW*0.1);
TIMERA_SpecifyOutputSta(TIMERA_UNIT1,TIMERA_UNIT1_CH1,TimeraSpecifyOutputInvalid);
}
void set_duty_cycle(uint16_t duty)
{
if(duty == 0)
{
TIMERA_SpecifyOutputSta(TIMERA_UNIT1, TIMERA_UNIT1_CH1, TimeraSpecifyOutputLow);
TIMERA_Cmd(TIMERA_UNIT1,Enable);
}
else if(duty >= TIMERA_COUNT_OVERFLOW)
{
TIMERA_SpecifyOutputSta(TIMERA_UNIT1, TIMERA_UNIT1_CH1, TimeraSpecifyOutputHigh);
TIMERA_Cmd(TIMERA_UNIT1,Enable);
}
else
{
stc_timera_compare_init_t stcTimerCompareInit;
MEM_ZERO_STRUCT(stcTimerCompareInit);
/* Configuration timera unit 1 compare structure */
stcTimerCompareInit.u16CompareVal = duty; //500
stcTimerCompareInit.enStartCountOutput = TimeraCountStartOutputHigh;
stcTimerCompareInit.enStopCountOutput = TimeraCountStopOutputHigh;
stcTimerCompareInit.enCompareMatchOutput = TimeraCompareMatchOutputReverse;
stcTimerCompareInit.enPeriodMatchOutput = TimeraPeriodMatchOutputHigh;
stcTimerCompareInit.enSpecifyOutput = TimeraSpecifyOutputInvalid;
stcTimerCompareInit.enCacheEn = Disable;
stcTimerCompareInit.enTriangularTroughTransEn = Disable;
stcTimerCompareInit.enTriangularCrestTransEn = Disable;
stcTimerCompareInit.u16CompareCacheVal = stcTimerCompareInit.u16CompareVal;
/* Configure Channel 1 */
TIMERA_CompareInit(TIMERA_UNIT1, TIMERA_UNIT1_CH1, &stcTimerCompareInit);
TIMERA_CompareCmd(TIMERA_UNIT1, TIMERA_UNIT1_CH1, Enable);
TIMERA_Cmd(TIMERA_UNIT1,Enable);
}
}
void set_steering_gear_dutyfactor(uint16_t dutyfactor)
{
/* 对超过范围的占空比进行边界处理 */
dutyfactor = 0.5/20.0*TIMERA_COUNT_OVERFLOW > dutyfactor ? 0.5/20.0*TIMERA_COUNT_OVERFLOW : dutyfactor;
dutyfactor = 2.5/20.0*TIMERA_COUNT_OVERFLOW < dutyfactor ? 2.5/20.0*TIMERA_COUNT_OVERFLOW : dutyfactor;
set_duty_cycle(dutyfactor);
}
void set_angle(uint16_t angle_temp)
{
angle_temp = (0.5 + angle_temp / 180.0 * (2.5 - 0.5)) / 20.0 * TIMERA_COUNT_OVERFLOW; // 计算角度对应的占空比
set_steering_gear_dutyfactor(angle_temp); // 设置占空比
}
void pwm_init()
{
Port_Init();
Tim_Config();
}