S3C2451有 5 个 16 位定时器。其中定时器 0、1、2 和 3 具有脉宽调制(PWM)功能。定时器 4 是一个无输出引脚的内部定时器。定时器 0 还包含用于大电流驱动的死区发生器。
定时器 0 和 1 共用一个 8 位预分频器,定时器 2、3 和 4 共用另外的 8 位预分频器。每个定时器都有一个可以生成 5 种不同分频信号(1/2,1/4,1/8,1/16 和 TCLK)的时钟分频器。每个定时器模块从相应 8 位预分频器得到时钟的时钟分频器中得到其自己的时钟信号。8 位预分频器是可编程的,并且按存储在 TCFG0 和 TCFG1 寄存器中的加载值来分频 PCLK。
定时计数缓冲寄存器(TCNTBn)包含了一个当使能了定时器时的被加载到递减计数器中的初始值。定时比较缓冲寄存器(TCMPBn)包含了一个被加载到比较寄存器中的与递减计数器相比较的初始值。
这种 TCNTBn 和TCMPBn 的双缓冲特征保证了改变频率和占空比时定时器产生稳定的输出。
每个定时器有它自己的由定时器时钟驱动的 16 位递减计数器。当递减计数器到达零时,产生定时器中断请求通知 CPU 定时器操作已经完成。当定时器计数器到达零时,相应的 TCNTBn 的值将自动被加载到递减计数器以继续下一次操作。然而,如果定时器停止了,例如,在定时器运行模式期间清除 TCONn 的定时器使能位,TCNTBn
的值将不会被重新加载到计数器中。
TCMPBn 的值是用于脉宽调制(PWM)。当递减计数器的值与定时器控制逻辑中的比较寄存器的值相匹配时定
时器控制逻辑改变输出电平。因此,比较寄存器决定 PWM 输出的开启时间(或关闭时间)
PWM:脉冲宽度调制 利用微处理器的数字输出来对模拟电路进行控制的技术
分频器一般都是跟计数单元一起结合使用。
预分频比是在计数单元值发生变化之前起作用(假如不用预分频时,计数器在每个上升沿到来时加1,而现在使用分频比为1:2的预分频器的话,那么必须等到两个上升沿的到来,计数器才会加1)后分频器与预分频器功能一样,只不过是在计数器值发生改变后起作用。像TMR2的后分频器,如果不使用,计数器一但发生溢出,将立即置位标志为TMR2IF,但是如果有1:2的后分频器的话,必须两次溢出后才会置位.
需要配置的寄存器:
1,TCFG0 TCFG1
TCFG0前8位设置TIMER0 TIMER1的预分频值 后8位设置TIMER2,3,4预分频值
TCFG1前四位设置TIMER0的分频值,之后以此类推,每四位设置一个定时器
定时器时钟频率 = PCLK/(预分频值+1)/(分频值)
预分频器和分频器
一个 8 位预分频器和一个 4 位分频器产生出以下输出频率:
4 位分频器设置 | 最小分辨率 (预分频器=0) | 最大分辨率 (预分频器=255) | 最大间隔时间 (TCNTBn=65535) |
1/2 (PCLK = 50 MHz) | 0.0400 µs (25.0000 MHz) | 10.2400 µs (97.6562 KHz) | 0.6710 秒 |
1/4 (PCLK = 50 MHz) | 0.0800 µs (25.0000 MHz) | 20.4800 µs (97.6562 KHz) | 1.3421 秒 |
1/8 (PCLK = 50 MHz) | 0.1600 µs (25.0000 MHz) | 40.9601 µs (97.6562 KHz) | 2.6843 秒 |
1/16 (PCLK = 50 MHz) | 0.3200 µs (25.0000 MHz) | 81.9188 µs (97.6562 KHz) | 5.3686 秒 |
2,TCNTB 计数缓冲寄存器 设置计数初始值,可通过计算来设置定时器的定时时间
TCMPB计数比较寄存器 设置PWM(占空比)
3,TCON 定时控制寄存器
4,TCNTO 计时监视寄存器 可以获取TCNT寄存器的值,观测计数到了那里
定时器开启步骤:
1,设置预分频
2,设置分频
3,设置重载值或者初始值
4,开启自动重载(间隙模式)
5,开启手动更新
6,开启定时器
7,关闭手动更新
程序如下:
s3c2451_timer.h
main.c
程序如下:
s3c2451_timer.h
#ifndef _S3C2451_H
#define _S3C2451_H
#include "typedef.h"
typedef struct {
U32 TCFG0;
U32 TCFG1;
U32 TCON;
U32 TCNTB0;
U32 TCMPB0;
U32 TCNTO0;
U32 TCNTB1;
U32 TCMPB1;
U32 TCNTO1;
U32 TCNTB2;
U32 TCMPB2;
U32 TCNTO2;
U32 TCNTB3;
U32 TCMPB3;
U32 TCNTO3;
U32 TCNTB4;
U32 TCNTO4;
}volatile* TIM_MemMapPtr;
#define TIM_BASE_PTR ((TIM_MemMapPtr)0x51000000)
typedef enum {
Tim_ch0 = 0,
Tim_ch1,
Tim_ch2,
Tim_ch3,
Tim_ch4
}TIM_Typedef;
typedef struct{
unsigned int TIM_prescale;
unsigned int TIM_scale;
unsigned int TIM_countval;
unsigned int TIM_compareval;
}TIM_InitTypedef;
extern void TIM_Init(TIM_Typedef timx, TIM_InitTypedef tim_init_typedef);
extern U32 TIM_getcount(TIM_Typedef timx);
extern void TIM_Interrupt_init(TIM_Typedef timx, U32 addr);
extern void MyTime_Init(void);
#endif
s3c2451_timer.c
#include "s3c2451_timer.h"
#include "s3c2451_vector.h"
#include "s3c2451_irq.h"
/**函数名:TIM_Init
*参数:
*功能:初始化定时器
**/
void TIM_Init(TIM_Typedef timx, TIM_InitTypedef tim_init_typedef)
{
TIM_BASE_PTR->TCFG0 &= ~(0xff); //先清零
TIM_BASE_PTR->TCFG0 |= 199; //预分频 199
TIM_BASE_PTR->TCFG1 &= ~(0xf); //先清零
TIM_BASE_PTR->TCFG1 |= 0x2; //8分频
TIM_BASE_PTR->TCNTB0 = 41250; //初值
TIM_BASE_PTR->TCMPB0 = 20625; //比较初值
TIM_BASE_PTR->TCON &= 0xf; //清零
TIM_BASE_PTR->TCON |= (1<<3); //设置自动加载
TIM_BASE_PTR->TCON |= (1<<1); //update
TIM_BASE_PTR->TCON |= 0x1; //start
TIM_BASE_PTR->TCON &= ~(1<<1); //清楚update位
}
/**函数名:TIM_getcount
*参数:
*功能:获取当前定时器计数值
**/
U32 TIM_getcount(TIM_Typedef timx)
{
return TIM_BASE_PTR->TCNTO0;
}
/**函数名:TIM_Interrupt_init
*参数:
*功能:初始化定时器中断
**/
void TIM_Interrupt_init(TIM_Typedef timx, U32 addr)
{
switch(timx)
{
case Tim_ch0: pISR_TIMER0 = addr; break;
case Tim_ch1: pISR_TIMER1 = addr; break;
case Tim_ch2: pISR_TIMER2 = addr; break;
case Tim_ch3: pISR_TIMER3 = addr; break;
default:break;
}
IRQ_INTMSK_Init(INT_TIMER0, ENABLE);
}
/**函数名:MyTime_Init
*参数:
*功能:
**/
void MyTime_Init()
{
TIM_InitTypedef tim_init_typedef;
TIM_Init(Tim_ch0, tim_init_typedef);
}
main.c
#include "main.h"
void delay(volatile int count)
{
while (count--);
}
void delay_ms(unsigned int xms)
{
unsigned int j;
for(; xms > 0; xms--)
{
for(j = 500; j > 0; j --);
}
}
void Main(void)
{
//My_interrupt_Uart(115200, (U32)UART0_IRQ);
LED_INIT();
MyTime_Init();
TIM_Interrupt_init(Tim_ch0, (U32)TIMER0_IRQ);
while(1)
{
if(TIM_getcount(Tim_ch0) == 20625)
{
GPIO_WriteBit(GPIOB, GPIO_Pin_6, BIT_RESET);
}
if(TIM_getcount(Tim_ch0) == 0)
{
GPIO_WriteBit(GPIOB, GPIO_Pin_6, BIT_SET);
}
}
}