任何一个ARM初始化的时候一般都会优先设置系统时间,尤其是在设置一些与系统时钟息息相关的外设的时候,
S3C2440也不例外,系统时钟设置如下:
/******************************
*文件名:clock.c *
*功能: 电子钟 *
*创建者: 潘星宇 *
*最后修改:2013.03.7 *
*备注: *
* *
*******************************/
#include "clock.h"
static U32 UPLL;
/*****************************************************************************
***函数名:cal_cpu_bus_clk()
***功能:读取系统时钟值,提供给别的外设使用
***参数:无
***返回:无
*****************************************************************************/
void cal_cpu_bus_clk(void)
{
U32 val;
U8 m, p, s;
/*从寄存器MPLLCON中提取MDIV,PDIV,SDIV的值,从而计算FCLK的值,
就是MPLLout val = rMPLLCON; */
val = rMPLLCON;
m = (val>>12)&0xff; //注意,之前在调用函数中已经设置好了rMPLLCON的值
p = (val>>4)&0x3f; //p=PDIV=MPLLCON[9:4] 6位取值
s = val&3; //s=SDIV=MPLLCON[1:0] 低2位取值
/*(m+8)*FIN*2 不要超出32位数! //(1<<s)表示第s位置1,也就是2^s.
公式MPLL=(2*(MDIV+8)*FIN)/((PDIV+2)*(2^s)) FIN=12000000*/
FCLK = ((m+8)*(FIN/100)*2)/((p+2)*(1<<s))*100;
/*从寄存器CLKDIVN中提取出HDIVN和PDIVN,进行FCLK:HCLK:PCLK分频比的设置*/
val = rCLKDIVN; //在调用函数里面已经设置了rCLKDIVN的值
m = (val>>1)&3; //从寄存器CAMDIVN中提取出CAMDIVN[9:8]
p = val&1; //在调用函数里面已经设置了rCAMDIVN的值
val = rCAMDIVN; //s[1:0]=CAMDIVN[9:8]=HCLK4_HALF,HCLK3_HALF
/*s[4]=CAMDIVN[12]=DVS_EN,如果DVS_EN=1,则CPU时钟为HCLK,否则为FCLK*/
s = val>>8;
switch (m) { //这里的m=HDIVN,对FCLK和HCLK进行分频设置
case 0:
HCLK = FCLK;
break;
case 1:
HCLK = FCLK>>1; //HCLK=FCLK/2
break;
case 2:
if(s&2) //如果s[1]=1,也即CAMDIVN[9]=HCLK4_HALF=1
HCLK = FCLK>>3; //HCLK=FCLK/8
else
HCLK = FCLK>>2; //HCLK=FCLK/4
break;
case 3:
if(s&1) //如果s[0]=1,也即CAMDIVN[8]=HCLK3_HALF=1
HCLK = FCLK/6; //HCLK=FCLK/6
else
HCLK = FCLK/3; //HCLK=FCLK/3
break;
}
if(p) //这里p=PDIVN,对HCLK和PCLK进行分频设置
PCLK = HCLK>>1; //PDIVN=1,则PCLK=HCLK/2;否则PCLK=HCLK
else
PCLK = HCLK; //如果s[4]=1,也即CAMDIVN[12]=DVS_EN=1
val = rUPLLCON; //读ytfrUPLLCON的值
m = (val>>12)&0xff; //m=MDIV=UPLLCON[19:12] 8位
p = (val>>4)&0x3f; //p=PDIV=UPLLCON[9:4] 6位
s = val&3; //s=SDIV=UPLLCON[1:0] 2位
/*公式UPLL=((MDIV+8)*FIN)/((PDIV+2)*(2^s)) FIN为输入时钟频率*/
UPLL = ((m+8)*FIN)/((p+2)*(1<<s));
/*如果CLKDIVN[3]=1,则UPLL需要分频*/
UCLK = (rCLKDIVN&8)?(UPLL>>1):UPLL;
}
/**************************************************************************
***** 函数名: clock(void)
***** 功能: 电子钟
***** 参数: 无
***** 返回值: 无
***** 创建者: 潘星宇
***** 创建时间: 2013-03-5
***** 最后更新:2013-03-7
****************************************************************************/
void clock(void)
{
static U8 str[30] = {0}; //串口寄存数组
U8 ch; //串口用变量
static U8 UART_i = 0; //串口数组计数用
U8 hour_i; //画小时刻度计数用的变量
U8 minute_i; //画分钟刻度计数用的变量
U32 hour; //从RTC读取的小时
U32 minute; //分钟
U32 second; //秒
U32 second_ch; //秒控制变量,用于控制每秒才显示一次
static U32 hour_register; //小时寄存器,用于储存上一次画时针的位置,用于清屏
static U32 minute_register; //分钟寄存器
static U32 second_register; //秒寄存器
Brush_Background(0x435c); //绘制背景品蓝色
RTC_time_set (0x13, 0x03, 0x07, 0x04, 0x14, 0x55, 0x35);
draw_circle(180,136,123,0xfea0); //表外框金黄色
//绘制返回
draw_return(400, 130, COLOR_BLACK, COLOR_LIGHT_GREEN); //背景浅绿色
/**********************************************
*已知起始点、两点距离和角度画线的参数分别为:*
*第一点坐标x1,y1; *
*长度; *
*角度(不是弧度); *
*颜色; *
*希望保留起始的点的个数; *
*希望保留最后的点的个数 *
**********************************************/
//画小时刻度
for (hour_i=0; hour_i<12; hour_i++)
{
one_point_to_another(180, 136, 120, hour_i*30, 0xfb00, 0, 15); //从0点画到11点 橙色
}
//画分钟刻度
for (minute_i=0; minute_i<60; minute_i++)
{
if (minute_i % 5) //整点处不画刻度
{
one_point_to_another(180, 136, 120, minute_i*6, 0xfc00, 0, 1 ); //从1分画到59分 橘黄色
}
}
while (function_flag==0)
{
hour = rBCDHOUR; //获取小时
minute = rBCDMIN; //获取分钟
second = rBCDSEC; //获取秒
hour = ((hour / 16)*10 + hour % 16) % 12;//由于从RTC读出的都是16进制的,先转成10进制,再将24小时格式转化为12小时格式
minute = (minute / 16)*10 + minute % 16;
second = (second / 16)*10 + second % 16;
if (second != second_ch)
{
//先清除掉上次画的时针,分针,秒针,长度暂分别定为35,60,90
if ((hour_register*30 + (minute_register / 10)*5) != (hour*30 + (minute / 10)*5)) //为了消除分针和时针闪屏的问
{ //只有当分针或时针确实移动了位置才消除上一次画的的值
one_point_to_another(180, 136, 120, hour_register*30 + (minute_register / 10)*5, 0x435c, 35, 0);
}
if (minute_register != minute)
{
one_point_to_another(180, 136, 120, minute_register*6, 0x435c, 60, 0);
}
one_point_to_another(180, 136, 120, second_register*6, 0x435c, 90, 0);
second_ch = second; //使秒控制变量等于当前时钟的秒值,这样直到秒变化,才再次进入这个内部来
one_point_to_another(180, 136, 120, hour*30 + (minute /10)*5, COLOR_BLACK, 35, 0); //时针每小时走30°,分钟动10分钟,时钟动5°
one_point_to_another(180, 136, 120, minute*6, 0x001f, 60, 0); //蓝色
one_point_to_another(180, 136, 120, second*6, 0xf800, 90, 0); //红色
rtc_display_lcd(320,150,0xb1dd,0x08a8); //显示电子钟,参数分别为横坐标、纵坐标、颜色、背景色
hour_register = hour; //将时分秒的值储存起来,用于下一秒清除上一秒的变化
minute_register = minute;
second_register = second;
}
while (rUTRSTAT0 & 0x1) //当串口接收缓冲器有数据时
{
ch = rURXH0; //接收数据
str[UART_i++] = ch;
if((ch == 0xff)||(UART_i == 29 )) //接收数据完成
{
RTC_time_set (str[0], str[1], str[2], str[3], str[4], str[5], str[6]);
UART_i = 0;
}
}
}
}
附送一部分电子时钟的代码,头文件如下:
#ifndef CLOCK_H
#define CLOCK_H
#include "LCD.h"
#include "zi.h"
#include "global_value.h"
#include "2440addr.h"
#include "RTC.h"
#include "interface.h"
#include "common_functions.h"
/*****************************************************************************
***函数名:cal_cpu_bus_clk()
***功能:读取系统时钟值,提供给别的外设使用
***参数:无
***返回:无
*****************************************************************************/
extern void cal_cpu_bus_clk(void);
/**************************************************************************
***** 函数名: clock(void)
***** 功能: 电子钟
***** 参数: 无
***** 返回值: 无
***** 创建者: 潘星宇
***** 创建时间: 2013-03-5
***** 最后更新:2013-03-7
****************************************************************************/
extern void clock(void);
#endif