历史上的今天
返回首页

历史上的今天

今天是:2024年10月12日(星期六)

正在发生

2021年10月12日 | S3C2440裸机------异常与中断__定时器中断程序示例

2021-10-12 来源:eefocus

1.定时器的工作原理

注意当TCNTn=TCMPn时不会产生中断。 

2.代码

2.1 timer.c

 

首先是根据上面的两个寄存器设置时钟;


/* 设置TIMER0的时钟 */

/* Timer clk = PCLK / {prescaler value+1} / {divider value} 

         = 50000000/(99+1)/16

         = 31250

*/

TCFG0 = 99;  /* Prescaler 0 = 99, 用于timer0,1 */

TCFG1 &= ~0xf;

TCFG1 |= 3;  /* MUX0 : 1/16 */

然后根据上图的寄存器设置初始值。


/* 设置TIMER0的初值 */

TCNTB0 = 15625;  /* 0.5s中断一次 */

然后根据上面的寄存器设置加载初值。


/* 加载初值, 启动timer0 */

TCON |= (1<<1);   /* Update from TCNTB0 & TCMPB0 */

然后还是根据上图的寄存器,设置为自动加载并启动。


/* 设置为自动加载并启动 */

TCON &= ~(1<<1);

TCON |= (1<<0) | (1<<3);  /* bit0: start, bit3: auto reload */

然后我们实现定时器中断处理函数,在里面循环点灯。


void timer_irq(void)

{

/* 点灯计数 */

static int cnt = 0;

int tmp;

 

cnt++;

 

tmp = ~cnt;

tmp &= 7;

GPFDAT &= ~(7<<4);

GPFDAT |= (tmp<<4);

}

完整的timer.c如下


 

#include "s3c2440_soc.h"

 

void timer_init(void)

{

/* 设置TIMER0的时钟 */

/* Timer clk = PCLK / {prescaler value+1} / {divider value} 

             = 50000000/(99+1)/16

             = 31250

*/

TCFG0 = 99;  /* Prescaler 0 = 99, 用于timer0,1 */

TCFG1 &= ~0xf;

TCFG1 |= 3;  /* MUX0 : 1/16 */

 

/* 设置TIMER0的初值 */

TCNTB0 = 15625;  /* 0.5s中断一次 */

 

/* 加载初值, 启动timer0 */

TCON |= (1<<1);   /* Update from TCNTB0 & TCMPB0 */

 

/* 设置为自动加载并启动 */

TCON &= ~(1<<1);

TCON |= (1<<0) | (1<<3);  /* bit0: start, bit3: auto reload */

 

/* 设置中断 */

}

 

void timer_irq(void)

{

/* 点灯计数 */

static int cnt = 0;

int tmp;

 

cnt++;

 

tmp = ~cnt;

tmp &= 7;

GPFDAT &= ~(7<<4);

GPFDAT |= (tmp<<4);

}

 

2.2 interrupt.c

然后还要设置中断控制器,开启定时器中断。


#include "s3c2440_soc.h"

 

 

/* 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 int */

}

 

/* 初始化按键, 设为中断源 */

void key_eint_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));

}

 

/* 读EINTPEND分辨率哪个EINT产生(eint4~23)

 * 清除中断时, 写EINTPEND的相应位

 */

 

 

void key_eint_irq(int irq)

{

unsigned int val = EINTPEND;

unsigned int val1 = GPFDAT;

unsigned int val2 = GPGDAT;

if (irq == 0) /* eint0 : s2 控制 D12 */

{

if (val1 & (1<<0)) /* s2 --> gpf6 */

{

/* 松开 */

GPFDAT |= (1<<6);

}

else

{

/* 按下 */

GPFDAT &= ~(1<<6);

}

}

else if (irq == 2) /* eint2 : s3 控制 D11 */

{

if (val1 & (1<<2)) /* s3 --> gpf5 */

{

/* 松开 */

GPFDAT |= (1<<5);

}

else

{

/* 按下 */

GPFDAT &= ~(1<<5);

}

}

else if (irq == 5) /* eint8_23, eint11--s4 控制 D10, eint19---s5 控制所有LED */

{

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;

 

/* 调用对应的处理函数 */

if (bit == 0 || bit == 2 || bit == 5)  /* eint0,2,eint8_23 */

{

key_eint_irq(bit); /* 处理中断, 清中断源EINTPEND */

}

else if (bit == 10)

{

timer_irq();

}

 

/* 清中断 : 从源头开始清 */

SRCPND = (1< INTPND = (1<

}

 

3. 代码改进

上面的代码我们可以看到,当我们添加了定时器中断之后,我们要在interrupt.c里面重新添加定时器中断相关的配置,那么如果我们以后再添加别的中断,那么还要再修改interrupt.c,太麻烦了,下面我们用函数指针数组改进代码。


我们首先定义一个数组,用来保存中断处理函数的指针。


typedef void(*irq_func)(int);

irq_func irq_array[32];

然后我们实现一个注册函数,在这个注册函数里面把中断处理函数存到数组里面,并且使能中断。


void register_irq(int irq, irq_func fp)

{

irq_array[irq] = fp;

 

INTMSK &= ~(1<}

3.1 优化后的interrupt.c

#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 int */

}

 

/* 读EINTPEND分辨率哪个EINT产生(eint4~23)

 * 清除中断时, 写EINTPEND的相应位

 */

 

 

void key_eint_irq(int irq)

{

unsigned int val = EINTPEND;

unsigned int val1 = GPFDAT;

unsigned int val2 = GPGDAT;

if (irq == 0) /* eint0 : s2 控制 D12 */

{

if (val1 & (1<<0)) /* s2 --> gpf6 */

{

/* 松开 */

GPFDAT |= (1<<6);

}

else

{

/* 按下 */

GPFDAT &= ~(1<<6);

}

}

else if (irq == 2) /* eint2 : s3 控制 D11 */

{

if (val1 & (1<<2)) /* s3 --> gpf5 */

{

/* 松开 */

GPFDAT |= (1<<5);

}

else

{

/* 按下 */

GPFDAT &= ~(1<<5);

}

}

else if (irq == 5) /* eint8_23, eint11--s4 控制 D10, eint19---s5 控制所有LED */

{

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);

/* 清中断 : 从源头开始清 */

SRCPND = (1< INTPND = (1<

}

 

void register_irq(int irq, irq_func fp)

{

irq_array[irq] = fp;

 

INTMSK &= ~(1<}

 

 

/* 初始化按键, 设为中断源 */

void key_eint_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);

}

 

3.2 优化后的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 timer_init(void)

{

/* 设置TIMER0的时钟 */

/* Timer clk = PCLK / {prescaler value+1} / {divider value} 

             = 50000000/(99+1)/16

             = 31250

*/

TCFG0 = 99;  /* Prescaler 0 = 99, 用于timer0,1 */

TCFG1 &= ~0xf;

TCFG1 |= 3;  /* MUX0 : 1/16 */

 

/* 设置TIMER0的初值 */

TCNTB0 = 15625;  /* 0.5s中断一次 */

 

/* 加载初值, 启动timer0 */

TCON |= (1<<1);   /* Update from TCNTB0 & TCMPB0 */

 

/* 设置为自动加载并启动 */

TCON &= ~(1<<1);

TCON |= (1<<0) | (1<<3);  /* bit0: start, bit3: auto reload */

 

/* 设置中断 */

register_irq(10, timer_irq);

}

推荐阅读

史海拾趣

东晶(ECEC)公司的发展小趣事

近年来,随着电子信息技术的快速发展和智能化趋势的加剧,东晶电子也面临着新的机遇和挑战。为了适应市场变化和满足客户需求,公司开始实施战略转型和升级。公司加大了对新型电子元器件的研发力度,推动产品向微型化、功能化、高精度方向发展。同时,公司还积极开拓新领域和新市场,拓展业务范围和市场份额。这些举措为公司未来的发展奠定了坚实的基础。

请注意,这些故事是基于已知信息的概括性描述,并非具体的历史事件。在实际情况中,东晶电子的发展历程可能更加复杂和多样化。

BSI公司的发展小趣事

近年来,随着环保意识的提高,电子行业对绿色发展的需求也日益迫切。BSI积极响应这一需求,推动了电子行业绿色标准的制定和实施。通过制定严格的环保标准,BSI引导电子产品制造企业采用更加环保的生产工艺和材料,减少了对环境的污染。同时,BSI还为企业提供了碳排放核查等服务,帮助企业了解自身的碳排放情况,制定了减排措施,推动了电子行业的绿色发展。

Dearborn Electronics Inc公司的发展小趣事

随着电子行业的快速发展和市场竞争的加剧,Dearborn Electronics Inc.面临着诸多挑战。为了保持竞争优势,公司不断进行转型升级,推出了一系列具有更高性能、更小尺寸、更低成本的新产品。同时,公司也积极拓展新的应用领域和市场,寻找新的增长点。

依必安派特(ebmpapst)公司的发展小趣事

在快速发展的过程中,依必安派特也面临着一些挑战。其中之一就是仿冒产品的泛滥。为了维护品牌形象和客户利益,依必安派特积极打击仿冒产品。例如,在2023年,依必安派特和地方政府联手突击了一家位于广东的仿冒产品工厂,揭示了其造假行为。这一行动不仅保护了依必安派特的品牌声誉和客户信任,也为中国市场的公平竞争环境做出了贡献。

Gulf Semiconductor公司的发展小趣事

在快速发展的过程中,依必安派特也面临着一些挑战。其中之一就是仿冒产品的泛滥。为了维护品牌形象和客户利益,依必安派特积极打击仿冒产品。例如,在2023年,依必安派特和地方政府联手突击了一家位于广东的仿冒产品工厂,揭示了其造假行为。这一行动不仅保护了依必安派特的品牌声誉和客户信任,也为中国市场的公平竞争环境做出了贡献。

Harris公司的发展小趣事

在过去的四十年中,Hammond将业务重心扩展到了美国和国际市场。通过在全球各地设立办事处和建立分销网络,Hammond成功地将其产品和服务推广到了世界各地。这一战略转型不仅极大地提升了Hammond的品牌影响力,还为其带来了更加广阔的市场空间和增长潜力。

问答坊 | AI 解惑

Windows Embedded之航运自动化

随着信息流的快速发展,许多船舶在建造的时候采用了自动化设备和嵌入式技术,使得船舶自动化系统在自动化、网络化和智能化方面取得了大幅度的提高。 嵌入式系统是集软、硬件于一体的可独立工作的“器件”,硬件部分包括处理器/微处理器、存储 ...…

查看全部问答>

FPGA和51测波形占空比的

本帖最后由 paulhyde 于 2014-9-15 09:21 编辑 用FPGA做的测占空比程序......  …

查看全部问答>

2410用什么可以代替串口线跟pc机超级终端通讯?

s3c2410跟pc机超级终端通讯 不用串口线,那用什么可以代替?网线?usb?…

查看全部问答>

求助:关于机器翻译

      现在公司需要找到稳定和高质量的机器翻译引擎,不知道目前有哪些公司(第三方)可以提供这样的机器翻译引擎给嵌入式系统 用呢?       我们公司是国内著名的企业,由于项目进度关系,诚意找合作伙伴~~ ...…

查看全部问答>

关于GSM协议07.10多路复用问题

大家好!    小弟最近在搞gprs,遇到了多路复用的问题,现在准备用GSM协议07.10,想要将本来仅有的一个通道复用成多个虚拟通道,通常有控制通道和其他通道,其他通道可根据功能将他作为比如GPRS专用通道或者短信通道,电话通道,及其他ATCM ...…

查看全部问答>

收到微芯力科赠送的MCU开发套件了,发帖庆祝一下。

                                 收到微芯力科赠送的MCU开发套件了,发帖庆祝一下…

查看全部问答>

RTC自动校验的方法

看了下官方的文档,对RTC校验是否如下: 1.先不管预分频,直接得出64分频后的频率f64,然后算出实际的晶振频率f,取其整数部分为F; 2.在F为预分频系数为前提下,计算出ppm,就是(f64-(float)F/64.0)/((float)F/64.0)*1000000, 3.对ppm四 ...…

查看全部问答>

cache 优化问题

本帖最后由 dontium 于 2015-1-23 13:28 编辑 请问 如何将某段程序或某个函数(这个函数经常调用)放到L2里,通过哪个API函数,谢谢 …

查看全部问答>

电子元器件的可靠性

这一本书,讲的还行…

查看全部问答>

题目快出啦!

本帖最后由 paulhyde 于 2014-9-15 09:00 编辑 我要题目!  …

查看全部问答>