MSP432速成教程(看这一篇就够了)

MSP432P401R基础使用

一、GPIO输出 点灯 跑马灯

(一)GPIO输出

打开芯片数据手册(msp432p401r)第17页的表详细描述了对应引脚的GPIO功能

1.库函数
  • 配置GPIO模式:
GPIO_setAOutputPin(Port,pin)//设置GPIO为输出模式
  • 设置高低电平
GPIO_setOutputHoghOnPin(Port,Pin)//设置GPIO为高电平
GPIO_setOutputLowOnPin(Port,Pin)//设置GPIO为低电平
GPIO_toggleOutputOnPin(Port,Pin)//翻转GPIO引脚电平
  • 配置驱动强度

只有P2.0、P2.1、P2.2、P2.3引脚可以配置为高驱动程度

This I/O can be configured for high drive operation with up to 20-mA drive capability.

此I/O可配置为高达20 mA驱动能力的高驱动操作。

GPIO_setDriveStrengthHigh(Port,Pin)//强驱动
GPIO_setDriveStrengthLow(Port,Pin)//弱驱动(无特殊要求,一般不用设置)
//几乎不用,需要使用时自行查看参数、返回值等详细信息
#include <ti/devices/msp432p4xx/driverlib/driverlib.h>

int main(void)
{
    // 初始化 MSP432P401R 微控制器
    MAP_WDT_A_holdTimer();

    // 配置 P1.0 引脚为输出模式
    MAP_GPIO_setAsOutputPin(GPIO_PORT_P1, GPIO_PIN0);

    // 设置 P1.0 引脚的驱动强度为高级别
    MAP_GPIO_setDriveStrengthHigh(GPIO_PORT_P1, GPIO_PIN0);

    while (1)
    {
        // 在 P1.0 引脚输出高电平
        MAP_GPIO_setOutputHighOnPin(GPIO_PORT_P1, GPIO_PIN0);

        // 延时约一秒钟
        MAP_PCM_gotoLPM0();
    }
}

(二)点亮LED灯

1.硬件连接

可以打开评估版手册(MSP432开发板手册/slau597f)37页原理图

在这里插入图片描述

共阴极连接,高电平亮,低电平熄灭

2.代码

led.h

#ifndef __LED_H
#define __LED_H
#include <ti/devices/msp432p4xx/driverlib/driverlib.h>

// 位带操作
#define LED_RED BITBAND_PERI(P1OUT,0)
#define LED_R BITBAND_PERI(P2OUT,0)
#define LED_G BITBAND_PERI(P2OUT,1)
#define LED_B BITBAND_PERI(P2OUT,2)

void LED_Init(void);//LED初始化函数

void LED_RED_On(void);//打开LED1
void LED_RED_Off(void);//关闭LED1
void LED_RED_Tog(void);//翻转LED1

void LED_Y_On(void);//打开黄色RGB灯
void LED_C_On(void);//打开青色RGB灯
void LED_P_On(void);//打开品红RGB灯

void LED_R_On(void);//红色RGB灯
void LED_G_On(void);//绿色RGB灯
void LED_B_On(void);//蓝色RGB灯

void LED_R_Off(void);
void LED_G_Off(void);
void LED_B_Off(void);

void LED_R_Tog(void);
void LED_G_Tog(void);
void LED_B_Tog(void);

void LED_W_On(void);//白色RGB灯
void LED_W_Off(void);
void LED_W_Tog(void);

#endif

led.c

#include "led.h"

void LED_Init(void)
{
    MAP_GPIO_setAsOutputPin(GPIO_PORT_P1, GPIO_PIN0);//设置GPIO为输出模式
    MAP_GPIO_setAsOutputPin(GPIO_PORT_P2, GPIO_PIN0 + GPIO_PIN1 + GPIO_PIN2);

    LED_RED_Off();
    LED_R_Off();
    LED_G_Off();
    LED_B_Off();
}
void LED_RED_On(void) { LED_RED = 1; }
void LED_RED_Off(void) { LED_RED = 0; }
void LED_RED_Tog(void) { LED_RED ^= 1; }

void LED_R_Off(void) { LED_R = 0;}
void LED_G_Off(void) { LED_G = 0;}
void LED_B_Off(void) { LED_B = 0; }

void LED_R_On(void) { LED_R = 1; }
void LED_G_On(void) { LED_G = 1;  }
void LED_B_On(void) { LED_B = 1;  }

void LED_R_Tog(void) { LED_R ^= 1; }
void LED_G_Tog(void) { LED_G ^= 1; }
void LED_B_Tog(void) { LED_B ^= 1; }

//白色 White
void LED_W_On(void)
{
    LED_R_On();
    LED_G_On();
    LED_B_On();
}
//白色 White
void LED_W_Off(void)
{
    LED_R_Off();
    LED_G_Off();
    LED_B_Off();
}
//白色 White
void LED_W_Tog(void)
{
    LED_R_Tog();
    LED_G_Tog();
    LED_B_Tog();
}
//黄色 Yellow
void LED_Y_On(void)
{
    LED_R_On();
    LED_G_On();
    LED_B_Off();
}
//品红 Pinkish red
void LED_P_On(void)
{
    LED_R_On();
    LED_G_Off();
    LED_B_On();
}
//青色 Cyan
void LED_C_On(void)
{
    LED_R_Off();
    LED_G_On();
    LED_B_On();
}

main.c

#include <ti/devices/msp432p4xx/driverlib/driverlib.h>

/* Standard Includes */
#include <stdint.h>
#include <stdbool.h>

#include "led.h"

int main(void)
{
    uint32_t i;

    /* Stop Watchdog  */
    MAP_WDT_A_holdTimer();//关闭看门狗

    LED_Init();//LED初始化
    
    while (1)
    {
        LED_RED_On();
        for (i = 0; i < 500000; i++);
        LED_RED_Off();

        LED_R_On();
        for (i = 0; i < 500000; i++);
        LED_R_Off();

        LED_G_On();
        for (i = 0; i < 500000; i++);
        LED_G_Off();

        LED_B_On();
        for (i = 0; i < 500000; i++);
        LED_B_Off();
		
		LED_C_On();
        for (i = 0; i < 500000; i++);
		
		LED_P_On();
        for (i = 0; i < 500000; i++);
		
		LED_Y_On();
        for (i = 0; i < 500000; i++);
		
		LED_W_On();
        for (i = 0; i < 500000; i++);
        LED_W_Off();
    }
}

二、GPIO做输入 按键输入

(一)GPIO做输入

1.库函数

配置GPIO模式:

GPIO_setAslnputPin(Port,Pin);//设置为浮空输入
GPIO_setAslnputWithPullUpResistor(Port,Pin);//设置为上拉输入模式
GPIO_setAslnputWithPullDownResistor(Port,Pin);//设置为下拉输入模式

获取电平状态:

GPIO_getlnputPinValue(Port,Pin);

(二)按键输入

1.硬件连接

可以打开评估版手册(MSP432开发板手册/slau597f)37页原理图

在这里插入图片描述

可以看到按下后被拉低为低电平,所以我们应该把引脚配置为上拉输入

2.代码

key.h

#ifndef __KEY_H
#define __KEY_H	 
	 
#include "driverlib.h"

#define KEY1 BITBAND_PERI(P1IN, 1) //读取按键1
#define KEY2 BITBAND_PERI(P1IN, 4) //读取按键2


#define KEY1_PRES 	1	//KEY0按下
#define KEY2_PRES	  2	//KEY1按下


void KEY_Init(void);//IO初始化
uint8_t KEY_Scan(uint8_t);  	//按键扫描函数					    
#endif

key.c

#include "driverlib.h"
#include "key.h"
								    
//按键初始化函数
void KEY_Init(void) //IO初始化
{
	GPIO_setAsInputPinWithPullUpResistor(GPIO_PORT_P1, GPIO_PIN1 | GPIO_PIN4);
}

//按键处理函数
//返回按键值
//mode:0,不支持连续按;1,支持连续按;
//0,没有任何按键按下
//1,KEY0按下
//2,KEY1按下
//3,KEY3按下 WK_UP
//注意此函数有响应优先级,KEY0>KEY1>KEY_UP!!
uint8_t KEY_Scan(uint8_t mode)
{
	uint16_t i;
	static uint8_t key_up = 1; //按键按松开标志
	if (mode)
		key_up = 1; //支持连按	
	if (key_up && (KEY2 == 0 || KEY1 == 0))
	{
		for (i = 0; i < 5000; i++)
			; //去抖动
		key_up = 0;
		if (KEY1 == 0)
			return KEY1_PRES;
		else if (KEY2 == 0)
			return KEY2_PRES;
	}
	else if (KEY2 == 1 && KEY1 == 1)
		key_up = 1;
	return 0;// 无按键按下
}

main.c

#include "driverlib.h"

/* Standard Includes */
#include <stdint.h>
#include <stdbool.h>

#include "led.h"
#include "key.h"

int main(void)
{
   
		uint8_t key;
	
    /* Stop Watchdog  */
    MAP_WDT_A_holdTimer();

    LED_Init();
    KEY_Init();
	
    while (1)
    {
				key = KEY_Scan(0);//不支持连按

				if (key == KEY1_PRES)
						LED_RED_On();//打开LED1
				else if (key == KEY2_PRES)
						LED_RED_Off();//关闭LED1
					
    }
}

三、外部中断

MSP432P401R并不是每一个IO口都可以中断,必须参考msp432p401r第17页

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JWUQ1klo-1690345264992)(D:\Typora\图片\image-20230721141203189.png)]

port interrupt:端口中断

只有P1到P7所以IO口可以做外部中断

(一)库函数

1.gpio.h
  • (1)开启外部中断
GPIO_enableInterrupt(GPIO_PORT_Px,GPIO_PINx);
  • 配置触发方式
GPIO_interruptEdgeSelect(GPIO_PORT_P1,GPIO_PIN4,Edge);

Edge有效值:

GPIO_HIGH_TO_LOW_TRANSITION//下降沿(从高到低)
GPIO_LOW_TO_HIGH_TRANSITION//上升沿(从低到高)
  • 获取GPIO中断状态
GPIO_getEnabledInterruptStatus(GPIO_PORT_Px);
  • 清除GPIO中断标志位
GPIO_clearInterruptFlag(GPIO_PORT_Px,GPIO_PINx);

配合使用

status=GPIO_getEnabledInterruptStatus(GPIO_PORT_Px);
GPIO_clearInterruptFlag(GPIO_PORT_Px,status);
2.interrupt.h
  • 开启总中断
Interrupt_enableMaster(void);
  • 开启端口中断
Interrupt_enableInterrupt(interruptNumber);

interruptNumber有效值:

INT_PORT1
INT_PORT2
INT_PORT3
INT_PORT4
INT_PORT5
INT_PORT6

(二)一般配置步骤

  1. 配置GPIO输入

    GPIO_setAsInputPinWithPullUpResistor(GPIO_PORT_P1, GPIO_PIN1); //P1.1
    GPIO_setAsInputPinWithPullUpResistor(GPIO_PORT_P1, GPIO_PIN4); //P1.4
    
  2. 清除中断标志位

    GPIO_clearInterruptFlag(GPIO_PORT_P1, GPIO_PIN1);
    GPIO_clearInterruptFlag(GPIO_PORT_P1, GPIO_PIN4);
    
  3. 配置触发方式

    GPIO_interruptEdgeSelect(GPIO_PORT_P1, GPIO_PIN1, GPIO_HIGH_TO_LOW_TRANSITION);
    GPIO_interruptEdgeSelect(GPIO_PORT_P1, GPIO_PIN4, GPIO_HIGH_TO_LOW_TRANSITION);
    
  4. 开启外部中断

    GPIO_enableInterrupt(GPIO_PORT_P1, GPIO_PIN1);
    GPIO_enableInterrupt(GPIO_PORT_P1, GPIO_PIN4);
    
  5. 开启端口中断

    Interrupt_enableInterrupt(INT_PORT1);
    
  6. 开启总中断

    Interrupt_enableMaster();
    
  7. 编写中断服务函数

void PORT1_IRQHandler(void)
{
	uint16_t status;
	
	status = GPIO_getEnabledInterruptStatus(GPIO_PORT_P1);
	GPIO_clearInterruptFlag(GPIO_PORT_P1, status);
	delay_ms(10);//按键消抖
	
	if (status & GPIO_PIN1) //对应P1.1
	{
		if (KEY1 == 0)
		{
			LED_RED_On(); //点亮红灯
			
		}
	}
	if (status & GPIO_PIN4) //对应P1.4
	{
		if (KEY2 == 0)
		{
			LED_RED_Tog();//翻转红灯
			
		}
	}
}

(三)中断优先级管理

详情见技术手册(slau356)82页

  • 等级越低,中断优先级越高,也就是说等级0的优先级最高。

  • 支持动态调整优先级

  • 将优先级分为组优先级和子优先级,组优先级高的是可以打断组优先级低的,组优先级一样时就不会被打断,如果发生了两个组优先级一样的中断,则子优先级高的会先执行,另一个挂起

  • 注意,这里的子优先级是硬件优先级,是已经设置好了的,不能更改

详情见msp432p401r第117页,中断号(NVIC INTERRUPT INPUT)越小,子优先级越高

例子:

​ 系统有两个中断,中断A和中断B,中断号分别为1和2。
​ 当不进行中断优先级配置时,组优先级一致,中断号即为中断优先级,中断号小的中断优先级高,所以中断优先级为A>B。假如此时系统正在执行中断B,而中断A发生了,系统会如何处理呢?因为它们组优先级一样,故中断A不能打断中断B,系统会先挂起中断A,待中断B执行完后,再执行中断A;
​ 倘若将中断A的组优先级设置为1,中断B的组优先级设置为2,此时系统正在执行中断B,而中断A发生了,系统会如何处理呢?因为组优先级小的优先级高,所以中断优先级是A>B,故系统打断中断B,执行中断A,待中断A执行完后,再继续执行中断B。

总结:

  • 组优先级高的能打断组优先级低的
  • 在组优先级一样的情况下,子优先级高的不能打断子优先级低的
1.代码
  • 设置组优先级
Interrupt_setPriority(interruptNuber,level);

level:x<<5,x∈[0,7]

只使用高3位,配置时左移5位。

(四)外部中断实验

exti.h

#ifndef __EXTI_H
#define __EXIT_H	 
#include "driverlib.h"
   	 
void EXTIX_Init(void);//外部中断初始化


#endif

exti.c

#include "driverlib.h"
#include "exti.h"


void EXTIX_Init(void)
{
	//1.配置GPIO输入
	GPIO_setAsInputPinWithPullUpResistor(GPIO_PORT_P1, GPIO_PIN1); //P1.1
	GPIO_setAsInputPinWithPullUpResistor(GPIO_PORT_P1, GPIO_PIN4); //P1.4

	//2.清除中断标志位
	GPIO_clearInterruptFlag(GPIO_PORT_P1, GPIO_PIN1);
	GPIO_clearInterruptFlag(GPIO_PORT_P1, GPIO_PIN4);

	//3.配置触发方式
	GPIO_interruptEdgeSelect(GPIO_PORT_P1, GPIO_PIN1, GPIO_HIGH_TO_LOW_TRANSITION);
	GPIO_interruptEdgeSelect(GPIO_PORT_P1, GPIO_PIN4, GPIO_HIGH_TO_LOW_TRANSITION);

	//4.5 配置组优先级
	Interrupt_setPriority(INT_PORT1, 1 << 5);
	Interrupt_setPriority(INT_PORT1, 2 << 5);

	//4.开启外部中断
	GPIO_enableInterrupt(GPIO_PORT_P1, GPIO_PIN1);
	GPIO_enableInterrupt(GPIO_PORT_P1, GPIO_PIN4);

	//5.开启端口中断
	Interrupt_enableInterrupt(INT_PORT1);

	//6.开启总中断
	Interrupt_enableMaster();
}

main.h

#include "driverlib.h"

/* Standard Includes */
#include <stdint.h>
#include <stdbool.h>

#include "led.h"
#include "key.h"
#include "delay.h"
#include "exti.h"

int main(void)
{
	
    /* Stop Watchdog  */
    MAP_WDT_A_holdTimer();

    LED_Init();
    EXTIX_Init();
		delay_init();
    while (1)
    {
    }
}

//7.编写中断服务函数
void PORT1_IRQHandler(void)
{
	uint16_t status;
	
	status = GPIO_getEnabledInterruptStatus(GPIO_PORT_P1);
	GPIO_clearInterruptFlag(GPIO_PORT_P1, status);
	delay_ms(10);//按键消抖
	
	if (status & GPIO_PIN1) //对应P1.1
	{
		if (KEY1 == 0)
		{
			LED_RED_On(); //点亮红灯
			
		}
	}
	if (status & GPIO_PIN4) //对应P1.4
	{
		if (KEY2 == 0)
		{
			LED_RED_Tog();//翻转红灯
			
		}
	}
}

四、串口收发

(一)MSP432P401R串口资源+

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wWrtfid0-1690345264992)(D:\Typora\图片\image-20230704220945418.png)]

详见msp432p401r第6页

A0的串口是通过跳线帽连接到调试器上的

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wUvcYTeL-1690345264992)(D:\Typora\图片\image-20230704221144484.png)]

开发板手册(slau597f)第38页

(二)UART模式的特性

  • 7/8个数据位、1个奇/偶/无奇偶效验位
  • 独立的发送和接收移位寄存器
  • 独立的发送和接收缓冲寄存器
  • LSP优先/MSB优先的数据发送和接收
  • 为多处理器系统内置空闲线和地址位通信协议
  • 支持分数波特率的可编程调制波特率
  • 用于错误检测和抑制的状态标志
  • 针对地址检测的状态标志
  • 针对接收、发送,起始位接收和发送完成的独立中断能力

数据手册(slau356)第904页

(三)库函数

1.uart.h

  • 初始化串口函数

    UART_initModule(EUSCI_Ax_BASE, &uartConfig);
    
  • 使能串口模块

    UART_enableModule(EUSCI_Ax_BASE);
    
  • 开启串口相关中断

    UART_enableInterrupt(EUSCI_Ax_BASE, EUSCI_x_INTERRUPT);
    
  • 获取数据

    UART_receiveData(EUSCI_Ax_BASE)
  • 发送数据

    UART_transmitData(EUSCI_Ax_BASE,Data_8bit);
    
  • 开启串口端口中断

    Interrupt_enableInterrupt(INT_EUSCIAx);
    
  • 开启总中断

    Interrupt_enableMaster(void);
    

(四)一般配置步骤

  1. 配置时钟
  2. 配置GPIO复用
  3. 配置结构体
  4. 初始化串口
  5. 开启串口
  6. 开启串口相关中断
  7. 开启串口端口中断
  8. 开启总中断
  9. 编写UART ISR

(五)代码

usart.h

/****************************************************/
// MSP432P401R
// 串口配置
// Bilibili:m-RNA
// E-mail:m-RNA@qq.com
/****************************************************/

/******************   版本更新说明   *****************
 * 
 * CCS支持printf
 * Keil支持标准C库跟微库
 * 用Keil开发终于可以不开微库啦
 * 
 * ? 需要注意:
 * ①使用标准C库时,将无法使用scanf。
 * 如果需要使用scanf时,请使用微库 MicroLIB
 * ①低频时钟频率下,高波特率使得传输时误差过大,
 * 比如35768Hz下19200波特率,
 * 会使得传输出错,这时可以尝试降低波特率。
 * ②baudrate_calculate的问题请去文件内查看。
 * 
 * **************************************************
 * 
 * ? v3.2  2021/10/28
 * 简化对CCS支持的printf代码
 *
 * ? v3.1  2021/10/18
 * 添加对CCS的printf支持
 *
 * ? v3.0  2021/10/15
 * 此版本支持使用 标准C库
 * 文件正式改名为与正点原子同名的
 * usart.c 和 usart.h,方便移植
 * 仅支持Keil平台开发
 *  
 * ? v2.1  2021/8/27
 * 添加支持固件库v3_21_00_05
 * 仅支持 MicroLIB 微库、Keil平台开发
 * 
 * ? v2.0  2021/8/25
 * uart_init增添了波特率传入参数,可直接配置波特率。
 * 计算UART的代码单独打包为名为
 * baudrate_calculate的c文件和h文件
 * 仅支持 MicroLIB 微库、Keil平台开发
 * 
 * ? v1.0 2021/7/17
 * 仅支持固件库v3_40_01_02
 * 配置了SMCLK 48MHz 波特率 115200的初始化代码,
 * 对接标准输入输出库,使其能使用printf、scanf函数
 * 仅支持 MicroLIB 微库、Keil平台开发
 * 
 ****************************************************/

#ifndef __USART_H
#define __USART_H
#include "driverlib.h"
#include "stdio.h" //1.61328125kb

#ifdef __TI_COMPILER_VERSION__
//CCS平台
#include "stdarg.h"
#include "string.h"
#define USART0_MAX_SEND_LEN     600                 //最大发送缓存字节数
int printf(const char *str, ...);
#endif

void uart_init(uint32_t baudRate);

#endif

usart.c

/****************************************************/
// MSP432P401R
// 串口配置
// Bilibili:m-RNA
// E-mail:m-RNA@qq.com
/****************************************************/

/******************   版本更新说明   *****************
 * 
 * CCS支持printf
 * Keil支持标准C库跟微库
 * 用Keil开发终于可以不开微库啦
 * 
 * ? 需要注意:
 * ①使用标准C库时,将无法使用scanf。
 * 如果需要使用scanf时,请使用微库 MicroLIB
 * ①低频时钟频率下,高波特率使得传输时误差过大,
 * 比如35768Hz下19200波特率,
 * 会使得传输出错,这时可以尝试降低波特率。
 * ②baudrate_calculate的问题请去文件内查看。
 * 
 * **************************************************
 * 
 * ? v3.2  2021/10/28
 * 简化对CCS支持的printf代码
 *
 * ? v3.1  2021/10/18
 * 添加对CCS的printf支持
 *
 * ? v3.0  2021/10/15
 * 此版本支持使用 标准C库
 * 文件正式改名为与正点原子同名的
 * usart.c 和 usart.h,方便移植
 * 仅支持Keil平台开发
 *  
 * ? v2.1  2021/8/27
 * 添加支持固件库v3_21_00_05
 * 仅支持 MicroLIB 微库、Keil平台开发
 * 
 * ? v2.0  2021/8/25
 * uart_init增添了波特率传入参数,可直接配置波特率。
 * 计算UART的代码单独打包为名为
 * baudrate_calculate的c文件和h文件
 * 仅支持 MicroLIB 微库、Keil平台开发
 * 
 * ? v1.0 2021/7/17
 * 仅支持固件库v3_40_01_02
 * 配置了SMCLK 48MHz 波特率 115200的初始化代码,
 * 对接标准输入输出库,使其能使用printf、scanf函数
 * 仅支持 MicroLIB 微库、Keil平台开发
 * 
 ****************************************************/

#include "usart.h"
#include "baudrate_calculate.h"

#ifdef __TI_COMPILER_VERSION__
//CCS平台
uint8_t  USART0_TX_BUF[USART0_MAX_SEND_LEN];             //发送缓冲,最大USART3_MAX_SEND_LEN字节
int printf(const char *str, ...)
{
    uint16_t i,j;
    va_list ap;
    va_start(ap,str);
    vsprintf((char*)USART0_TX_BUF,str,ap);
    va_end(ap);
    i=strlen((const char*)USART0_TX_BUF);       //此次发送数据的长度
    for(j=0;j<i;j++)                            //循环发送数据
    {
      //while(USART_GetFlagStatus(USART3,USART_FLAG_TC)==RESET); //循环发送,直到发送完毕
        UART_transmitData(EUSCI_A0_BASE, USART0_TX_BUF[j]);
    }
    return 0;
}
/*****************   函数说明   *****************
 *
 * 函数:int printf(const char *str, ...);
 * 源码来自@正点原子
 * 稍作改动适配CCS工程,在此也表感谢正点原子。
 *
 *****************   说明结束   *****************/

#else
//Keil支持标准C库跟微库
//预编译
//if 1 使用标准C库 如果报错就使用微库
//if 0 使用微库 得去勾选魔术棒里的 Use MicroLIB
#if 1
#pragma import(__use_no_semihosting)
//标准库需要的支持函数
struct __FILE
{
  int handle;
};
FILE __stdout;
//定义_sys_exit()以避免使用半主机模式
void _sys_exit(int x)
{
  x = x;
}
#else
int fgetc(FILE *f)
{
  while (EUSCI_A_UART_RECEIVE_INTERRUPT_FLAG !=
         UART_getInterruptStatus(EUSCI_A0_BASE, EUSCI_A_UART_RECEIVE_INTERRUPT_FLAG))
    ;
  return UART_receiveData(EUSCI_A0_BASE);
}
#endif
int fputc(int ch, FILE *f)
{
  UART_transmitData(EUSCI_A0_BASE, ch & 0xFF);
  return ch;
}
/*****************   函数说明   *****************
 *
 * 以上两条对接标准输入输出库的函数:
 * int fputc(int ch, FILE *f);
 * int fgetc(FILE *f);
 * 源码为BiliBili平台UP主 “CloudBoyStudio” 编写
 * 本人RNA,不是作者
 * 在此也表感谢
 *
 *****************   说明结束   *****************/
#endif

void uart_init(uint32_t baudRate)
{
#ifdef EUSCI_A_UART_7_BIT_LEN
  //固件库v3_40_01_02
  //默认SMCLK 48MHz 比特率 115200
  const eUSCI_UART_ConfigV1 uartConfig =
      {
          EUSCI_A_UART_CLOCKSOURCE_SMCLK,                // SMCLK Clock Source
          26,                                            // BRDIV = 26
          0,                                             // UCxBRF = 0
          111,                                           // UCxBRS = 111
          EUSCI_A_UART_NO_PARITY,                        // No Parity
          EUSCI_A_UART_LSB_FIRST,                        // MSB First
          EUSCI_A_UART_ONE_STOP_BIT,                     // One stop bit
          EUSCI_A_UART_MODE,                             // UART mode
          EUSCI_A_UART_OVERSAMPLING_BAUDRATE_GENERATION, // Oversampling
          EUSCI_A_UART_8_BIT_LEN                         // 8 bit data length
      };
  eusci_calcBaudDividers((eUSCI_UART_ConfigV1 *)&uartConfig, baudRate); //配置波特率
#else
  //固件库v3_21_00_05
  //默认SMCLK 48MHz 比特率 115200
  const eUSCI_UART_Config uartConfig =
      {
          EUSCI_A_UART_CLOCKSOURCE_SMCLK,                // SMCLK Clock Source
          26,                                            // BRDIV = 26
          0,                                             // UCxBRF = 0
          111,                                           // UCxBRS = 111
          EUSCI_A_UART_NO_PARITY,                        // No Parity
          EUSCI_A_UART_LSB_FIRST,                        // MSB First
          EUSCI_A_UART_ONE_STOP_BIT,                     // One stop bit
          EUSCI_A_UART_MODE,                             // UART mode
          EUSCI_A_UART_OVERSAMPLING_BAUDRATE_GENERATION, // Oversampling
      };
  eusci_calcBaudDividers((eUSCI_UART_Config *)&uartConfig, baudRate); //配置波特率
#endif

  MAP_GPIO_setAsPeripheralModuleFunctionOutputPin(GPIO_PORT_P1, GPIO_PIN2 | GPIO_PIN3, GPIO_PRIMARY_MODULE_FUNCTION);//2.配置GPIO复用
  MAP_UART_initModule(EUSCI_A0_BASE, &uartConfig);//3.初始化串口
  MAP_UART_enableModule(EUSCI_A0_BASE);//4.开启串口模块
	UART_enableInterrupt(EUSCI_A0_BASE, EUSCI_A_UART_RECEIVE_INTERRUPT);//5.开启串口相关中断
	Interrupt_enableInterrupt(INT_EUSCIA0);//6.开启串口端口中断
	Interrupt_enableMaster();//7.开启总中断
}

//8.编写UART ISR
void EUSCIA0_IRQHandler(void)
{
    uint32_t status = UART_getEnabledInterruptStatus(EUSCI_A0_BASE);

    if(status & EUSCI_A_UART_RECEIVE_INTERRUPT_FLAG) //接收中断
    {
        UART_transmitData(EUSCI_A0_BASE, MAP_UART_receiveData(EUSCI_A0_BASE)); //发送数据
    }

}

sysinit.h

/* --COPYRIGHT--,BSD
 * Copyright (c) 2017, Texas Instruments Incorporated
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * *  Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * *  Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * *  Neither the name of Texas Instruments Incorporated nor the names of
 *    its contributors may be used to endorse or promote products derived
 *    from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 * --/COPYRIGHT--*/
#ifndef __SYSCTL_H__
#define __SYSCTL_H__

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

/* Define to ensure that our current MSP432 has the SYSCTL module. This
    definition is included in the device specific header file */
#ifdef __MCU_HAS_SYSCTL__

//*****************************************************************************
//
//! \addtogroup sysctl_api
//! @{
//
//*****************************************************************************

//*****************************************************************************
//
// If building with a C++ compiler, make all of the definitions in this header
// have a C binding.
//
//*****************************************************************************
#ifdef __cplusplus
extern "C"
{
#endif

//*****************************************************************************
//
// Control specific variables
//
//*****************************************************************************
#define SYSCTL_SRAM_BANK7 SYSCTL_SRAM_BANKEN_BNK7_EN
#define SYSCTL_SRAM_BANK6 SYSCTL_SRAM_BANKEN_BNK6_EN
#define SYSCTL_SRAM_BANK5 SYSCTL_SRAM_BANKEN_BNK5_EN
#define SYSCTL_SRAM_BANK4 SYSCTL_SRAM_BANKEN_BNK4_EN
#define SYSCTL_SRAM_BANK3 SYSCTL_SRAM_BANKEN_BNK3_EN
#define SYSCTL_SRAM_BANK2 SYSCTL_SRAM_BANKEN_BNK2_EN
#define SYSCTL_SRAM_BANK1 SYSCTL_SRAM_BANKEN_BNK1_EN

#define SYSCTL_HARD_RESET 1
#define SYSCTL_SOFT_RESET 0

#define SYSCTL_PERIPH_DMA SYSCTL_PERIHALT_CTL_HALT_DMA
#define SYSCTL_PERIPH_WDT SYSCTL_PERIHALT_CTL_HALT_WDT
#define SYSCTL_PERIPH_ADC SYSCTL_PERIHALT_CTL_HALT_ADC
#define SYSCTL_PERIPH_EUSCIB3 SYSCTL_PERIHALT_CTL_HALT_EUB3
#define SYSCTL_PERIPH_EUSCIB2 SYSCTL_PERIHALT_CTL_HALT_EUB2
#define SYSCTL_PERIPH_EUSCIB1 SYSCTL_PERIHALT_CTL_HALT_EUB1
#define SYSCTL_PERIPH_EUSCIB0 SYSCTL_PERIHALT_CTL_HALT_EUB0
#define SYSCTL_PERIPH_EUSCIA3 SYSCTL_PERIHALT_CTL_HALT_EUA3
#define SYSCTL_PERIPH_EUSCIA2 SYSCTL_PERIHALT_CTL_HALT_EUA2
#define SYSCTL_PERIPH_EUSCIA1 SYSCTL_PERIHALT_CTL_HALT_EUA1
#define SYSCTL_PERIPH_EUSCIA0 SYSCTL_PERIHALT_CTL_HALT_EUA0
#define SYSCTL_PERIPH_TIMER32_0_MODULE SYSCTL_PERIHALT_CTL_HALT_T32_0
#define SYSCTL_PERIPH_TIMER16_3 SYSCTL_PERIHALT_CTL_HALT_T16_3
#define SYSCTL_PERIPH_TIMER16_2 SYSCTL_PERIHALT_CTL_HALT_T16_2
#define SYSCTL_PERIPH_TIMER16_1 SYSCTL_PERIHALT_CTL_HALT_T16_1
#define SYSCTL_PERIPH_TIMER16_0 SYSCTL_PERIHALT_CTL_HALT_T16_0

#define SYSCTL_NMIPIN_SRC SYSCTL_NMI_CTLSTAT_PIN_SRC
#define SYSCTL_PCM_SRC SYSCTL_NMI_CTLSTAT_PCM_SRC
#define SYSCTL_PSS_SRC SYSCTL_NMI_CTLSTAT_PSS_SRC
#define SYSCTL_CS_SRC SYSCTL_NMI_CTLSTAT_CS_SRC

#define SYSCTL_REBOOT_KEY   0x6900

#define SYSCTL_1_2V_REF        (uint32_t)&TLV->ADC14_REF1P2V_TS30C - (uint32_t)TLV_BASE
#define SYSCTL_1_45V_REF       (uint32_t)&TLV->ADC14_REF1P45V_TS30C - (uint32_t)TLV_BASE
#define SYSCTL_2_5V_REF        (uint32_t)&TLV->ADC14_REF2P5V_TS30C - (uint32_t)TLV_BASE

#define SYSCTL_85_DEGREES_C    4
#define SYSCTL_30_DEGREES_C    0


#define TLV_START               0x00201004
#define TLV_TAG_RESERVED1      1
#define TLV_TAG_RESERVED2      2
#define TLV_TAG_CS             3
#define TLV_TAG_FLASHCTL       4
#define TLV_TAG_ADC14          5
#define TLV_TAG_RESERVED6      6
#define TLV_TAG_RESERVED7      7
#define TLV_TAG_REF            8
#define TLV_TAG_RESERVED9      9
#define TLV_TAG_RESERVED10     10
#define TLV_TAG_DEVINFO        11
#define TLV_TAG_DIEREC         12
#define TLV_TAG_RANDNUM        13
#define TLV_TAG_RESERVED14     14
#define TLV_TAG_BSL            15
#define TLV_TAGEND             0x0BD0E11D

//*****************************************************************************
//
// Structures for TLV definitions
//
//*****************************************************************************
typedef struct
{
    uint32_t    maxProgramPulses;
    uint32_t    maxErasePulses;
} SysCtl_FlashTLV_Info;

typedef struct
{
    uint32_t rDCOIR_FCAL_RSEL04;
    uint32_t rDCOIR_FCAL_RSEL5;
    uint32_t rDCOIR_MAXPOSTUNE_RSEL04;
    uint32_t rDCOIR_MAXNEGTUNE_RSEL04;
    uint32_t rDCOIR_MAXPOSTUNE_RSEL5;
    uint32_t rDCOIR_MAXNEGTUNE_RSEL5;
    uint32_t rDCOIR_CONSTK_RSEL04;
    uint32_t rDCOIR_CONSTK_RSEL5;
    uint32_t rDCOER_FCAL_RSEL04;
    uint32_t rDCOER_FCAL_RSEL5;
    uint32_t rDCOER_MAXPOSTUNE_RSEL04;
    uint32_t rDCOER_MAXNEGTUNE_RSEL04;
    uint32_t rDCOER_MAXPOSTUNE_RSEL5;
    uint32_t rDCOER_MAXNEGTUNE_RSEL5;
    uint32_t rDCOER_CONSTK_RSEL04;
    uint32_t rDCOER_CONSTK_RSEL5;

} SysCtl_CSCalTLV_Info;

//*****************************************************************************
//
// Prototypes for the APIs.
//
//*****************************************************************************

//*****************************************************************************
//
//! Gets the size of the SRAM.
//!
//! \return The total number of bytes of SRAM.
//
//*****************************************************************************
extern uint_least32_t SysCtl_getSRAMSize(void);

//*****************************************************************************
//
//! Gets the size of the flash.
//!
//! \return The total number of bytes of flash.
//
//*****************************************************************************
extern uint_least32_t SysCtl_getFlashSize(void);

//*****************************************************************************
//
//! Reboots the device and causes the device to re-initialize itself.
//!
//! \return This function does not return.
//
//*****************************************************************************
extern void SysCtl_rebootDevice(void);

//*****************************************************************************
//
//! The TLV structure uses a tag or base address to identify segments of the
//! table where information is stored. Some examples of TLV tags are Peripheral
//! Descriptor, Interrupts, Info Block and Die Record. This function retrieves
//! the value of a tag and the length of the tag.
//!
//! \param tag represents the tag for which the information needs to be
//!        retrieved.
//!        Valid values are:
//!        - \b TLV_TAG_RESERVED1
//!        - \b TLV_TAG_RESERVED2
//!        - \b TLV_TAG_CS
//!        - \b TLV_TAG_FLASHCTL
//!        - \b TLV_TAG_ADC14
//!        - \b TLV_TAG_RESERVED6
//!        - \b TLV_TAG_RESERVED7
//!        - \b TLV_TAG_REF
//!        - \b TLV_TAG_RESERVED9
//!        - \b TLV_TAG_RESERVED10
//!        - \b TLV_TAG_DEVINFO
//!        - \b TLV_TAG_DIEREC
//!        - \b TLV_TAG_RANDNUM
//!        - \b TLV_TAG_RESERVED14
//! \param instance In some cases a specific tag may have more than one
//!        instance. For example there may be multiple instances of timer
//!        calibration data present under a single Timer Cal tag. This variable
//!        specifies the instance for which information is to be retrieved (0,
//!        1, etc.). When only one instance exists; 0 is passed.
//! \param length Acts as a return through indirect reference. The function
//!        retrieves the value of the TLV tag length. This value is pointed to
//!        by *length and can be used by the application level once the
//!        function is called. If the specified tag is not found then the
//!        pointer is null 0.
//! \param data_address acts as a return through indirect reference. Once the
//!        function is called data_address points to the pointer that holds the
//!        value retrieved from the specified TLV tag. If the specified tag is
//!        not found then the pointer is null 0.
//!
//! \return None
//
//*****************************************************************************
extern void SysCtl_getTLVInfo(uint_fast8_t tag, uint_fast8_t instance,
        uint_fast8_t *length, uint32_t **data_address);

//*****************************************************************************
//
//! Enables a set of banks in the SRAM. This can be used to optimize power
//! consumption when every SRAM bank isn't needed. It is important to note
//! that when a  higher bank is enabled, all of the SRAM banks below that bank
//! are also enabled. For example, if the user enables SYSCTL_SRAM_BANK7,
//! the banks SYSCTL_SRAM_BANK1 through SYSCTL_SRAM_BANK7 will be enabled
//! (SRAM_BANK0 is reserved and always enabled).
//!
//! \param sramBank The SRAM bank tier to enable.
//!        Must be only one of the following values:
//!                 - \b SYSCTL_SRAM_BANK1,
//!                 - \b SYSCTL_SRAM_BANK2,
//!                 - \b SYSCTL_SRAM_BANK3,
//!                 - \b SYSCTL_SRAM_BANK4,
//!                 - \b SYSCTL_SRAM_BANK5,
//!                 - \b SYSCTL_SRAM_BANK6,
//!                 - \b SYSCTL_SRAM_BANK7
//!
//! \note \b SYSCTL_SRAM_BANK0 is reserved and always enabled.
//!
//! \return None.
//
//*****************************************************************************
extern void SysCtl_enableSRAMBank(uint_fast8_t sramBank);

//*****************************************************************************
//
//! Disables a set of banks in the SRAM. This can be used to optimize power
//! consumption when every SRAM bank isn't needed. It is important to note
//! that when a  higher bank is disabled, all of the SRAM banks above that bank
//! are also disabled. For example, if the user disables SYSCTL_SRAM_BANK5,
//! the banks SYSCTL_SRAM_BANK6 through SYSCTL_SRAM_BANK7 will be disabled.
//!
//! \param sramBank The SRAM bank tier to disable.
//!        Must be only one of the following values:
//!                 - \b SYSCTL_SRAM_BANK1,
//!                 - \b SYSCTL_SRAM_BANK2,
//!                 - \b SYSCTL_SRAM_BANK3,
//!                 - \b SYSCTL_SRAM_BANK4,
//!                 - \b SYSCTL_SRAM_BANK5,
//!                 - \b SYSCTL_SRAM_BANK6,
//!                 - \b SYSCTL_SRAM_BANK7
//!
//! \note \b SYSCTL_SRAM_BANK0 is reserved and always enabled.
//!
//! \return None.
//
//*****************************************************************************
extern void SysCtl_disableSRAMBank(uint_fast8_t sramBank);

//*****************************************************************************
//
//! Enables retention of the specified SRAM bank register when the device goes
//! into LPM3 mode. When the system is placed in LPM3 mode, the SRAM
//! banks specified with this function will be placed into retention mode. By
//! default, retention of every SRAM bank except SYSCTL_SRAM_BANK0 (reserved) is
//! disabled. Retention of individual banks can be set without the restrictions
//! of the enable/disable functions.
//!
//! \param sramBank The SRAM banks to enable retention
//!        Can be a bitwise OR of the following values:
//!                 - \b SYSCTL_SRAM_BANK1,
//!                 - \b SYSCTL_SRAM_BANK2,
//!                 - \b SYSCTL_SRAM_BANK3,
//!                 - \b SYSCTL_SRAM_BANK4,
//!                 - \b SYSCTL_SRAM_BANK5,
//!                 - \b SYSCTL_SRAM_BANK6,
//!                 - \b SYSCTL_SRAM_BANK7
//! \note  \b SYSCTL_SRAM_BANK0 is reserved and retention is always enabled.
//!
//!
//! \return None.
//
//*****************************************************************************
extern void SysCtl_enableSRAMBankRetention(uint_fast8_t sramBank);

//*****************************************************************************
//
//! Disables retention of the specified SRAM bank register when the device goes
//! into LPM3 mode. When the system is placed in LPM3 mode, the SRAM
//! banks specified with this function will not be placed into retention mode.
//! By default, retention of every SRAM bank except SYSCTL_SRAM_BANK0 (reserved)
//! is disabled. Retention of individual banks can be set without the
//! restrictions of the enable/disable SRAM bank functions.
//!
//! \param sramBank The SRAM banks to disable retention
//!        Can be a bitwise OR of the following values:
//!                 - \b SYSCTL_SRAM_BANK1,
//!                 - \b SYSCTL_SRAM_BANK2,
//!                 - \b SYSCTL_SRAM_BANK3,
//!                 - \b SYSCTL_SRAM_BANK4,
//!                 - \b SYSCTL_SRAM_BANK5,
//!                 - \b SYSCTL_SRAM_BANK6,
//!                 - \b SYSCTL_SRAM_BANK7
//! \note  \b SYSCTL_SRAM_BANK0 is reserved and retention is always enabled.
//!
//! \return None.
//
//
//*****************************************************************************
extern void SysCtl_disableSRAMBankRetention(uint_fast8_t sramBank);

//*****************************************************************************
//
//! Makes it so that the provided peripherals will either halt execution after
//! a CPU HALT. Parameters in this function can be combined to account for
//! multiple peripherals. By default, all peripherals keep running after a
//! CPU HALT.
//!
//! \param devices The peripherals to continue running after a CPU HALT
//!         This can be a bitwise OR of the following values:
//!                 - \b SYSCTL_PERIPH_DMA,
//!                 - \b SYSCTL_PERIPH_WDT,
//!                 - \b SYSCTL_PERIPH_ADC,
//!                 - \b SYSCTL_PERIPH_EUSCIB3,
//!                 - \b SYSCTL_PERIPH_EUSCIB2,
//!                 - \b SYSCTL_PERIPH_EUSCIB1
//!                 - \b SYSCTL_PERIPH_EUSCIB0,
//!                 - \b SYSCTL_PERIPH_EUSCIA3,
//!                 - \b SYSCTL_PERIPH_EUSCIA2
//!                 - \b SYSCTL_PERIPH_EUSCIA1,
//!                 - \b SYSCTL_PERIPH_EUSCIA0,
//!                 - \b SYSCTL_PERIPH_TIMER32_0_MODULE,
//!                 - \b SYSCTL_PERIPH_TIMER16_3,
//!                 - \b SYSCTL_PERIPH_TIMER16_2,
//!                 - \b SYSCTL_PERIPH_TIMER16_1,
//!                 - \b SYSCTL_PERIPH_TIMER16_0
//!
//! \return None.
//
//
//*****************************************************************************
extern void SysCtl_enablePeripheralAtCPUHalt(uint_fast16_t devices);

//*****************************************************************************
//
//! Makes it so that the provided peripherals will either halt execution after
//! a CPU HALT. Parameters in this function can be combined to account for
//! multiple peripherals. By default, all peripherals keep running after a
//! CPU HALT.
//!
//! \param devices The peripherals to disable after a CPU HALT
//!
//! The \e devices parameter can be a bitwise OR of the following values:
//!         This can be a bitwise OR of the following values:
//!                 - \b SYSCTL_PERIPH_DMA,
//!                 - \b SYSCTL_PERIPH_WDT,
//!                 - \b SYSCTL_PERIPH_ADC,
//!                 - \b SYSCTL_PERIPH_EUSCIB3,
//!                 - \b SYSCTL_PERIPH_EUSCIB2,
//!                 - \b SYSCTL_PERIPH_EUSCIB1
//!                 - \b SYSCTL_PERIPH_EUSCIB0,
//!                 - \b SYSCTL_PERIPH_EUSCIA3,
//!                 - \b SYSCTL_PERIPH_EUSCIA2
//!                 - \b SYSCTL_PERIPH_EUSCIA1,
//!                 - \b SYSCTL_PERIPH_EUSCIA0,
//!                 - \b SYSCTL_PERIPH_TIMER32_0_MODULE,
//!                 - \b SYSCTL_PERIPH_TIMER16_3,
//!                 - \b SYSCTL_PERIPH_TIMER16_2,
//!                 - \b SYSCTL_PERIPH_TIMER16_1,
//!                 - \b SYSCTL_PERIPH_TIMER16_0
//!
//! \return None.
//
//
//*****************************************************************************
extern void SysCtl_disablePeripheralAtCPUHalt(uint_fast16_t devices);

//*****************************************************************************
//
//! Sets the type of RESET that happens when a watchdog timeout occurs.
//!
//! \param resetType The type of reset to set
//!
//! The \e resetType parameter must be only one of the following values:
//!         - \b SYSCTL_HARD_RESET,
//!         - \b SYSCTL_SOFT_RESET
//!
//! \return None.
//
//
//*****************************************************************************
extern void SysCtl_setWDTTimeoutResetType(uint_fast8_t resetType);

//*****************************************************************************
//
//! Sets the type of RESET that happens when a watchdog password violation
//! occurs.
//!
//! \param resetType The type of reset to set
//!
//! The \e resetType parameter must be only one of the following values:
//!         - \b SYSCTL_HARD_RESET,
//!         - \b SYSCTL_SOFT_RESET
//!
//! \return None.
//
//
//*****************************************************************************
extern void SysCtl_setWDTPasswordViolationResetType(uint_fast8_t resetType);

//*****************************************************************************
//
//! Disables NMIs for the provided modules. When disabled, a NMI flag will not
//! occur when a fault condition comes from the corresponding modules.
//!
//! \param flags The NMI sources to disable
//! Can be a bitwise OR of the following parameters:
//!         - \b SYSCTL_NMIPIN_SRC,
//!         - \b SYSCTL_PCM_SRC,
//!         - \b SYSCTL_PSS_SRC,
//!         - \b SYSCTL_CS_SRC
//!
//
//*****************************************************************************
extern void SysCtl_disableNMISource(uint_fast8_t flags);

//*****************************************************************************
//
//! Enables NMIs for the provided modules. When enabled, a NMI flag will
//! occur when a fault condition comes from the corresponding modules.
//!
//! \param flags The NMI sources to enable
//! Can be a bitwise OR of the following parameters:
//!         - \b SYSCTL_NMIPIN_SRC,
//!         - \b SYSCTL_PCM_SRC,
//!         - \b SYSCTL_PSS_SRC,
//!         - \b SYSCTL_CS_SRC
//!
//
//*****************************************************************************
extern void SysCtl_enableNMISource(uint_fast8_t flags);

//*****************************************************************************
//
//! Returns the current sources of NMIs that are enabled
//!
//! \return Bitwise OR of NMI flags that are enabled
//
//*****************************************************************************
extern uint_fast8_t SysCtl_getNMISourceStatus(void);

//*****************************************************************************
//
//! Enables glitch suppression on the reset pin of the device. Refer to the
//! device data sheet for specific information about glitch suppression
//!
//! \return None.
//
//
//*****************************************************************************
extern void SysCtl_enableGlitchFilter(void);

//*****************************************************************************
//
//! Disables glitch suppression on the reset pin of the device. Refer to the
//! device data sheet for specific information about glitch suppression
//!
//! \return None.
//
//
//*****************************************************************************
extern void SysCtl_disableGlitchFilter(void);

//*****************************************************************************
//
//! Retrieves the calibration constant of the temperature sensor to be used
//! in temperature calculation.
//!
//! \param refVoltage Reference voltage being used.
//!
//! The \e refVoltage parameter must be only one of the following values:
//!         - \b SYSCTL_1_2V_REF
//!         - \b SYSCTL_1_45V_REF
//!         - \b SYSCTL_2_5V_REF
//!
//! \param temperature is the calibration temperature that the user wants to be
//!     returned.
//!
//! The \e temperature parameter must be only one of the following values:
//!         - \b SYSCTL_30_DEGREES_C
//!         - \b SYSCTL_85_DEGREES_C
//!
//! \return None.
//
//
//*****************************************************************************
extern uint_fast16_t SysCtl_getTempCalibrationConstant(uint32_t refVoltage,
        uint32_t temperature);

//*****************************************************************************
//
// Mark the end of the C bindings section for C++ compilers.
//
//*****************************************************************************
#ifdef __cplusplus
}
#endif

//*****************************************************************************
//
// Close the Doxygen group.
//! @}
//
//*****************************************************************************

#endif /* __MCU_HAS_SYSCTL__ */

#endif // __SYSCTL_H__

sysinit.c

/****************************************************/
//MSP432P401R
//时钟配置
//Bilibili:m-RNA
//E-mail:m-RNA@qq.com
//创建日期:2021/8/11
/****************************************************/

#include "sysinit.h"

//High:48MHz  Low:32768Hz
//MCLK=48MHz  SMCLK=48MHz
void SysInit(void)
{
    WDTCTL = WDTPW | WDTHOLD; // 停用看门狗

    /* 第一步需要配置我们的时钟引脚,这里的高速时钟使用的是外部晶振*/
    //低速时钟初始化比较慢
    MAP_GPIO_setAsPeripheralModuleFunctionOutputPin(GPIO_PORT_PJ, GPIO_PIN3 | GPIO_PIN2, GPIO_PRIMARY_MODULE_FUNCTION); //High
    MAP_GPIO_setAsPeripheralModuleFunctionOutputPin(GPIO_PORT_PJ, GPIO_PIN0 | GPIO_PIN1, GPIO_PRIMARY_MODULE_FUNCTION); //Low
    CS_setExternalClockSourceFrequency(32768, 48000000);

    /* Starting HFXT in non-bypass mode without a timeout. Before we start
     * we have to change VCORE to 1 to support the 48MHz frequency */
    MAP_PCM_setCoreVoltageLevel(PCM_VCORE1);

    /* 更改闪存控制器使用的等待状态数用于读取操作。
    当改变时钟的频率范围时,必须使用此函数以允许可读闪存
    通俗来讲就是CPU跑太快了,Flash跟不上,让CPU等等它 */
    MAP_FlashCtl_setWaitState(FLASH_BANK0, 1);
    MAP_FlashCtl_setWaitState(FLASH_BANK1, 1);

    CS_startHFXT(false);          //这是晶体 需要驱动
    CS_startLFXT(CS_LFXT_DRIVE3); //驱动等级3

    MAP_CS_initClockSignal(CS_MCLK, CS_HFXTCLK_SELECT, CS_CLOCK_DIVIDER_1);  //48MHz   16分频时,滴答延时可达到最长
    MAP_CS_initClockSignal(CS_SMCLK, CS_HFXTCLK_SELECT, CS_CLOCK_DIVIDER_1); //48MHz
}

baudrate_calculate.h

/****************************************************/
// MSP432P401R
// 串口波特率计算
// Bilibili:m-RNA
// E-mail:m-RNA@qq.com
/****************************************************/

/******************************    说明    ******************************
 *
 * 源码为TI官方编写,本人只是将JS程序移植到了C语言平台,仅作为学习使用。源码出处为:
 * http://software-dl.ti.com/msp430/msp430_public_sw/mcu/msp430/MSP430BaudRateConverter/index.html
 * 
 * ? 已知问题:
 * 调试时发现某些情况下,C语言的小数的大小与JS的相差较大,
 * 导致了算出的UCSx(即secondModReg)不一样,
 * 这时如果出现不能准确传输时,请换一个波特率。
 *
 * ? 需要注意:
 * 波特率不能大于时钟频率,否则会退出函数
 * 
 * *****************************   版本说明   ******************************
 * 
 * ? v1.2 2021/8/29
 * 注释掉了闪烁灯的代码
 * 
 * ? v1.1  2021/8/27
 * 添加支持固件库v3_21_00_05 
 * 
 * ? v1.0  2021/8/25
 * 仅支持固件库v3_40_01_02
 * 
 * *******************************   结束    *******************************/
 
 #ifndef __RNA_BAUDRATE_CALCULATE_H
#define __RNA_BAUDRATE_CALCULATE_H
#include "driverlib.h"

//错误指示灯宏定义 方便移植使用
//MSP432P401R 有两个红灯P1.0 P2.0
//#define WARN_LED_1_PORT GPIO_PORT_P1
//#define WARN_LED_2_PORT GPIO_PORT_P2
//#define WARN_LED_1_PIN GPIO_PIN0
//#define WARN_LED_2_PIN GPIO_PIN0
//#define WARN_LED_INIT MAP_GPIO_setAsOutputPin
//#define WARN_LED_ON MAP_GPIO_setOutputHighOnPin
//#define WARN_LED_OFF MAP_GPIO_setOutputLowOnPin

#ifdef EUSCI_A_UART_7_BIT_LEN
void eusci_calcBaudDividers(eUSCI_UART_ConfigV1 *uart_config, uint32_t baudRate); //固件库v3_40_01_02
#else
void eusci_calcBaudDividers(eUSCI_UART_Config *uart_config, uint32_t baudRate); //固件库v3_21_00_05
#endif

#endif

baudrate_calculate.c

/****************************************************/
// MSP432P401R
// 串口波特率计算
// Bilibili:m-RNA
// E-mail:m-RNA@qq.com
/****************************************************/

/******************************    说明    ******************************
 *
 * 源码为TI官方编写,本人只是将JS程序移植到了C语言平台,仅作为学习使用。源码出处为:
 * http://software-dl.ti.com/msp430/msp430_public_sw/mcu/msp430/MSP430BaudRateConverter/index.html
 *
 * ? 已知问题:
 * 调试时发现某些情况下,C语言的小数的大小与JS的相差较大,
 * 导致了算出的UCSx(即secondModReg)不一样,
 * 这时如果出现不能准确传输时,请换一个波特率。
 *
 * ? 需要注意:
 * 波特率不能大于时钟频率,否则会退出函数
 *
 * *****************************   版本说明   ******************************
 *
 * ? v1.2 2021/8/29
 * 注释掉了闪烁灯的代码
 * 
 * ? v1.1  2021/8/27
 * 添加支持固件库v3_21_00_05
 *
 * ? v1.0  2021/8/25
 * 仅支持固件库v3_40_01_02
 *
 * *******************************   结束    *******************************/

#include "baudrate_calculate.h"

//void uart_warning_led(void);

/*
 *  ======== bitPosition ========
 *  return 1(0) if the specified bit position in value is set(clear)
 */
bool bitPosition(uint16_t value, uint16_t position)
{
    if ((value & (1 << position)))
        return 1;
    return 0;
}

/*
 *  ======== eusci_calcBaudDividers ========
 *  computes the eUSCI_UART register settings for a given clock and baud rate
 *
 *      UCOS16:      the oversampling bit (0 or 1)
 *      UCBRx:       the Baud Rate Control Word
 *      UCFx:        the First modulation stage select (UCBRFx)
 *      UCSx:        the Second modulation stage select (UCBRSx)
 *      maxAbsError: the maximum TX error for the register setting above
 *
 *  The first four field names match the names used in Table 18-5,
 *  "Recommended Settings for Typical Crystals and Baudrates", of the
 *  MSP430FR57xx Family User's Guide (SLAU272A).
 */
#ifdef EUSCI_A_UART_7_BIT_LEN
void eusci_calcBaudDividers(eUSCI_UART_ConfigV1 *uart_config, uint32_t baudRate) //固件库v3_40_01_02
#else
void eusci_calcBaudDividers(eUSCI_UART_Config *uart_config, uint32_t baudRate) //固件库v3_21_00_05
#endif
{
    float maxAbsErrorInByte;
    float minAbsError;
    float error;
    uint8_t ii;
    uint16_t jj;
    uint16_t NN;
    uint32_t count;
    uint32_t clockRate;

    if (!uart_config || !baudRate) //传参错误 退出函数
    {
        //uart_warning_led(); //闪烁错误指示灯10次
        return;
    }

    if (uart_config->selectClockSource == EUSCI_A_UART_CLOCKSOURCE_SMCLK)
        clockRate = MAP_CS_getSMCLK();
    else if (uart_config->selectClockSource == EUSCI_A_UART_CLOCKSOURCE_ACLK)
        clockRate = MAP_CS_getACLK();
    else
    {
        uart_config->selectClockSource = EUSCI_A_UART_CLOCKSOURCE_SMCLK;
        clockRate = MAP_CS_getSMCLK();
    }
    if (baudRate > clockRate) //判断波特率是否大于时钟频率 是则退出函数
    {
        //uart_warning_led(); //闪烁错误指示灯10次
        return;
    }
    //var result = {UCOS16 : 0, UCBRx : 0, UCFx : 0, UCSx : 0, maxAbsError : 0};

    NN = (uint16_t)((float)clockRate / (float)baudRate); //应该是不需要floor

    minAbsError = 100000;
    for (jj = 0; jj <= 255; jj++)
    {

        maxAbsErrorInByte = 0;
        count = 0;
        for (ii = 0; ii <= 10; ii++)
        {
            count += NN + bitPosition(jj, 7 - (ii % 8));

            //error = (ii + 1) * baudPeriod - count * clockPeriod;
            error = (ii + 1) / (float)baudRate - count / (float)clockRate; //为了减少变量,改为此代码

            if (error < 0)
                error = -error;

            if (error > maxAbsErrorInByte)
                maxAbsErrorInByte = error;
        }
        if (maxAbsErrorInByte - minAbsError < -7.3e-12f) //这里就是“已知问题”
        {
            minAbsError = maxAbsErrorInByte;
            uart_config->secondModReg = jj;
        }
    }

    if (NN < 20)
    {
        uart_config->overSampling = 0;
        uart_config->clockPrescalar = NN;
        uart_config->firstModReg = 0;
    }
    else
    {
        uart_config->overSampling = 1;
        uart_config->clockPrescalar = (uint16_t)((float)NN / 16.0f); //应该是不需要floor
        uart_config->firstModReg = NN - (uart_config->clockPrescalar * 16);
    }
    //return minAbsError * baudRate * 100;
}

闪烁错误指示灯10次
//void uart_warning_led(void)
//{
//    uint8_t ii;
//    uint32_t jj;
//    WARN_LED_INIT(WARN_LED_1_PORT, WARN_LED_1_PIN);
//    WARN_LED_INIT(WARN_LED_2_PORT, WARN_LED_2_PIN);
//    for (ii = 0; ii < 10; ii++)
//    {
//        WARN_LED_ON(WARN_LED_1_PORT, WARN_LED_1_PIN);
//        WARN_LED_OFF(WARN_LED_2_PORT, WARN_LED_2_PIN);
//        for (jj = 0; jj < 100000; jj++)
//            ;
//        WARN_LED_OFF(WARN_LED_1_PORT, WARN_LED_1_PIN);
//        WARN_LED_ON(WARN_LED_2_PORT, WARN_LED_2_PIN);
//        for (jj = 0; jj < 100000; jj++)
//            ;
//    }
//}

main.c

#include "driverlib.h"

/* Standard Includes */
#include <stdint.h>
#include <stdbool.h>

#include "sysinit.h"
#include "usart.h"
#include "baudrate_calculate.h"

int main(void)
{
	SysInit();		 //1.配置时钟
	uart_init(115200); //包含了2.配置GPIO复用   3.初始化串口   4.开启串口模块
	
	printf("MSP432\r\n");
	printf("2021/8/24\r\n\r\n");

	char c = '!';
	char *s = "printf test";
	int i = -12345;
	unsigned u = 4321;
	long int l = -123456780;
	unsigned long n = 1098765432;
	unsigned x = 0x89AB;

	printf("Char           %c\r\n", c);
	printf("String         %s\r\n", s);
	printf("Integer        %d\r\n", i);
	printf("Unsigned       %u\r\n", u);
	printf("Long           %d\r\n", l);
	printf("Unsigned long  %u\r\n", n);
	printf("HEX            %X\r\n", x);

	while (1)
	{
//		 使用微库则可支持 scanf
//		 char a[100];
//		 scanf("%s", a);
//		 printf("%s\r\n", a);
	}
}

注意:未知原因scanf用不了,勾选了微库也无法解决

五、定时器A中断

(一)MSP432P401R定时器A资源

MSP432P401R共有4个定时器A,每一个定时器A共有5个通道

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rHAWOoWn-1690345264993)(D:\Typora\图片\image-20230705150356304.png)]

Timer_A的特性包括

  • 具有4种操作模式的异步16位定时/计数器;
  • 可选择和可配置的时钟源;
  • 最多达7个可配置的捕获/比较模块;
  • 具有PWM 功能的可配置输出;
  • 异步输入和输出锁存。

详见技术手册第783页

(二)计数模式

  • 连续计数模式

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Vk2F64ZP-1690345264994)(D:\Typora\图片\image-20230705152737087.png)]

从0开始计数,直到计数到216(65535),然后又从0计数,不断循环,可用于定时器捕获

  • 增计数模式

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-54uIKhSp-1690345264994)(D:\Typora\图片\image-20230705152852465.png)]

需要设置CCR0比较值寄存器0,CCR0确定定时器周期,可以将CCR0理解为STM32的ARR自动重装载值,定时器中断周期的计算公式也是通用的:Ttimer_a= C l k D i v × ( C C R 0 + 1 ) f   c l k   \quad {ClkDiv×(CCR0+1)\over f~clk~} f clk ClkDiv×(CCR0+1)【时钟分频乘以计数值(CCR0+1)的和除以时钟频率】

==ClkDiv ∈ [1, 8] ∪ {10, 12, 14, 16, 20, 24, 28, 32, 40, 48, 56, 64 };==这里与STM32不同,是固定的

  • 增减计数模式

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mbgfEyFo-1690345264994)(D:\Typora\图片\image-20230705152949119.png)]

从0开始计数到CCR0递减为0

(三)库函数

1.初始化定时器模块

Timer_A_configureUpMode(TIMER_Ax_BASE, &upConfig);

2.选择模式开始计数

Timer_A_startCounter(TIMER_Ax_BASE, TIMER_A_UP_MODE);

3.清除比较中断标志位

Timer_A_clearCaptureCompareInterrupt(TIMER_Ax, REGISTER_0);

4.开启定时器A端口中断

Interrupt_enableInterrupt(INT_TAx_0);

5.开启总中断

Interrupt_enableMaster(void);

(四)定时器中断的一般配置

  1. 配置时钟
  2. 配置结构体
  3. 初始化定时器A
  4. 选择模式开始计数
  5. 清除比较中断标志位
  6. 开启定时器端口中断
  7. 开启总中断
  8. 编写TIMA ISR

(五)TIMER_A0定时0.5秒闪灯

timA.h

#ifndef __RNA_TIMA_H
#define __RNA_TIMA_H
#include <ti/devices/msp432p4xx/driverlib/driverlib.h>

void TimA0_Int_Init(uint16_t ccr0, uint16_t psc);

#endif

timA.c

#include "timA.h"

void TimA0_Int_Init(uint16_t ccr0, uint16_t psc)
{
    // 1.增计数模式初始化
    Timer_A_UpModeConfig upConfig;
    upConfig.clockSource = TIMER_A_CLOCKSOURCE_SMCLK;                                      //时钟源
    upConfig.clockSourceDivider = psc;                                                     //时钟分频 范围1-64
    upConfig.timerPeriod = ccr0;                                                           //自动重装载值(ARR)
    upConfig.timerInterruptEnable_TAIE = TIMER_A_TAIE_INTERRUPT_DISABLE;                   //禁用 tim溢出中断
    upConfig.captureCompareInterruptEnable_CCR0_CCIE = TIMER_A_CCIE_CCR0_INTERRUPT_ENABLE; //启用 ccr0更新中断
    upConfig.timerClear = TIMER_A_DO_CLEAR;                                                // Clear value

    // 2.初始化定时器A
    MAP_Timer_A_configureUpMode(TIMER_A0_BASE, &upConfig);

    // 3.选择模式开始计数
    MAP_Timer_A_startCounter(TIMER_A0_BASE, TIMER_A_UP_MODE);

    // 4.清除比较中断标志位
    MAP_Timer_A_clearCaptureCompareInterrupt(TIMER_A0_BASE, TIMER_A_CAPTURECOMPARE_REGISTER_0);

    // 5.开启串口端口中断
    MAP_Interrupt_enableInterrupt(INT_TA0_0);
}

// 6.编写TIMA ISR
void TA0_0_IRQHandler(void)
{
    MAP_Timer_A_clearCaptureCompareInterrupt(TIMER_A0_BASE, TIMER_A_CAPTURECOMPARE_REGISTER_0);

    /*开始填充用户代码*/

    MAP_GPIO_toggleOutputOnPin(GPIO_PORT_P1, GPIO_PIN0);

    /*结束填充用户代码*/
}
/*********************************************************************************************************/

main.c

#include "sysinit.h"
#include "usart.h"
#include "timA.h"
#include "usart.h"
#include "led.h"

#define CLKDIV 64   //时钟源分频
#define CCR0 37499  // 比较值0

/*
 * 定时器中断周期:
 *
 * T_timer_a = CLKDIV * (CCR0 + 1) / f_clk 
 *           = 64 * 37500 / 48000000 
 *           = 0.05s = 20Hz
 */
 
int main(void)
{
    SysInit();  			     // 第3讲 时钟配置
	LED_Init();					 // 第2讲 GPIO输出
	TimA0_Int_Init(CCR0,CLKDIV); // 第8讲 TIMA中断
    
    MAP_Interrupt_enableMaster(); // 开启总中断
    while (1)
    {
    }
}

六、定时器A PWM模式

(一)计数模式

  • 增计数模式

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ntdCf3QU-1690345264994)(D:\Typora\图片\image-20230705152852465.png)]

需要设置CCR0比较值寄存器0,CCR0确定定时器周期,可以将CCR0理解为STM32的ARR自动重装载值,定时器中断周期的计算公式也是通用的:Ttimer_a= C l k D i v × ( C C R 0 + 1 ) f   c l k   \quad {ClkDiv×(CCR0+1)\over f~clk~} f clk ClkDiv×(CCR0+1)【时钟分频乘以计数值(CCR0+1)的和除以时钟频率】

==ClkDiv ∈ [1, 8] ∪ {10, 12, 14, 16, 20, 24, 28, 32, 40, 48, 56, 64 };==这里与STM32不同,是固定的

  • 增减计数模式

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HARZl8qg-1690345264995)(D:\Typora\图片\image-20230705152949119.png)]

从0开始计数到CCR0递减为0

(二)输出模式

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LshlM5Dw-1690345264995)(D:\Typora\图片\image-20230705212358007.png)]

​ 增计数模式 增减计数模式

定时器A有7种输出模式,但常用的只有两种

  • Output Mode 2:Toggle/Reset

    当计时器计数到TAxCCRn值时,输出切换。当计时器计数到TAxCCR0值时,它被重置

  • Output Mode 6:Toggle/Set

    当计时器计数到TAxCCRn值时,输出切换。当计时器计数到TAxCCR0值时设置

详见msp432p401r第791页

1.增计数模式:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BBU0QtDf-1690345264995)(D:\Typora\图片\image-20230705212755577.png)]

定时器A从0计数到比较值1(CCR1)时,模式6输出高电平,之后比较值1计数到比较值0(CCR0)时,输出为低电平

比较值0是确定了整个定时器的周期

当选择输出模式2时,可以看到输出是相反的。

2.增减计数模式:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Yfjr1MLN-1690345264996)(D:\Typora\图片\image-20230705213922999.png)]

模式2和模式6配合后能生成带死区的互补PWM

一个定时器A能生成2路的带死区的互补PWM

(三)定时器A输出通道资源

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Cg0ljXQt-1690345264996)(D:\Typora\图片\image-20230705214540751.png)]

带有PM是支持端口重映射的意思

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KtpaNgDP-1690345264996)(D:\Typora\图片\image-20230705214714199.png)]

(四)库函数

  • 初始化定时器为PWM模式
Timer_A_generatePWM(TIMER_Ax_BASE, &TimAx_PWMConfig);
  • 改变比较值(占空比/周期)
Timer_A_setCompareValue(TIMER_Ax, COMPARE_REGISTER_x, CCR);

(五)一般配置步骤

  1. 配置时钟
  2. 配置GPIO复用
  3. 配置结构体
  4. 初始化定时器

(六)PWM驱动舵机

timA.h

#ifndef __RNA_TIMA_H
#define __RNA_TIMA_H
#include <ti/devices/msp432p4xx/driverlib/driverlib.h>

void TimA1_PWM_Init(uint16_t ccr0, uint16_t psc);


#endif

timA.c

#include "timA.h"

void TimA1_PWM_Init(uint16_t ccr0, uint16_t psc)
{
    /*初始化引脚*/
    MAP_GPIO_setAsPeripheralModuleFunctionOutputPin(GPIO_PORT_P7, GPIO_PIN7, GPIO_PRIMARY_MODULE_FUNCTION);

    Timer_A_PWMConfig TimA1_PWMConfig;
    /*定时器PWM初始化*/
    TimA1_PWMConfig.clockSource = TIMER_A_CLOCKSOURCE_SMCLK;             //时钟源
    TimA1_PWMConfig.clockSourceDivider = psc;                            //时钟分频 范围1-64
    TimA1_PWMConfig.timerPeriod = ccr0;                                  //自动重装载值(ARR)
    TimA1_PWMConfig.compareRegister = TIMER_A_CAPTURECOMPARE_REGISTER_1; //通道一 (引脚定义)
    TimA1_PWMConfig.compareOutputMode = TIMER_A_OUTPUTMODE_TOGGLE_SET;   //输出模式
    TimA1_PWMConfig.dutyCycle = ccr0;                                    //这里是改变占空比的地方 默认100%

    MAP_Timer_A_generatePWM(TIMER_A1_BASE, &TimA1_PWMConfig); /* 初始化比较寄存器以产生 PWM1 */
}

main.c

#include "sysinit.h"
#include "usart.h"
#include "delay.h"
#include "timA.h"

/*
 * 定时器PWM周期:
 *`   
 * T_timer_a = CLKDIV * (CCR0 + 1) / f_clk
 *           = 48 * (19999 + 1) / 48000000
 *           = 0.02s = 50Hz
 */

#define CLKDIV 48     // 时钟源分频
#define CCR0 19999    // 比较值0
#define CCR1_MIN 499  // ( 499 + 1) / (19999 + 1) =  500 / 20000 =  2.5%
#define CCR1_MAX 2499 // (2499 + 1) / (19999 + 1) = 2500 / 20000 = 12.5%

int main(void)
{
    bool dir = 1;
    uint16_t i = CCR1_MIN;

    SysInit();    //第3讲 时钟配置
    delay_init(); //第4讲 滴答延时
	
    TimA1_PWM_Init(CCR0, CLKDIV); //第8讲 定时器A PWM
    while (1)
    {
        if (dir)
            i++;
        else
            i--;

        if (i == CCR1_MAX)
        {
            dir = 0;
            delay_ms(50);
        }
        else if (i == CCR1_MIN)
        {
            dir = 1;
            delay_ms(50);
        }
        MAP_Timer_A_setCompareValue(TIMER_A1_BASE, TIMER_A_CAPTURECOMPARE_REGISTER_1, i);
        delay_us(600);
    }
}

七、定时器32

(一)定时器32介绍

Timer32的主要特性包括:

  • 两个独立的计数器,每个都可配置成32位递减或16位计数器;
  • 每个计数器具有3种不同的定时器模式;
  • 每个计数器都可独立产生中断,而且两个计数器可生成一个组合中断。
  • 输入时钟可预分频为1、1/16或1/256;(MCLK)

中断向量:

  • INT_T32_INT1(定时器32_0)
  • INT_T32_INT2(定时器32_1)
  • INT_T32_INTC (Combine 结合)

定时器时钟使能由分频单元产生,并使能由计数器创建的具有下列条件之一的定时时钟:

  • MCLK #define TIMER32_PRESCALER_1 0x00

  • 由4位预分频产生的16分频MCLK #define TIMER32_PRESCALER_16 0x04

  • 由总共8位预分频产生的256分频MCLK #define TIMER32_PRESCALER_256 0x08

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sl5XiQQ6-1690345264996)(D:\Typora\图片\image-20230706151006407.png)]

详见技术手册第756、766页

(二)Timer32的计数模式

  • 自由运行模式: 计数器在递减到0后,继续从最大值递减。这是默认模式
  • 周期定时器模式:需要设置ARR(自动重装载值),ARR确定定时器32的周期,然后计数器以恒定的间隔生成一个中断,在递减到0后重新加载原始值(ARR)。常用
  • 单次定时器模式:计数器产生一次中断。当计数器达到零时,它会停止,直到被用户重新编程。

定时器周期计算:

Ttimer_a= C l k D i v × ( A R R + 1 ) f   c l k   \quad {ClkDiv×(ARR+1)\over f~clk~} f clk ClkDiv×(ARR+1)【时钟分频乘以计数值(CCR0+1)的和除以时钟频率】

ClkDiv ∈ {1, 16, 256 };

例 1s= 1 (不分频) × ( A R R + 1 ) 48000000 \quad {1(不分频)×(ARR+1)\over 48000000} 480000001(不分频)×(ARR+1)

得出ARR+1=48000000

(三)库函数

  • 初始化定时器
 MAP_Timer32_initModule(TIMER32_0_BASE, psc, TIMER32_32BIT, TIMER32_PERIODIC_MODE);
  • 设置ARR重装载值
MAP_Timer32_setCount(TIMER32_0_BASE, aar);
  • 配置定时器32开始连续计数 false
MAP_Timer32_startTimer(TIMER32_0_BASE, false); //连续计数模式 false
  • 清除中断标志位
MAP_Timer32_clearInterruptFlag(TIMER32_0_BASE);
  • 使能定时器32中断
MAP_Timer32_enableInterrupt(TIMER32_0_BASE);
  • 开启定时器32端口中断
MAP_Interrupt_enableInterrupt(INT_T32_INT1);

(四)一般配置步骤

配置时钟

  • 初始化为32位周期计数模式
  • 设置ARR自动重装载值
  • 清除中断标志位
  • 使能定时器32中断
  • 配置定时器32开始连续计数
  • 开启定时器32端口中断
  • 开启总中断
  • 编写TIM32 ISR

(五)打印一个自增的数值

tim32.h

#ifndef __RNA_TIM32_H
#define __RNA_TIM32_H
#include <ti/devices/msp432p4xx/driverlib/driverlib.h>

void Tim32_0_Int_Init(uint32_t aar, uint8_t psc);

#endif

tim32.c

#include "tim32.h"
#include "usart.h"

void Tim32_0_Int_Init(uint32_t aar, uint8_t psc)
{
    MAP_Timer32_initModule(TIMER32_0_BASE, psc, TIMER32_32BIT, TIMER32_PERIODIC_MODE);

    MAP_Timer32_setCount(TIMER32_0_BASE, aar);

    MAP_Timer32_enableInterrupt(TIMER32_0_BASE);

    MAP_Timer32_startTimer(TIMER32_0_BASE, false); //连续计数模式 false

    MAP_Interrupt_enableInterrupt(INT_T32_INT1);
}

/* Timer32 ISR */
void T32_INT1_IRQHandler(void)
{
    MAP_Timer32_clearInterruptFlag(TIMER32_0_BASE);

    /*开始填充用户代码*/
    static uint8_t timer_second = 0;

    //一般在频率较高的中断不常用 这个printf比较费时间 这里只是演示
    printf("%d秒过去了\r\n\r\n", ++timer_second);

    /*结束填充用户代码*/
}

main.c

#include "sysinit.h"
#include "usart.h"
#include "led.h"
#include "tim32.h"

/*
 * 定时器中断周期:
 *
 * T_timer_32 = CLKDIV * (ARR + 1) / f_clk 
 *            = 1 * 48000000 / 48000000 
 *            = 1s = 1Hz
 */

#define CLKDIV TIMER32_PRESCALER_1 // 时钟源分频
#define ARR 47999999               // 自动重装载值

int main(void)
{
    SysInit();                     // 第3讲 时钟配置
    uart_init(115200);             // 第7讲 串口配置
	
    Tim32_0_Int_Init(ARR, CLKDIV); // 第9讲 TIM32中断
	
	printf("砸瓦鲁多\r\n\r\n");

    MAP_Interrupt_enableMaster(); // 开启总中断

    while (1)
    {
    }
}

八、GPIO复用

(一)库函数

  • 配置GPIO模式:
GPIO_setAsPeripheralModuleFunctionInputPin(Port, Pin,mode);//复用输入
GPIO_setAsPeripheralModuleFunctionOutputPin(Port, Pin,mode);//复用输出
  • mode参数有效值
GPIO_PRIMARY_MODULE_FUNCTION     //主功能
GPIO_SECONDARY_MODULE_FUNCTION   //第二功能
GPIO_TERTIARY_MODULE_FUNCTION    //第三功能

功能详见msp432o401r第138页

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-eKLnMSwk-1690345264997)(D:\Typora\图片\image-20230706170948920.png)]

看P1SEL1.x+P1SEL0.x:

  • 0 1:主功能
  • 1 0:第二功能
  • 1 1:第三功能

P1DIR.x:方向寄存器

1为输出

0为输入

x表示无需关心。例:使用串口时GPIO的输入输出是由模块接管的,所以配置为复用输入或复用输出都可

需要完整工程代码的点赞加关注,评论留下邮箱我发你

MSP432 低功耗高性能并存10.1 Digital I/O Introduction The digital I/O features include: • Independently programmable individual I/Os • Any combination of input or output • Individually configurable interrupts for ports (available for certain ports only) • Independent input and output data registers • Individually configurable pullup or pulldown resistors • Wake-up capability from ultra-low power modes (available for certain ports only) • Individually configurable high drive I/Os (available for certain I/Os only) Devices within the family may have up to eleven digital I/O ports implemented (P1 to P10 and PJ). Most ports contain eight I/O lines; however, some ports may contain less (see the device-specific data sheet for ports available). Each I/O line is individually configurable for input or output direction, and each can be individually read or written. Each I/O line is individually configurable for pullup or pulldown resistors. Certain ports have interrupt and wake-up capability from ultra-low power modes (see device specific data sheet for ports with interrupt and wake-up capability). Each interrupt can be individually enabled and configured to provide an interrupt on a rising or falling edge of an input signal. All interrupts are fed into an encoded Interrupt Vector register, allowing the application to determine which sub-pin of a port has generated the event. Individual ports can be accessed as byte-wide ports or can be combined into half-word-wide ports. Port pairs P1 and P2, P3 and P4, P5 and P6, P7 and P8, and so on, are associated with the names PA, PB, PC, PD, and so on, respectively. All port registers are handled in this manner with this naming convention. The main exception are the interrupt vector registers, for example, interrupts for ports P1 and P2 must be handled through P1IV and P2IV, PAIV does not exist. When writing to port PA with half-word operations, all 16 bits are written to the port. When writing to the lower byte of port PA using byte operations, the upper byte remains unchanged. Similarly, writing to the upper byte of port PA using byte instructions leaves the lower byte unchanged. When writing to a port that contains less than the maximum number of bits possible, the unused bits are don't care. Ports PB, PC, PD, PE, and PF behave similarly.
评论 48
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

命运从未公平

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

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

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

打赏作者

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

抵扣说明:

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

余额充值