先导知识:
1.关于中断
AVR编程中
#pragma interrupt_handler Timer_interrupt:7是什
总的是中断申明
固定格式为:
#pragma interrupt_handler 中断子程序的函数名:该中断所对应的中断向量号
是定时器中断的声明 ,“7”表示中断向量号,及代表中断的入口地址,不同的向量号所表征的中断是不相同的。7表示的是T1中断向量号,不管是在该中断中发生“比较匹配中断”还是“溢出中断”,都是同样的向量号。
但是这只是某种编译器的编写习惯,如ICC,GCC,其他编译器的编写习惯不太一样,但是,中断向量号是一样的,即使你前面写的是T1中断,数字写成10,它照样进到T0中断(T0初始化过)。
2.关于ccu6
CCU6单元由具有三个捕获/比较通道的定时器T12块和具有一个比较通道的定时器T13块组成。T12通道可以独立地产生PWM信号或接受捕获触发器,或 它们可以共同产生控制信号模式来驱动直流电动机或逆变器。一组丰富的状态位,通过阴影寄存器同步更新参数值,并灵活生成中断请求信号提供有效的软件控制。
用CCU6生成T PWM的初始化代码
用CCU6生成PWM,如果是驱动带霍尔传感器的无刷直流电机,就用PWMBC更合适;一般的基于定时器的PWM生成可使用TPWM。
PWM PWMBC TPWM各是什么?
#include <Ccu6/TPwm/IfxCcu6_TPwm.h>//需要的头文件
static IfxCcu6_TPwm tPwm;// used globally 申明的全局变量
这两个名字接着写是什么意思
设置中断:
定义中断优先级:
#define IFX_INTPRIO_CCU6 1// priorities are normally defined in Ifx_IntPrioDef.h
添加用户代码:
IFX_INTERRUPT(ccu60ISR_TPwm, 0, IFX_INTPRIO_CCU6)
{
//user code
}
最后在初始化函数中设置中断:
IfxCpu_Irq_installInterruptHandler(&ccu60ISR_TPwm, IFX_INTPRIO_CCU6);
IfxCpu_enableInterrupts();
初始化模块:
IfxCcu6_TPwm_Config tPwmConfig;// create configuration
IfxCcu6_TPwm_initModuleConfig(&tPwmConfig, &MODULE_CCU60);
tPwmConfig.base.frequency = 400000;// 在内部启动的情况下配置定时器的频率// 此频率将为稍后选择的定时器块设置
tPwmConfig.base.period = 100;// 配置定时器的周期
tPwmConfig.base.waitingTime = 20;// 配置延迟 T13 启动与 T12 同步的等待时间
tPwmConfig.base.activeState = Ifx_ActiveState_high;// 选择输出的活动状态
tPwmConfig.timer = IfxCcu6_TimerId_t13;// 选择通过其生成 PWM 的定时器13
tPwmConfig.clock.t13ExtClockEnabled = FALSE;
tPwmConfig.clock.t13ExtClockInput = NULL_PTR;
tPwmConfig.clock.t13countingInputMode = IfxCcu6_CountingInputMode_internal;
// 为内部模式配置时钟
tPwmConfig.timer13.counterValue = 0;
tPwmConfig.timer13.compareValue = 100;// 配置选定的定时器块
tPwmConfig.timer13.t12SyncEvent = IfxCcu6_T13TriggerEvent_onCC60RCompare;
tPwmConfig.timer13.t12SyncDirection = IfxCcu6_T13TriggerDirection_onT12CountingUp;
// 配置同步,如果同步从 T12 开始
tPwmConfig.channelOut = IfxCcu6_ChannelOut_cout3;//选择要调制的通道输出
// 引脚配置
const IfxCcu6_TPwm_Pins pins = {
NULL, // CC60Out pin not used
NULL, // CC61Out pin not used
NULL, // CC62Out pin not used
NULL, // COUT60 pin not used
NULL, // COUT61 pin not used
NULL, // COUT62 pin not used
IfxCcu60_COUT63_P00_0_OUT, // COUT63 pin
IfxPort_OutputMode_pushPull,
IfxPort_PadDriver_cmosAutomotiveSpeed1
};
tPwmConfig.pins = &pins;
// 配置中断
tPwmConfig.interrupt1.interruptSource = IfxCcu6_InterruptSource_t13CompareMatch;
tPwmConfig.interrupt1.serviceRequest = IfxCcu6_ServiceRequest_2;
tPwmConfig.interrupt1.priority = IFX_INTPRIO_CCU6;
tPwmConfig.interrupt1.typeOfService = IfxSrc_Tos_cpu0;
// 配置输入和输出触发器
tPwmConfig.trigger.t12ExtInputTrigger = IfxCcu60_T12HRB_P00_7_IN;
tPwmConfig.trigger.t13ExtInputTrigger = NULL_PTR;
tPwmConfig.trigger.extInputTriggerMode = IfxCcu6_ExternalTriggerMode_risingEdge;
tPwmConfig.trigger.t13InSyncWithT12 = TRUE;
tPwmConfig.trigger.outputTriggerEnabled = TRUE;
tPwmConfig.trigger.outputLine = IfxCcu6_TrigOut_0;
tPwmConfig.trigger.outputTrigger = IfxCcu6_TrigSel_cout63;
// 初始化模块
IfxCcu6_TPwm_initModule(&tPwm, &tPwmConfig);
经过如上设置TPWM功能就基本可以使用了,例程中的程序也基本就是这样编写的。
TPWM的控制代码:
开始:
IfxCcu6_TPwm_start(&tPwm);
停止:
IfxCcu6_TPwm_stop(&tPwm);
暂停:
IfxCcu6_TPwm_pause(&tPwm);
恢复:
IfxCcu6_TPwm_resume(&tPwm);
(定时器T12可以在其三个信道的捕获和/或比较模式下工作。模式也可以组合(例如,一个通道在比较模式下工作,而另一个通道在捕获模式下工作)。定时器T13可以仅在比较模式下工作。多通道控制单元产生输出模式,可由T12和/或T13。可以选择调制源并组合用于信号调制。 )
3.什么是pit
PIT是个非常准的定时中断(相比delay函数来说),说好的1ms触发一次中断就是1ms触发一次。
PIT中断的配置也很简单。设置好中断时间间隔(这里是1ms),写好中断处理函数,就可以啦。
关于这几个定时器
好多人问PIT、Systick、LPTMR、PDB到底有什么不同呢,他们不都是定时器吗?干嘛非得用PIT,不用其他的呢?
其实这是一个比较尴尬的问题,如同问自行车、汽车、飞机不都是交通工具吗?都可以从甲地到乙地,干嘛非用某某呢?
好了,一开始我们就说了,PIT是最简单的定时器,用起来极其简单,如果你想周期性的产生中断,OK,用PIT就足够了。
原理:无需了解(2条消息) PIT工作原理_白小白-CSDN博客_pit中断
PIT: PIT有两个定时器,两个定时器可以连到一起去的。
该计数器的值和上面不一样,它是倒序的,跟systick有点像,从一个值往下递减,减到0的时候重新加载。该定时器还有两个寄存器表示生命周期,可以用来计算该计算机运行了多久,多长时间,对了,该定时器还有一个功能,就是累加(chain)也可以说连接吧,就比如KL25里面有2个TIMER,当第一个TIMER达到0的时候,第二个TIMER减1.
控制寄存器CR也没有几个功能,就是一个模块使能。和一个freeze
每个定时器都有以下的值:
PIT加载值,该值就是该计数器数到0的时候重新加载的值,
PIT当前值:计数当前计数器的值,
PIT时间控制寄存器。可以设置chain累加到前面一个计数器。timer0肯定没有这个功能。TIE中断使能位,TEN时钟使能。
PIT标志位:该位标志了计数器的值达到timer
(Systick是什么呢,它是Cortex内核的定时器,也就是说不管是M3\M4,不管是ST的单片机还是飞思卡尔的单片机,这个定时器的结构和用法是一样的,它也可以产生周期中断,也可以作为精准延时函数。但是他的真正用武之地值操作系统的嘀嗒时钟,也就是为uC/OS等操作系统提供时钟节拍。一来他是内核级别的时钟,中断优先级比其他外设模块要高;二来他比较通用,可以不用改任何代码就移植到其他单片机上。)
正文
zf_ccu6_pit.c
#include "IfxCcu6_Timer.h"
#include "SysSe/Bsp/Bsp.h"
#include "isr_config.h"
#include "zf_ccu6_pit.h"
1.pit初始化函数
函数定义:void pit_init(CCU6N_enum ccu6n, CCU6_CHN_enum pit_ch, uint32 time)
调用:pit_init(CCU6_0, PIT_CH0, 5000); //设置周期中断5000us
说明
ccu6n选择CCU6模块(CCU6_0、CCU6_1)
pit_ch选择通道(PIT_CH0、PIT_CH1)
time周期时间
注意:请使用.h文件中 带时间单位的宏定义函数?啥意思
2.pit 关闭
函数定义:void pit_close(CCU6N_enum ccu6n, CCU6_CHN_enum pit_ch)
// Sample usage: pit_close(CCU6_0, PIT_CH0); //关闭CCU60 通道0的计时器
ccu6n选择CCU6模块(CCU6_0、CCU6_1)
pit_ch选择通道(PIT_CH0、PIT_CH1)
3.pit开始
void pit_start(CCU6N_enum ccu6n, CCU6_CHN_enum pit_ch)
调用: pit_start(CCU6_0, PIT_CH0); //打开CCU60 通道0的计时器
4.禁止pit中断
void pit_disable_interrupt(CCU6N_enum ccu6n, CCU6_CHN_enum pit_ch)
// pit_disable_interrupt(CCU6_0, PIT_CH0); //禁止CCU60 通道0的中断
5.使能pit中断
void pit_enable_interrupt(CCU6N_enum ccu6n, CCU6_CHN_enum pit_ch)
// pit_enable_interrupt(CCU6_0, PIT_CH0); //开启CCU60 通道0的中断
zf_ccu6_pit.h
//------------------------------------以下代码用于PIT中断------------------------------------
#define pit_interrupt_ms(ccu6n, pit_ch, time) pit_init(ccu6n, pit_ch, time*1000) //(单位为 毫秒)
#define pit_interrupt_us(ccu6n, pit_ch, time) pit_init(ccu6n, pit_ch, time) //(单位为 微秒)
pit_interrupt_ms(CCU6_0, PIT_CH0, 10);//10ms间隔中断初始化
实战调用
#include "isr_config.h"
#include "isr.h"
//在isr.c的中断函数,函数定义的第二个参数固定为0,请不要更改,即使你用CPU1处理中断也不要更改,需要CPU1处理中断只需要在isr_config.h内修改对应的宏定义即可
//PIT中断函数 示例
uint16 time;
IFX_INTERRUPT(cc60_pit_ch0_isr, 0, CCU6_0_CH0_ISR_PRIORITY)
//分别在: pit_config.h(内含服务类型编号和优先级编号)
{
enableInterrupts();//开启中断嵌套
PIT_CLEAR_FLAG(CCU6_0, PIT_CH0);
time++;
printf("pit count: %d\n", time);
}