dsPIC系列-1:dsPIC33点灯 [I/O、RCC、定时器]

文章目录


前言

dsPIC系列教程少之又少,因工作接触到dsPIC借此机会记录一下学习过程。

本例采用芯片dsPIC33FJ128GP804


一、I/O端口配置(GPIO)

本例以RC9引脚为例


1.TRISx 寄存器

TRISx 寄存器设置输入or输出引脚

配置 方向
0 输出
1 输入

2.PORTx 寄存器

通过PORTx寄存器访问I/O引脚上的数据。读PORTx寄存器是读取I/O引脚上的值,而写PORTx寄存器是将值写入端口数据锁存器。

3.LATx 寄存器

与 I/O 引脚相关的 LATx 寄存器消除了可能在执行读 - 修改 - 写指令时发生的问题。

写 LATx 寄存器就是将数据值写入端口锁存器。

读 LATx 寄存器就是读取保存在端口锁存器中的数据值。

4.代码

c 复制代码
void GPIO_Init(void)
{
    // 配置RC9为数字输出高电平
    TRISCbits.TRISC9 = 0;   // 设置RC9为输出模式 (0 = 输出)
    LATCbits.LATC9 = 1;     // 设置RC9初始输出为高电平 (1 = 高)
}

二、系统时钟配置(RCC)

1.时钟树

本例选择外部陶瓷晶振(24MHz)

主振荡器经过PLL将分给系统频率FOSC,指令周期时钟表示为 FCY,程序计数器时钟FPC

2.时钟分频

本例外部晶振为24MHz,因此运行在HS模式

本例芯片最大指令周期为40MIPS

因此设定N1=3, M=20, N2=2

同时满足以下条件

F_IN = 24MHz / 3 = 8.0 MHz

F_VCO = 8.0MHz * 20 = 160 MHz

Fosc = 160MHz / 2 = 80 MHz

Fcy = 80MHz / 2 = 40 MHz (40 MIPS达成)

配置举例:

例程代码:

c 复制代码
// Select Internal FRC at POR
_FOSCSEL(FNOSC_FRC & IESO_OFF);
// Enable Clock Switching and Configure POSC in HS mode
_FOSC(FCKSM_CSECMD & OSCIOFNC_OFF & POSCMD_HS);
int main()
{
// Configure PLL prescaler, PLL postscaler, PLL divisor
PLLFBD=18; // M=20
CLKDIVbits.PLLPOST=0; // N2=2
CLKDIVbits.PLLPRE=1; // N1=3
// Initiate Clock Switch to Primary Oscillator with PLL (NOSC=0b011)
__builtin_write_OSCCONH(0x03);
__builtin_write_OSCCONL(OSCCON | 0x01);
// Wait for Clock switch to occur
while (OSCCONbits.COSC!= 0b011);
// Wait for PLL to lock
while (OSCCONbits.LOCK!= 1);

三、定时器1配置(Timer1)

本例选择FCY内部时钟源

1.T1CON:Timer1 控制寄存器

详细介绍看这里

2.TMR1:Timer1 寄存器

实时计数

3.PR1:Timer1 周期寄存器

设置周期

4.实例

本例设定定时器1为1ms中断作为系统时基

FCY = 40MHz

想要1ms中断 FTIMER1 = FCY / TCKPS / (PR1+1)

c 复制代码
volatile uint32_t systemTickCount = 0; // 系统时基计数器

void TMR1_Initialize(void) {
    T1CON = 0x0; //清空寄存器
    TMR1 = 0; // 清空计数器
    
    T1CONbits.TON = 0; // 先关闭定时器
    T1CONbits.TCS = 0; // 选择内部指令周期时钟(F_cy)
    T1CONbits.TGATE = 0; // 禁止门控模式
    T1CONbits.TCKPS = 0b01; // 设置预分频比 1:8 (根据计算调整)
    
    PR1 = 4999; // 设置周期寄存器值 (根据计算调整)

    IFS0bits.T1IF = 0; // 清除定时器1中断标志
    IEC0bits.T1IE = 1; // 使能定时器1中断
    IPC0bits.T1IP = 4; // 设置中断优先级(1-7),根据系统需要设定

    T1CONbits.TON = 1; // 启动定时器
}

void __attribute__((interrupt, auto_psv)) _T1Interrupt(void) {
    IFS0bits.T1IF = 0; // 必须手动清除中断标志
    systemTickCount++; // 系统时基加1,每1ms加一次
}

4.点灯完整代码

c 复制代码
#include <xc.h>
#include <stdio.h>
#include <stdlib.h>


void GPIO_Init(void);
void TMR1_Initialize(void);
volatile uint32_t systemTickCount = 0; // 系统时基计数器
#define _XTAL_FREQ 80000000UL // 定义为80MHz,指示Fosc

// Select Internal FRC at POR
_FOSCSEL(FNOSC_FRC & IESO_OFF);
// Enable Clock Switching and Configure POSC in HS mode
_FOSC(FCKSM_CSECMD & OSCIOFNC_OFF & POSCMD_HS);

int main(void) {
    uint32_t u32LEDLastTime;
    OSC_Init_Safe_40MIPS();
    GPIO_Init();
    TMR1_Initialize();
    // 全局中断使能
    INTCON1bits.NSTDIS = 0; // 允许中断嵌套(根据需求)
    __builtin_enable_interrupts(); // 使能全局中断
    u32LEDLastTime = systemTickCount;
    while(1) {
        if(systemTickCount - u32LEDLastTime> 1000)
        {
            LATCbits.LATC9 = ~LATCbits.LATC9; // 翻转RC9电平
            u32LEDLastTime = systemTickCount;
        }
    }
    return 0;
}

void GPIO_Init(void)
{
    // 配置RC9为数字输出高电平
    TRISCbits.TRISC9 = 0;   // 设置RC9为输出模式 (0 = 输出)
    LATCbits.LATC9 = 1;     // 设置RC9初始输出为高电平 (1 = 高)
}

void TMR1_Initialize(void) {
    T1CON = 0x0; //清空寄存器
    TMR1 = 0; // 清空计数器
    
    T1CONbits.TON = 0; // 先关闭定时器
    T1CONbits.TCS = 0; // 选择内部指令周期时钟(F_cy)
    T1CONbits.TGATE = 0; // 禁止门控模式
    T1CONbits.TCKPS = 0b01; // 设置预分频比 1:8 (根据计算调整)
    
    PR1 = 4999; // 设置周期寄存器值 (根据计算调整)

    IFS0bits.T1IF = 0; // 清除定时器1中断标志
    IEC0bits.T1IE = 1; // 使能定时器1中断
    IPC0bits.T1IP = 4; // 设置中断优先级(1-7),根据系统需要设定

    T1CONbits.TON = 1; // 启动定时器
}

void OSC_Init_Safe_40MIPS(void){
    // Configure PLL prescaler, PLL postscaler, PLL divisor
    PLLFBD=18; // M=48
    CLKDIVbits.PLLPOST=0; // N2=2
    CLKDIVbits.PLLPRE=1; // N1=2
    // Initiate Clock Switch to Primary Oscillator with PLL (NOSC=0b011)
    __builtin_write_OSCCONH(0x03);
    __builtin_write_OSCCONL(OSCCON | 0x01);
    // Wait for Clock switch to occur
    while (OSCCONbits.COSC!= 0b011);
    // Wait for PLL to lock
    while (OSCCONbits.LOCK!= 1);
}


void __attribute__((interrupt, auto_psv)) _T1Interrupt(void) {
    IFS0bits.T1IF = 0; // 必须手动清除中断标志
    systemTickCount++; // 系统时基加1,每1ms加一次
}

总结

本例实现LED间隔1s闪烁功能,涉及IO配置,RCC时钟配置,定时器配置。(本人学习记录,切勿转载)

相关推荐
v先v关v住v获v取3 小时前
塔式立体车库5张cad+设计说明书+三维图
科技·单片机·51单片机
恒锐丰小吕4 小时前
屹晶微 EG2106D 600V耐压、半桥MOS/IGBT驱动芯片技术解析
嵌入式硬件·硬件工程
Ghost Face...4 小时前
U-Boot与PMON:配置与设备树解析对比
linux·单片机·嵌入式硬件
冲,干,闯4 小时前
操作MCU内存
单片机·嵌入式硬件
猫猫的小茶馆5 小时前
【ARM】从零封装STM32标准库
汇编·arm开发·stm32·单片机·嵌入式硬件·架构
ACP广源盛139246256735 小时前
GSV6701A@ACP#6701A产品规格详解及产品应用分享
网络·嵌入式硬件·音视频
国科安芯5 小时前
商业卫星光电载荷控制系统中MCU抗辐照性能评估方法研究
单片机·嵌入式硬件·数码相机·性能优化·架构·risc-v
Terasic友晶科技6 小时前
5-DE10-Nano的HDMI方块移动案例——基于FPGA的I2C控制模块设计
单片机·嵌入式硬件·fpga开发·时钟分频·hdmi方块移动·i2c控制模块设计·配置寄存器
v先v关v住v获v取6 小时前
杨柳絮收集装置设计cad1张总图+三维图+设计说明书
科技·单片机·51单片机