現在將一個(ge) 實際編製的、帶有調整時間功能的算盤碼新型時鍾程序發布。硬件電路由於(yu) 隻有一個(ge) 三基色LED和一個(ge) 按鍵開關(guan) ,就不貼出了。所選MCU主要是利用其內(nei) 置的RTCC。
單個(ge) 按鍵開關(guan) 有短按和長按兩(liang) 種用法。在正常報時狀態,短按無作用,長按可以進入調時狀態。進入調時狀態後,按照十小時、小時、十分、分的順序依次調整。每次短按鍵循環進行增量步進,長按鍵進入下一檔位,4種都調完最後一次長按鍵就回到正常報時狀態。在調整狀態,調整“小時”和“分鍾”時用白色和藍色分別顯示,白色表示正在調整的檔位,藍色則表示不調整的檔位。例如,在調整到第三檔的時候,第一個(ge) 拍發的數碼是白色,表示“十分”,第二個(ge) 拍發的數碼是藍色,表示“分”,在這個(ge) 檔位短按鍵隻調整白色的“十分”,不調整藍色的“分”。
/*-------------------------------------------------------------------
編譯器:MCC18 V3.40
日期:2011 0924
版本:V1.1
功能:用過去在Pic16論壇上發布過的算盤碼編碼格式,在pic18f26j13的RTCC上實現可以
用兩(liang) 位碼和光色來表示小時與(yu) 分鍾的新型時鍾。
前一位碼的光色表示“十小時”,碼型表示“小時”。後一位碼的光色表示“十分鍾”,碼型表示“分鍾”。
光色表示的數值依照“藍,綠,黃,紅,青,紫”依次表示“0,1,2,3,4,5”。
碼型以長短發光表示,以“劃”表示發光時間略長,“點”表示發光時間很短。以下從(cong) 0--9的碼型分別為(wei)
劃劃,點,點點,點點點,點點點點,劃,劃點,劃點點,劃點點點,劃點點點點。
用較短的停頓區分前後碼,用較長的停頓表示分組。
例如,21點整,表示為(wei) “黃點,藍劃劃”
修改時鍾,要長按唯一的按鍵,直到發出持續的白光(白裏泛紫),鬆鍵就用白光點劃表示等待修改的位,用藍光點劃表示不修改的位。
修改狀態連續發出的兩(liang) 個(ge) 碼型,前麵一組表示十小時和小時,後麵一組表示十分鍾和分鍾。每次修改時,先修改十小時位,再修改小時位。
此時顯示的兩(liang) 個(ge) 碼前麵是十小時,後麵是小時。前碼白光後碼藍光時修改十小時,通過短按鍵循環改變該位的值,修改完畢長按鍵就轉入後位修改,
這時是前碼藍光,後碼白光,同樣是循環改變,完成這組後長按就進入十分鍾和分鍾修改。後一組的修改過程和結束方式同前。
長按鍵要看到一組兩(liang) 個(ge) 碼完整顯示再鬆手,才能保證進入下一步。
修改完成後會(hui) 自動保存到RTCC,繼續正常發光報時任務。
硬件電路非常簡單,除去主振蕩器12m和實時鍾晶體(ti) 32768Hz外,隻有程序最前部鍵定義(yi) 連接的一個(ge) 按鍵和一個(ge) 三基色led。其它均按MCU手冊(ce) 要求配電容電阻即可。
特別聲明,本算盤碼的編碼方式,修改時鍾方式和整個(ge) 程序屬於(yu) 本人原創,可基於(yu) 個(ge) 人研究目的進行引用和複製,但不得作為(wei) 商業(ye) 用途使用。
-------------------------------------------------------------------*/
#include <P18f26j13.h>
#define Key PORTCbits.RC2
#define LEDR TRISBbits.TRISB2 //紅led
#define LEDG TRISBbits.TRISB0 //綠led
#define LEDB TRISBbits.TRISB3 //藍led
void main (void);
void InterruptHandlerHigh (void);
unsigned char *ppptr;
static const unsigned int morse_code[12]={0xee00,0x8000,0xa000,0xa800,0xaa00,0xe000,0xe800,0xea00,
0xea80,0xeaa0,0x0000,0x0000}; //算盤碼碼型
static const unsigned char code_lenth[12]={0x0c,0x06,0x08,0x0a,0x0c,0x08,0x0a,0x0c,0x0f,0x11,0x0a,0x0a};
//算盤碼碼長
unsigned int *morse_ptr;
unsigned char *code_lenth_ptr;
static unsigned char morse_lenth;
static unsigned int timing_code[4]={0x0000,0xaa00,0x0000,0x0000}; //輪流拍發的碼型存放位置
static unsigned char timing_code_lenth[4]={0x05,0x05,0x00,0x05}; //輪流拍發的碼長存放位置
unsigned char tens_or_ones;
unsigned char colour,minus;
unsigned char key_pules,key_count;
static unsigned long key_status=0xffffffff; //存儲(chu) 按鍵曆史的變量,每次中斷存一位,為(wei) 0表示長按鍵
unsigned char key_down,key_up,last_key; //表征按鍵按下、抬起的變量
unsigned char t=0;
unsigned char minut_colour,minut;
unsigned char hour,hour_colour;
unsigned char in_hour=1; //區別小時和分鍾的變量
unsigned int temp;
unsigned int temperature; //測試的變量名,沒有改正
unsigned char Rtimehi[4]={0x0,0x09,0x1,0x54},Rtimelo[4]={0x11,0x11,0x15,0x30}; //保存RTCC日期時間的兩(liang) 組變量
//***************主函數*****************
void main()
{
unsigned char i,j;
//**********RC2作為(wei) 按鍵使用初始化**********************
ANCON1bits.PCFG11=1; //RC2作為(wei) 數字IO,不給ADC
TRISCbits.TRISC2=1; //輸入,接Key
//*************************RTCC初始化*******************
T1GCON=0;
T1CON=0X8B; //允許tmr1的振蕩器
RTCCFG=0X07;
RTCCAL=0X0; //校準值
PADCFG1=0X02; //輸出秒時鍾
_asm movlw 0x55 _endasm
_asm movwf EECON2,0 _endasm
_asm movlw 0xAA _endasm
_asm movwf EECON2,0 _endasm
_asm bsf RTCCFG,5,1 _endasm //開啟寫(xie) 入
RTCCFGbits.RTCEN=1;
RTCCFG|=0x03; //置指針為(wei) 0b11
while (RTCCFGbits.RTCSYNC); //等待不忙
for (i=0;i<4;i++) //讀
{
Rtimelo[i]=RTCVALL;
Rtimehi[i]=RTCVALH;
}
//****************TIMERS*******************
T0CON=0X84; //定時器, 分頻
INTCONbits.T0IE=1;
T5CON=0X3F; //1/4Fosc,1:8 prescale,T1OSC, 16 bits WR,enabled
T5GCON=0; //no gate
PIE5bits.TMR5IE=1;
//*****************中斷開啟***************
INTCONbits.PEIE=1;
INTCONbits.GIE=1;
//****************按鍵相關(guan) 設置*************
morse_ptr=timing_code;
code_lenth_ptr=timing_code_lenth;
t=timing_code_lenth[1];
temp=timing_code[1];
key_up=0; //缺省為(wei) 按鍵抬起狀態
key_down=0;
last_key=1;
//**************************主循環************************
while(1)
{
RTCCFG|=0x03; //置指針為(wei) 0b11
Rtimelo[0]=RTCVALL; //讀年
Rtimehi[0]=RTCVALH; //讀空
Rtimelo[1]=RTCVALL; //讀日
Rtimehi[1]=RTCVALH; //讀月
Rtimelo[2]=RTCVALL; //讀小時
Rtimehi[2]=RTCVALH; //讀星期
Rtimelo[3]=RTCVALL; //讀秒
Rtimehi[3]=RTCVALH; //讀分
hour_colour=Rtimelo[2]>>4; //十小時顏色
hour=Rtimelo[2]&0x0f; //小時
minut_colour=Rtimehi[3]>>4; //十分顏色
minut=Rtimehi[3]&0x0f; //分鍾
timing_code[1]=morse_code[hour]; //小時的碼型
timing_code_lenth[1]=code_lenth[hour]; //小時的碼長
timing_code[2]=morse_code[minut]; //分的碼型
timing_code_lenth[2]=code_lenth[minut]; //分的碼長
//以下為(wei) 修改時鍾的鍵操作部分
if (key_status==0)
{
hour_colour=6; //白色光
minut_colour=0;
for (i=0;i<3;i++)
timing_code[i]=0xffff; //全長劃,表示進入調整時鍾模式
while (key_status==0);
for (i=0;i<3;i++)
timing_code[i]=0;
while (key_status) //一次長按鍵之前,修改十小時值
{
timing_code[1]=morse_code[Rtimelo[2]>>4]; //十小時
timing_code_lenth[1]=code_lenth[Rtimelo[2]>>4];
timing_code[2]=morse_code[Rtimelo[2]&0x0f]; //小時
timing_code_lenth[2]=code_lenth[Rtimelo[2]&0x0f];
if (key_up==1) //如果發現短時間按鍵的抬鍵信號
{
Rtimelo[2]+=0x10; //步進十小時
key_up=0; //清除短時間按鍵標誌
}
if (Rtimelo[2]>0x23)
Rtimelo[2]=0;
}
while (key_status==0) key_up=0; //防止一次按鍵連續動作
hour_colour=0; //lan色光
minut_colour=6; //白色光
while (key_status) //一次長按鍵之前,修改小時值
{
timing_code[1]=morse_code[Rtimelo[2]>>4]; //十小時
timing_code_lenth[1]=code_lenth[Rtimelo[2]>>4];
timing_code[2]=morse_code[Rtimelo[2]&0x0f]; //小時
timing_code_lenth[2]=code_lenth[Rtimelo[2]&0x0f];
if (key_up==1) //如果發現短時間按鍵的抬鍵信號
{
Rtimelo[2]++; //步進小時
key_up=0; //清除短時間按鍵標誌
}
if (Rtimelo[2]>0x23) //總小時數若大於(yu) 23,則小時個(ge) 位置0
Rtimelo[2]=0x20;
if ((Rtimelo[2]&0x0f)>9) //小時值若大於(yu) 9
Rtimelo[2]&=0xf0; //修改為(wei) 0
}
while (key_status==0) key_up=0; //防止一次按鍵連續動作
//以下修改分鍾
hour_colour=6; //白色光
minut_colour=0; //藍色光
while (key_status) //一次長按鍵之前,修改十分鍾值
{
timing_code[1]=morse_code[Rtimehi[3]>>4]; //十分鍾
timing_code_lenth[1]=code_lenth[Rtimehi[3]>>4];
timing_code[2]=morse_code[Rtimehi[3]&0x0f]; //分鍾
timing_code_lenth[2]=code_lenth[Rtimehi[3]&0x0f];
if (key_up==1) //如果發現短時間按鍵的抬鍵信號
{
Rtimehi[3]+=0x10; //步進十分鍾
key_up=0; //清除短時間按鍵標誌
}
if (Rtimehi[3]>0x59) //總fen數若大於(yu) 59,則十分鍾位置0
Rtimehi[3]&=0x0f;
}
while (key_status==0) key_up=0; //防止一次按鍵連續動作
hour_colour=0; //藍色光
minut_colour=6; //白色光
bwhile (key_status) //一次長按鍵之前,修改分鍾值
{
timing_code[1]=morse_code[Rtimehi[3]>>4]; //十分鍾
timing_code_lenth[1]=code_lenth[Rtimehi[3]>>4];
timing_code[2]=morse_code[Rtimehi[3]&0x0f]; //分鍾
timing_code_lenth[2]=code_lenth[Rtimehi[3]&0x0f];
if (key_up==1) //如果發現短時間按鍵的抬鍵信號
{
Rtimehi[3]++; //步進分鍾
key_up=0; //清除短時間按鍵標誌
}
if ((Rtimehi[3]&0x0f)>9) //fen數個(ge) 位若大於(yu) 9,則分鍾位置0
Rtimehi[3]=Rtimehi[3]&0xf0;
}
while (key_status==0) key_up=0; //防止一次按鍵連續動作
//寫(xie) 入RTCC
RTCCFG|=0x03; //置指針為(wei) 0b11
while (RTCCFGbits.RTCSYNC); //等待不忙
for (i=0;i<4;i++) //寫(xie)
{
RTCVALL=Rtimelo[i];
RTCVALH=Rtimehi[i];
}
}
//到達MAIN最後部分
}
}
//----------------------------------------------------------------------------
// High priority interrupt vector
#pragma code InterruptVectorHigh = 0x08
void InterruptVectorHigh (void)
{
_asm
goto InterruptHandlerHigh //jump to interrupt routine
_endasm
}
//----------------------------------------------------------------------------
// High priority interrupt routine
#pragma code
#pragma interrupt InterruptHandlerHigh
void
InterruptHandlerHigh ()
{
if (INTCONbits.TMR0IF)
{ //check for TMR0 overflow
INTCONbits.TMR0IF = 0; //clear interrupt flag
TMR0H=0X20; //略加快點劃速率
TMR0L=0;
if ((t<=0)|t>25)
{
if (morse_ptr>&timing_code[2])
{
morse_ptr=timing_code;
code_lenth_ptr=timing_code_lenth;
}
else
{
morse_ptr++;
code_lenth_ptr++;
}
if (morse_ptr>(&timing_code[1])) //小時在1,分在2,據此決(jue) 定in_hour
in_hour=0;
else
in_hour=1;
if (in_hour==0) //十分鍾顏色
{
if (minut_colour==0) //藍
{
LEDG=1;
LEDR=1;
LEDB=0;
}
else if (minut_colour==1) //綠
{
LEDG=0;
LEDR=1;
LEDB=1;
}
else if (minut_colour==2) //黃
{
LEDG=0;
LEDR=0;
LEDB=1;
}
else if (minut_colour==3) //紅
{
LEDG=1;
LEDR=0;
LEDB=1;
}
else if (minut_colour==4) //青
{
LEDG=0;
LEDR=1;
LEDB=0;
}
else if (minut_colour==5) //紫
{
LEDG=1;
LEDR=0;
LEDB=0;
}
else //白
{
LEDG=0;
LEDR=0;
LEDB=0;
}
}
else //十小時顏色
{
if (hour_colour==0) //藍
{
LEDG=1;
LEDR=1;
LEDB=0;
}
else if (hour_colour==1) //綠
{
LEDG=0;
LEDR=1;
LEDB=1;
}
else if (hour_colour==2) //黃
{
LEDG=0;
LEDR=0;
LEDB=1;
}
else if (hour_colour==3) //紅
{
LEDG=1;
LEDR=0;
LEDB=1;
}
else if (hour_colour==4) //青
{
LEDG=0;
LEDR=1;
LEDB=0;
}
else if (hour_colour==5) //紫
{
LEDG=1;
LEDR=0;
LEDB=0;
}
else //白
{
LEDG=0;
LEDR=0;
LEDB=0;
}
}
temp=*morse_ptr; //取得指針位置的值
t=*code_lenth_ptr; //同上
}
else
{
t--;
}
if ((temp&0x8000)==0) //這段是拍發算盤碼的執行部分
LATB = LATB|0b00001101;
else
LATB = LATB&0b1110010;
temp=temp<<1;
}
else if (PIR5bits.TMR5IF) //該定時器用來識別按鍵動作
{
PIR5bits.TMR5IF = 0; //clear interrupt flag
if (key_down==1&last_key==1) //隻有下鍵後才進入判斷
{
if (key_status) //在沒有全0序列情況下
if (Key==1) //確認抬鍵
{
key_up=1;
key_down=0;
}
}
else if (last_key==0)
{
if (Key==0)
{
key_down=1; //確認下鍵
key_up=0;
}
}
last_key=Key; //當前鍵值賦予舊鍵值
key_status=key_status<<1; //鍵狀態左移1位
key_status|=Key; //末位置Key的值
}
}