1. 程式人生 > >S3C2440之設定系統時鐘

S3C2440之設定系統時鐘

任何一個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