前言
上节是做了dsPIC的准备工作,熟悉了开发环境与一些基本配置位的操作,项目种选用dsPIC芯片目的还是用来做电机控制的,对于电机控制来说,PWM,ADC,定时器是非常重要的功能,本节就开始介绍dsPIC的时钟配置,并使用定时器来验证。
首先,接入电路中的外部晶振是8M晶振,因此根据手册,可以选择主振荡器Posc:
根据上表,选择带PLL的主振荡器,由于使用的是XT晶振,因此使用XT模式,之后,修改配置位:
生成代码为:
// FOSC
#pragma config POSCMD = XT // 主振荡器模式选择位(XT晶体振荡器模式)
#pragma config OSCIOFNC = OFF // OSC2 Pin Function bit (OSC2 is clock output)
#pragma config IOL1WAY = ON // Peripheral pin select configuration (Allow only one reconfiguration)
#pragma config FCKSM = CSDCMD // Clock Switching Mode bits (Both Clock switching and Fail-safe Clock Monitor are disabled)
// FOSCSEL
#pragma config FNOSC = PRIPLL // 振荡器源选择(带PLL<a class="decoration-color" href="https://buy.icxbk.com/index.php?ctl=Product&met=lists&category_id=1047" target="_blank">模块</a>的主振荡器(XT + PLL,HS + PLL,EC + PLL))
#pragma config PWMLOCK = ON // PWM Lock Enable bit (Certain PWM registers may only be written after key sequence)
#pragma config IESO = ON // Two-speed Oscillator Start-up Enable bit (Start up device with FRC, then switch to user-selected oscillator source)
之后要做的便是时钟计算,根据我们的配置来计算出我们现在的各个频率是多少。dsPIC33 PLL框图如下:
公式中:
N1对应 CLKDIV寄存器的PLLPRE位
N2对应 PLLFBD寄存器的PLLDIV位
M对应 CLKDIV的PLLPOST位
此时我们需要将Fosc锁定在120M,此时系统的工作频率即为60M,由于晶振使用的是8M晶振,因此,取N1 = 2,N2 = 2,M = 60
按照手册的说明:系统的工作频率为Fosc频率的一半。
代码如下:
//产生Fosc = 120MHz
CLKDIVbits.PLLPRE = 0; //N1 = 2
PLLFBDbits.PLLDIV = 58; //M = 60
CLKDIVbits.PLLPOST = 0; //N2 = 2 8 * (60 / (2 + 2)) = 120M
while (OSCCONbits.COSC!= 0b011)
while (OSCCONbits.LOCK!= 1) {};//PLL 处于锁定状态
配置完成,那么接下来就是验证我们配置的60M频率对不对,就使用一个定时器来验证好了。
关于dsPIC33的定时器,是把他们分成了三类,ABC三类定时器,如果要使用32位定时器,可以使用B类与C类定时器组合构成23位定时器,此时B类定时器控制寄存器中的T32控制位(TxCON<3>)必须置1,对于32位的工作,C类定时器保存最高有效字(即高16位),而B类定时器保存最低有效字(即低16位)。具体的32位定时器的使用,手册中直接给出了例子,因此就不再赘述。现在使用一个普通定时器来验证时钟就好,我选用的是timer3,C类定时器。
现在使用timer3来构造一个4ms的定时器,然后在中断里翻转一个IO口的电平状态来验证。
定时时间为4ms,因此设置分频率为1:8
T3CONbits.TCKPS = 0x01;//输入时钟预分频比1:8
周期寄存器的值为30000,(主频为60M)
PR3 = 30000;
注意:timer3定时器的优先级寄存器为 IPC2 timer1的优先级寄存器为 IPC0
程序如下:
void Tim3_Init()
{
T3CONbits.TON = 0;//禁止16位Timer3
T3CONbits.TCS = 0;//内部时钟Fosc/2 60M
T3CONbits.TGATE = 0;//门控时间累加位 禁止
T3CONbits.TCKPS = 0x01;//输入时钟预分频比1:8
TMR3 = 0; //初始值 相当于CNT
PR3 = 30000; //由于是8分频,也就是7.5M频率 因此取30000为定时4ms
IPC2bits.T3IP = 0x03; // 优先级1 定时器3的中断优先级为 IPC2 定时器1为IPC0
IFS0bits.T3IF = 0; // Timer3中断标志状态位 清零
IEC0bits.T3IE = 1; // Timer3中断允许位 允许
T3CONbits.TON = 1; //启动使能16位Timer3
}
void __attribute__((__interrupt__, no_auto_psv)) _T3Interrupt(void)
{
static uint8_t led_flag = 0;
IFS0bits.T3IF = 0; //清楚中断标志
led_flag = 1 - led_flag;
if (led_flag == 0)
{
PORTAbits.RA4 = 0;
}
else
{
PORTAbits.RA4 = 1;
}
}
实验结果:
时钟正确。