实验目的和内容:
1. 了解实时时钟,实现每秒显示实时时钟和每分钟的第n秒告警(结合中断)
2. 了解看门狗,在保证系统正常运行,一旦出现系统瘫痪等问题时,恢复系统的正常运行。设系统程序完整运行一周期时间为Tp(喂狗时间),看门狗的定时周期(狗粮能吃的时间)为Ti,则必须满足Ti>Tp。
实验过程(含步骤):
1.新建工程:参照watchdog设置,在C/武汉创维特/CVT-S3C2440/example位置新建工程并命名,设置当前工程为此工程;然后在ADT IDE中新建工程,选择ARM9usb,命名与第一步工程名一样;打开工作区第一个文件夹,右键添加文件,即main.c、2440slib.c以及interrupt.c 在第三个文件夹中添加include/2440init.o和include/2440lib.OE然后再第四个文件夹,添加文件:misc/ldscrpt和misc/E... 最后在setting目录下的compile选项的category中选择genernal,头文件目录下添加include文件夹以导入头文件,Link目录下选择Library Search Path添加与看门狗相同的路径(这里需要对比,完全相同为止),Link选项下的Genernal下的路径依然类比看门狗直至相同,最后在Image Entry Options下的文件目录依然类比看门狗,总而言之在完成初始创建工作后,setting中各个设置全部按照看门狗工程设置,相同为止。
详情见实验书 p23的工程建立
2.在超级终端上,每隔一秒重新显示时间,并在每分钟的第5秒告警,打印“Alarm”,LED变换,当修改狗粮能吃的时间,使喂狗时间大于狗粮能吃的时间,一定时间后,看门狗复位,目标机重启,在超级终端上可以看到复位的启动信息
3.之后尝试修改时钟,发现时钟的日子始终不能被正确的修改,怀疑可能是硬件本身的问题。
/* 包含文件 */
#include "def.h"
#include "2410lib.h"
#include "option.h"
#include "2410addr.h"
#include "interrupt.h"
//extern unsigned char seg7table[];
#define U8 unsigned char
void Delay1(int time);
/* 表示日期、时间的数据结构 */
typedef struct ST_DATE
{
short year; // 年
char mon; // 月
char day; // 日
char week_day; // 星期
char hour; // 时
char min; // 分
char sec; // 秒
} st_date;
/* 全局变量 */
int led_index = 0;
int ext0_count = 0;
/* functions */
void rtc_tick_isr(void) __attribute__ ((interrupt("IRQ")));;//jishi
void rtc_int_isr(void) __attribute__ ((interrupt("IRQ")));;
#define WDT_ENABLE (0x01<<5)//开看门狗
#define WDT_INT_ENABLE (0x01<<2)//开看门狗中断
#define WDT_RST_ENABLE (0x01<<0)//允许复位
#define WDT_CLK_SEL (0X3 <<3) /决定时钟分频因子* 1/128 */
#define WDT_PRE_SCALER ((PCLK/1000000-1) <<8) /* 预分频值 */
/********************************************************************
// Function name : watchdog_init
// Description : 看门狗初始化
// Return type : void
// Argument :
*********************************************************************/
void watchdog_init()
{
rWTCNT = 8448 * 2; /* 设置看门狗初始值,即狗粮能吃的时间 *///2.16s
rWTCON = WDT_ENABLE | WDT_RST_ENABLE | WDT_CLK_SEL | WDT_PRE_SCALER; /* 打开看门狗 */ /* 打开看门狗,允许复位,时钟选择1/128,预分频值 */
}
/*****************************************************************************
// Function name : rtc_set_date
// Description : 修改实时时钟当前时间、日期
// Return type : void
// Argument : p_date, 待设置的日期
*****************************************************************************/
void rtc_set_date(st_date* p_date) //将传入的参数设置为时钟的时间
{
rRTCCON = 0x01; //先允许RTC(实时时钟)读写
rBCDYEAR = p_date->year;
rBCDMON = p_date->mon;
rBCDDAY = p_date->day;
rBCDDATE = p_date->week_day;
rBCDHOUR = p_date->hour;
rBCDMIN = p_date->min;
rBCDSEC = p_date->sec;
rRTCCON = 0x00; //后关闭RTC读写
}
/*****************************************************************************
// Function name : rtc_get_date
// Description : 获取实时时钟当前时间、日期
// Return type : void
// Argument : p_date, 返回日期的指针
*****************************************************************************/
void rtc_get_date(st_date* p_date) //将传入的参数修改为时钟的当前时间
{
rRTCCON = 0x01;
p_date->year = rBCDYEAR ;
p_date->mon = rBCDMON ;
p_date->day = rBCDDAY ;
p_date->week_day= rBCDDATE ;
p_date->hour = rBCDHOUR ;
p_date->min = rBCDMIN ;
p_date->sec = rBCDSEC ;
rRTCCON = 0x00;
}
/*****************************************************************************
// Function name : rtc_tick_init
// Description : 初始化S3C2410的TICK定时器
// Return type : void
// Argument : tick, 设置的TICK频率(时钟滴答的周期为 (1+tick)/128秒)
*****************************************************************************/
void rtc_tick_init( char tick )
{
Irq_Request(IRQ_TICK, rtc_tick_isr);//注册时钟中断(9)
rRTCCON = 0x0; //No reset[3], Merge BCD counters[2], BCD clock select XTAL[1], RTC Control disable[0]
rTICNT = (tick&0x7f)|0x80; /*TICK 中断使能,周期为(1+tick)/128秒*/
Irq_Enable(IRQ_TICK);
}
/*****************************************************************************
// Function name : rtc_alarm_set
// Description : 设置S3C2410的告警时间以及方式
// Return type : void
// Argument : p_date, 告警的时间
// mode, 告警模式
*****************************************************************************/
void rtc_alarm_set(st_date* p_date, unsigned char mode)
{
Irq_Request(IRQ_RTC, rtc_int_isr);
rRTCCON = 0x01;
rALMYEAR = p_date->year;
rALMMON = p_date->mon;
rALMDATE = p_date->day;
rALMHOUR = p_date->hour;
rALMMIN = p_date->min;
rALMSEC = p_date->sec;
rRTCALM = mode;
rRTCCON = 0x00;
Irq_Enable(IRQ_RTC);
}
/*****************************************************************************
// Function name : Main
// Description : JXARM9-2410 看门狗实验主程序
// 完成功能:
// 在实时时钟实验的基础上添加看门狗功能,并在时钟滴答
// 中断中实现喂狗处理.
//
// Return type : void
// Argument : void
*****************************************************************************/
void Main(void)
{
int old_index ;
st_date m_date;
/* 配置系统时钟 */
ChangeClockDivider(2,1);
U32 mpll_val = 0 ;
mpll_val = (92<<12)|(1<<4)|(1);
ChangeMPllValue((mpll_val>>12)&0xff, (mpll_val>>4)&0x3f, mpll_val&3);
/* 中断初始化 */
Isr_Init();
/* 初始化端口 */
Port_Init();
/* 初始化串口 */
Uart_Init(0,115200);
Uart_Select(0);
/* 打印提示信息 */
PRINTF("\n---看门狗测试程序---\n");
PRINTF("\n请将UART0与PC串口进行连接,然后启动超级终端程序(115200, 8, N, 1)\n");
PRINTF("\n看门狗测试开始\n");
/* 采用BCD编码,如2018年需要设置的值为0x2018 */
/*BCD码是用4位二进制数来表示1位十进制数中的0-9这10个数码*/
m_date.year = 0x2000+0x18 ;
m_date.mon = 0x04 ;
m_date.day = 0x13 ;//寄存器有问题,无法正常显示十位,即只能显示03
m_date.week_day = 0x07 ;
m_date.hour = 0x15 ;
m_date.min = 0x40 ;
m_date.sec = 0x00 ;
/* 修改当前日期和时间 */
rtc_set_date(&m_date);
m_date.sec = 0x05 ;//每分钟的第5秒触发告警中断
/* 设置告警的时间及方式,0x41表示使能RTC告警,以及使能秒时钟告警 */
rtc_alarm_set(&m_date, 0x41);
rtc_tick_init(127);//(127+1)/128=1s,即每1秒触发一次时钟中断
/* 打开看门狗复位功能 */
watchdog_init();
old_index = led_index;
PRINTF("请在2秒内喂狗,否则系统将在约2秒后复位\n\n");
rtc_get_date(&m_date);
while(1)
{
if(old_index != led_index) /* 每隔一秒更新一次数据 */
{
old_index = led_index;
PRINTF( /* 时钟数据为BCD码格式,以16进制显示 */
"\r%02x:%02x:%02x:%02x %02x:%02x:%02x",m_date.year,m_date.day,m_date.mon,m_date.week_day, m_date.hour, m_date.min, m_date.sec);
}
};
}
/*****************************************************************************
// Function name : rtc_tick_isr
// Description : TICK中断处理程序,程序中设置每秒钟引发一次中断
// 为避免看门狗复位在此处喂狗
// Return type : int
// Argument : void
*****************************************************************************/
void rtc_tick_isr(void)
{
Irq_Clear(IRQ_TICK); /* 清除TICK中断 */
led_index++;
/* 喂狗 */
if(led_index%2==0) //该中断处理函数每1秒执行一次,为实现每2s喂狗,通过全局变量来控制喂狗是否执行(偶数执行,奇数不执行),即每隔两秒喂一次
rWTCNT = 8448 * 2;
}
/*****************************************************************************
// Function name : rtc_int_isr
// Description : rtc中断处理程序,程序中设置每分钟的第5秒引发该中断
// Return type : int
// Argument : void
*****************************************************************************/
int f = 1;
void rtc_int_isr(void)
{
Irq_Clear(IRQ_RTC); /*清除RTC中断 */
ext0_count++;
PRINTF("\r\nAlarm\r\n"); //看门狗启动时输出Alarm到超级终端上
if (f==1) *((U8*) 0x20005000) = 0x55; //修改led灯的发光模式,f参数每次会对自己做一个!操作,使用led的发光模式可以一直的改变
else *((U8*) 0x20005000) = 0xaa;
f = !f;
}
实验总结:
wq:
呃,这次我们又花了超级长都时间来连设备,对,就是“又”,设备真是对我们租不太友好啊。不过后面还是连接上了,然后开始了新建工程,一步一步,知道了哪些文件应该在哪些文件夹里面寻找。
然后就开始看门狗实验了,倒霉×2,我们组实验过程中发现寄存器传输数据显示到超级终端上时,无论设值为多少,date的十位数部分总是0。苦改代码40分钟无果,问老师才知原因竟是硬件问题。老师说:"你们应该问问其他组的数据啊,有没有出错,不要自己在这里默默改半天"。呃...学到了,以后要到处问问,看看大家是否也出现了类似问题。
由于时间实在不足,本组最终未完成将时间显示在数码管上,希望下次实验开工,佛祖保佑。
zhy:
通过这次实验我进一步了解了看门狗的工作原理和功能,以及看门狗寄存器定时周期的计算方法。
在实验过程中遇到了很多的问题,例如,无法连接到超级终端、USB驱动无法正确装载、计算机寄存器硬件无法读出1的问题等等,要通过反反复复的操作,即便如此,也费了好大的力气才能看到最终的结果。
yy:
这次看门狗实验又是历尽波折,先是老问题:设备连接故障,然后好不容易解决了,又发现因为设置问题,导致编译失败,等到所有设置与正常的同步之后,总算看到运行结果了,却又发现日期的输出与预想始终不符合,直到最后老师提醒我们问问别的组是否也有这个问题才知道原来是硬件有问题。耽误太多时间,导致没来得及实现数码管显示时间,很遗憾。
这次实验算是一个教训吧,充分了解到了硬件知识的重要性,以及与其他人交流的重要性。希望以后不要再出现类似的问题了。
cxy:
这次实验清楚的了解了看门狗和时钟的具体实现。但是在调节日期的时候出现了一些问题,day的参数始终没法调节正常。花了很多的时间,最后发现是所有机器都有的问题。做软件开发还是不能太完美主义,不可能去解决所有的问题,而是发现问题尽力避免
lg:
学校的机器有点问题,要注意USB插口以及其他设备连接时的松紧问题。另外对于新建一个工程的基本要求不太清楚,之前太依赖原有的工程了,都只是在原有的基础修修改改,以后得自己深究一下,否则可能脱离了现有的工程就什么都不会了。此次试验知道了ARM的实时时钟其实不是和想象中的时间一样,但设置初始时间后能一直计时,可以在某个固定时间实行告警。还有看门狗对于处理死机的用处,也可以用来计时。