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

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

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

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 <stdint.h>
#include <stdbool.h>
#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 <stdio.h>

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 <stdint.h>
#include <stdbool.h>
#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 <stdio.h>

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
}

  • 3
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
TM4C123G是德州仪器(Texas Instruments)推出的一款32位ARM Cortex-M4内核的微控制器。它内置了多个定时器模块,其中包括SysTick定时器,也即滴答定时器滴答定时器TM4C123G微控制器上的一个基本定时器,它是一个24位的递减计数器。它可以用来生成延时、定时中断以及系统时钟等功能。 要使用TM4C123G滴答定时器,你需要进行以下步骤: 1. 配置滴答定时器的控制寄存器(SysTick Control Register,SYST_CSR),设置滴答定时器的工作方式和使能定时器。 2. 配置滴答定时器的加载寄存器(SysTick Reload Value Register,SYST_RVR),设置定时器的初始值。 3. 编写滴答定时器的中断服务函数,并将其注册到中断向量表中。 4. 在程序中调用滴答定时器的启动函数,开始定时器的计数。 下面是一个简单的示例代码,演示如何使用TM4C123G滴答定时器实现延时功能: ```c #include <stdint.h> #include "tm4c123gh6pm.h" void SysTick_Handler(void) { // 滴答定时器中断服务函数 // 在此处编写滴答定时器中断处理的代码 } void delay_ms(uint32_t milliseconds) { // 配置滴答定时器的加载寄存器 SysTick->LOAD = (16000 * milliseconds) - 1; // 配置滴答定时器的控制寄存器 SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk | SysTick_CTRL_ENABLE_Msk; // 等待滴答定时器计数结束 while(!(SysTick->CTRL & SysTick_CTRL_COUNTFLAG_Msk)); // 关闭滴答定时器 SysTick->CTRL = 0; } int main() { // 初始化系统时钟等设置 // ... while(1) { // 在此处编写程序逻辑 // ... // 延时1秒钟 delay_ms(1000); } } ``` 在上面的示例中,`delay_ms` 函数用来实现延时功能,通过配置滴答定时器的加载寄存器和控制寄存器来实现指定时间的延时。在主函数中,我们可以调用 `delay_ms` 函数来实现需要的延时效果。 请注意,以上代码只是一个简单示例,实际使用中还需要根据具体需求进行适当的配置和修改。另外,具体的寄存器地址和位定义请参考TM4C123G微控制器的数据手册。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值