打印
[应用方案]

NUC970(ARM9)裸机定时器驱动

[复制链接]
6830|12
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
renzheshengui|  楼主 | 2021-7-1 13:13 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
定时器结构比较简单,只需要初始化3个寄存器即可,但是需要使用AIC中断控制器


//定时器基址


//TIM========================================================================================================
#define TIMER0_BASE               (0xB8001000)      //寄存器基址
#define TIMER1_BASE               (0xB8001010)      //寄存器基址
#define TIMER2_BASE               (0xB8001020)      //寄存器基址
#define TIMER3_BASE               (0xB8001030)      //寄存器基址
#define TIMER4_BASE               (0xB8001040)      //寄存器基址
#define TIMER_ISR_ADDR                          (0xB8001060)

typedef struct
{
        vu32 CSP;
        vu32 CMPR;
        vu32 DR;
}TIM_TypeDef;

#define TIM0                       ((TIM_TypeDef *) TIMER0_BASE)
#define TIM1                       ((TIM_TypeDef *) TIMER1_BASE)
#define TIM2                       ((TIM_TypeDef *) TIMER2_BASE)
#define TIM3                       ((TIM_TypeDef *) TIMER3_BASE)
#define TIM4                       ((TIM_TypeDef *) TIMER4_BASE)



使用特权

评论回复
沙发
renzheshengui|  楼主 | 2021-7-1 13:13 | 只看该作者
//timer.c

/*************************************************************************************************************
* 文件名:                        timer.c
* 功能:                        NUC970 定时器支持
* 作者:                        cp1300@139.com
* 创建时间:                2020-08-31
* 最后修改时间:        2020-08-31
* 详细:                        定时器支持
*************************************************************************************************************/
#include "nuc970_system.h"
#include "timer.h"
#include "typedef.h"
#include "irq_aic.h"


static void TIM0_IRQHandler(void);        //定时器0中断服务程序
static void TIM1_IRQHandler(void);        //定时器1中断服务程序
static void TIM2_IRQHandler(void);        //定时器2中断服务程序
static void TIM3_IRQHandler(void);        //定时器3中断服务程序
static void TIM4_IRQHandler(void);        //定时器4中断服务程序

static const u32 scg_TIMx_BASE[TIMER_ChMax] = {TIMER0_BASE, TIMER1_BASE, TIMER2_BASE, TIMER3_BASE, TIMER4_BASE};                                        //定时器基址
static const SYS_DEV_CLOCK scg_TIMx_Clock[TIMER_ChMax] = {DEV_TIMER0, DEV_TIMER1, DEV_TIMER2, DEV_TIMER3, DEV_TIMER4};                                //定时器时钟使能
static const AIC_IRQ_Typedef scg_TIMx_IntIRQ[TIMER_ChMax] = {AIC_TMR0_INT, AIC_TMR1_INT, AIC_TMR2_INT, AIC_TMR3_INT, AIC_TMR4_INT};        //定时器中断号
static const void* sg_TIMx_IRQHandler[TIMER_ChMax] = {TIM0_IRQHandler, TIM1_IRQHandler, TIM2_IRQHandler, TIM3_IRQHandler, TIM4_IRQHandler};//定时器中断服务程序地址
static void * sg_TIMx_CallBack[TIMER_ChMax] = {NULL, NULL, NULL, NULL, NULL};                                                                                                                //定时器中断用户回调函数                                                                                               


/*************************************************************************************************************************
*函数                :        void TIMERx_Start(TIMER_CH_Type ch)
*功能                :        定时器开始计数
*参数                :        ch:定时器通道号
*返回                :        无
*依赖                        :         底层宏定义
*作者               :        cp1300@139.com
*时间                     :        2020-08-31
*最后修改时间        :        2020-08-31
*说明                :        请提前配置好串口
*************************************************************************************************************************/
void TIMERx_Start(TIMER_CH_Type ch)
{
        TIM_TypeDef *TIMx;
       
        if(ch > (TIMER_ChMax-1)) return;                        //定时器通道超出范围
        TIMx = (TIM_TypeDef *)scg_TIMx_BASE[ch];        //获取定时器寄存器
       
        TIMx->CSP |= BIT30;                                                        //使能定时器       
}



使用特权

评论回复
板凳
renzheshengui|  楼主 | 2021-7-1 13:13 | 只看该作者
/*************************************************************************************************************************
*函数                :        void TIMERx_Stop(TIMER_CH_Type ch)
*功能                :        定时器停止计数
*参数                :        ch:定时器通道号
*返回                :        无
*依赖                        :         底层宏定义
*作者               :        cp1300@139.com
*时间                     :        2020-08-31
*最后修改时间        :        2020-08-31
*说明                :        请提前配置好串口
*************************************************************************************************************************/
void TIMERx_Stop(TIMER_CH_Type ch)
{
        TIM_TypeDef *TIMx;
       
        if(ch > (TIMER_ChMax-1)) return;                        //定时器通道超出范围
        TIMx = (TIM_TypeDef *)scg_TIMx_BASE[ch];        //获取定时器寄存器
       
        TIMx->CSP &= ~BIT30;                                                //关闭定时器       
}



使用特权

评论回复
地板
renzheshengui|  楼主 | 2021-7-1 13:14 | 只看该作者
/*************************************************************************************************************************
*函数                :        void TIMERx_CounterReset(TIMER_CH_Type ch)
*功能                :        定时器重置(重置预分配器与计数器,会关闭定时器)
*参数                :        ch:定时器通道号
*返回                :        无
*依赖                        :         底层宏定义
*作者               :        cp1300@139.com
*时间                     :        2020-08-31
*最后修改时间        :        2020-08-31
*说明                :       
*************************************************************************************************************************/
void TIMERx_CounterReset(TIMER_CH_Type ch)
{
        TIM_TypeDef *TIMx;
       
        if(ch > (TIMER_ChMax-1)) return;                        //定时器通道超出范围
        TIMx = (TIM_TypeDef *)scg_TIMx_BASE[ch];        //获取定时器寄存器
       
        TIMx->CSP |= BIT26;                                                        //重置定时器
}


使用特权

评论回复
5
renzheshengui|  楼主 | 2021-7-1 13:14 | 只看该作者
/*************************************************************************************************************************
*函数                :        bool TIMERx_GetActive(TIMER_CH_Type ch)
*功能                :        获取定时器工作状态
*参数                :        ch:定时器通道号
*返回                :        无
*依赖                        :         底层宏定义
*作者               :        cp1300@139.com
*时间                     :        2020-08-31
*最后修改时间        :        2020-08-31
*说明                :       
*************************************************************************************************************************/
bool TIMERx_GetActive(TIMER_CH_Type ch)
{
        TIM_TypeDef *TIMx;
       
        if(ch > (TIMER_ChMax-1)) return FALSE;                //定时器通道超出范围
        TIMx = (TIM_TypeDef *)scg_TIMx_BASE[ch];        //获取定时器寄存器
       
        return (TIMx->CSP & BIT25) ? TRUE : FALSE;        //定时器激活状态
}



使用特权

评论回复
6
renzheshengui|  楼主 | 2021-7-1 13:14 | 只看该作者
/*************************************************************************************************************************
*函数                :        void TIMERx_SetComparedValue(TIMER_CH_Type ch, u32 Count)
*功能                :        设置定时器比较值
*参数                :        ch:定时器通道号,Count:24bit比较值,不能为0
*返回                :        无
*依赖                        :         底层宏定义
*作者               :        cp1300@139.com
*时间                     :        2020-08-31
*最后修改时间        :        2020-08-31
*说明                :        设置后会清楚计数器值,并重新开始计数,不能设置为0
*************************************************************************************************************************/
void TIMERx_SetComparedValue(TIMER_CH_Type ch, u32 Count)
{
        TIM_TypeDef *TIMx;
       
        if(ch > (TIMER_ChMax-1)) return;                        //定时器通道超出范围
        TIMx = (TIM_TypeDef *)scg_TIMx_BASE[ch];        //获取定时器寄存器
        Count &= 0xFFFFFF;
        if(Count < 1) Count = 1;                                        //不能设置为0
       
        TIMx->CMPR = Count;
}



使用特权

评论回复
7
renzheshengui|  楼主 | 2021-7-1 13:14 | 只看该作者
/*************************************************************************************************************************
*函数                :        bool TIMERx_GetCount(TIMER_CH_Type ch)
*功能                :        获取定时器计数器值
*参数                :        ch:定时器通道号
*返回                :        无
*依赖                        :         底层宏定义
*作者               :        cp1300@139.com
*时间                     :        2020-08-31
*最后修改时间        :        2020-08-31
*说明                :        24bit计数器
*************************************************************************************************************************/
u32 TIMERx_GetCount(TIMER_CH_Type ch)
{
        TIM_TypeDef *TIMx;
       
        if(ch > (TIMER_ChMax-1)) return FALSE;                //定时器通道超出范围
        TIMx = (TIM_TypeDef *)scg_TIMx_BASE[ch];        //获取定时器寄存器
       
        return TIMx->DR & 0xFFFFFF;
}



使用特权

评论回复
8
renzheshengui|  楼主 | 2021-7-1 13:14 | 只看该作者
/*************************************************************************************************************************
*函数                :        void TIMERx_ClearIntFlag(TIMER_CH_Type ch)
*功能                :        清除指定定时器的中断标志
*参数                :        ch:定时器通道号
*返回                :        无
*依赖                        :         底层宏定义
*作者               :        cp1300@139.com
*时间                     :        2020-08-31
*最后修改时间        :        2020-08-31
*说明                :       
*************************************************************************************************************************/
void TIMERx_ClearIntFlag(TIMER_CH_Type ch)
{
        if(ch > (TIMER_ChMax-1)) return;                        //定时器通道超出范围
       
        SYS_REG_TYPE(TIMER_ISR_ADDR) |= 1<<ch;                //写1清除中断标志
}



使用特权

评论回复
9
renzheshengui|  楼主 | 2021-7-1 13:15 | 只看该作者

/*************************************************************************************************************************
*函数                :        bool TIMERx_Config(TIMER_CH_Type ch, TIMER_CONFIG *pConfig)
*功能                :        定时器配置
*参数                :        ch:定时器通道号;pConfig:配置结构,见 TIMER_CONFIG
*返回                :        TRUE:配置成功;FALSE:配置失败
*依赖                        :         底层宏定义
*作者               :        cp1300@139.com
*时间                     :        2020-08-31
*最后修改时间        :        2020-08-31
*说明                :       
*************************************************************************************************************************/
bool TIMERx_Config(TIMER_CH_Type ch, TIMER_CONFIG *pConfig)
{
        TIM_TypeDef *TIMx;
        u32 temp = 0;
        u8 IntPro;
       
        if(ch > (TIMER_ChMax-1) || pConfig == NULL) return FALSE;                        //定时器通道超出范围
        TIMx = (TIM_TypeDef *)scg_TIMx_BASE[ch];                                                        //获取定时器寄存器
       
        SYS_DeviceClockEnable(scg_TIMx_Clock[ch], TRUE);                                        //使能定时器时钟
        TIMx->CSP = 0;                                                                                                                //清除配置
        TIMERx_CounterReset(ch);                                                                                        //重置定时器-会关闭定时器
        TIMERx_SetComparedValue(ch, pConfig->ComparedValue);                                //设置比较值,设置后会自动清除计数器
        temp |= pConfig->ClockPre & 0xFF;                                                                        //设置预分频
        temp |= (pConfig->mode&0x3) << 27;                                                                        //设置工作模式
        if(pConfig->isEnableInt)
        {
                temp |= 1 << 29;                                                                                                //需要开启中断
                IntPro = pConfig->IntPro;
                if(IntPro < 1) IntPro = 1;
                if(IntPro > 7) IntPro = 7;                                                                                        //中断优先级范围限制为1-7
                sg_TIMx_CallBack[ch] = pConfig->pIntCallBack;                                                //记录用户中断回调函数
                AIC_RegisterIRQHandler(scg_TIMx_IntIRQ[ch], (void(*)(void))sg_TIMx_IRQHandler[ch]);//注册中断服务程序
                AIC_SetIrqTriggered(scg_TIMx_IntIRQ[ch], AIC_HIGHT_EDGE);                        //设置一个中断触发方式-上升沿触发
                AIC_SetIrqPriority(scg_TIMx_IntIRQ[ch], IntPro);                                        //设置一个中断优先级
                TIMERx_ClearIntFlag(ch);                                                                                        //清除中断
                AIC_IrqEnable(scg_TIMx_IntIRQ[ch], TRUE);                                                        //设置一个中断使能状态-使能中断
        }
        else
        {
                AIC_IrqEnable(scg_TIMx_IntIRQ[ch], FALSE);                                                        //关闭中断
        }
        TIMx->CSP = temp;                                                                                                                //设置寄存器
        if(pConfig->isStart)
        {
                TIMx->CSP |= 1 << 30;                                                                                                //使能定时器
        }
       
        return TRUE;
}



使用特权

评论回复
10
renzheshengui|  楼主 | 2021-7-1 13:15 | 只看该作者
//定时器0中断服务程序
static __inline void TIM0_IRQHandler(void)
{
        static const TIMER_CH_Type ch = TIMER_CH0;
       
        if(sg_TIMx_CallBack[ch] != NULL)
        {
                ((void (*)(void))sg_TIMx_CallBack[ch])();                                        //执行中断回调函数
        }
        SYS_REG_TYPE(TIMER_ISR_ADDR) |= 1<<ch;                                                        //写1清除中断标志
}

//定时器1中断服务程序
static __inline void TIM1_IRQHandler(void)
{
        static const TIMER_CH_Type ch = TIMER_CH1;
       
        if(sg_TIMx_CallBack[ch] != NULL)
        {
                ((void (*)(void))sg_TIMx_CallBack[ch])();                                        //执行中断回调函数
        }
        SYS_REG_TYPE(TIMER_ISR_ADDR) |= 1<<ch;                                                        //写1清除中断标志
}

//定时器2中断服务程序
static __inline void TIM2_IRQHandler(void)
{
        static const TIMER_CH_Type ch = TIMER_CH2;
       
        if(sg_TIMx_CallBack[ch] != NULL)
        {
                ((void (*)(void))sg_TIMx_CallBack[ch])();                                        //执行中断回调函数
        }
        SYS_REG_TYPE(TIMER_ISR_ADDR) |= 1<<ch;                                                        //写1清除中断标志
}

//定时器3中断服务程序
static __inline void TIM3_IRQHandler(void)
{
        static const TIMER_CH_Type ch = TIMER_CH3;
       
        if(sg_TIMx_CallBack[ch] != NULL)
        {
                ((void (*)(void))sg_TIMx_CallBack[ch])();                                        //执行中断回调函数
        }
        SYS_REG_TYPE(TIMER_ISR_ADDR) |= 1<<ch;                                                        //写1清除中断标志
}

//定时器4中断服务程序
static __inline void TIM4_IRQHandler(void)
{
        static const TIMER_CH_Type ch = TIMER_CH4;
       
        if(sg_TIMx_CallBack[ch] != NULL)
        {
                ((void (*)(void))sg_TIMx_CallBack[ch])();                                        //执行中断回调函数
        }
        SYS_REG_TYPE(TIMER_ISR_ADDR) |= 1<<ch;                                                        //写1清除中断标志
}


使用特权

评论回复
11
renzheshengui|  楼主 | 2021-7-1 13:15 | 只看该作者
//timer.h


/*************************************************************************************************************
* 文件名:                        timer.h
* 功能:                        NUC970 定时器支持
* 作者:                        cp1300@139.com
* 创建时间:                2020-08-31
* 最后修改时间:        2020-08-31
* 详细:                        定时器支持
*************************************************************************************************************/
#ifndef _NUC970_TIMER_H_  
#define _NUC970_TIMER_H_
#include "nuc970_system.h"


//定时器选择
typedef enum
{
        TIMER_CH0        =                0,        //TIMER0
        TIMER_CH1        =                1,        //TIMER1
        TIMER_CH2        =                2,        //TIMER2
        TIMER_CH3        =                3,        //TIMER3
        TIMER_CH4        =                4,        //TIMER4
}TIMER_CH_Type;
#define TIMER_ChMax                5                        //定时器数量

//定时器模式
typedef enum
{
        TIMER_MODE_ONE_SHOT                =        0,        //单次模式,触发后会自动停止,溢出后定时器会定制工作,并触发一次中断
        TIMER_MODE_PERIODIC                =        1,        //周期模式,会周期性产生中断信号,相当于边沿触发,定时器会连续工作,周期性触发中断
        TIMER_MODE_CONTINUOUS        =        3,        //连续模式,会不停的产生中断信号,相当于电平触发,定时器会连续工作,但是只会触发一次中断
}TIMER_MODE;

typedef struct
{
        u32 ComparedValue;                        //比较值
        TIMER_MODE mode;                        //工作模式
        void (*pIntCallBack)(void);        //中断回调函数
        bool isStart;                                //是否开始计数
        u8        ClockPre;                                //时钟预分配,分频值=设置值+1,比如设置为1,则为2分频
        bool isEnableInt;                        //是否使能定时器中断
        u8 IntPro;                                        //中断优先级
}TIMER_CONFIG;


bool TIMERx_Config(TIMER_CH_Type ch, TIMER_CONFIG *pConfig);//定时器配置
void TIMERx_Start(TIMER_CH_Type ch);                                                //定时器开始计数
void TIMERx_Stop(TIMER_CH_Type ch);                                                        //定时器停止计数
void TIMERx_CounterReset(TIMER_CH_Type ch);                                        //定时器重置(重置预分配器与计数器,会关闭定时器)
bool TIMERx_GetActive(TIMER_CH_Type ch);                                        //获取定时器工作状态
void TIMERx_SetComparedValue(TIMER_CH_Type ch, u32 Count);        //设置定时器比较值
u32 TIMERx_GetCount(TIMER_CH_Type ch);                                                //获取定时器计数器值
void TIMERx_ClearIntFlag(TIMER_CH_Type ch);                                        //清除指定定时器的中断标志

#endif //_NUC970_TIMER_H_


使用特权

评论回复
12
renzheshengui|  楼主 | 2021-7-1 13:15 | 只看该作者
//测试


//周期性LED闪烁
void Time0_CallBack(void)
{
        static bool status = FALSE;
       
        if(status)
        {
                GPIOB->DATAOUT &= ~BIT1;       
        }
        else
        {
                GPIOB->DATAOUT |= BIT1;
        }
       
        status = !status;
}

//测试代码
SYS_DeviceClockEnable(DEV_GPIO, TRUE);                //使能IO时钟
        GPIOB->DIR |= BIT1;                                                        //输出模式
TIMER_CONFIG mTimConfig;
SYS_EnableIrq();        //使能系统总中断
       
        //定时器测试
        mTimConfig.ComparedValue = 100000;                        //比较值
        mTimConfig.mode = TIMER_MODE_PERIODIC;                //工作模式-周期
        mTimConfig.pIntCallBack = Time0_CallBack;        //中断回调函数
        mTimConfig.isStart = TRUE;                                        //是否开始计数
        mTimConfig.ClockPre = 12;                                        //时钟预分配,分频值=设置值+1,比如设置为1,则为2分频
        mTimConfig.isEnableInt = TRUE;                                //是否使能定时器中断
        mTimConfig.IntPro = 4;                                                //中断优先级
        TIMERx_Config(TIMER_CH0, &mTimConfig);                //定时器配置


使用特权

评论回复
13
feikeer| | 2021-9-15 11:19 | 只看该作者
兄弟,有972的裸机开发包?

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

78

主题

4079

帖子

2

粉丝