文章目录
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页
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
(二)一般配置步骤
配置GPIO输入
GPIO_setAsInputPinWithPullUpResistor(GPIO_PORT_P1, GPIO_PIN1); //P1.1 GPIO_setAsInputPinWithPullUpResistor(GPIO_PORT_P1, GPIO_PIN4); //P1.4
清除中断标志位
GPIO_clearInterruptFlag(GPIO_PORT_P1, GPIO_PIN1); GPIO_clearInterruptFlag(GPIO_PORT_P1, GPIO_PIN4);
配置触发方式
GPIO_interruptEdgeSelect(GPIO_PORT_P1, GPIO_PIN1, GPIO_HIGH_TO_LOW_TRANSITION); GPIO_interruptEdgeSelect(GPIO_PORT_P1, GPIO_PIN4, GPIO_HIGH_TO_LOW_TRANSITION);
开启外部中断
GPIO_enableInterrupt(GPIO_PORT_P1, GPIO_PIN1); GPIO_enableInterrupt(GPIO_PORT_P1, GPIO_PIN4);
开启端口中断
Interrupt_enableInterrupt(INT_PORT1);
开启总中断
Interrupt_enableMaster();
编写中断服务函数
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串口资源+
详见msp432p401r第6页
A0的串口是通过跳线帽连接到调试器上的
开发板手册(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);
(四)一般配置步骤
- 配置时钟
- 配置GPIO复用
- 配置结构体
- 初始化串口
- 开启串口
- 开启串口相关中断
- 开启串口端口中断
- 开启总中断
- 编写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个通道
Timer_A的特性包括
- 具有4种操作模式的异步16位定时/计数器;
- 可选择和可配置的时钟源;
- 最多达7个可配置的捕获/比较模块;
- 具有PWM 功能的可配置输出;
- 异步输入和输出锁存。
详见技术手册第783页
(二)计数模式
- 连续计数模式
从0开始计数,直到计数到216(65535),然后又从0计数,不断循环,可用于定时器捕获
- 增计数模式
需要设置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不同,是固定的
- 增减计数模式
从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);
(四)定时器中断的一般配置
- 配置时钟
- 配置结构体
- 初始化定时器A
- 选择模式开始计数
- 清除比较中断标志位
- 开启定时器端口中断
- 开启总中断
- 编写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模式
(一)计数模式
- 增计数模式
需要设置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不同,是固定的
- 增减计数模式
从0开始计数到CCR0递减为0
(二)输出模式
增计数模式 增减计数模式
定时器A有7种输出模式,但常用的只有两种
Output Mode 2:Toggle/Reset
当计时器计数到TAxCCRn值时,输出切换。当计时器计数到TAxCCR0值时,它被重置。
Output Mode 6:Toggle/Set
当计时器计数到TAxCCRn值时,输出切换。当计时器计数到TAxCCR0值时设置。
详见msp432p401r第791页
1.增计数模式:
定时器A从0计数到比较值1(CCR1)时,模式6输出高电平,之后比较值1计数到比较值0(CCR0)时,输出为低电平
比较值0是确定了整个定时器的周期
当选择输出模式2时,可以看到输出是相反的。
2.增减计数模式:
模式2和模式6配合后能生成带死区的互补PWM
一个定时器A能生成2路的带死区的互补PWM
(三)定时器A输出通道资源
带有PM是支持端口重映射的意思
(四)库函数
- 初始化定时器为PWM模式
Timer_A_generatePWM(TIMER_Ax_BASE, &TimAx_PWMConfig);
- 改变比较值(占空比/周期)
Timer_A_setCompareValue(TIMER_Ax, COMPARE_REGISTER_x, CCR);
(五)一般配置步骤
- 配置时钟
- 配置GPIO复用
- 配置结构体
- 初始化定时器
(六)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
详见技术手册第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页
看P1SEL1.x+P1SEL0.x:
- 0 1:主功能
- 1 0:第二功能
- 1 1:第三功能
P1DIR.x:方向寄存器
1为输出
0为输入
x表示无需关心。例:使用串口时GPIO的输入输出是由模块接管的,所以配置为复用输入或复用输出都可
需要完整工程代码的点赞加关注,评论留下邮箱我发你