合泰单片机 | HT66F3195 | 个人库开发过程 | 【10】定时器

定时器区别

一开始我以为三个不同的定时器模块区别很大,后来粗略对比了一下发现,其实大部分内容是一样的。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
从这几个图来看的话,主要能看到区别是CCRA和CCRP的位数。我对比了一下不同计时器的工作模式,发现居然没有那个输入捕获功能,我记得这个功能虽然用的少,但是应该都有这个功能才对?可能真的不常用所以就砍掉了。
我个人对那个比较匹配输出的模式没有什么好感🤬比较匹配输出可能是跟定时计数模式时一样的,不过前者带一个硬件输出接口,还有其他不同的吗?

在这里插入图片描述
另外一个比较大的区别就是,STM是有单独一个中断向量的,算是吧。但是PTM和CTM要公用一个中断向量。
而且PTM没有那个选择CCRA和CCRP哪个作为占空比和哪个作为周期的寄存器,数据手册显示的是未定义。

注意事项

在这里插入图片描述
具体也没有看太明白,主要了解一个点就是,写CCRA和CCRP的值先写低位再写高位。
读的话,先读高位再读低位,但是这个值个人觉得读取意义并不大。

在这里插入图片描述
意思应该是比较器P是不能控制到定时器的输出口,而且CCRA的溢出周期也不能设置成0。

定时器属性

HT66F3195的定时器模块并不算太复杂,如果只是简单用定时功能带中断的话,需要配置的内容直接少了一半。因为很多配置都是针对那些输出控制的。
大概汇总一下需要配置的一些寄存器:

  • 模块使能
  • 模块中断使能
  • 多功能中断使能
  • 定时器工作模式
  • 定时器时钟源
  • 定时器触发引脚功能
  • 定时器初始输出控制
  • 定时器输出极性
  • PWM模式下占空比周期选择
  • 比较器选择
  • 比较器溢出周期

也不是很多吧,具体就不介绍了,看看后续有没有特殊应用案例可以仔细讲讲,个人觉得定时器模块预留了太多的功能,以至于有些寄存器配置的说明我都没有想到是哪些时候能用得上的。

#ifndef	_TM_H_
#define	_TM_H_


/*-------------------函数声明------------------- */
void CTM_Init(void);


/*-------------------宏定义封装------------------- */
#define	CTM_Cmd(x)					_cton = x
#define STM_Cmd(x)					_ston = x
#define PTM_Cmd(x)					_pton = x


#define	CTM_A_FlagReset()			_ctmaf = 0
#define	CTM_P_FlagReset()			_ctmpf = 0

#define	STM_A_FlagReset()			_stmaf = 0
#define	STM_P_FlagReset()			_stmpf = 0

#define	PTM_A_FlagReset()			_ptmaf = 0
#define	PTM_P_FlagReset()			_ptmpf = 0

#define	CTM_A_InterruptCmd(x)		_ctmae = x
#define	CTM_P_InterruptCmd(x)		_ctmpe = x

#define	STM_A_InterruptCmd(x)		_stmae = x
#define	STM_P_InterruptCmd(x)		_stmpe = x

#define	PTM_A_InterruptCmd(x)		_ptmae = x
#define	PTM_P_InterruptCmd(x)		_ptmpe = x


#define	CTM_Clock(x)				_ctmc0 = (_ctmc0&(~(REG_3_BIT<<4)))|(x<<4)
#define	STM_Clock(x)				_stmc0 = (_stmc0&(~(REG_3_BIT<<4)))|(x<<4)
#define	PTM_Clock(x)				_ptmc0 = (_ptmc0&(~(REG_3_BIT<<4)))|(x<<4)
/* 时钟选择 */
typedef enum
{
	TM_Clock_Fsys_Div4 = 0,
	TM_Clock_Fsys,
	TM_Clock_Fh_Div16,
	TM_Clock_Fh_Div64,
	TM_Clock_Fsub,
	TM_Clock_xTCK_Rise = 6,
	TM_Clock_xTCK_Fall,

}TM_Clock_T;


#define	CTM_Mode(x)					_ctmc1 = (_ctmc1&(~(REG_2_BIT<<6)))|(x<<6)
#define	STM_Mode(x)					_stmc1 = (_stmc1&(~(REG_2_BIT<<6)))|(x<<6)
#define	PTM_Mode(x)					_ptmc1 = (_ptmc1&(~(REG_2_BIT<<6)))|(x<<6)
/* 工作模式 */
typedef enum
{
	TM_Mode_CompareOutput = 0,
	TM_Mode_Null,
	TM_Mode_PWM,
	TM_Mode_Counter,

}TM_Mode_T;


#define	CTM_Output_Mode(x)			_ctmc1 = (_ctmc1&(~(REG_2_BIT<<4)))|(x<<4)
#define	STM_Output_Mode(x)			_stmc1 = (_stmc1&(~(REG_2_BIT<<4)))|(x<<4)
#define	PTM_Output_Mode(x)			_ptmc1 = (_ptmc1&(~(REG_2_BIT<<4)))|(x<<4)
/* 输出功能 */
typedef enum
{
	TM_Output_Mode1 = 0,
	TM_Output_Mode2,
	TM_Output_Mode3,
	TM_Output_Mode4,

}TM_Output_Mode_T;
/*
比较匹配输出模式
00:无变化
01:输出低
10:输出高
11:输出翻转

PWM 输出模式
00:强制无效状态
01:强制有效状态
10:PWM 输出
11:未定义
*/


#define	CTM_Output_Control(x)			_ctoc = x
#define	STM_Output_Control(x)			_stoc = x
#define	PTM_Output_Control(x)			_ptoc = x
/* 输出控制 */
typedef enum
{
	TM_Output_Low = 0,
	TM_Output_High,

}TM_Output_Control_T;
/*
比较匹配输出模式
0: 初始低
1: 初始高

PWM 输出模式
0: 低有效
1: 高有效
*/


#define	CTM_Output_Polarity(x)			_ctpol = x
#define	STM_Output_Polarity(x)			_stpol = x
#define	PTM_Output_Polarity(x)			_ptpol = x
/* 输出同相反相 */
typedef enum 
{
	TM_Polarity_Inphase = 0,
	TM_Polarity_Outphase,

}TM_Output_Polarity_T;


#define	CTM_Duty_Period(x)				_ctdpx = x
#define	STM_Duty_Period(x)				_stdpx = x
/* PTM 貌似没有预留这个位 */
/* 占空比周期选择 */
typedef enum
{
	TM_A_Duty_P_Period = 0,
	TM_P_Duty_A_Period,

}TM_Duty_Period_T;


#define	CTM_Match(x)					_ctcclr = x
#define	STM_Match(x)					_stcclr = x
#define	PTM_Match(x)					_ptcclr = x
/* 比较器选择 */
typedef enum
{
	TM_Match_P = 0,
	TM_Match_A,

}TM_Match_T;


#define	CTM_CCRA_Period(x)			_ctmal = (x&0xFF); _ctmah = (x>>8)
#define	STM_CCRA_Period(x)			_stmal = (x&0xFF); _stmah = (x>>8)
#define	PTM_CCRA_Period(x)			_ptmal = (x&0xFF); _ptmah = ((x>>8)&0x03)
/* 比较器A溢出周期 */


#define	CTM_CCRP_Period(x)			_ctmrp = x
#define	STM_CCRP_Period(x)			_stmrp = x
#define	PTM_CCRP_Period(x)			_ptmrpl = (x&0xFF); _ptmrph = ((x>>8)&0x03)
/* 比较器P溢出周期 */


#endif

定时器PWM呼吸灯

这个实现起来比之前用时基中断模拟的PWM就简单太多了,只需要完成一件事情:每隔一段时间去改变那个PWM值。
定时器本身的配置我已经封装成库了,按照顺序一路配置下来就基本不会有问题的。
但是需要注意的是,如果配置的占空比大于溢出周期的话,会一直都处于有效状态,即亮度不变。
在这里插入图片描述
这里用到的CTM输出引脚CTP,可以从引脚分布看到CTP分布在PB3和PD3上面。
如果要使用这些IO的定时器引脚输出功能,要切换它们的复用功能。
在这里插入图片描述

void CTM_Init()
{
	GPIOB_3_Mode(IO_Mode2);

	CTM_A_InterruptCmd(Enable);		/* PWM这两个应该都可以不用打开吧 */
	CTM_P_InterruptCmd(Enable);

	CTM_Clock(TM_Clock_Fsys);
	CTM_Mode(TM_Mode_PWM);
	CTM_Output_Mode(TM_Output_Mode3);
	CTM_Output_Control(TM_Output_High);
	CTM_Output_Polarity(TM_Polarity_Inphase);
	CTM_Duty_Period(TM_A_Duty_P_Period);

	CTM_CCRA_Period(1);		/* 手动计算PWM值,可以封装一下自动计算的函数 */
	CTM_CCRP_Period(1);
	
	MUL_FUNC_1_InterruptCmd(Enable);
	CTM_Cmd(Enable);
}

中断函数这边暂时没有用上。

DEFINE_ISR(mul_1_int, MUL_FUNC_1_IntAddress)
{
	if(CTM_A_IntFlag)
	{
		CTM_A_FlagReset();

	}
	MUL_FUNC_1_FlagReset();
}

这个LED_PWM_Dir变量定义成bit类型即可,是控制PWM亮度边界然后转向用的。

void LED_PWM_UpdateHandler()
{
	if(LED_PWM_Dir)
    {
    	LED_PWM_Duty += 1;
    	if(LED_PWM_Duty == 255)
    	{
			LED_PWM_Dir = 0;
    	}
    }
    else
    {
		LED_PWM_Duty -= 1;
    	if(LED_PWM_Duty == 0)
    	{
			LED_PWM_Dir = 1;
    	}
    }
	CTM_CCRA_Period(LED_PWM_Duty);
}

更新PWM占空比的话,频率可以自己控制,10ms更新一次的话现象会比较明显一些。

if(TB0.FragmentFlag & Fragment_10ms_Mask)
{
    TB0.FragmentFlag ^= Fragment_10ms_Mask;
	LED_PWM_UpdateHandler();
}
  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值