MSP430学习笔记(三)丨MSP4305529定时器及其应用(定时中断、PWM、驱动舵机)

​  笔者学习采用单片机型号为MSP430F5529,使用MSP-EXP430F5529LP开发板。


一、MSP430定时器简介

1.1 定时器简介

​  MSP430含有三个定时器模块,分别为Timer_A、Timer_B和Timer_D。对于每个模块,都有对应的实例化子模块,例如对于Timer_A而言,它拥有三个子模块,即Timer_A0、Timer_A1、Timer_A2、Timer_A
3。每个子模块都拥有7个捕获/比较通道,一般可以用来测量脉冲频率,输出PWM波形,定时产生中断等。定时器的中断可以由计数溢出产生,也可以由捕获/比较寄存器产生。
​  Timer_A相关的寄存器主要有TAxCTL、TAxR、TAxCCTLn、TAxCCRn、TAxIV、TAxEX0这几个寄存器。

1.2 时基单元的四种工作模式

在这里插入图片描述
​  定时器有四种工作模式:停止模式、向上模式、连续模式和向上/向下模式。使用 MC 位(两位)选择工作模式。

MC模式描述
00停止定时器停止计数。
01向上定时器从零重复计数到 TAxCCR0 的值。
10连续定时器从零不断计数到 0FFFFh。
11向上/向下定时器从零重复计数到 TAxCCR0 的值,然后回到零计数。

1.3 定时器中断优先级

在这里插入图片描述
​  以上图的Timer_A的中断向量寄存器TAxIV为例,可以看到与定时器相关的中断一共有7个,分别是通道1到通道6的输入捕获/输出比较中断和时基单元的溢出中断,且这些中断的优先级是从高到低排列的。MSP430在这里并不支持中断优先级的自由配置。

1.4 输出比较模块

​  Timer_A 中有最多七个相同的捕获/比较模块,TAxCCRn(其中n = 0 到 7)。任何一个模块都可以用来捕获定时器数据或生成时间间隔。

二、定时器相关库函数

2.1 Timer_A库函数

// 启动计数
extern void Timer_A_startCounter(uint16_t baseAddress, uint16_t timerMode);

// 初始化循环计数模式
extern void Timer_A_initContinuousMode(uint16_t baseAddress, Timer_A_initContinuousModeParam *param);

// 初始化向上计数模式
extern void Timer_A_initUpMode(uint16_t baseAddress, Timer_A_initUpModeParam *param);

// 初始化上下计数模式
extern void Timer_A_initUpDownMode(uint16_t baseAddress, Timer_A_initUpDownModeParam *param);

// 初始化捕获模式
extern void Timer_A_initCaptureMode(uint16_t baseAddress, Timer_A_initCaptureModeParam *param);

// 初始化比较模式
extern void Timer_A_initCompareMode(uint16_t baseAddress, Timer_A_initCompareModeParam *param);

// 使能中断
extern void Timer_A_enableInterrupt(uint16_t baseAddress);

// 禁止中断
extern void Timer_A_disableInterrupt(uint16_t baseAddress);

// 获取中断标志位状态
extern uint32_t Timer_A_getInterruptStatus(uint16_t baseAddress);

// 使能捕获/比较中断
extern void Timer_A_enableCaptureCompareInterrupt(uint16_t baseAddress, uint16_t captureCompareRegister);

// 禁止捕获/比较中断
extern void Timer_A_disableCaptureCompareInterrupt(uint16_t baseAddress, uint16_t captureCompareRegister);

// 获取捕获/比较中断标志位
extern uint32_t Timer_A_getCaptureCompareInterruptStatus(uint16_t baseAddress, uint16_t captureCompareRegister, uint16_t mask);

// 重置/清除定时器相关设置
extern void Timer_A_clear(uint16_t baseAddress);

// 获取同步的CCR输入
extern uint8_t Timer_A_getSynchronizedCaptureCompareInput(uint16_t baseAddress, uint16_t captureCompareRegister, uint16_t synchronized);

// 获取输出模式的输出位
extern uint8_t Timer_A_getOutputForOutputModeOutBitValue(uint16_t baseAddress, uint16_t captureCompareRegister);

// 获取CCR的值
extern uint16_t Timer_A_getCaptureCompareCount(uint16_t baseAddress, uint16_t captureCompareRegister);

// 设置输出模式的输出位
extern void Timer_A_setOutputForOutputModeOutBitValue(uint16_t baseAddress, uint16_t captureCompareRegister, uint8_t outputModeOutBitValue);

// 输出PWM
extern void Timer_A_outputPWM(uint16_t baseAddress, Timer_A_outputPWMParam *param);

// 停止定时器运行
extern void Timer_A_stop(uint16_t baseAddress);

// 设置CCR的值
extern void Timer_A_setCompareValue(uint16_t baseAddress, uint16_t compareRegister, uint16_t compareValue);

// 设置输出模式
extern void Timer_A_setOutputMode(uint16_t baseAddress, uint16_t compareRegister, uint16_t compareOutputMode);

// 清除中断标志
extern void Timer_A_clearTimerInterrupt(uint16_t baseAddress);

// 清除捕获/比较中断标志
extern void Timer_A_clearCaptureCompareInterrupt(uint16_t baseAddress, uint16_t captureCompareRegister);

// 获取定时器的计数值
extern uint16_t Timer_A_getCounterValue(uint16_t baseAddress);

三、代码实现

3.1 定时器定时产生中断

  • main.c
#include <driverlib.h>

void Delay_ms(int x_ms)
{
    while (x_ms--)
    {
        __delay_cycles(1000);
    }
}


void Timer_A_Init(void)
{
    Timer_A_initUpModeParam Timer_A_InitStructure;
    Timer_A_InitStructure.captureCompareInterruptEnable_CCR0_CCIE = TIMER_A_CCIE_CCR0_INTERRUPT_DISABLE;
    Timer_A_InitStructure.clockSource = TIMER_A_CLOCKSOURCE_SMCLK;
    Timer_A_InitStructure.clockSourceDivider = TIMER_A_CLOCKSOURCE_DIVIDER_10;
    Timer_A_InitStructure.startTimer = true;
    Timer_A_InitStructure.timerClear = TIMER_A_SKIP_CLEAR;
    Timer_A_InitStructure.timerInterruptEnable_TAIE = TIMER_A_TAIE_INTERRUPT_ENABLE;
    Timer_A_InitStructure.timerPeriod = 32767;      // 计数的目标值,即将要被写入CCR0的值
    Timer_A_initUpMode(TIMER_A1_BASE, &Timer_A_InitStructure);
}

/**
 * main.c
 */
int main(void)
{
    WDTCTL = WDTPW | WDTHOLD;   // stop watchdog timer

    Timer_A_Init();
    Timer_A_enableInterrupt(TIMER_A1_BASE);

    GPIO_setAsOutputPin(GPIO_PORT_P2, GPIO_PIN0);


    _EINT();    // 开启全局中断使能


    while (1)
    {

    }
}

#pragma vector = TIMER1_A1_VECTOR;
__interrupt void Port1_interrupt_process(void)
{
    _DINT();    // 关闭全局中断

    GPIO_toggleOutputOnPin(GPIO_PORT_P2, GPIO_PIN0);

    Timer_A_clearTimerInterrupt(TIMER_A1_BASE);

    _EINT();    // 开启全局中断
}


3.2 PWM波形驱动位置伺服舵机

  • PWM.h
/*
 * PWM.h
 *
 *  Created on: 2023年7月18日
 *      Author: Include everything
 */

#ifndef HARDWARE_PWM_H_
#define HARDWARE_PWM_H_

void PWM_Init(void);
void PWM_SetPeriod(uint16_t periodValue);
void PWM_SetCompare1(uint16_t value);
void PWM_SetCompare2(uint16_t value);

#endif /* HARDWARE_PWM_H_ */

  • PWM.c
/*
 * PWM.c
 *
 *  Created on: 2023年7月18日
 *      Author: Include everything
 */

#include <driverlib.h>

void PWM_Init(void)
{
    GPIO_setAsPeripheralModuleFunctionOutputPin(GPIO_PORT_P1, GPIO_PIN2);   // TA0.1
    GPIO_setAsPeripheralModuleFunctionOutputPin(GPIO_PORT_P1, GPIO_PIN3);   // TA0.2

    Timer_A_initUpModeParam Timer_A_UpModeInitStructure = {0};
    Timer_A_UpModeInitStructure.captureCompareInterruptEnable_CCR0_CCIE = TIMER_A_CCIE_CCR0_INTERRUPT_ENABLE;
    Timer_A_UpModeInitStructure.clockSource = TIMER_A_CLOCKSOURCE_SMCLK;    // 32MHz
    Timer_A_UpModeInitStructure.clockSourceDivider = TIMER_A_CLOCKSOURCE_DIVIDER_32;    // 计时频率为1MHz
    Timer_A_UpModeInitStructure.startTimer = true;
    Timer_A_UpModeInitStructure.timerClear = TIMER_A_SKIP_CLEAR;
    Timer_A_UpModeInitStructure.timerInterruptEnable_TAIE = TIMER_A_TAIE_INTERRUPT_DISABLE;
    Timer_A_UpModeInitStructure.timerPeriod = 20000 - 1;    // 周期为20ms
    Timer_A_initUpMode(TIMER_A0_BASE, &Timer_A_UpModeInitStructure);

    Timer_A_outputPWMParam Timer_A_outputPWMInitStructure;
    Timer_A_outputPWMInitStructure.clockSource = TIMER_A_CLOCKSOURCE_SMCLK;    // 32MHz
    Timer_A_outputPWMInitStructure.clockSourceDivider = TIMER_A_CLOCKSOURCE_DIVIDER_32;    // 计时频率为1MHz
    Timer_A_outputPWMInitStructure.compareOutputMode = TIMER_A_OUTPUTMODE_RESET_SET;
    Timer_A_outputPWMInitStructure.compareRegister = TIMER_A_CAPTURECOMPARE_REGISTER_1;
    Timer_A_outputPWMInitStructure.timerPeriod = 20000 - 1;     // 写入CCR0的值
    Timer_A_outputPWMInitStructure.dutyCycle = 500;             // 写入CCR1的值
    Timer_A_outputPWM(TIMER_A0_BASE, &Timer_A_outputPWMInitStructure);      // 在TA0.1引脚输出PWM波形

    Timer_A_outputPWMInitStructure.compareRegister = TIMER_A_CAPTURECOMPARE_REGISTER_2;
    Timer_A_outputPWMInitStructure.compareOutputMode = TIMER_A_OUTPUTMODE_SET_RESET;
    Timer_A_outputPWMInitStructure.dutyCycle = 1000;          // 写入CCR2的值
    Timer_A_outputPWM(TIMER_A0_BASE, &Timer_A_outputPWMInitStructure);      // 在TA0.2引脚输出PWM波形
}

// 设置周期
void PWM_SetPeriod(uint16_t periodValue)
{
    Timer_A_setCompareValue(TIMER_A0_BASE, TIMER_A_CAPTURECOMPARE_REGISTER_0, periodValue);
}

void PWM_SetCompare1(uint16_t value)
{
    Timer_A_setCompareValue(TIMER_A0_BASE, TIMER_A_CAPTURECOMPARE_REGISTER_1, value);
}

void PWM_SetCompare2(uint16_t value)
{
    Timer_A_setCompareValue(TIMER_A0_BASE, TIMER_A_CAPTURECOMPARE_REGISTER_2, value);
}


  • Servo.h
/*
 * Servo.h
 *
 *  Created on: 2023年7月26日
 *      Author: Include everything
 */

#ifndef HARDWARE_SERVO_H_
#define HARDWARE_SERVO_H_


void Servo_Init(void);
void Servo_SetAngle_270(float angle);
void Servo_SetAngle_180(float angle);


#endif /* HARDWARE_SERVO_H_ */

  • Servo.c
/*
 * Servo.c
 *
 *  Created on: 2023年7月26日
 *      Author: Include everything
 */

#include <driverlib.h>
#include "PWM.h"

void Servo_Init(void)
{
    PWM_Init();
}

// 驱动270°舵机
void Servo_SetAngle_270(float angle)
{
    PWM_SetCompare1((angle / 270) * 2000 + 500);
}

// 驱动180°舵机
void Servo_SetAngle_180(float angle)
{
    PWM_SetCompare2((angle / 180) * 2000 + 500);
}

  • main.c
#include <driverlib.h>
#include "OLED.h"
#include "System_CLK.h"
#include "Servo.h"
#include "Key.h"
#include "Delay.h"
#include "PWM.h"

uint8_t KeyNum;
float servoAngle_1, servoAngle_2;

/**
 * main.c
 */
int main(void)
{
    WDTCTL = WDTPW | WDTHOLD;   // stop watchdog timer

    SystemClock_Init();
    Key_Init();
    OLED_Init();
    Servo_Init();

    OLED_ShowString(1, 1, "Servo Control");
    OLED_ShowString(2, 1, "Angle:");
    while (1)
    {
        KeyNum = Key_GetNum();
        if (KeyNum == 1)
        {
            servoAngle_1 = 45.0;
        }
        if (KeyNum == 2)
        {
            servoAngle_1 = 225.0;
        }
        OLED_ShowNum(2, 7, servoAngle_1, 3);
        Servo_SetAngle_270(servoAngle_1);
    }
}


  持续更新完善中……


  原创笔记,码字不易,欢迎点赞,收藏~ 如有谬误敬请在评论区不吝告知,感激不尽!博主将持续更新有关嵌入式开发、机器学习方面的学习笔记~

  • 6
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Include everything

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值