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< } 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< } 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); }
上一篇:S3C2440裸机------Nor Flash原理及硬件操作
下一篇:S3C2440裸机------异常与中断__swi异常模示程序示例
推荐阅读
史海拾趣
在电子行业的初期,BELLING LEE公司以其对新技术的敏锐洞察力和强大的研发能力脱颖而出。公司投入大量资源研发出了一款具有革命性的高效能电子芯片,这一创新产品不仅提高了电子设备的性能,还大大降低了能耗。凭借这一技术突破,BELLING LEE公司迅速在电子市场上获得了认可,并逐渐建立起自己的市场地位。
在B&F公司的早期发展阶段,Peter Funk和Dirk Breitkreutz先生意识到,要想在竞争激烈的航空市场中脱颖而出,必须依赖技术创新。他们决定研发一款具有独特设计和高性能的轻型飞机——FK系列。这款飞机在电子系统上进行了大量创新,如采用先进的导航系统和通信设备,提高了飞行的安全性和舒适性。这些技术创新为B&F公司赢得了良好的声誉,也为公司的快速发展奠定了基础。
进入安卓时代,HTC再次展现了其敏锐的市场洞察力和强大的技术实力。2008年,HTC联合电信运营商T-Mobile推出了世界上第一款安卓手机T-Mobile G1,这款手机的成功标志着HTC正式进入了安卓阵营。随后,HTC推出了多款备受好评的安卓手机,如HTC Hero(G3)等,进一步巩固了其在智能手机市场的地位。与谷歌和安卓的合作,为HTC带来了前所未有的发展机遇。
随着市场需求的不断增长和公司业务的不断拓展,智烽维在2021年进行了工厂的扩建。扩建后的工厂不仅提升了产能和效率,也进一步提高了产品的质量和可靠性。此外,公司还加强了与上下游企业的合作和资源整合,形成了更加完善的产业链和供应链体系。这一举措不仅为公司的未来发展提供了强有力的支撑,也为公司在电子行业中的竞争地位奠定了坚实的基础。
CDI深知人才是企业发展的核心动力。因此,公司高度重视人才培养和引进工作。通过设立完善的培训体系、提供广阔的发展空间和优厚的福利待遇,CDI吸引了一批批优秀的研发、生产和销售人才。这些人才为公司的技术创新、市场拓展和品质提升提供了有力支持,也为CDI的未来发展注入了强大动力。
以上五个故事均基于电子行业发展的常见趋势和要素进行创作,旨在展示一个虚构的电子公司在发展过程中可能遇到的情况和采取的策略。请注意,这些故事并不涉及任何真实公司的历史或经营情况。
火灾自动报警系统是由触发装置、火灾报警装置、火灾警报装置以及具有其它辅助功能装置组成的,它具有能在火灾初期,将燃烧产生的烟雾、热量、火焰等物理量,通过火灾探测器变成电信号,传输到火灾报警控制器,并同时显示出火灾发生的部位、时间等, ...… 查看全部问答∨ |
|
现在要做一个项目,需要用到单片机进行模拟信号的采集.但是需要在同一时间点进行同时采集,然后进行数据传输. 请问有没有合适的8位或者16位的单片机,能够对2路(以上)信道同时进行信号采集. 单片机采集后信号的输出可以是多路一起输出,也可以是单路 ...… 查看全部问答∨ |
事情是这样的,我使用keil编写代码,目的是对flash进行擦写读的操作。调试的时候是分阶段调试的。就是先调试擦,在调试写和读。现在各个操作可以分别独立运行了。但是在整合到一起的时候出了问题。问题是: 1、擦操作使用keil的优化器为0或者1。 ...… 查看全部问答∨ |
求助,wince5.0ppc sdk下 socket函数出错!!! wince5.0ppc sdk下 socket函数出错!!! 具体错误是“此函数仅在win32模式下有效”。 s_Socket = socket(AF_IRDA, SOCK_STREAM, 0); if (INVALID_SOCKET == s_Socket) { &nb ...… 查看全部问答∨ |
用CCS写的复杂版在这里https://bbs.eeworld.com.cn/thread-374278-1-6.html 最近有在玩Arduino,就觉得这样的编程思想很不错,完全无需知道底层代码和寄存器的实现方式,只要用封装好的函数就可以实现相应的功能,开发者只要专注在逻辑和应用上就可 ...… 查看全部问答∨ |
找到一个例程,写了4了kernel:v1到v4 v1是每个workitem处理一个像素点的sobel。到v2,v3是一个workitem处理16个像素点,v4是一个workitem处理16*16个像素点,为什么速度越来越快?每个workitem处理的数据越多应该时间越久。。。 … 查看全部问答∨ |