定时器(timer0)中断步骤:
- 设置timer0时钟
Timer input clock Frequency = PCLK / {prescaler value+1} / {divider value}
=50000000/(99+1)/16=31500
- 设置timer0初值
- 加载初值,启动timer0
- 设置为自动加载并启动
- 设置中断
定时器代码:
void timer0_init(void)
{
//设置timer0的时钟
//Timer input clock Frequency = PCLK / {prescaler value+1} / {divider value}
// =50000000/(99+1)/16
// =31250
TCFG0 = 99;
TCFG1 &=~0xf;
TCFG1 = 0x3;
//设置timer0的初值
TCNTB0= 15625; //0.5s中断一次
//加载初值,启动timer0
TCON |= (1<<1); //Update from TCNTB0 & TCMPB0
//设置为自动加载并启动
TCON &=~(1<<1);
TCON |= (1<<0)|(1<<3);
//设置中断
}
设置中断代码:
//初始化中断控制器
void interrupt_init(void)
{
INTMSK &= ~((1<<0) | (1<<2) | (1<<5));
INTMSK &= ~(1<<10); //enable timer0
}
调用中断代码:
void handle_irq_c(void)
{
//分辨中断源
int bit = INTOFFSET;
//调用对应的处理函数
if(bit==0||bit==2||bit==5) //eint0 or eint2 or eint 8-23
{
key_eint_irq(bit);//处理中断,清中断源EINTPEND
}
else if (bit == 10)
{
timer_irq();
}
//清中断:从源头开始清
SRCPND=(1<<bit);
INTPND=(1<<bit);
}
中断处理函数代码:
void timer_irq(void)
{
static int cnt=0;
int tmp;
cnt++;
tmp=~cnt;
tmp &= 7;
GPFDAT &= ~(7<<4);
GPFDAT |= (tmp<<4);
}
代码改进:为了不用每次产生中断都设置中断控制器和调用中断函数,可以使用typedef函数指针进行简化。
typedef char (*PTRFUN)(int);
PTRFUN pFun;
改进代码如下:
interrupt:
#include "s3c2440_soc.h"
typedef void (*irq_func)(int);
irq_func irq_array[32];
//SRCPND用来显示哪个中断产生了,需要清清除对应位 bit0-eint0 bit2-eint2 bit5-eint8-23
//INTMSK用来屏蔽中断,1-masked bit0-eint0 bit2-eint2 bit5-eint8-23
//INTPND用来显示当前优先级最高,正在发生的中断,需要清除对应位 bit0-eint0 bit2-eint2 bit5-eint8-23
//INTOFFSET用来显示INTPND哪一位被设置为1
//初始化中断控制器
void interrupt_init(void)
{
INTMSK &= ~((1<<0) | (1<<2) | (1<<5));
INTMSK &= ~(1<<10);//enable timer0
}
//初始化按键,设为中断源
void key_eint_irq(int irq)
{
unsigned int val =EINTPEND;
unsigned int val1=GPFDAT;
unsigned int val2=GPGDAT;
if (irq==0)//eint0 :s2
{
if (val1 & (1<<0)) /* s2 --> gpf6 */
{
/* 松开 */
GPFDAT |= (1<<6);
}
else
{
/* 按下 */
GPFDAT &= ~(1<<6);
}
}
else if (irq==2)//eint2 :s3
{
if (val1 & (1<<2)) /* s3 --> gpf5 */
{
/* 松开 */
GPFDAT |= (1<<5);
}
else
{
/* 按下 */
GPFDAT &= ~(1<<5);
}
}
else if (irq==5)//eint8-23,eint11--s4 eint19--s5
{
if (val & (1<<11)) /* eint11 */
{
if (val2 & (1<<3)) /* s4 --> gpf4 */
{
/* 松开 */
GPFDAT |= (1<<4);
}
else
{
/* 按下 */
GPFDAT &= ~(1<<4);
}
}
else if (val & (1<<19)) /* eint19 */
{
if (val2 & (1<<11))
{
/* 松开 */
/* 熄灭所有LED */
GPFDAT |= ((1<<4) | (1<<5) | (1<<6));
}
else
{
/* 按下: 点亮所有LED */
GPFDAT &= ~((1<<4) | (1<<5) | (1<<6));
}
}
}
EINTPEND=val;
}
void handle_irq_c(void)
{
//分辨中断源
int bit = INTOFFSET;
//调用对应的处理函数
irq_array[bit](bit);
INTMSK &= ~(1<<bit);
//清中断:从源头开始清
SRCPND=(1<<bit);
INTPND=(1<<bit);
}
int led_init(void)
{
/* 设置GPFCON让GPF4/5/6配置为输出引脚 */
GPFCON &= ~((3<<8) | (3<<10) | (3<<12));
GPFCON |= ((1<<8) | (1<<10) | (1<<12));
}
void register_irq(int irq,irq_func fp)
{
irq_array[irq]=fp;
INTMSK &= ~(1<<irq);
}
void key_enit_init(void)
{
//配置GPIO为中断引脚
GPFCON &=~((3<<0)|(3<<4));
GPFCON |= ((2<<0)|(2<<4)); //s2,s3被设置为中断引脚
GPGCON &=~((3<<6)|(3<<22));
GPGCON |= ((2<<6)|(2<<22)); //s4,s5被设置为中断引脚
//设置中断触发方式:双边沿触发
EXTINT0 |= ((7<<0)|(7<<8)); //s2,s3
EXTINT1 |=(7<<12); //s4
EXTINT2 |=(7<<12); //s5
//设置EINTMASK使能eint11,19
EINTMASK &=~((1<<11)|(1<<19));
register_irq(0,key_eint_irq);
register_irq(2,key_eint_irq);
register_irq(5,key_eint_irq);
}
timer.c:
#include "s3c2440_soc.h"
void timer_irq(void)
{
static int cnt=0;
int tmp;
cnt++;
tmp=~cnt;
tmp &= 7;
GPFDAT &= ~(7<<4);
GPFDAT |= (tmp<<4);
}
void timer0_init(void)
{
//设置timer0的时钟
//Timer input clock Frequency = PCLK / {prescaler value+1} / {divider value}
// =50000000/(99+1)/16
// =31250
TCFG0 = 99;
TCFG1 &=~0xf;
TCFG1 = 0x3;
//设置timer0的初值
TCNTB0= 15625; //0.5s中断一次
//加载初值,启动timer0
TCON |= (1<<1); //Update from TCNTB0 & TCMPB0
//设置为自动加载并启动
TCON &=~(1<<1);
TCON |= (1<<0)|(1<<3);
//设置中断
register_irq(10,timer_irq);
}