代码使用官方库2.2.0版本的timera_triangular_wave_compare_output
例程修改而来。
总结写在前面,要注意的点:
1、周期计数值PeriodVal最大值是65535,注意不要溢出,配合分频系数可以灵活改动输出PWM的频率。
2、输出PWM建议使用锯齿波,并配置周期匹配和比较匹配时输出确定的高/低电平,而不是像官方例程里那样反转电平,看了别人博客说有问题自己也试过了,确实有问题= =。
3、配置项里那个Func_Tima0/1/2使我困惑了很久(宏定义里配置的),搜帮助文档也没搜出什么名堂,后来发现可能是对应数据手册2.2引脚功能表的Func4/5/6
比如要使用上图PE2引脚输出PWM,就是TIMA-UNIT3-CH5,对应Func_Tima0
(不确定是不是对的,没试过)
头文件宏定义相关
/*******************************************************************************
* Local pre-processor symbols/macros ('#define')
******************************************************************************/
/* TIMERA unit and clock definition */
#define TIMERA_UNIT3 (M4_TMRA3)
#define TIMERA_UNIT3_CLOCK (PWC_FCG2_PERIPH_TIMA3)
#define TIMERA_UNIT3_OVERFLOW_INT (INT_TMRA3_OVF)
/* TIMERA channel 1 Port/Pin definition */
#define TIMERA_UNIT3_CH5 (TimeraCh5)
#define TIMERA_UNIT3_CH5_PORT (PortA)
#define TIMERA_UNIT3_CH5_PIN (Pin04)
#define TIMERA_UNIT3_CH5_FUNC (Func_Tima1)
#define TIMERA_COUNT_OVERFLOW (SystemCoreClock/2U/256U/10U) //10hz 计数值最大65535
代码如下
static uint8_t u8TmraUnit3Cnt;
static uint8_t m_NowDuty; // 当前PWM占空比
/**
*******************************************************************************
** \brief Configure Timera peripheral function
**
** \param [in] None
**
** \retval None
**
******************************************************************************/
static void Timera_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;
stc_port_init_t stcPortInit;
/* configuration structure initialization */
MEM_ZERO_STRUCT(stcTimeraInit);
MEM_ZERO_STRUCT(stcIrqRegiConf);
MEM_ZERO_STRUCT(stcTimerCompareInit);
MEM_ZERO_STRUCT(stcTimeraHwConfig);
MEM_ZERO_STRUCT(stcPortInit);
/* Configuration peripheral clock */
PWC_Fcg2PeriphClockCmd(TIMERA_UNIT3_CLOCK, Enable);
/* Configuration TIMERA compare pin */
PORT_SetFunc(TIMERA_UNIT3_CH5_PORT, TIMERA_UNIT3_CH5_PIN, TIMERA_UNIT3_CH5_FUNC, Disable);
/* Configuration timera unit 2 base structure */
stcTimeraInit.enClkDiv = TimeraPclkDiv256; // 时钟源 PCLK1分频 100M/128
stcTimeraInit.enCntMode = TimeraCountModeSawtoothWave; // 锯齿波 原为三角波TimeraCountModeTriangularWave
stcTimeraInit.enCntDir = TimeraCountDirUp; // 向上计数
stcTimeraInit.enSyncStartupEn = Disable; // 关闭同步
stcTimeraInit.u16PeriodVal = TIMERA_COUNT_OVERFLOW; // 10Hz
TIMERA_BaseInit(TIMERA_UNIT3, &stcTimeraInit);
/* Configuration timera unit 2 compare structure */
stcTimerCompareInit.u16CompareVal = stcTimeraInit.u16PeriodVal * 4u / 5u; // 占空比20
stcTimerCompareInit.enStartCountOutput = TimeraCountStartOutputLow; // 计数开始时输出低电平
stcTimerCompareInit.enStopCountOutput = TimeraCountStopOutputLow; // 计数停止时输出低电平
stcTimerCompareInit.enCompareMatchOutput = TimeraCompareMatchOutputHigh; // 比较匹配时输出高电平(不要反转!)
stcTimerCompareInit.enPeriodMatchOutput = TimeraPeriodMatchOutputLow; // 周期匹配时输出低电平(不要反转!)
stcTimerCompareInit.enSpecifyOutput = TimeraSpecifyOutputInvalid; // 强制端口状态设定无效
// stcTimerCompareInit.enCacheEn = Enable; //
// stcTimerCompareInit.enTriangularTroughTransEn = Enable; //
// stcTimerCompareInit.enTriangularCrestTransEn = Disable; //
// stcTimerCompareInit.u16CompareCacheVal = stcTimerCompareInit.u16CompareVal; // 比较缓存值
/* Configure Channel 2 */
TIMERA_CompareInit(TIMERA_UNIT3, TIMERA_UNIT3_CH5, &stcTimerCompareInit); // 初始化定时器比较功能
TIMERA_CompareCmd(TIMERA_UNIT3, TIMERA_UNIT3_CH5, Enable); // 使能定时器比较功能
/* Enable period count interrupt */
TIMERA_IrqCmd(TIMERA_UNIT3, TimeraIrqOverflow, Enable); // 中断使能
/* Interrupt of timera unit 2 */
stcIrqRegiConf.enIntSrc = TIMERA_UNIT3_OVERFLOW_INT;
stcIrqRegiConf.enIRQn = Int013_IRQn;
stcIrqRegiConf.pfnCallback = &TimeraUnit3_IrqCallback; // 计时周期匹配中断
enIrqRegistration(&stcIrqRegiConf);
NVIC_ClearPendingIRQ(stcIrqRegiConf.enIRQn);
NVIC_SetPriority(stcIrqRegiConf.enIRQn, DDL_IRQ_PRIORITY_DEFAULT);
NVIC_EnableIRQ(stcIrqRegiConf.enIRQn);
TIMERA_Cmd(TIMERA_UNIT3, Enable); // 使能启动定时器A
}
// 周期匹配中断回调
static void TimeraUnit3_IrqCallback(void)
{
u8TmraUnit3Cnt++;
if(u8TmraUnit3Cnt >= 20u) //2s
{
PWM_ChangeDuty(m_NowDuty+20);
u8TmraUnit3Cnt = 0u;
}
TIMERA_ClearFlag(TIMERA_UNIT3, TimeraFlagOverflow);
}
/** 修改PWM占空比
*******************************************************************************
** \brief Timera unit2 CH2 change PWM Duty Ratio
**
** \param [in] NewDuty 要修改的占空比百分比数值,范围0-100
**
** \retval None
**
******************************************************************************/
void PWM_ChangeDuty(uint8_t NewDuty)
{
uint16_t u16TimerPeriod = 0u, u16DutyCycle = 0u;
u16DutyCycle = TIMERA_GetCompareValue(TIMERA_UNIT3, TIMERA_UNIT3_CH5); // 比较值
u16TimerPeriod = TIMERA_GetPeriodValue(TIMERA_UNIT3); // 计数周期值
if (NewDuty > 100)
{
NewDuty = 0u;
}
u16DutyCycle = u16TimerPeriod *(100-NewDuty)/100;
TIMERA_SetCompareValue(TIMERA_UNIT3, TIMERA_UNIT3_CH5, u16DutyCycle); // 设置比较值
m_NowDuty = NewDuty;
}
一些关于代码的说明:
TIMA时钟源是PCLK1,官方例程里系统时钟是200MHz(SystemCoreClock),PCLK1分频系数为2,既PLCK1=100MHZ。
代码的结果是每隔2秒钟输出的占空比会增加20%,增加到100%后变回0%(输出的PWM占空比含100和0)。
参考博客
TimerA输出可调占空比PWM——华大HC32F460
HC32f460 如何动态改pwm的占空比
关于HC32F460 输出可调占空比PWM波遇到的问题记录
【技术问答】hc32f460系列输出可调占空比的PWM波
【HC32F448测评】+用高级定时器6输出PWM