本文编写于 131 天前,最后修改于 131 天前,其中某些信息可能已经过时。
MSP430F5529 硬件部分
硬件特性
- 工作电压 1.8-3.6V
- 系统时钟频率最大 25MHz
- 128KB Flash, 8KB RAM
板卡引出引脚
隔离跳线帽(DEBUG 和 MCU 之间的)
时钟
时钟源
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, ¶m);
}
输出比较中断(连续计数模式)
// 代码改自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, ¶m);
//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();
}