現(xiàn)在將一個(gè)實(shí)際編制的、帶有調(diào)整時(shí)間功能的算盤碼新型時(shí)鐘程序發(fā)布。硬件電路由于只有一個(gè)三基色LED和一個(gè)按鍵開關(guān),就不貼出了。所選MCU主要是利用其內(nèi)置的RTCC。
單個(gè)按鍵開關(guān)有短按和長按兩種用法。在正常報(bào)時(shí)狀態(tài),短按無作用,長按可以進(jìn)入調(diào)時(shí)狀態(tài)。進(jìn)入調(diào)時(shí)狀態(tài)后,按照十小時(shí)、小時(shí)、十分、分的順序依次調(diào)整。每次短按鍵循環(huán)進(jìn)行增量步進(jìn),長按鍵進(jìn)入下一檔位,4種都調(diào)完最后一次長按鍵就回到正常報(bào)時(shí)狀態(tài)。在調(diào)整狀態(tài),調(diào)整“小時(shí)”和“分鐘”時(shí)用白色和藍(lán)色分別顯示,白色表示正在調(diào)整的檔位,藍(lán)色則表示不調(diào)整的檔位。例如,在調(diào)整到第三檔的時(shí)候,第一個(gè)拍發(fā)的數(shù)碼是白色,表示“十分”,第二個(gè)拍發(fā)的數(shù)碼是藍(lán)色,表示“分”,在這個(gè)檔位短按鍵只調(diào)整白色的“十分”,不調(diào)整藍(lán)色的“分”。
/*-------------------------------------------------------------------
編譯器:MCC18 V3.40
日期:2011 0924
版本:V1.1
功能:用過去在Pic16論壇上發(fā)布過的算盤碼編碼格式,在pic18f26j13的RTCC上實(shí)現(xiàn)可以
用兩位碼和光色來表示小時(shí)與分鐘的新型時(shí)鐘。
前一位碼的光色表示“十小時(shí)”,碼型表示“小時(shí)”。后一位碼的光色表示“十分鐘”,碼型表示“分鐘”。
光色表示的數(shù)值依照“藍(lán),綠,黃,紅,青,紫”依次表示“0,1,2,3,4,5”。
碼型以長短發(fā)光表示,以“劃”表示發(fā)光時(shí)間略長,“點(diǎn)”表示發(fā)光時(shí)間很短。以下從0--9的碼型分別為
劃劃,點(diǎn),點(diǎn)點(diǎn),點(diǎn)點(diǎn)點(diǎn),點(diǎn)點(diǎn)點(diǎn)點(diǎn),劃,劃點(diǎn),劃點(diǎn)點(diǎn),劃點(diǎn)點(diǎn)點(diǎn),劃點(diǎn)點(diǎn)點(diǎn)點(diǎn)。
用較短的停頓區(qū)分前后碼,用較長的停頓表示分組。
例如,21點(diǎn)整,表示為“黃點(diǎn),藍(lán)劃劃”
修改時(shí)鐘,要長按唯一的按鍵,直到發(fā)出持續(xù)的白光(白里泛紫),松鍵就用白光點(diǎn)劃表示等待修改的位,用藍(lán)光點(diǎn)劃表示不修改的位。
修改狀態(tài)連續(xù)發(fā)出的兩個(gè)碼型,前面一組表示十小時(shí)和小時(shí),后面一組表示十分鐘和分鐘。每次修改時(shí),先修改十小時(shí)位,再修改小時(shí)位。
此時(shí)顯示的兩個(gè)碼前面是十小時(shí),后面是小時(shí)。前碼白光后碼藍(lán)光時(shí)修改十小時(shí),通過短按鍵循環(huán)改變?cè)撐坏闹担薷耐戤呴L按鍵就轉(zhuǎn)入后位修改,
這時(shí)是前碼藍(lán)光,后碼白光,同樣是循環(huán)改變,完成這組后長按就進(jìn)入十分鐘和分鐘修改。后一組的修改過程和結(jié)束方式同前。
長按鍵要看到一組兩個(gè)碼完整顯示再松手,才能保證進(jìn)入下一步。
修改完成后會(huì)自動(dòng)保存到RTCC,繼續(xù)正常發(fā)光報(bào)時(shí)任務(wù)。
硬件電路非常簡單,除去主振蕩器12m和實(shí)時(shí)鐘晶體32768Hz外,只有程序最前部鍵定義連接的一個(gè)按鍵和一個(gè)三基色led。其它均按MCU手冊(cè)要求配電容電阻即可。
特別聲明,本算盤碼的編碼方式,修改時(shí)鐘方式和整個(gè)程序?qū)儆诒救嗽瓌?chuàng),可基于個(gè)人研究目的進(jìn)行引用和復(fù)制,但不得作為商業(yè)用途使用。
-------------------------------------------------------------------*/
#include <P18f26j13.h>
#define Key PORTCbits.RC2
#define LEDR TRISBbits.TRISB2 //紅led
#define LEDG TRISBbits.TRISB0 //綠led
#define LEDB TRISBbits.TRISB3 //藍(lán)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}; //輪流拍發(fā)的碼型存放位置
static unsigned char timing_code_lenth[4]={0x05,0x05,0x00,0x05}; //輪流拍發(fā)的碼長存放位置
unsigned char tens_or_ones;
unsigned char colour,minus;
unsigned char key_pules,key_count;
static unsigned long key_status=0xffffffff; //存儲(chǔ)按鍵歷史的變量,每次中斷存一位,為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; //區(qū)別小時(shí)和分鐘的變量
unsigned int temp;
unsigned int temperature; //測試的變量名,沒有改正
unsigned char Rtimehi[4]={0x0,0x09,0x1,0x54},Rtimelo[4]={0x11,0x11,0x15,0x30}; //保存RTCC日期時(shí)間的兩組變量
//***************主函數(shù)*****************
void main()
{
unsigned char i,j;
//**********RC2作為按鍵使用初始化**********************
ANCON1bits.PCFG11=1; //RC2作為數(shù)字IO,不給ADC
TRISCbits.TRISC2=1; //輸入,接Key
//*************************RTCC初始化*******************
T1GCON=0;
T1CON=0X8B; //允許tmr1的振蕩器
RTCCFG=0X07;
RTCCAL=0X0; //校準(zhǔn)值
PADCFG1=0X02; //輸出秒時(shí)鐘
_asm movlw 0x55 _endasm
_asm movwf EECON2,0 _endasm
_asm movlw 0xAA _endasm
_asm movwf EECON2,0 _endasm
_asm bsf RTCCFG,5,1 _endasm //開啟寫入
RTCCFGbits.RTCEN=1;
RTCCFG|=0x03; //置指針為0b11
while (RTCCFGbits.RTCSYNC); //等待不忙
for (i=0;i<4;i++) //讀
{
Rtimelo[i]=RTCVALL;
Rtimehi[i]=RTCVALH;
}
//****************TIMERS*******************
T0CON=0X84; //定時(shí)器, 分頻
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;
//****************按鍵相關(guān)設(shè)置*************
morse_ptr=timing_code;
code_lenth_ptr=timing_code_lenth;
t=timing_code_lenth[1];
temp=timing_code[1];
key_up=0; //缺省為按鍵抬起狀態(tài)
key_down=0;
last_key=1;
//**************************主循環(huán)************************
while(1)
{
RTCCFG|=0x03; //置指針為0b11
Rtimelo[0]=RTCVALL; //讀年
Rtimehi[0]=RTCVALH; //讀空
Rtimelo[1]=RTCVALL; //讀日
Rtimehi[1]=RTCVALH; //讀月
Rtimelo[2]=RTCVALL; //讀小時(shí)
Rtimehi[2]=RTCVALH; //讀星期
Rtimelo[3]=RTCVALL; //讀秒
Rtimehi[3]=RTCVALH; //讀分
hour_colour=Rtimelo[2]>>4; //十小時(shí)顏色
hour=Rtimelo[2]&0x0f; //小時(shí)
minut_colour=Rtimehi[3]>>4; //十分顏色
minut=Rtimehi[3]&0x0f; //分鐘
timing_code[1]=morse_code[hour]; //小時(shí)的碼型
timing_code_lenth[1]=code_lenth[hour]; //小時(shí)的碼長
timing_code[2]=morse_code[minut]; //分的碼型
timing_code_lenth[2]=code_lenth[minut]; //分的碼長
//以下為修改時(shí)鐘的鍵操作部分
if (key_status==0)
{
hour_colour=6; //白色光
minut_colour=0;
for (i=0;i<3;i++)
timing_code[i]=0xffff; //全長劃,表示進(jìn)入調(diào)整時(shí)鐘模式
while (key_status==0);
for (i=0;i<3;i++)
timing_code[i]=0;
while (key_status) //一次長按鍵之前,修改十小時(shí)值
{
timing_code[1]=morse_code[Rtimelo[2]>>4]; //十小時(shí)
timing_code_lenth[1]=code_lenth[Rtimelo[2]>>4];
timing_code[2]=morse_code[Rtimelo[2]&0x0f]; //小時(shí)
timing_code_lenth[2]=code_lenth[Rtimelo[2]&0x0f];
if (key_up==1) //如果發(fā)現(xiàn)短時(shí)間按鍵的抬鍵信號(hào)
{
Rtimelo[2]+=0x10; //步進(jìn)十小時(shí)
key_up=0; //清除短時(shí)間按鍵標(biāo)志
}
if (Rtimelo[2]>0x23)
Rtimelo[2]=0;
}
while (key_status==0) key_up=0; //防止一次按鍵連續(xù)動(dòng)作
hour_colour=0; //lan色光
minut_colour=6; //白色光
while (key_status) //一次長按鍵之前,修改小時(shí)值
{
timing_code[1]=morse_code[Rtimelo[2]>>4]; //十小時(shí)
timing_code_lenth[1]=code_lenth[Rtimelo[2]>>4];
timing_code[2]=morse_code[Rtimelo[2]&0x0f]; //小時(shí)
timing_code_lenth[2]=code_lenth[Rtimelo[2]&0x0f];
if (key_up==1) //如果發(fā)現(xiàn)短時(shí)間按鍵的抬鍵信號(hào)
{
Rtimelo[2]++; //步進(jìn)小時(shí)
key_up=0; //清除短時(shí)間按鍵標(biāo)志
}
if (Rtimelo[2]>0x23) //總小時(shí)數(shù)若大于23,則小時(shí)個(gè)位置0
Rtimelo[2]=0x20;
if ((Rtimelo[2]&0x0f)>9) //小時(shí)值若大于9
Rtimelo[2]&=0xf0; //修改為0
}
while (key_status==0) key_up=0; //防止一次按鍵連續(xù)動(dòng)作
//以下修改分鐘
hour_colour=6; //白色光
minut_colour=0; //藍(lán)色光
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) //如果發(fā)現(xiàn)短時(shí)間按鍵的抬鍵信號(hào)
{
Rtimehi[3]+=0x10; //步進(jìn)十分鐘
key_up=0; //清除短時(shí)間按鍵標(biāo)志
}
if (Rtimehi[3]>0x59) //總fen數(shù)若大于59,則十分鐘位置0
Rtimehi[3]&=0x0f;
}
while (key_status==0) key_up=0; //防止一次按鍵連續(xù)動(dòng)作
hour_colour=0; //藍(lán)色光
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) //如果發(fā)現(xiàn)短時(shí)間按鍵的抬鍵信號(hào)
{
Rtimehi[3]++; //步進(jìn)分鐘
key_up=0; //清除短時(shí)間按鍵標(biāo)志
}
if ((Rtimehi[3]&0x0f)>9) //fen數(shù)個(gè)位若大于9,則分鐘位置0
Rtimehi[3]=Rtimehi[3]&0xf0;
}
while (key_status==0) key_up=0; //防止一次按鍵連續(xù)動(dòng)作
//寫入RTCC
RTCCFG|=0x03; //置指針為0b11
while (RTCCFGbits.RTCSYNC); //等待不忙
for (i=0;i<4;i++) //寫
{
RTCVALL=Rtimelo[i];
RTCVALH=Rtimehi[i];
}
}
//到達(dá)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; //略加快點(diǎn)劃速率
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])) //小時(shí)在1,分在2,據(jù)此決定in_hour
in_hour=0;
else
in_hour=1;
if (in_hour==0) //十分鐘顏色
{
if (minut_colour==0) //藍(lán)
{
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 //十小時(shí)顏色
{
if (hour_colour==0) //藍(lán)
{
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) //這段是拍發(fā)算盤碼的執(zhí)行部分
LATB = LATB|0b00001101;
else
LATB = LATB&0b1110010;
temp=temp<<1;
}
else if (PIR5bits.TMR5IF) //該定時(shí)器用來識(shí)別按鍵動(dòng)作
{
PIR5bits.TMR5IF = 0; //clear interrupt flag
if (key_down==1&last_key==1) //只有下鍵后才進(jìn)入判斷
{
if (key_status) //在沒有全0序列情況下
if (Key==1) //確認(rèn)抬鍵
{
key_up=1;
key_down=0;
}
}
else if (last_key==0)
{
if (Key==0)
{
key_down=1; //確認(rèn)下鍵
key_up=0;
}
}
last_key=Key; //當(dāng)前鍵值賦予舊鍵值
key_status=key_status<<1; //鍵狀態(tài)左移1位
key_status|=Key; //末位置Key的值
}
}
