嵌入式系统原理课件

zengjiangyi   2009-10-15 11:26 楼主
第7章        定时部件
定时部件是嵌入式系统中常用的部件,其主要用作定时功能或计数功能。不同的定时部件在使用上有所差异,但它们的逻辑原理是相同的。本章具体以S3C2410芯片中的定时部件来介绍定时部件的工作原理、初始化编程及应用。
S3C2410芯片中的定时部件有多个,不同的定时部件有不同的应用。本章中主要介绍其中的看门狗定时器、RTC部件和Timer部件的控制原理及应用。
7.1 定时部件的原理
定时器或计数器的逻辑电路本质上是相同的,它们之间的区别主要在用途上。它们都是主要由带有保存当前值的寄存器和当前寄存器值加1或减1逻辑组成。在应用时,定时器的计数信号是由内部的、周期性的时钟信号承担,以便产生具有固定时间间隔的脉冲信号,实现定时的功能。而计数器的计数信号是由非周期性的信号承担,通常是外部事件产生的脉冲信号,以便对外部事件发生的次数进行计数。因为同样的逻辑电路可用于这两个目的,所以该功能部件通常被称为“定时/计数器”。
图7-1是一个定时/计数器内部工作原理图,它是以一个N位的加1或减1计数器为核心,计数器的初始值由初始化编程设置,计数脉冲的来源有两类:系统时钟和外部事件脉冲。
初始值


K
回0信号


图7-1 定时/计数器内部原理图

若编程设置定时/计数器为定时工作方式时,则N位计数器的计数脉冲来源于内部系统时钟,并经过M分频。每个计数脉冲使计数器加1或减1,当N位计数器里的数加到0或减到0时,则会产生一个“回0信号”,该信号有效时表示N位计数器里的当前值是0。因为系统时钟的频率是固定的,其M分频后所得到的计数脉冲频率也就是固定的,因此通过对该频率脉冲的计数就转换为定时,实现了定时功能。
若编程设置定时/计数器为计数方式时,则N位计数器的计数脉冲来源于外部事件产生的脉冲信号。有一个外部事件脉冲,计数器加1或减1,直到N位计数器中的值为0,产生“回0信号”。
N位计数器里初始值的计算,在不同的定时部件中其具体的计算公式是不同的。但它们计算公式的原理基本相似,既若是在定时工作方式下,N位计数器的初始值由计数脉冲的频率和所需的定时间隔确定。若是在计数工作方式下,则直接是所需的计数设定值。

回复评论 (8)

7.2 看门狗定时器
S3C2410芯片看门狗定时器的作用是,当系统程序出现功能错乱,引起系统程序死循环时,能中断该系统程序的不正常运行,恢复系统程序的正常运行。
嵌入式系统由于运行环境的复杂,既所处环境中有较强的干扰信号,或者系统程序本身的不完善,因而,不能排除系统程序不会出现死循环现象。在系统中加入看门狗部件,当系统程序出现死循环时,看门狗定时器产成一个具有一定时间宽度的复位信号,迫使系统复位,恢复系统正常运行。
7.2.1 看门狗定时器概述
S3C2410芯片的看门狗定时器有2种工作模式:
•带中断请求信号的常规时隙定时器。
•产生内部复位信号的定时器,即当定时器中的计数器值变为0时,产生一个宽度为128 个PCLK(系统时钟周期)的复位脉冲信号。
图7-2是看门狗定时器逻辑功能框图。从图中我们可以知道,看门狗定时器使用了系统时钟PCLK作为唯一的时钟源,PLCK信号经过预分频后再分割产生相应的看门狗计数器的时钟信号,该时钟信号控制计数器进行计数,计数器值变为0后产生中断请求信号或复位信号。

图7-2 看门狗定时器
预分频器的值和频率分解因子可由看门狗定时器的控制寄存器(WTCON)进行编程设定。预分频器值的可选范围是: 0~28-1。频率分割因子可选择的值为16,32,64,128。使用下面公式来计算看门狗定时器的计数时钟周期:
计数时钟周期 = 1/ (PCLK / (预分频器值 + 1) / 分割因子)
一旦看门狗定时器被启动工作,看门狗定时器中的计数常数寄存器(WTDAT)就无法自动的重载到计数寄存器(WTCNT)中。因此,应该在看门狗定时器启动工作之前,通过初始化编程使计数常数写入计数寄存器(WTCNT)中。

7.2.2 看门狗控制寄存器
S3C2410芯片的看门狗定时器逻辑中含有3个控制其操作的专用寄存器:看门狗控制寄存器(WTCON)、计数常数寄存器(WTDAT)和看门狗计数器寄存器(WTCNT)。下面分别介绍各寄存器的格式。

(1)看门狗控制寄存器(WTCON)
看门狗控制寄存器用来控制看门狗定时器是否允许工作,如果不希望系统在出现程序紊乱时重启,则看门狗定时器的看门狗功能可以被禁止工作。WTCON寄存器是可读/写的,地址为:0x53000000,复位后的初值为0x8021。WTCON寄存器的具体格式如表7-1所示。
表7-1 WTCON寄存器的格式
符号        位        描述        初始状态
Prescaler Value         [15:8]         预分频器值,值的范围是0~255。         0x80
Reserved         [7:6]         保留,这2位必须是00。         00
Watchdog Timer         [5]         确定看门狗定时器使能/不使能
1 = 使能  0 = 不使能         1
Clock Select         [4:3]         确定分割器因子
00 = 16  01 = 32  10 = 64  11 = 128         00
Interrupt Generation         [2]         确定中断请求使能/不使能
1 = 使能  0 = 不使能         0
Reserved         [1]         保留,这1位必须是0。         0
Reset Enable/Disable         [0]         确定看门狗定时器复位信号输出使能/不使能
1 = 在看门狗定时器回0时复位信号有效;
0 = 禁止看门狗定时器的复位功能。         1

(2)计数常数寄存器(WTDAT)
计数常数寄存器用来存储看门狗定时器的溢出时间间隔值,既从定时器的计数器开始工作,到计数器值变为0的时间间隔。WTDAT寄存器通常存储的是一个计数常数,该常数是通过下面公式计算求得。
计数常数 = 所需时间间隔/计数时钟周期
         = 所需时间间隔×(PCLK / (预分频器值 + 1) / 分割因子)
WTDAT寄存器是可读/写的,地址为:0x53000004,复位后的初值为0x8000。WTDAT寄存器的具体格式如表7-2所示。
表7-2 WTDAT寄存器的格式
符号        位        描述        初始状态
Count Reload Value         [15:0]         看门狗定时器计数常数值。         0x8000

WTDAT寄存器是16位的,它不能在看门狗定时器初始化过程中被自动的装载到计数器中。但是,使用0x8000(初始值)将促使第一次时间溢出。在这种情况下,WTDAT寄存器的值将自动的重载到WTCNT中。

(3)看门狗计数器寄存器(WTCNT)
看门狗计数器寄存器正常情况下用作减1计数器,它对计数时钟信号进行减1计数,既每来一个计数时钟脉冲,计数器内的值减1。WTCNT寄存器是可读/写的,地址为:0x53000008,复位后的初值为0x8000。WTCNT寄存器的具体格式如表7-3所示。
表7-3 WTCNT寄存器的格式
符号        位        描述        初始状态
Count Value         [15:0]         计数器当前值。         0x8000

WTCNT寄存器在看门狗定时器工作时存储当前计数值。注意,WTDAT寄存器的值在看门狗定时器初始使能时,不能自动的装载到WTCNT寄存器中,因此,WTCNT寄存器必须在使能之前,设置一个初始值。
7.2.3 使用实例
S3C2410芯片的看门狗电路集成在芯片内部,它与ARM920T微处理器核之间的关系如图7-3所示。其作用主要是定时监视系统,以防止系统软件死锁。
系统总线






图7-3 看门狗的作用示意图
在系统程序正常执行的情况下,因为系统的软件被设计成在看门狗定时器未达到超时限制前,周期性地重置看门狗。也就是说,设计者在设计系统程序时,必须在一定的周期内(这个周期不能大于看门狗定时器所产生的时间间隔),执行读/写看门狗定时器的指令,以达到重置看门狗定时器,使其计数器值不会递减到0,因而也不会产生复位信号。但一旦系统程序出现死锁,就不能周期性地执行重置看门狗的指令,因而看门狗定时器计数溢出,产生一个“回0信号”,利用该信号复位微处理器,从而使系统程序退出死锁,重新进入正常运行。
使用看门狗功能时,必须事先进行初始化。初始化的主要工作是设置看门狗控制寄存器(WTCON)和看门狗计数常数寄存器(WTDAT)。
例如:若一个采用S3C2410芯片为核心开发的嵌入式系统需要看门狗功能,监测系统程序的周期不大于40us,PCLK=50MHz。那么,我们需要使用下面一段程序来完成初始化看门狗:
ldr        r0,=WTDAT     ;WTDAT寄存器对应的地址赋给R0
ldr        r1,=0x7d        ;计数器初始值
str        r1,[r0]
ldr        r0,=WTCON                ;WTCON寄存器对应的地址赋给R0
                ldr        r1,=0x0021            ;使能看门狗及其复位功能,分割器值设为16
str        r1,[r0]
上面的计数器初始值是通过7.2.2小节中介绍的计数常数计算公式求得的。经过初始化后,看门狗电路即启动工作,40us之前若没有对看门狗定时器进行重置操作,则在40us时产生“回0信号”,引起系统复位。
除了上面初始化程序外,设计者需要在系统程序的适当地方设置重置看门狗计数器的指令。本例中,“适当地方”含义是指上一次执行看门狗计数器重置指令到本次执行看门狗计数器重置指令的间隔应小于40us。
7.3        RTC部件
实时时钟部件RTC是用于提供年、月、日、时、分、秒、星期等实时时间信息的定时部件。它通常在系统电源关闭后,由后备电池供电。下面对S3C2410芯片内部的RTC部件的工作原理、工作控制寄存器及应用进行介绍。
7.3.1 概述
RTC部件可以将年、月、日、时、分、秒、星期等信息的8位数据以BCD码格式输出。它由外部时钟驱动工作,外部时钟频率为32.768 kHz晶体。同时RTC部件还可以具有报警功能。它的主要特点有:
•年、月、日、时、分、秒、星期等信息采用BCD码表示。
•闰年发生器。
•具有报警功能,能提供报警中断或者系统在节电模式下的唤醒。
•拥有独立的电源引脚(RTCVDD)。
•支持RTOS内核时间片所需的毫秒计时中断。
•进位复位功能。
S3C2410芯片内部的RTC部件功能框图如图7-4所示。

图7-4 RTC功能框图
图7-4中,XTIrtc、XTOrtc是外部时钟的引脚,可以外接32.768KHz的晶振,如图7-5 所示。它为RTC内部提供基准工作频率。

图7-5  实时时钟振荡频率32.768 kHz

RTC 部件内部的闰年发生器(leap Year Generator)可以通过年、月、日的BCD码确定每个月份的天数是28,29,30,还是31。因为,一个8位的计数器只能表示2位BCD码。因此仅仅通过判断年的末尾两位是否为零,来确定闰年是行不通的。例如,计数器内部两位是00,它不能具体指明是1900还是2000。为了解决这个问题,S3C2410芯片内部的RTC部件通过硬件逻辑电路来处理2000的闰年的问题。即计数器的两位为00表示的是2000,而非1900。
RTC部件可以由后备电池提供电力。后备电池通过RTCVDD 引脚接到RTC 部件,当系统电源关闭时,微处理器接口和RTC逻辑电路均是断开的,后备电池仅驱动RTC部件的振荡器电路和BCD计数器,以使功耗降到最小。
在节电模式或正常运行模式下,RTC可以在特定的时候触发蜂鸣器。在正常运行模式下,激活的是报警中断信号(ALMINT)。在节电模式下,电源管理部件的唤醒信号(PMWKUP)激活的同时激活中断信号(ALMINT)。RTC内部的报警寄存器(RTCALM)可以设置报警工作状态的使能/不使能,以及报警时间条件的设置。
RTC的时间片计时器用于产生一个中断请求,TICNT 寄存器有一个中断使能位,和计数器中的值一起用来控制中断。当计数器的值变为0时,引起时间片计时中断。中断信号的周期用下列公司计算:
点赞  2009-10-15 11:26
周期=( n + 1 )/128s
上式中,n代表时间片计数器中的值,范围是1~127。RTC的时间片计时器可以用来产生实时操作系统内核所需的时间片。
进位复位功能可以由RTC的进位复位寄存器(RTCRST)来控制。秒的进位周期可以进行选择(30、40、50),在进位复位发生后秒,秒的数值又循回到0。例如,当前时间是23:37:47,进位周期选为40秒,则当前时间将变为23:38:00。
7.3.2         RTC控制寄存器
RTC部件内部有许多用于控制其操作的寄存器。通过编程对这些寄存器进行设定,用户就可以控制RTC部件的工作。下面对这些寄存器的格式进行介绍。

(1)RTC控制寄存器(RTCCON)
RTC控制寄存器(RTCCON)是可读/写的,地址为:0x57000040,复位后的初值为0x0。RTCCON寄存器的具体格式如表7-4所示。

表7-4 RTCCON寄存器的格式
符号        位        描述        初始状态
CLKRST        [3]        确定RTC时钟计数器是否复位
1 = 复位  0 = 不复位        0
CNTSEL        [2]        选择BCD码
1 = 保留  0 = 合并BCD码        0
CLKSEL        [1]        选择BCD时钟
1 = 保留(仅在测试时选择XTAL 时钟)
0 = XTAL的1/215         0
RTCEN        [0]        确定RTC使能/不使能
1 = 使能  0 = 不使能        0

该寄存器只包括4位,RTCEN、CLKSEL、CNTSEL、CLKRST。RTCEN控制BCD寄存器读/写使能,同时控制微处理器核和RTC间的所有接口的读/写使能。因此,在系统复位后需要对RTC内部寄存器进行读/写时该位必须设置为1。而在其他时间,该位应该被清为0,以防数据无意地写入RTC寄存器中。CLKSEL,CNTSEL和CLKRST用于测试。

(2)时间片计数器(TICNT)
时间片计数器(TICNT)是可读/写的,地址为:0x57000044,复位后的初值为0x0。TICNT寄存器的具体格式如表7-5所示。

表7-5 TICNT寄存器的格式
符号        位        描述        初始状态
TICNT INT ENABLE        [7]        时间片计数器中断使能
1 = 使能  0 = 不使能        0
TICK TIMECOUNT        [6:0]        时间片计数器的值,范围为1~127。
该计数器是减1计数,在计数过程中不能进行读操作。       

(3)报警控制寄存器(RTCALM)
报警控制寄存器(RTCALM)是可读/写的,用来确定报警功能和报警时间。其地址为:0x57000050,复位后的初值为0x0。RTCALM寄存器的具体格式如表7-6所示。注意:在节电模式下,RTCALM寄存器通过ALMINT和PMWKUP来产生报警信号,而在正常操作模式下,只通过ALMINT来产生报警信号。

表7-6 RTCALM寄存器的格式
符号        位        描述        初始状态
Reserved        [7]        保留        0
ALMEN        [6]        全局报警使能位
1 = 使能  0 = 不使能        0
YEAREN        [5]        年报警使能位
1 = 使能  0 = 不使能       
MONREN        [4]        月报警使能位
1 = 使能  0 = 不使能       
DATEEN        [3]        日报警使能位
1 = 使能  0 = 不使能       
HOUREN        [2]        时报警使能位
1 = 使能  0 = 不使能       
MINEN        [1]        分报警使能位
1 = 使能  0 = 不使能       
SECEN        [0]        秒报警使能位
1 = 使能  0 = 不使能       

(4)报警秒数据寄存器(ALMSEC)
报警秒数据寄存器(ALMSEC)是可读/写的,用来存储报警定时器的秒信号数据。其地址为:0x57000054,复位后的初值为0x0。ALMSEC寄存器的具体格式如表7-7所示。

表7-7 ALMSEC寄存器的格式
符号        位        描述        初始状态
Reserved        [7]        保留        0
SECDATA        [6:4]        报警定时器秒数据的十位数BCD值,值范围为0~5。        000
        [3:0]        报警定时器秒数据的个位数BCD值,值范围为0~9。        0000

(5)报警分数据寄存器(ALMMIN)
报警分数据寄存器(ALMMIN)是可读/写的,用来存储报警定时器的分信号数据。其地址为:0x57000058,复位后的初值为0x0。ALMMIN寄存器的具体格式如表7-8所示。
表7-8 ALMMIN寄存器的格式
符号        位        描述        初始状态
Reserved        [7]        保留        0
MINDATA        [6:4]        报警定时器分数据的十位数BCD值,值范围为0~5。        000
        [3:0]        报警定时器分数据的个位数BCD值,值范围为0~9。        0000

(6)报警时数据寄存器(ALMHOUR)
报警时数据寄存器(ALMHOUR)是可读/写的,用来存储报警定时器的时信号数据。其地址为:0x5700005C,复位后的初值为0x0。ALMHOUR寄存器的具体格式如表7-9所示。
表7-9 ALMHOUR寄存器的格式
符号        位        描述        初始状态
Reserved        [7:6]        保留        00
HOURDATA        [5:4]        报警定时器时数据的十位数BCD值,值范围为0~2。        00
        [3:0]        报警定时器时数据的个位数BCD值,值范围为0~9。        0000

(7)报警日数据寄存器(ALMDATE)
报警日数据寄存器(ALMDATE)是可读/写的,用来存储报警定时器的日信号数据。其地址为:0x57000060,复位后的初值为0x01。ALMDATE寄存器的具体格式如表7-10所示。

表7-10 ALMDATE寄存器的格式
符号        位        描述        初始状态
Reserved        [7:6]        保留        00
DATEDATA        [5:4]        报警定时器日数据的十位数BCD值,值范围为0~3。        00
        [3:0]        报警定时器日数据的个位数BCD值,值范围为0~9。        0001

(8)报警月数据寄存器(ALMMON)
报警月数据寄存器(ALMMON)是可读/写的,用来存储报警定时器的月信号数据。其地址为:0x57000064,复位后的初值为0x01。ALMMON寄存器的具体格式如表7-11所示。

表7-11 ALMMON寄存器的格式
符号        位        描述        初始状态
Reserved        [7:5]        保留        000
MONDATA        [4]        报警定时器月数据的十位数BCD值,值范围为0~1。        0
        [3:0]        报警定时器月数据的个位数BCD值,值范围为0~9。        0001

(9)报警年数据寄存器(ALMYEAR)
报警年数据寄存器(ALMYEAR)是可读/写的,用来存储报警定时器的年信号数据。其地址为:0x57000068,复位后的初值为0x0。ALMYEAR寄存器的具体格式如表7-12所示。

表7-12 ALMYEAR寄存器的格式
符号        位        描述        初始状态
YEARDATA        [7:0]        报警定时器年数据的BCD值,值范围为00~99。        0x0

(10)循环复位寄存器(RTCRST)
循环复位寄存器(RTCRST)是可读/写的,其地址为:0x5700006C,复位后的初值为0x0。RTCRST寄存器的具体格式如表7-13所示。


表7-13 RTCRST寄存器的格式
符号        位        描述        初始状态
SRSTEN        [3]        秒循环复位使能位
1 = 使能  0 = 不使能        0
SECCR        [2:0]        确定秒循环进位的周期
011 = 超过30秒
100 = 超过40秒
101 = 超过50秒
注意:如果该3位设置为(000、001、010、110或111)时,不会发生进位。但是秒的值还是可以复位。        000

(11)秒数据寄存器(BCDSEC)
秒数据寄存器(BCDSEC)是可读/写的,用来存储当前时间的秒数据(合并BCD码格式)。其地址为:0x57000070,复位后的初值不确定。BCDSEC寄存器的具体格式如表7-14所示。

表7-14 BCDSEC寄存器的格式
符号        位        描述        初始状态
SECDATA        [6:4]        秒数据十位的BCD码值,范围为0~5        -
        [3:0]        秒数据个位的BCD码值,范围为0~9       

(12)分数据寄存器(BCDMIN)
分数据寄存器(BCDMIN)是可读/写的,用来存储当前时间的分数据(合并BCD码格式)。其地址为:0x57000074,复位后的初值不确定。BCDMIN寄存器的具体格式如表7-15所示。

表7-15 BCDMIN寄存器的格式
符号        位        描述        初始状态
MINDATA        [6:4]        分数据十位的BCD码值,范围为0~5        -
        [3:0]        分数据个位的BCD码值,范围为0~9       

(13)时数据寄存器(BCDHOUR)
时数据寄存器(BCDHOUR)是可读/写的,用来存储当前时间的时数据(合并BCD码格式)。其地址为:0x57000078,复位后的初值不确定。BCDHOUR寄存器的具体格式如表7-16所示。


表7-16 BCDHOUR寄存器的格式
符号        位        描述        初始状态
Reserved        [7:6]        保留       
HOURDATA        [5:4]        时数据十位的BCD码值,范围为0~2        -
        [3:0]        时数据个位的BCD码值,范围为0~9       

(14)日数据寄存器(BCDDATE)
日数据寄存器(BCDDATE)是可读/写的,用来存储当前日期的日数据(合并BCD码格式)。其地址为:0x5700007C,复位后的初值不确定。BCDDATE寄存器的具体格式如表7-17所示。
表7-17 BCDDATE寄存器的格式
符号        位        描述        初始状态
Reserved        [7:6]        保留       
DATEDATA        [5:4]        时数据十位的BCD码值,范围为0~3        -
        [3:0]        时数据个位的BCD码值,范围为0~9       

(15)星期数据寄存器(BCDDAY)
星期数据寄存器(BCDDAY)是可读/写的,用来存储当前日期对应的星期数据(合并BCD码格式)。其地址为:0x57000080,复位后的初值不确定。BCDDAY寄存器的具体格式如表7-18所示。
表7-18 BCDDAY寄存器的格式
符号        位        描述        初始状态
Reserved        [7:3]        保留       
DAYDATA        [2:0]        星期数据的BCD码值,范围为1~7        -
点赞  2009-10-15 11:27
(16)月数据寄存器(BCDMON)
月数据寄存器(BCDMON)是可读/写的,用来存储当前日期的月数据(合并BCD码格式)。其地址为:0x57000084,复位后的初值不确定。BCDMON寄存器的具体格式如表7-19所示。
表7-19 BCDMON寄存器的格式
符号        位        描述        初始状态
Reserved        [7:5]        保留       
MONDATA        [4]        月数据十位的BCD码值,范围为0~1        -
        [3:0]        月数据个位的BCD码值,范围为0~9        -

(17)年数据寄存器(BCDYEAR)
年数据寄存器(BCDYEAR)是可读/写的,用来存储当前日期的年数据(合并BCD码格式)。其地址为:0x57000088,复位后的初值不确定。BCDYEAR寄存器的具体格式如表7-20所示。
表7-20 BCDYEAR寄存器的格式
符号        位        描述        初始状态
YEARDATA        [7:0]        年数据的BCD码值,范围为00~99        -
7.3.3 编程实例
RTC部件的主要功能是产生实时时间,提供年、月、日、时、分、秒等信息。在使用RTC部件之前,需要对其进行初始化。下面程序段完成的是对RTC内部寄存器初始化的工作。
//*****************************************************************
//**函数名:rtcinit()
//**功  能:初始化RTC,同时可以在此设定当前时间,但是需要用户写入
//*****************************************************************
volatile char year,month,day ,wkday ,hour, minute ,second,flag ;
void rtcinit(void)
{
//**用变量记录当前时间:2006-9-10 14:48:28
        year    =6;
        month   =9;
        day     =10;
        wkday   =7;
        hour    =14;
        minute  =48;
        second  =28;
//**初始化设置,首先使能RTC读写操作
        rRTCCON=(INT8U)(rRTCCON|0x01);
//**关闭提醒设置       
        rRTCALM=(INT8U)0x00;
//**关闭复位操作
        rRTCRST=(INT8U)0x00;
//**关闭定时中断
        rTICINT=(INT8U)0x00;
//**关闭RTC读写操作
        rRTCCON=(INT8U)(rRTCCON&0xfe);
}
下面一段程序完成的是对RTC内部寄存器写入操作。
//***************************************************************
//**函数名:rtcwrite()
//**功  能:将当前时间写到RTC
//***************************************************************
void rtcwrite(void )
{
//**为了快速写好RTC,定义部分中间变量,首先完成转换格式的工作
        INT8U Y,MO,D,W,H,MI,S;
//**完成十进制数到合并BCD码的转换工作
        if (year >1999)  year= year-2000;
        Y =(INT8U) ( year /10*16  + year%10) ;
        MO=(INT8U) ( month/10*16  + month%10) ;
        D =(INT8U) ( day /10*16   + day %10 ) ;
        W =(INT8U) ( wkday) ;
        H =(INT8U) ( hour /10*16 +hour%10 ) ;
        MI=(INT8U) ( minute/10*16+minute%10);
        S =(INT8U) ( second/10*16+second%10);
//**使能RTC读/写操作
        rRTCCON   =(INT8U)(rRTCCON|0x01);
//**将当前时间写入RTC对应的寄存器中
        rBCDYEAR  =Y ;
        rBCDMON   =MO;
        rBCDDAY   =D ;
        rBCDDATE  =W ;
        rBCDHOUR  =H;
        rBCDMIN   =MI;
        rBCDSEC   =S;
//**关闭RTC读写操作
        rRTCCON   =(INT8U)(rRTCCON&0xfe);
}

下面程序段完成的是对RTC内部寄存器读取操作。
//***************************************************************
//**函数名:rtcread()
//**功  能:读取RTC的当前值
//***************************************************************
void  rtcread(void)
{
//**为了快速读到数据,定义部分中间变量,转换格式的工作就放在了后面
        INT8U Y,MO,D,W,H,MI,S;
//**使能RTC读写操作
        rRTCCON=(INT8U)(rRTCCON|0x01);
//**读取日期和时间值
        Y  =rBCDYEAR;
        MO =rBCDMON;
        D  =rBCDDAY;
        W  =rBCDDATE;
        H  =rBCDHOUR;
        MI =rBCDMIN;
        S  =rBCDSEC;
//**关闭RTC读写操作
点赞  2009-10-15 11:27
rRTCCON=(INT8U)(rRTCCON&0xfe);
//**将合并BCD码转换为十进制数,放到对应的变量中
        year  =(Y&0x0f)+(Y&0xf0)/16*10+2000;
        month =(MO&0x0f)+(MO&0x10)/16*10;
        day   =(D&0x0f)+(D&0x30)/16*10;
        wkday =W&0x07;
        hour  =(H&0x0f)+(H&0x30)/16*10;
        minute=(MI&0x0f)+(MI&0x70)/16*10;
        second=(S&0x0f)+(S&0x70)/16*10;
}
本例中,涉及到的内部寄存器使用了变量表示,其定义见附录中的reg2410.h文件。下面一段程序是一个主程序的例子,初始化RTC部件后,既把当前的时间写入RTC内部对应的寄存器中,RTC部件既在当前时间的基础上,开始进行计时。若在某一时刻需要读出RTC的计时值,则调用rtcread()函数。
void Main(void)
{
rtcinit();
mydelay(10,10);        //延时函数
rtcwrite();

}
7.4 Timer部件
Timer部件主要是用于提供定时功能、脉宽调制(PWM)功能的部件,它的应用比较灵活,对于需要一定频率的脉冲信号、一定时间间隔的定时信号的应用场合,它都能提供应用支持。本节主要对S3C2410芯片内部的Timer部件进行介绍。
7.4.1 Timer部件概况
S3C2410芯片内部拥有5个16位的Timer部件。其中Timer0,Timer 1,Timer 2,Timer 3具有脉宽调制(PWM)功能。Timer4仅作定时器用,不具有PWM功能,因为它没有输出引脚。Timer0有一个死区(dead-zone)发生器,通常用于大电流设备应用。
Timer 0和Timer 1共享一个8位的预分频器,而Timer 2,Timer 3,Timer 4共享另一个8位的预分频器。另外还有2个具有5种分频系数的时钟分割器,5种不同的分频系数是:1/2,1/4,1/8,1/16和TCLK。其中,Timer 0和Timer 1共享一个4位的分割器,而Timer 2,Timer 3,Timer 4共享另一个4位的分割器。每个Timer部件接收的时钟是经过预分频器、分割器分频后的、仅提供给自己的时钟信号。8位的预分频器、分割器均可编程设定。S3C2410芯片内部的Timer部件功能框图如图7-6所示。

图7-6  Timer部件内部功能框图

图中, TCNTBn是定时器的计数缓冲寄存器,初始化应给其赋一个初值,该初值在定时器启动时加载进递减计数器中。TCMPBn是定时器(但Timer4没有)的比较缓冲寄存器,初始化时也给其赋一个初值,该初值被加载进比较寄存器,以便与递减计数器中的值比较。TCNTBn和TCMPBn的双缓冲机制,保证了Timer部件在频率和占空比发生改变时能有一个稳定的输出。
7.4.2 Timer部件的操作
每个定时器都有他自己的16位递减计数器TCNTn,该计数器是通过定时器自己的时钟驱动的。当递减计数器减为0时,可产生定时器中断请求信号,该中断信号通知微处理器定时器的操作已经完成了。当定时器计数器中的值为0时,TCNTBn的值将自动加载到递减计数器,以开始下一轮定时操作。但是,如果定时器停止工作,那么TCNTBn的值就不会被重新加载到计数器中。
TCMPBn的值用于脉宽调制。当递减计数器的值和定时器控制逻辑中的比较寄存器值相匹配时,定时器控制逻辑将改变输出电平(output level)。因此,比较寄存器确定脉宽调制信号输出的上升时间(或者下降时间)。
点赞  2009-10-15 11:28
(1)        基本的定时器操作
每个定时器(除了定时器4外)都有TCNTBn,TCNTn,TCMPBn和TCMPn。在TCNTn的值达到0时,TCNTBn和TCMPBn被分别加载到TCNTn和TCMPn中。同时,如果中断使能的话,将会提出中断请求。TCNTn和TCMPn是内部寄存器,TCNTn计数器的值可以通过TCNTOn寄存器读出。定时器基本操作的过程如图7-7所示。

图7-7  定时器操作

(2)自动重载和双缓冲器
S3C2410芯片的PWM定时器有双缓冲功能,该功能可以在不停止当前定时器操作的情况下,重新加载为下一轮定时器操作而改变的值。在这种机制下,尽管设置了新的定时器计数值,但是当前定时器的操作不受影响,还是按原计数值完成操作。
定时器计数值可以写入定时器计数缓冲寄存器(TCNTBn)中,而当前定时器的计数值可以从定时器计数观察寄存器(TCNTOn)中读到。如果读取TCNTBn的值,读到的值不一定是当前定时器的计数值,但一定是下一轮定时器操作的计数值。
当TCNTn值达到0时,自动重载操作将TCNTBn的值拷贝至TCNTn中。写入到TCNTBn中的值,仅在TCNTn值为0并且自动重载使能时,被加载到TCNTn中。如果TCNTn值变为0并且自动重载不使能,那么,TCNTn就不会进一步操作。一个双缓冲功能的例子如图7-8所示。

图7-8  一个双缓冲功能的例子

(3)采用手动更新方式初始化定时器
当递减计数器的值为0时,定时器自动重载操作就会发生。但若在重载发生之前,TCNTn的初始值还没有设置,在这种情况下,就必须通过手动更新位来加载TCNTn的初值。启动一个定时器操作的步骤如下:
1)        将初始值写到TCNTBn和TCMPBn中
2)        设置相应的定时器的手动更新位。
3)        设置相应的定时器的启动位来启动定时器,并清除手动更新位。
如果定时器被强制停止,TCNTn仍保持着当前计数值,而不会从TCNTBn重新加载计数值。如果需要重新启动定时操作,则必须设置新的计数值,这也要采用手动更新的方式。
如图7-9所示,若要产生图中所示脉冲信号波形,则要进行如下步骤的操作:
1)使能自动重载功能位。设置TCNTBn的值为160(50+110),TCMPBn的值为110。设置手动更新位和配置反转器位(开/关)。手动更新位分别设置TCNTn和TCMPn为TCNTBn和TCMPBn的值。然后,再分别设置TCNTBn的值和TCMPBn的值为80(40+40)和40,用作下一轮的重载值。
2)设置启动位,将手动更新位清为0,反转器置为off,自动重载使能。定时器的递减计数器开始启动工作。
3)当TCNTn的值达到与TCMPn的值相同时,TOUTn的逻辑电平由低变高。
4)当TCNTn的值达到0时,产生中断请求,同时TCNTBn的值加载到一个临时寄存器中。在下一节拍的定时器操作开始时,TCNTn从临时寄存器中重新加载计数值。
5)在中断服务程序中,TCNTBn的值和TCMPBn的值分别设置为80(20+60)和60,用于下一轮的定时操作。
6)当TCNTn的值达到与TCMPn的值相同时,TOUTn的逻辑电平由低变高。
7)当TCNTn的值达到0时,TCNTn自动重载TCNTBn中的值,并触发一个中断请求。
8)在中断服务程序中,自动重载和中断请求被禁止,从而停止定时器工作。
9)当TCNTn的值达到与TCMPn的值相同时,TOUTn的逻辑电平由低变高。
10)当TCNTn的值递减计数到0时,由于自动重载被禁止,因此TCNTn不再重载计数值,并且定时器停止。
11)不再产生中断请求。

图7-9  定时器产生的一个脉冲信号

(4)脉宽调制(PWM)
PWM脉冲宽度值由TCMPBn确定,而PWM脉冲频率值由TCNTBn确定。如图7-10所示。若要得到一个较高的PWM脉宽输出值,需增加TCMPBn的值。若要得到一个较低的PWM脉宽输出值,需减少TCMPBn的值。如果输出反转器被使能,增加和减少的结果将是反转的,既若要得到一个较高的PWM脉宽输出值,需减少TCMPBn的值。若要得到一个较低的PWM脉宽输出值,需增加TCMPBn的值。
基于双缓冲器的功能,下一轮PWM周期的TCMPBn的值,可以通过中断服务程序或其他方法,在当前PWM周期内任何时刻写入。

图7-10  PWM的脉宽实例
(5)输出电平控制
以下的方法用来保持TOUT的电平为高或低(假设反转器关闭):
•关闭自动加载位。然后,TOUTn的电平变为高,定时器在TCNTn递减计数到0时停止,推荐使用这种模式。
•通过将定时器的启动/停止位清为0来停止定时器工作。如果TCNTn的值小于等于TCMPn的值,输出电平为高。如果TCNTn的值大于TCMPn的值,输出电平为低。
•TOUTn可以通过设置TCON中的反转器的on/off位来反转。经过反转器反转的PWM信号如图7-11所示。

图7-11  反转器反转后的效果

(6)死区发生器
死区发生器用于对大功率设备进行PWM控制。这个功能用于在一个开关设备的断开和另一个开关设备的闭合之间插入一个时间间隙。这个时间间隙使得两个开关设备不可能同时被打开,即使是很短的一段时间。
图7-12所示的是死区使能时的输出波形图。TOUT0是PWM的输出,nTOUT0是TOUT0的反转输出。如果死区被使能,那么从TOUT0和nTOUT0输出的波形将分别是TOUT0_DZ和nTOUT0_DZ(如图7-12所示)。在死区的间隙中,TOUT0_DZ和nTOUT0_DZ不可能同时出现高电平。

图7-12  死区使能时的输出波形
7.4.3 Timer部件内部寄存器
控制Timer部件的操作,需要编程设定Timer部件内部的许多寄存器。本小节将具体介绍了这些寄存器的格式。

(1)定时器配置寄存器0(TCFG0)
定时器配置寄存器0(TCFG0)是可读/写的,主要用来设置预分频系数。其地址为:0x51000000,复位后的初值为0x00000000。TCFG0寄存器的具体格式如表7-21所示。
表7-21  TCFG0寄存器的格式
符号        位        描述        初始状态
Reserved        [31:24]        保留        0x00
Dead zone length        [23:16]        这8位用于确定死区长度,死区长度的1个单位等于Timer0的定时间隔。        0x00
Prescaler 1        [15:8]        这8位确定Timer2、Timer3、Timer4的预分频器值。         0x00
Prescaler 0        [7:0]        这8位确定Timer0、Timer1的预分频器值。        0x00
点赞  2009-10-15 11:28
(2)定时器配置寄存器1(TCFG1)
定时器配置寄存器1(TCFG1)是可读/写的,主要用来设置分割器值。其地址为:0x51000004,复位后的初值为0x00000000。TCFG1寄存器的具体格式如表7-22所示。
表7-22  TCFG1寄存器的格式
符号        位        描述        初始状态
Reserved        [31:24]        保留        0x00
DMA mode        [23:20]        选择产生DMA请求的定时器。
0000=不选择(所有采用中断请求)
0001=Timer0    0010=Timer1
0011=Timer2    0100=Timer3
0101=Timer4    0110=保留        0000
MUX4        [19:16]        选择Timer4的分割器值。
0000=1/2   0001=1/4   0010=1/8
0011=1/16  01XX=外部TCLK1         0000
MUX3        [15:12]        选择Timer3的分割器值。
0000=1/2   0001=1/4   0010=1/8
0011=1/16  01XX=外部TCLK1        0000
MUX2        [11:8]        选择Timer2的分割器值。
0000=1/2   0001=1/4   0010=1/8
0011=1/16  01XX=外部TCLK1        0000
                   表7-22  TCFG1寄存器的格式               续表
MUX1        [7:4]        选择Timer1的分割器值。
0000=1/2   0001=1/4   0010=1/8
0011=1/16  01XX=外部TCLK0        0000
MUX0        [3:0]        选择Timer0的分割器值。
0000=1/2   0001=1/4   0010=1/8
0011=1/16  01XX=外部TCLK0        0000

通过TCFG0、TCFG1的设置,可以确定预分频系数和分割器值,最终通过下面公式计算定时器输入时钟频率。
定时器输入时钟频率= PCLK /(预分频系数+1) / (分割器值)
预分频系数的范围 = 0~255
分割器值的取值范围 = 2, 4, 8, 16

(3)定时器控制寄存器(TCON)
定时器控制寄存器(TCON)是可读/写的,其地址为:0x51000008,复位后的初值为0x00000000。TCON寄存器的具体格式如表7-23所示。
表7-23  TCON寄存器的格式
符号        位        描述        初始状态
Timer4        [22]        确定Timer4的自动装载功能位
1=自动装载   0=一次停止         0
Timer4        [21]        确定Timer4的手动更新位
1=更新TCNTB4   0=不操作        0
Timer4        [20]        确定Timer4的启动/停止位
1=启动   0=停止        0
Timer3        [19]        确定Timer3的自动装载功能位
1=自动装载   0=一次停止         0
Timer3        [18]        确定Timer3的输出反转位
1=TOUT3反转   0=不反转        0
Timer3        [17]        确定Timer3的手动更新位
1=更新TCNTB3和TCMPB3   0=不操作        0
Timer3        [16]        确定Timer3的启动/停止位
1=启动   0=停止        0
Timer2        [15]        确定Timer2的自动装载功能位
1=自动装载   0=一次停止         0
Timer2        [14]        确定Timer2的输出反转位
1=TOUT2反转   0=不反转        0
Timer2        [13]        确定Timer2的手动更新位
1=更新TCNTB2和TCMPB2   0=不操作        0
                   表7-23  TCON寄存器的格式                续表
Timer2        [12]        确定Timer2的启动/停止位
1=启动   0=停止        0
Timer1        [11]        确定Timer1的自动装载功能位
1=自动装载   0=一次停止         0
Timer1        [10]        确定Timer1的输出反转位
1=TOUT1反转   0=不反转        0
Timer1        [9]        确定Timer1的手动更新位
1=更新TCNTB1和TCMPB1   0=不操作        0
Timer1        [8]        确定Timer1的启动/停止位
1=启动   0=停止        0
Reserved        [7:5]        保留        000
Dead zone         [4]        确定死区操作位
1=使能   0=不使能        0
Timer0        [3]        确定Timer0的自动装载功能位
1=自动装载   0=一次停止         0
Timer0        [2]        确定Timer0的输出反转位
1=TOUT0反转   0=不反转        0
Timer0        [1]        确定Timer0的手动更新位
1=更新TCNTB0和TCMPB0   0=不操作        0
Timer0        [0]        确定Timer0的启动/停止位
1=启动   0=停止        0

(4)Timer0计数缓冲寄存器和比较缓冲寄存器(TCNTB0/TCMPB0)
Timer0计数缓冲寄存器(TCNTB0)是可读/写的,其地址为:0x5100000C,复位后的初值为0x00000000。Timer0比较缓冲寄存器(TCMPB0)是可读/写的,其地址为:0x51000010,复位后的初值为0x00000000。TCNTB0和TCMPB0寄存器的具体格式如表7-24所示。
表7-24  TCNTB0/TCMPB0寄存器的格式
符号        位        描述        初始状态
TCNTB0        [15:0]        存放Timer0的计数初始值         0x0000
TCMPB0        [15:0]        存放Timer0的比较缓冲值        0x0000

(5)Timer0计数观察寄存器(TCNTO0)
Timer0计数观察寄存器(TCNTO0)是只读的,其地址为:0x51000014。复位后的初值为0x00000000。TCNTO0寄存器的具体格式如表7-25所示。
表7-25  TCNTO0寄存器的格式
符号        位        描述        初始状态
TCNTO0        [15:0]        存放Timer0的当前计数值         0x0000
定时器通道Timer1、Timer2、Timer3的计数缓冲寄存器(TCNTBn)、比较缓冲寄存器(TCMPBn)、计数观察寄存器(TCNTOn)与Timer0对应的寄存器格式相同。地址分别为:0x51000018(TCNTB1)、0x5100001C(TCMPB1)、0x51000020(TCNTO1);0x51000024(TCNTB2)、0x51000028(TCMPB2)、0x5100002C(TCNTO2);0x51000030(TCNTB3)、0x51000034(TCMPB3)、0x51000038(TCNTO3)。Timer4没有比较缓冲寄存器,但有计数缓冲寄存器(TCNTB4)和计数观察寄存器(TCNTO4),寄存器格式与Timer0对应的寄存器格式相同,地址分别为:0x5100003C(TCNTB4)、0x51000040(TCNTO4)。
7.4.4 应用实例
定时器的应用非常广泛,也非常灵活,不同的应用要求,将决定了定时器初始化编程的不同。但,无论用户需求有什么不同,均应根据用户要求,计算出需要定时器产生的定时时间间隔、脉冲宽度等参数值,然后再确定预分频系数、分割器值,把它们写入对应的寄存器。
例如:若需要产生一个周期约为500ms的脉冲信号,系统的PCLK=66MHz。选用Timer0来产生该脉冲信号,初始化编程如下:
首先,根据需要的脉冲信号周期及系统PCLK的频率值,确定预分频系数和分割器值,并计算出计数常数。在本例中,Timer0的预分频系数选择31,分割器值选择16。那么,计数常数则为:
计数常数= 定时时间间隔/(1 / (PCLK / (预分频系数+1) / (分割器值)))
        =500ms/(1/ (66M / 32 / 16))=64453
计数常数64453对应的十六进制数为0xfbc5。计算出计数常数后,下面即可编写定时器初始化程序。初始化程序中,首先设置TCFG0寄存器、TCFG1寄存器,然后再设置TCNTB0寄存器,最后通过设置TCON寄存器启动Timer0工作。Timer0启动工作后,当其递减计数器的值减到0时,会在TOUT0引脚上产生“回0信号”,该信号即是符合要求的脉冲信号。
//***************************************************************
//**定时器的编程
//***************************************************************
void Test_TimerInt(void)
{
    //设置定时器配置寄存器0(TCFG0)
rTCFG0=0x00001f;        //dead zone=0, Timer0预分频系数设31
    //设置定时器配置寄存器1(TCFG1)
rTCFG1=0x000003;        //都工作在中断方式,mux0=1/16
    //设置计数常数
rTCNTB0=0xfbc5;          //(1/(66MHz/32/16))*0xfbc5=0.5s
    //设置控制寄存器TCON
    rTCON=0x000002;        //更新TCNTB0和TCMPB0
    rTCON=0x000009;        //设置Timer0自动装载,并启动
         …
         //其他程序语句
    …
}
Timer0递减计数器的值递减到0时,还会产生中断请求信号。若需要微处理器进行中断服务,则还需要初始化芯片内部的中断控制器的寄存器。相关内容在第5章中进行了介绍。
点赞  2009-10-15 11:29
谢谢!不错,多学习学习啊!
点赞  2009-10-29 12:37
学习中...
点赞  2009-11-20 19:48
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 京公网安备 11010802033920号
    写回复