【ARM裸板】定时器中断示例与分析
程序员文章站
2022-06-09 08:54:20
...
1.定时器结构分析
- 1.每来一个CLK,TCNTn减1
-
2.当
TCNTn == TCMPn
时,(可以把对应的PWM引脚翻转)-
TCNTn
与TCMPn
的值来自寄存器TCNPBn
与TCMTBn
-
-
3.TCNTn继续减1,当
TCNTn == 0
时,可以产生中断(PWM引脚再次翻转) -
4.
TCNTn == 0
时,可自动加载初值
2.初始化
- 1.设置时钟源
- 2.设置初值
- 3.加载初值,启动Timer
- 4.设置为自动加载
- 5.中断相关
- 需要设置:1.Prescaler,2.MUX(Divider),3.TCMPB0(不是PWM测试,因此该不需要设置),4.TCNTB0,5.TCON0
2.1 设置时钟源
- 由上公式:
- 设置Prescaler
- 设置MUX
/* 1.设置timer0的时钟
* Timer CLK = PCLK / {prescaler value+1} / {divider value}
* 50000000/(99+1)/(16) = 31250
*/
TCFG0 = 99; //Prescaler = 99,用于timer0,timer1
TCFG1 &= ~0xFF;
TCFG1 |= 3; //MUX0=1/16(即是 divider value)
2.2 设置初值
//2.设置timer0的初值
TCNTB0 = 15625; //0.5s中断一次(15625/31250=0.5s)
2.3 手动加载初值
- 手动加载初值至TCNT0与TCMT0,启动timer0
- 置1
TCON |= (1<<1);//Update from (TCNTB0 & TCMPB0) to (TCNT0 & TCMT0)
2.4 清除手动加载
- 清零
TCON &= ~(1<<1);
2.5 设置自动重装载并启动
TCON |= (1<<0) | (1<<3);//bit0:start, bit3:auto reload
3. 构造函数指针
- 把每一个中断的处理函数放置在指针数组中,当发生中断时,通过判断中断号,调用对应的函数即可
3.1 定义
- 定义函数指针,指针的变量名为
irq_func
typedef void (*irq_func)(int);
irq_func irq_array[32];//定义存放函数指针数组(即:数组中存放的是函数指针)
-
typedef void(*Func)(void)
的用途,先来看下其基本用法
typedef void (*func)(void);
void myfunc(void);
func pfun = myfunc;/*赋值*/
pfun();/*调用*/
3.2 由来
-
typedef void(*Func)(void);
的由来 - 其实这样的形式声明函数指针是有"问题"的。如果仿照变量类型声明,声明函数指针似乎应该这样:
typedef void(*)() variable;
但是c标准的创建者没有这样做,不知道为什么,而选择了这样的声明:
typedef void(*variable)();
C编译器非常清楚,这就是在声明一个void(*)() 类型的函数指针variable。
3.4 注册函数
/* 注册中断
* param:1.中断号,2.中断服务函数
*/
void register_irq(int irq,irq_func fp)
{
irq_array[irq] = fp;//将fp指向的函数地址 存放在arr中
INTMSK &= (1<<irq);
}
- eg:
register_irq(10, timer0_irq);
3.5 调用函数
/* 中断处理函数
*
*/
void handle_irq_c(void)
{
/* 1.分辨中断源 */
int bit = INTOFFSET;//判断谁在请求中断
/* 2.调用对应的处理函数 */
irq_array[bit](bit); //irq_array存放的是函数指针,加一个()即表示调用该函数
/* 3.清中断 :从源头开始清 */
SRCPND = (1<<bit);
INTPND = (1<<bit);
}
上一篇: 51单片机定时器
下一篇: 树莓派物联网入门 - 系统安装(一)