8、TM4单片机的滴答定时器,及利用定时器精确延时

在我们日常使用单片机的时候,延时一般采用循环的方式,但是这样的方式只能用于粗略的延时,但我们需要精准的时间控制的时候,便需要利用定时器获得精确的延时。

本次采用TM4内的滴答定时器

文章目录

    • 1、滴答定时器使用
      • (1)初始化代码
      • (2)解释
    • 2、利用定时器进行延时的方法
      • 1、精髓:micros()函数
      • 2、利用micros()实现延时
    • 测试例程1
    • 测试例程2

1、滴答定时器使用

滴答定时器结构比较简单,在TM4内部是一个24位自减的计数器。

(1)初始化代码

SysTickPeriodSet(SysCtlClockGet()/1000);    // 1ms
SysTickIntRegister(SysTick_IntHandler);
SysTickIntEnable();
SysTickEnable();

(2)解释

1、首先进行周期设置,用系统频率除以1000,表示1ms的中断。

计算方法:定时器的工作原理便是在系统时钟驱动下进行计数,假设系统时钟频率是10KHz,代表1秒钟可以计10000个数,即:即计一个数的时间t = 1/10000 s = 0.1 ms,那么如果我要设置一个一毫秒的中断,即需要数10个数,因为10*(1/10000) = 1/1000 s = 1ms

因此对于SysTickPeriodSet()这个函数来说,我需要一毫秒的中断,便将系统时钟除以1000作为参数传进去即可。

2、然后设置中断函数的地址

SysTick_IntHandler便是中断处理函数的函数名称,代表该函数的地址。

3、使能中断,打开定时器

SysTickIntEnable();
SysTickEnable();

4、写中断处理函数

这里是设置了一个全局变量,每进入一次中断便将其加1。

void SysTick_IntHandler(void)
{
    System_Time_ms++;
}

5、测试:见文末测试例程1。

2、利用定时器进行延时的方法

1、精髓:micros()函数

首先我们需要知道系统的当前精确时间,这里实现了一个micros()函数,以微秒为单位。

uint32_t micros(void)
{
    register uint32_t ms, tick;     
    do{
        ms   = System_Time_ms;
        tick = HWREG(NVIC_ST_CURRENT); 
    }while(ms != System_Time_ms);
    
    return (ms+1)*1000 - tick/usTicks;    
}

在这个函数中,因为滴答定时器的中断是1ms,所以System_Time_ms便是系统运行的ms数,HWREG(NVIC_ST_CURRENT)是针对寄存器的操作,获得当前滴答定时器内部的计数值。usTicks = Clock/1000000,所以tick/usTicks = tick*(1000000/Clock),即将定时器计数值转换为实际的us数,然后通过(ms+1)*1000 - tick/usTicks的运算,即得到了us级的系统时间。

2、利用micros()实现延时

这里的逻辑就是进入函数时记录当前时间,然后一直用实时时间和开始时间进行比较,作差,得到延时时间。

void delay_us(uint32_t nus)
{
    uint32_t t0 = micros();
    while(micros() - t0 < nus)
        ;	
}

void delay_ms(uint32_t nms)
{
    uint32_t t0 = micros();
    while(micros() - t0 < nms*1000)
        ;
}

测试:见测试例程2。

测试例程1

功能:打印系统当前时间,以毫秒为单位。

#include 
#include 
#include "inc/hw_gpio.h"
#include "inc/hw_memmap.h"
#include "driverlib/gpio.h"
#include "driverlib/pin_map.h"
#include "driverlib/sysctl.h"
#include "driverlib/uart.h"
#include "driverlib/systick.h"
#include 

uint32_t System_Time_ms = 0;

void delay_ms(int n)
{
    for(int i = 0; i < n; i++)
        SysCtlDelay(SysCtlClockGet()/3000);
}

//重写fputc函数以支持printf
int fputc(int ch, FILE *f)
{
	UARTCharPut(UART0_BASE,(unsigned char)ch);//如果用其他串口,只需修改基址(UART0_BASE)即可。
	return ch;
}

void SysTick_IntHandler(void)
{
    System_Time_ms++;
}

int main()
{   
    SysCtlClockSet(SYSCTL_SYSDIV_5 | SYSCTL_USE_PLL | SYSCTL_OSC_MAIN |  SYSCTL_XTAL_16MHZ);

    //初始化串口0
    SysCtlPeripheralEnable(SYSCTL_PERIPH_UART0);
    while(!SysCtlPeripheralReady(SYSCTL_PERIPH_UART0))
        ;
    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);
    while(!SysCtlPeripheralReady(SYSCTL_PERIPH_GPIOA))
        ;
    GPIOPinConfigure(GPIO_PA0_U0RX);
    GPIOPinConfigure(GPIO_PA1_U0TX);
    GPIOPinTypeUART(GPIO_PORTA_BASE, GPIO_PIN_0 | GPIO_PIN_1);
    UARTClockSourceSet(UART0_BASE, UART_CLOCK_PIOSC);
    UARTConfigSetExpClk(UART0_BASE, 16000000, 115200, (UART_CONFIG_WLEN_8 | UART_CONFIG_STOP_ONE | UART_CONFIG_PAR_NONE));

    //初始化滴答定时器
    SysTickPeriodSet(SysCtlClockGet()/1000);    // 1ms
    SysTickIntRegister(SysTick_IntHandler);
    SysTickIntEnable();
    SysTickEnable();
    
    while(1)
    {
        printf("%d\n", System_Time_ms);//打印系统时间
        delay_ms(100);
    }
}

测试例程2

功能:延时10ms,然后打印出来花费的具体时间。

#include 
#include 
#include "inc/hw_gpio.h"
#include "inc/hw_memmap.h"
#include "driverlib/gpio.h"
#include "driverlib/pin_map.h"
#include "driverlib/sysctl.h"
#include "driverlib/uart.h"
#include "driverlib/systick.h"
#include "inc/hw_types.h"
#include "inc/hw_nvic.h"
#include 

volatile uint32_t usTicks        = 0;
volatile uint32_t System_Time_ms = 0;

void     delay_us(uint32_t nus);
void     delay_ms(uint32_t nms);
int      fputc(int ch, FILE *f);
void     SysTick_IntHandler(void);
uint32_t micros(void);
void     UART0_Init(uint32_t Baud);
void     SysTick_Init(void);

int main(void)
{   
    SysCtlClockSet(SYSCTL_SYSDIV_2_5 | SYSCTL_USE_PLL | SYSCTL_OSC_MAIN |  SYSCTL_XTAL_16MHZ);

    UART0_Init(115200);
    SysTick_Init();
    
    uint32_t t0,t1;
    while(1)
    {
        t0 = micros();
        delay_ms(10);
        t1 = micros();
        printf("%d\n", t1-t0);//打印系统时间
    }
}

void delay_us(uint32_t nus)
{
    uint32_t t0 = micros();
    while(micros() - t0 < nus)
        ;	
}

void delay_ms(uint32_t nms)
{
    uint32_t t0 = micros();
    while(micros() - t0 < nms*1000)
        ;
}

int fputc(int ch, FILE *f)
{
	UARTCharPut(UART0_BASE,(unsigned char)ch);
	return ch;
}

void SysTick_IntHandler(void)
{
    System_Time_ms++;
}

uint32_t micros(void)
{
    register uint32_t ms, tick;     
    do{
        ms   = System_Time_ms;
        tick = HWREG(NVIC_ST_CURRENT); 
    }while(ms != System_Time_ms);
    
    return (ms+1)*1000 - tick/usTicks;    
}

void UART0_Init(uint32_t Baud)
{
    SysCtlPeripheralEnable(SYSCTL_PERIPH_UART0);
    while(!SysCtlPeripheralReady(SYSCTL_PERIPH_UART0))
        ;
    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);
    while(!SysCtlPeripheralReady(SYSCTL_PERIPH_GPIOA))
        ;
    GPIOPinConfigure(GPIO_PA0_U0RX);
    GPIOPinConfigure(GPIO_PA1_U0TX);
    GPIOPinTypeUART(GPIO_PORTA_BASE, GPIO_PIN_0 | GPIO_PIN_1);
    UARTClockSourceSet(UART0_BASE, UART_CLOCK_PIOSC);
    UARTConfigSetExpClk(UART0_BASE, 16000000, Baud, (UART_CONFIG_WLEN_8 | UART_CONFIG_STOP_ONE | UART_CONFIG_PAR_NONE));
}

void SysTick_Init(void)
{
    SysTickPeriodSet(SysCtlClockGet()/1000);    // 1ms
    SysTickIntRegister(SysTick_IntHandler);
    SysTickIntEnable();
    SysTickEnable();
    usTicks = SysCtlClockGet() / 1000000;       // usTicks = 80
}

你可能感兴趣的:(TM4单片机学习)