登录后台

页面导航

本文编写于 102 天前,最后修改于 102 天前,其中某些信息可能已经过时。

MSP430F5529 硬件部分

硬件特性

  1. 工作电压 1.8-3.6V
  2. 系统时钟频率最大 25MHz
  3. 128KB Flash, 8KB RAM

板卡引出引脚

PIN

隔离跳线帽(DEBUG 和 MCU 之间的)

Jumper

时钟

  • 时钟源

    XT1CLK:外部低速晶振,32.768KHz
    VLOCLK:典型频率为 9.4 kHz 的内部超低功耗低频振荡器
    REFOCLK:典型频率为 32.768 KHz 的内部低速振荡器
    DCOCLK(DIV):具有可选频率的内部数控振荡器,可由 FLL 稳定后得到
    XT2CLK:外部高速晶振,4MHz

  • 时钟信号
    ACLK --> 辅助时钟,用于低速外设
    MCLK --> 主时钟,用于 CPU 和系统
    SMCLK --> 子系统时钟,用于高速外设
  • FLL
    参考时钟 XT1CLK,REFOCLK,XT2CLK
    f~DCOCLK~ = D x (N + 1) x (f~参考时钟~ / n)
    f~DCOCLKDIV~ = (N + 1) x (f~参考时钟~ / n)
    D 可取 1、2、4、8、16、32,默认值为 2
    N 可取 1~1023,默认值为 31
    n 可取 1、2、4、8、16,默认值为 1
  • MODCLK
    典型频率为 5 MHz 的内部低功耗振荡器,可为 Flash,ADC 提供时钟信号

MSPMSP430F5529 软件部分

GPIO

  • 库函数

void GPIO_setAsOutputPin (uint8_t selectedPort, uint16_t selectedPins)
// This function configures the selected Pin as output pin.
// 引脚设置为输出模式

void GPIO_setAsInputPin (uint8_t selectedPort, uint16_t selectedPins)
// This function configures the selected Pin as input pin.
// 引脚设置为输入模式

void GPIO_setAsPeripheralModuleFunctionOutputPin (uint8_t selectedPort, uint16_t selectedPins)
// This function configures the peripheral module function in the output direction for the selected pin.
// 设置为外围模块输出模式

void GPIO_setAsPeripheralModuleFunctionInputPin (uint8_t selectedPort, uint16_t selectedPins)
// This function configures the peripheral module functionin the input direction for the selected pin.
// 设置为外围模块输入模式

void GPIO_setOutputHighOnPin (uint8_t selectedPort, uint16_t selectedPins)
// This function sets output HIGH on the selected Pin.
// 输出高电平

void GPIO_setOutputLowOnPin (uint8_t selectedPort, uint16_t selectedPins)
// This function sets output LOW on the selected Pin.
// 输出低电平

void GPIO_toggleOutputOnPin (uint8_t selectedPort, uint16_t selectedPins)
// This function toggles the output on the selected Pin.
// 翻转电平

void GPIO_setAsInputPinWithPullDownResistor (uint8_t selectedPort, uint16_t selectedPins)
// This function sets the selected Pin in input Mode with Pull Down resistor.
// 设置为下拉输入

void GPIO_setAsInputPinWithPullUpResistor (uint8_t selectedPort, uint16_t selectedPins)
// This function sets the selected Pin in input Mode with Pull Up resistor.
// 设置为上拉输入

uint8_t GPIO_getInputPinValue (uint8_t selectedPort, uint16_t selectedPins)
// This function gets the input value on the selected pin.
// 读取电平  返回值如下
#define GPIO_INPUT_PIN_HIGH    (0x01)
#define GPIO_INPUT_PIN_LOW     (0x00)

void GPIO_enableInterrupt (uint8_t selectedPort, uint16_t selectedPins)
// This function enables the port interrupt on the selected pin.
// 使能中断

void GPIO_disableInterrupt (uint8_t selectedPort, uint16_t selectedPins)
// This function disables the port interrupt on the selected pin.
// 失能中断

uint16_t GPIO_getInterruptStatus (uint8_t selectedPort, uint16_t selectedPins)
// This function gets the interrupt status of the selected pin.
// 读取中断状态

void GPIO_clearInterrupt (uint8_t selectedPort, uint16_t selectedPins)
// This function clears the interrupt flag on the selected pin.
// 清除中断标志位

void GPIO_selectInterruptEdge (uint8_t selectedPort, uint16_t selectedPins, uint8_t edgeSelect)
// This function selects on what edge the port interrupt flag should be set for a transition.
//设置上升沿或下降沿触发,edgeSelect选项如下
#define GPIO_HIGH_TO_LOW_TRANSITION    (0x01)
#define GPIO_LOW_TO_HIGH_TRANSITION    (0x00)

void GPIO_setDriveStrength (uint8_t selectedPort, uint16_t selectedPins, uint8_t driveStrength)
// This function sets the drive strength for the selected port pin.
// 设置驱动能力(0:欠驱动模式,1:强驱动模式;默认为0)
  • eg:按下 S1,翻转 LED1 的电平,按下 S2,翻转 LED2 的电平,S1 使用中断模式,S2 使用查询模式(未消抖,未等待,会有重复触发情况)
#include <msp430.h>
#include <driverlib.h>

#define LED1    GPIO_PORT_P1, GPIO_PIN0
#define LED2    GPIO_PORT_P4, GPIO_PIN7
#define S1      GPIO_PORT_P2, GPIO_PIN1
#define S2      GPIO_PORT_P1, GPIO_PIN1

void main(void)
{
    WDTCTL = WDTPW + WDTHOLD; // Stop watchdog timer

//    设置LED1 LED2为输出模式
    GPIO_setAsOutputPin(LED1);
    GPIO_setAsOutputPin(LED2);

//    将LED1 LED2设置为低电平
    GPIO_setOutputLowOnPin(LED1);
    GPIO_setOutputLowOnPin(LED2);

//    设置按键S1为上拉输入模式
    GPIO_setAsInputPinWithPullUpResistor(S1);
    GPIO_setAsInputPinWithPullUpResistor(S2);

//    使能按键S1中断
    GPIO_enableInterrupt(S1);

//    设置中断下降沿触发
    GPIO_selectInterruptEdge(S1, GPIO_HIGH_TO_LOW_TRANSITION);

    __bis_SR_register(GIE); // 开启中断

    while (1)
    {
        if(GPIO_getInputPinValue(S2) == 0)
        {
            GPIO_toggleOutputOnPin(LED2);
        }
    }
}

#pragma vector = PORT2_VECTOR
__interrupt void port2(void){
    if(GPIO_getInputPinValue(S1) == 0)
    {
        GPIO_toggleOutputOnPin(LED1);
        GPIO_clearInterrupt(S1);
    }
}

Unified Clock System

eg:封装好的时钟系统初始化函数

void SystemClock_Init(void)
{
    PMM_setVCore(PMM_CORE_LEVEL_3);     //高主频工作需要较高的核心电压

    //XT1引脚复用
    GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_P5, GPIO_PIN4);
    GPIO_setAsPeripheralModuleFunctionOutputPin(GPIO_PORT_P5, GPIO_PIN5);

    //起振XT1
    UCS_turnOnLFXT1(UCS_XT1_DRIVE_3,UCS_XCAP_3);

    //XT2引脚复用
    GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_P5, GPIO_PIN2);
    GPIO_setAsPeripheralModuleFunctionOutputPin(GPIO_PORT_P5, GPIO_PIN3);

    //起振XT2
    UCS_turnOnXT2(UCS_XT2_DRIVE_4MHZ_8MHZ);

    //XT2作为FLL参考时钟,先8分频,再50倍频 4MHz / 8 * 50 = 25MHz
    UCS_initClockSignal(UCS_FLLREF, UCS_XT2CLK_SELECT, UCS_CLOCK_DIVIDER_8);
    UCS_initFLLSettle(25000, 50);

    //XT1作为ACLK时钟源 = 32768Hz
    UCS_initClockSignal(UCS_ACLK, UCS_XT1CLK_SELECT, UCS_CLOCK_DIVIDER_1);

    //DCOCLK作为MCLK时钟源 = 25MHz
    UCS_initClockSignal(UCS_MCLK, UCS_DCOCLK_SELECT, UCS_CLOCK_DIVIDER_1);

    //DCOCLK作为SMCLK时钟源 = 25MHz
    UCS_initClockSignal(UCS_SMCLK, UCS_DCOCLK_SELECT, UCS_CLOCK_DIVIDER_1);

    //设置外部时钟源的频率,使得在调用UCS_getMCLK, UCS_getSMCLK 或 UCS_getACLK时可得到正确值
    UCS_setExternalClockSource(32768, 4000000);
}

关于延时,使用内联函数__delay_cycles()延时 n 个时钟周期(MCLK 的频率分之一)

#define CPU_F           ((double)25000000)
#define delay_us(x)     __delay_cycles((long)(CPU_F*(double)x/1000000.0))
#define delay_ms(x)     __delay_cycles((long)(CPU_F*(double)x/1000.0))

定时器

PWM 输出(增计数模式)

// 代码改自timer_a_ex1_pwmSingle

#include "driverlib.h"

#define TIMER_PERIOD 50000-1
#define DUTY_CYCLE  25000

void main (void)
{
    //Stop WDT
    WDT_A_hold(WDT_A_BASE);

    //P2.0 as PWM output
    GPIO_setAsPeripheralModuleFunctionOutputPin(
        GPIO_PORT_P2,
        GPIO_PIN0
        );

    //Generate PWM - Timer runs in Up mode
    Timer_A_outputPWMParam param = {0};

    // 设置时钟为SMCLK,假设时钟为25MHz
    param.clockSource = TIMER_A_CLOCKSOURCE_SMCLK;

    // 设置分频系数为10,时钟周期即0.4μs
    param.clockSourceDivider = TIMER_A_CLOCKSOURCE_DIVIDER_10;

    // 设置计数值为50000-1,即0.4x50000/1000 = 20ms
    param.timerPeriod = TIMER_PERIOD;

    // 设置比较寄存器为1,对应于P2.0是A1.1
    param.compareRegister = TIMER_A_CAPTURECOMPARE_REGISTER_1;

    // 设置比较输出模式
    param.compareOutputMode = TIMER_A_OUTPUTMODE_RESET_SET;

    // 设置比较值,设置为25000即50%占空比
    param.dutyCycle = DUTY_CYCLE;

    //启动定时器A的PWM输出
    Timer_A_outputPWM(TIMER_A1_BASE, &param);

}

输出比较中断(连续计数模式)

// 代码改自timer_a_ex2_continousModeOperationWithCCR0Interrupt

#include "driverlib.h"

#define COMPARE_VALUE 50000

void main (void)
{
    //Stop WDT
    WDT_A_hold(WDT_A_BASE);

    //Set P1.0 to output direction
    GPIO_setAsOutputPin(
        GPIO_PORT_P1,
        GPIO_PIN0
        );

    //Start timer in continuous mode sourced by SMCLK
    // 连续计数模式初始化
    Timer_A_initContinuousModeParam initContParam = {0};
    initContParam.clockSource = TIMER_A_CLOCKSOURCE_SMCLK;
    initContParam.clockSourceDivider = TIMER_A_CLOCKSOURCE_DIVIDER_1;

    // 禁用定时器溢出中断
    initContParam.timerInterruptEnable_TAIE = TIMER_A_TAIE_INTERRUPT_DISABLE;

    // 定时器清零
    initContParam.timerClear = TIMER_A_DO_CLEAR;

    // 禁止立即启动定时器
    initContParam.startTimer = false;
    Timer_A_initContinuousMode(TIMER_A1_BASE, &initContParam);

    //Initiaze compare mode
    Timer_A_clearCaptureCompareInterrupt(TIMER_A1_BASE, TIMER_A_CAPTURECOMPARE_REGISTER_0);

    // 比较输出初始化
    Timer_A_initCompareModeParam initCompParam = {0};
    initCompParam.compareRegister = TIMER_A_CAPTURECOMPARE_REGISTER_0;

    // 开启定时器比较中断
    initCompParam.compareInterruptEnable = TIMER_A_CAPTURECOMPARE_INTERRUPT_ENABLE;

    // 设置比较输出模式
    initCompParam.compareOutputMode = TIMER_A_OUTPUTMODE_OUTBITVALUE;

    // 设置
    initCompParam.compareValue = COMPARE_VALUE;
    Timer_A_initCompareMode(TIMER_A1_BASE, &initCompParam);

    // 启动定时器
    Timer_A_startCounter(TIMER_A1_BASE, TIMER_A_CONTINUOUS_MODE);

    //Enter LPM0, enable interrupts
    __bis_SR_register(LPM0_bits + GIE);

    //For debugger
    __no_operation();
}

//******************************************************************************
//
//This is the TIMER1_A3 interrupt vector service routine.
//
//******************************************************************************
// 连续计数模式,定时器只能从 0 开始计数一直增加到 65535
/*
计时器开始从0计数,比较寄存器CCR0初始设定为50000。当计时器计数到50000时,会触发中断服务程序(ISR)。在ISR中,获取当前比较寄存器的值。
compVal = 50000(Timer_A_getCaptureCompareCount()的返回值) + 50000(COMPARE_VALUE) = 100000
更新时,将compVal(100000)写入CCR0。
由于计时器只能计数到65535,然后回到0继续计数,这意味着下一次中断会在计数器计数到34464(100000 - 65536)时触发。
*/
#pragma vector=TIMER1_A0_VECTOR
__interruptvoid TIMER1_A0_ISR (void){
    uint16_t compVal = Timer_A_getCaptureCompareCount(TIMER_A1_BASE,
            TIMER_A_CAPTURECOMPARE_REGISTER_0)
            + COMPARE_VALUE;

    //Toggle P1.0
    GPIO_toggleOutputOnPin(
        GPIO_PORT_P1,
        GPIO_PIN0
        );

    //Add Offset to CCR0
    Timer_A_setCompareValue(TIMER_A1_BASE,
        TIMER_A_CAPTURECOMPARE_REGISTER_0,
        compVal
        );
}

定时器溢出中断(连续计数模式)

// 代码改自timer_a_ex3_continousModeOperationWithTAIEInterrupt

#include "driverlib.h"

void main (void)
{
    //Stop WDT
    WDT_A_hold(WDT_A_BASE);

    //Set P1.0 to output direction
    GPIO_setAsOutputPin(
        GPIO_PORT_P1,
        GPIO_PIN0
        );

    //Start timer in continuous mode sourced by SMCLK
    Timer_A_clearTimerInterrupt(TIMER_A1_BASE);

    Timer_A_initContinuousModeParam param = {0};
    param.clockSource = TIMER_A_CLOCKSOURCE_SMCLK;
    param.clockSourceDivider = TIMER_A_CLOCKSOURCE_DIVIDER_1;
    param.timerInterruptEnable_TAIE = TIMER_A_TAIE_INTERRUPT_ENABLE;
    param.timerClear = TIMER_A_DO_CLEAR;
    param.startTimer = true;
    Timer_A_initContinuousMode(TIMER_A1_BASE, &param);

    //Enter LPM0, enable interrupts
    __bis_SR_register(LPM0_bits + GIE);

    //For debugger
    __no_operation();
}

//******************************************************************************
//
//This is the TIMER1_A3 interrupt vector service routine.
//
//******************************************************************************

#pragma vector=TIMER1_A1_VECTOR
__interrupt
void TIMER1_A1_ISR (void)
{
    //Any access, read or write, of the TAIV register automatically resets the
    //highest "pending" interrupt flag
    // 查看寄存器 TA1IV 的值,让定时器溢出触发中断,CCRx为比较值触发中断
    // 时钟已经切换为 SMCLK ,1 / 25 * 65536 约为2.62ms
    // 将 ACLK 用作时钟(XT1CLK 或 REFOCLK),理论值2s,实际值2.5s
    switch ( __even_in_range(TA1IV,14) ){
        case  0: break;                          //No interrupt
        case  2: break;                          //CCR1 not used
        case  4: break;                          //CCR2 not used
        case  6: break;                          //CCR3 not used
        case  8: break;                          //CCR4 not used
        case 10: break;                          //CCR5 not used
        case 12: break;                          //CCR6 not used
        case 14:
            //Toggle P1.0           // overflow
            GPIO_toggleOutputOnPin(
                GPIO_PORT_P1,
                GPIO_PIN0
            );
            break;
        default: break;
    }
}

PWM输出(增减计数模式)

// 代码改自timer_a_ex6_upDownModeOperation

#include "driverlib.h"

#define TIMER_A_PERIOD 250
#define DUTY_CYCLE 250

void main (void)
{
    //Stop WDT
    WDT_A_hold(WDT_A_BASE);

    //P1.7 output
    //P1.7 option select
    GPIO_setAsPeripheralModuleFunctionOutputPin(
        GPIO_PORT_P1,
        GPIO_PIN7
        );

    //Start timer in up down mode
    // 以增减计数模式启动
    Timer_A_initUpDownModeParam initUpDownParam = {0};
    initUpDownParam.clockSource = TIMER_A_CLOCKSOURCE_SMCLK;
    initUpDownParam.clockSourceDivider = TIMER_A_CLOCKSOURCE_DIVIDER_1;

    // 设置计数周期为250
    initUpDownParam.timerPeriod = TIMER_A_PERIOD;
    initUpDownParam.timerInterruptEnable_TAIE = TIMER_A_TAIE_INTERRUPT_DISABLE;
    initUpDownParam.captureCompareInterruptEnable_CCR0_CCIE =
        TIMER_A_CAPTURECOMPARE_INTERRUPT_DISABLE;

    // 计数器清零
    initUpDownParam.timerClear = TIMER_A_DO_CLEAR;
    initUpDownParam.startTimer = false;
    Timer_A_initUpDownMode(TIMER_A1_BASE, &initUpDownParam);

    //Init compare mode
    Timer_A_initCompareModeParam initCompParam = {0};
    initCompParam.compareRegister = TIMER_A_CAPTURECOMPARE_REGISTER_0;
    initCompParam.compareInterruptEnable = TIMER_A_CAPTURECOMPARE_INTERRUPT_DISABLE;
    initCompParam.compareOutputMode = TIMER_A_OUTPUTMODE_TOGGLE;

    // 设置触发(翻转)值为250
    initCompParam.compareValue = DUTY_CYCLE;
    Timer_A_initCompareMode(TIMER_A1_BASE, &initCompParam);

    Timer_A_startCounter(
        TIMER_A1_BASE,
        TIMER_A_UPDOWN_MODE
        );

/*
从0开始计数,向上计数到250,翻转电平,从250向下计数到0,再从0向上计数到250翻转电平...
假设SMCLK为25MHz,一个时钟周期为0.04μs,一次高电平应该是(250 + 250) * 0.04 = 20μs
第一个波形是错误的,少了一半,只有10μs(从0到250就会翻转一次),后面的就正常了
完全的硬件PWM,无需CPU的参与即可完成
*/
    //Enter LPM0
    __bis_SR_register(LPM0_bits);

    //For debugger
    __no_operation();
}