文章提供源码与工程,芯片型号MSP432P401R
在前些日子的学习里,我们深刻认识了具有强大功能的定时器A,这是一种广泛存在于各类现有 MSP430 器件的 16 位定时器。同 时,它也是灵活性最高的定时器,由于其可用于众多不同案例,因而堪称“瑞士军刀”级的定时器。
今日学习使用MSP432的另一个定时器: Timer_32 定时器~
目录
Timer_32 定时器的基础概念:
Timer_32 定时器相关初始化函数介绍:
1.Timer_32 定时器初始化函数:
2.设定自动重载值:
3.设定计数模式:
4.开启定时器中断:
5.清除中断标志位:
Timer_32 定时器实战使用编写:
程序下载测试截图:
完整代码贴出:
首先我们将数据手册(1053页的那本)翻阅到765页,看到Timer_32的介绍:
当然~这开头的手册贴图它只是个玩笑,这充满了英文,我怎么可能看得懂~~
所以我将其翻译了:
通过下段介绍,我们知道Timer32有俩个定时器,俩个定时器可以被编程为32或者16位,使用时需要将它选择的时钟进行预分频处理
18.1介绍
Timer32是一款符合AMBA标准的外设,由Arm有限公司开发、测试和授权。的
Timer32由两个可编程的32位或16位下行计数器组成,可以在计数达到零时产生中断。
Timer32的主要特性包括:
•两个独立的计数器,每个可配置为32位或16位计数器大小
•每个计数器支持三种不同的计时器模式
•将输入时钟分频除以1、16或256的预刻度单元
•来自每个计数器的独立中断,以及来自两个计数器的组合中断计数器
通过下段介绍,我们知道了Timer32俩个定时器之间是相互独立的,他们有三种计时模式需要注意说明的是:前面俩种自由运行与周期计数模式是二选一的,第三个一次性定时模式是选择性开关的。
18.2功能介绍
Timer32中有两个独立的计时器。对于每个定时器,有以下操作模式是可用的:
•自由运行模式:计数器在达到零值后轮回,并继续从最大值。这是默认设置的模式。
•周期定时器模式:计数器以恒定的间隔产生中断,重新加载原始数据值。
•一次性定时器模式:计数器产生一次中断。当计数器达到零时,它暂停,直到用户重新编程。这可以通过清除One Shot Count位来实现。在控制寄存器中,在这种情况下,计数根据自由运行或选择进行
周期模式,或通过向加载值寄存器写入一个新值。
通过下段介绍,我们知道了Timer32俩个定时器在对于寄存器的操作上是相同的,也知道了俩种计数模式在计数中断,写入寄存器等操作后的不同状态,以及知道了它的时钟是MCLK的不同分频
18.3操作
每个计时器都有一组相同的寄存器,每个计时器的操作也是相同的。计时器是通过写入加载寄存器进行加载,如果启用使能,则计数降至零。当一个计数器已经运行时,写入加载寄存器将导致计数器立即在新值处重新启动。写命令给后台负载值对当前计数没有影响。如果在周期模式,而不是选中一次性定时器模式:计数器继续递减到零,然后从新的重载值重新开始。
当达到零时,就会产生中断。可以通过写入clear寄存器来清除中断登记。如果选择“一次性定时器模式”,则计数器在达到零时停止,直到“一次性定时器模式”被取消选择,或者写入新的Load值。否则,在达到零计数后,如果计时器正在自由运行模式下,它从最大值继续递减。如果选择周期定时器模式,计时器从加载寄存器重新加载计数值并继续递减。在这种模式下
计数器有效地产生周期性中断。模式由定时器控制中的一个位来选择登记。在任何时候,都可以从当前值寄存器中读取当前计数器的值。通过T32CONTROLx寄存器中的ENABLE位使能。
在重置时,计数器被禁用,中断被清除,负载寄存器被设置为零。模式和预调值设置为自由运行,时钟分频分别为1。
定时器时钟使能是由一个预置单元产生的。然后计数器使用启用来创建一个时钟:具有下列时间之一的时钟:
•MCLK
•MCLK除以16,由4位预刻度生成
•MCLK除以256,由总共8位的预分频产生
图18-1显示了在预刻度单元中定时器时钟频率的选择。这使定时器能够他的时钟频率不同。
通过下段介绍,我们知道了Timer32有三种中断
18.4中断生成。
当完整的32位计数器达到零时会生成中断,并且仅当。T32INTCLRx寄存器被写入值了。寄存器保存该值,直到中断被清除。最多的。计数器的有效进位位检测到计数器达到零。
通过将0写入T32CONTROLx寄存器中的中断使能位,可以屏蔽中断。无论是在原始中断状态,在掩蔽之前,和最终中断状态可以读取屏蔽前的原始中断状态和屏蔽后的最终中断状态。状态寄存器。来自各个计数器的中断在屏蔽之后被逻辑地或进一个。组合中断TIMINTC提供来自定时器32外设的附加中断条件。因此,该模块总共支持三个中断-TIMINT1、TIMINT2和TIMINTC。
此函数初始化设置 定时器预分频、32或16位计数、计数模式这四个参数
MAP_Timer32_initModule(uint32_t timer,uint32_t preScaler,uint32_t resolution, uint32_t mode);
#define ROM_Timer32_initModule \
((void (*)(uint32_t timer, \
uint32_t preScaler, \
uint32_t resolution, \
uint32_t mode))ROM_TIMER32TABLE[0])
uint32_t timer ,可以选择以下定时器之一:
#define TIMER32_0_BASE (uint32_t)TIMER32_1
#define TIMER32_1_BASE (uint32_t)TIMER32_2
uint32_t preScaler:可以选择以下预分频之一( 1、16、256):
#define TIMER32_PRESCALER_1 0x00
#define TIMER32_PRESCALER_16 0x04
#define TIMER32_PRESCALER_256 0x08
uint32_t resolution:可以选择以下计数位数之一(16位或32位):
这个设置影响的是最大重载值不同
#define TIMER32_16BIT 0x00
#define TIMER32_32BIT 0x01
uint32_t mode:可以选择以下计数模式之一:
自由运行模式、周期模式 ,一般使用周期模式
#define TIMER32_FREE_RUN_MODE 0x00
#define TIMER32_PERIODIC_MODE 0x01
MAP_Timer32_setCount(uint32_t timer, uint32_t count);
#define ROM_Timer32_setCount \
((void (*)(uint32_t timer, \
uint32_t count))ROM_TIMER32TABLE[1])
uint32_t count 就是需要填入的自动重载值
MAP_Timer32_startTimer(TIMER32_0_BASE, false); //连续计数模式 false
#define ROM_Timer32_startTimer \
((void (*)(uint32_t timer, \
bool oneShot))ROM_TIMER32TABLE[4])
此处的计数模式选择参数用的是bool类型变量
MAP_Interrupt_enableInterrupt(INT_T32_INT1);
这里的参数可以选择俩个中断,对应32定时器1和2的中断:
#define INT_T32_INT1 (41) /* T32_INT1 IRQ */
#define INT_T32_INT2 (42) /* T32_INT2 IRQ */
MAP_Timer32_clearInterruptFlag(TIMER32_0_BASE);
这个函数就是在中断服务函数中清除中断标志位的,必不可少~
现在进入我们的实战使用环节:
目标:
驱动Timer32定时器0,以1s为周期发送串口测试
首先编写初始化函数,这相较于定时器A,Timer32的初始化十分简单:
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的时钟是MCLK,便可以提供以下公式进行计算:
/*
* 定时器中断周期:
*
* T_timer_32 = CLKDIV * (ARR + 1) / MCLK
* = 1 * 48000000 / 48000000
* = 1s = 1Hz
*/
在这里我希望其周期是1S,因此我作以下初始化:
#define CLKDIV TIMER32_PRESCALER_1 // 时钟源分频
#define ARR 47999999 // 自动重装载值
最后编写中断服务函数:
/* Timer32 ISR */
void T32_INT1_IRQHandler(void)
{
MAP_Timer32_clearInterruptFlag(TIMER32_0_BASE);
static uint8_t timer_second = 0;
//一般在频率较高的中断不常用 这个printf比较费时间 这里只是演示
printf("timer_second=%d\r\n", ++timer_second);
}
完整工程下载地址:
https://download.csdn.net/download/qq_64257614/88041003?spm=1001.2014.3001.5503
移植此代码须知:
将原先RNA的库大部分移除了在复制,只留下截图中有的:
/*TIMER32定时器初始化与使用*/
#include "main.h"
/*
* 定时器中断周期:
*
* T_timer_32 = CLKDIV * (ARR + 1) / MCLK
* = 1 * 48000000 / 48000000
* = 1s = 1Hz
*/
#define CLKDIV TIMER32_PRESCALER_1 // 时钟源分频
#define ARR 47999999 // 自动重装载值
int main(void)
{
inint_all(); //初始化所有模块
while (1)
{
}
}
//初始化所有模块
void inint_all(void)
{
SysInit(); //时钟配置
delay_init(); //delay_ms函数配置
Tim32_0_Int_Init(ARR, CLKDIV);
uart_init(115200); //串口配置
printf("Hello,MSP432!\r\n"); //串口打印测试字符
MAP_Interrupt_enableMaster(); // 开启总中断
}
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("timer_second=%d\r\n", ++timer_second);
}
//串口A0初始化
void uart_init(uint32_t baudRate)
{
//固件库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); //配置波特率
MAP_GPIO_setAsPeripheralModuleFunctionOutputPin(GPIO_PORT_P1, GPIO_PIN2 | GPIO_PIN3, GPIO_PRIMARY_MODULE_FUNCTION);//初始化串口引脚
MAP_UART_initModule(EUSCI_A0_BASE, &uartConfig); //用配置好的结构体初始化串口
MAP_UART_enableModule(EUSCI_A0_BASE); //开启串口模块
MAP_UART_enableInterrupt(EUSCI_A0_BASE,EUSCI_A_UART_RECEIVE_INTERRUPT);//开启串口中断
MAP_Interrupt_enableInterrupt(INT_EUSCIA0);
}
//串口相关:
#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
//重定向Printf,可以切换printf函数对应的串口
int fputc(int ch, FILE *f)
{
UART_transmitData(EUSCI_A0_BASE, ch & 0xFF);
return ch;
}
#ifndef _main_h_
#define _main_h_
#include
#include "string.h" //C标准库、字符串处理库
#include "sysinit.h" //时钟配置
#include "delay.h" //滴答定时器初始化(提供delay_ms延时)
#include "usart.h" //串口初始化库
#include "baudrate_calculate.h"
void inint_all(void); //初始化所有模块
void Tim32_0_Int_Init(uint32_t aar, uint8_t psc);
void uart_init(uint32_t baudRate);
#endif