PIC时钟程序
PIC单片机之时钟设置

PIC单片机之时钟设置什么时钟?首先我们先讲讲什么是时钟。
时钟就是单片机的心脏。
每跳动一下。
整个单片机的各个电路就同步的动作一下。
就好像我们做广播体操的时候广播上喊的节拍1234 2234 3234。
然后我们全部的同学就按照这个节奏进行一个个动作。
节拍越快我们动作越快。
节拍越慢我们动作的越慢。
内部时钟和外部时钟?PIC单片机有许多型号可以设置成用外部时钟(如外部接个4MHZ 的石英晶振),也可以设置成用内部RC时钟。
而且还有许多型号可以选择多种频率的时钟。
如PICLF1823 内部时钟最高可以到达32MHZ 最低可以达到31kHz. 这事实上提供了一条降低功耗的新路子。
一般的单片机降低功耗常常用的睡眠,而睡眠期间CPU是什么都不做。
如果希望降低功耗,而且CPU也能工作。
降低时钟频率无疑是个非常好的选择。
时钟的设置?时钟设置一般只和两处有关一个是配置字,一个是振荡器控制寄存器OSCCON 下面我们以PICLF1823为例子进行讲解。
PICLF1823 配置字设置中与时钟有关的就是FOSC<2:0>:振荡器选择位,和PLLEN:PLL使能位。
OSCCON 是有关内部时钟频率选择,如果只用外部时钟一般不理会。
以下是数据手册中OSCCON寄存器的详细介绍。
实例讲解:使用内部时钟将时钟频率设置成8MHZ开发环境:MPLAB X IDE芯片型号:PICLF1823#include<pic.h>__CONFIG(FOSC_INTOSC&WDTE_OFF&PWRTE_ON&MCLRE_OFF &CP_ON&CPD_OFF&BOREN_ON&CLKOUTEN_OFF&IESO_ON&FC MEN_ON);__CONFIG(PLLEN_OFF&LVP_OFF) ;//将FOSC<2:0>:振荡器选择位设置成INTOSC,void init_fosc(void){OSCCON = 0x70;//8MHZ IRCF<3:0>时钟频率选择位设置成8MHZ }int main(int argc, char** argv) {init_fosc();while(1);}PLL是用来做什么的呢?他的作用就是能将8MHZ的时钟频率X4变成32MHZ,记住只有8MHZ可以,其他频率是不行的。
pic单片机C语言程序例程之stopwatch

//此程序实现计时秒表功能,时钟显示范围00.00~99.99秒,分辨度:0.01秒#include "p18f458.h"unsigned char s[4]; //定义0.01 秒、0.1 秒、1秒、10秒计时器unsigned char k,data,sreg;unsigned int i;const table[11]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0XD8,0x80,0x90};//不带小数点的显示段码表const table0[10]={0X40,0X79,0X24,0X30,0X19,0X12,0X02,0X78,0X00,0X10};//带小数点的显示段码表void clkint(void);//TMR0初始化子程序void tmint(){T0CON=0XCF; //设定TMR0L工作于8位定时器方式//内部时钟,TMR0不用分频INTCON=0X20; //总中断禁止,TMR0中断允许,清除TMR0的中断标志INTCON2bits.TMR0IP=1; //TMR0中断高优先级RCONbits.IPEN=1; //使能中断优先级}//系统其它部分初始化子程序void initial(){TRISA=0x00; //A口设置为输出TRISB=0XF0; //RB1输出,RB4输入TRISC=0x00; //SDO引脚为输出,SCK引脚为输出TRISE=0x00; //E口设置为输出SSPCON1=0x30; //SSPEN=1;CKP=1,FOSC/4SSPSTA T=0xC0; //时钟下降沿发送数据PIR1=0; //清除SSPIF标志data=0X00; //待显示的寄存器赋初值PORTBbits.RB1=0;PORTAbits.RA3=0;PORTE=0; //将K1,K2,K3,K4四条列线置0//SPI传输数据子程序void SPILED(char data){SSPBUF=data; //启动发送do{;}while(PIR1bits.SSPIF==0);PIR1bits.SSPIF=0;}//显示子程序,显示4位数void dispaly(){PORTAbits.RA5=0; //准备锁存for(k=0;k<4;k++){data=s[k];if(k==2) data=table0[data]; //个位需要显示小数点else data=table[data];SPILED(data); //发送显示段码}for(k=0;k<4;k++){data=0xFF;SPILED(data); //连续发送4个DARK,使显示好看一些}PORTAbits.RA5=1; //最后给锁存信号,代表显示任务完成}//软件延时子程序void DELA Y(){for(i = 3553; --i ;)continue;}//键扫描子程序void KEYSCAN(){while(1){dispaly(); //调用一次显示子程序while(PORTBbits.RB4==0){DELA Y(); //若有键按下,则软件延时break;}if (PORTBbits.RB4==0) break; //若还有键按下,则终止循环扫描,返回}}//等键松开子程序void keyrelax(){while(1){dispaly(); //调用一次显示子程序if (PORTBbits.RB4==1) break; //为防止按键过于灵敏,每次等键松开才返回}}/*高优先级中断向量*/#pragma code InterruptV ectorHigh=0x08void InterruptV ectorHigh (void){_asmgoto clkint //跳到中断程序_endasm}//中断服务程序#pragma code#pragma interrupt clkintvoid clkint(){TMR0=0X13; //对TMR0写入一个调整值。
PIC单片机在ICD做lcd显示时钟演示程序

PIC单片机在ICD做lcd显示时钟演示程序include <p16f877.inc>;*----; 定义LCD数据& 控制I/O口LCD_DA TA equ PORTBLCD_CNTL1 equ PORTBLCD_CNTL2 equ PORTA; 定义 LCD控制相应的I/O引脚RS equ 1E equ 5; LCD 模块命令DISP_ON EQU 0x00C ; 开显示DISP_ON_C EQU 0x00E ; 开显示, 开指针DISP_ON_B EQU 0x00F ; 开显示, 开指针,开闪烁DISP_OFF EQU 0x008 ; 关显示CLR_DISP EQU 0x001 ; 清显示的操作数ENTRY_INC EQU 0x006 ; 操作数ENTRY_INC_S EQU 0x007 ; 操作数ENTRY_DEC EQU 0x004 ; 操作数ENTRY_DEC_S EQU 0x005 ; 操作数DD_RAM_ADDR EQU 0x080 ; 初始化第一行显示的操作数DD_RAM_UL EQU 0x0c0 ; 初始化第二行显示的操作数; 设置显示相关寄存器Byte EQU 20HCount EQU 21HCount1 EQU 22HCount2 EQU 23HLCD_DATA1 EQU 24HPORTDB EQU 25HTemp EQU 26HTempH EQU 27HTempL EQU 28HINTSIG EQU 29HRTCCSIG1 EQU 2AHRTCCSIG EQU 2BHALRSIG EQU 2CHHour EQU 2DHHourH EQU 2EHHourL EQU 2FHHourL1 EQU 30HHourH1 EQU 31HMins EQU 32HMins1 EQU 33HMinsH EQU 34HMinsL EQU 35HMinsH1 EQU 36HMinsL1 EQU 37HSecs EQU 38HSecsH EQU 39HSecsL EQU 3AHALRH1 EQU 3BHALRM1 EQU 3CHALRH2 EQU 3DHALRM2 EQU 3EHALRH3 EQU 3FHALRM3 EQU 40H_WREG EQU 41H_STATUS EQU 42HHour1 EQU 43HADRESB EQU 44HBKM EQU 45H;*----org 0nopgoto startorg 4goto ISRorg 10CalTablebcf STATUS,RP0bcf PCLATH,0movlw 0x66 ; 进行校准处理subwf Temp,w ;addwf PCL,f ; 将补偿结果与 PCL相加dt 0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5dt 6,6,6,7,7,7,8,8,8,9,9,0xa,0xa,0xb,0xb,0xc,0xcdt 0xd,0xd,0xe,0xe,0xf,0xf,0xf,0x10,0x10,0x10dt 0x11,0x11,0x12,0x12,0x12,0x13,0x13,0x14,0x14,0x14 dt 0x15,0x15,0x15,0x16,0x16,0x16,0x17,0x17,0x18,0x18 dt 0x19,0x19,0x1a,0x1a,0x1b,0x1b,0x1c,0x1c,0x1cdt 0x1d,0x1d,0x1d,0x1e,0x1e,0x1f,0x1f,0x20,0x20dt 0x21,0x21,0x22,0x22,0x23,0x23,0x24,0x24,0x25,0x25dt 0x26,0x26,0x27,0x28,0x29,0x29,0x2a,0x2a,0x2b,0x2b dt 0x2c,0x2d,0x2e,0x2f,0x30,0x32startcall InitLCDclrf RTCCSIGclrf RTCCSIG1clrf INTSIGclrf Hourclrf Hour1clrf Minsclrf Mins1clrf Secsclrf ALRSIGmovlw 20hmovwf BKMmovlw b'10001111'movwf PORTDBmovlw 0ffhmovwf TMR0movlw 00movwf TMR1Lmovlw 80hmovwf TMR1Hmovlw b'00001111'movwf T1CONbsf STATUS,RP0bsf PIE1,TMR1IEbcf STATUS,RP0movlw b'10111111'OPTIONmovlw b'11110000'movwf INTCONmainmovlw 80hcall SendCmdcall DisplayTime ;显示时间movlw 0c0hcall SendCmdmovlw 'H'call putcLCDmovlw 'e'call putcLCDmovlw 'l'call putcLCDmovlw 'l'call putcLCDmovlw 'o'call putcLCDmovlw ' 'call putcLCDmovlw '!'call putcLCDmovlw ' 'call putcLCDmovlw ':'call putcLCDmovlw ')'call putcLCDmovlw ' 'call putcLCDmovlw ' 'call putcLCDcall BkLight ;背光控制call TempM ;显示温度btfsc ALRSIG,1call ALR1btfsc ALRSIG,2call ALR2btfsc ALRSIG,3call ALR3bcf STATUS,RP0bcf PCLATH,0movf RTCCSIG,Waddwf PCL,1goto maingoto RtccS1goto RtccS2goto Rtccs3goto Rtccs4clrf RTCCSIGclrf RTCCSIG1goto main;*=====ALR1 bcf STATUS,RP0 movf Hour,Wxorwf ALRH1,Wbtfss STATUS,Zmovf Mins,Wxorwf ALRM1,Wbtfss STATUS,Zgoto ALRENDbsf STATUS,RP0clrf TRISDbcf STATUS,RP0bcf STATUS,Crlf PORTDB,1btfsc STATUS,Cbsf PORTDB,0movf PORTDB,W movwf PORTDreturn;*---ALR2 bcf STATUS,RP0 movf Hour,Wxorwf ALRH2,Wbtfss STATUS,Zgoto ALRENDmovf Mins,Wxorwf ALRM2,Wbtfss STATUS,Zgoto ALRENDbsf STATUS,RP0clrf TRISDbcf STATUS,RP0bcf STATUS,Crlf PORTDB,1btfsc STATUS,Cbsf PORTDB,0movf PORTDB,W movwf PORTDreturn;*----ALR3 bcf STATUS,RP0 movf Hour,Wxorwf ALRH3,Wbtfss STATUS,Zgoto ALRENDmovf Mins,Wxorwf ALRM3,Wbtfss STATUS,Zbsf STATUS,RP0clrf TRISDbcf STATUS,RP0bcf STATUS,Crlf PORTDB,1btfsc STATUS,Cbsf PORTDB,0movf PORTDB,Wmovwf PORTDreturn;*---ALRENDbsf STATUS,RP0movlw 0ffhmovwf TRISDreturn;*=====RtccS1movlw 80hcall SendCmdcall DisplayTimecall LongDelaymovlw 0c0hcall SendCmd ;line2, 00 movlw 'S'call putcLCDmovlw 'e'call putcLCDmovlw 't'call putcLCDmovlw ' 'call putcLCDmovlw 'T'call putcLCDmovlw 'i'call putcLCDmovlw 'm'call putcLCDmovlw 'e'call putcLCD ;show "Set Time" movlw ' 'call putcLCDmovlw ' 'call putcLCD movlw ' 'call putcLCD movlw ' 'call putcLCD bsf PCLATH,0 movf RTCCSIG1,W addwf PCL,1 goto SetHour goto SetMins clrf INTSIGincf RTCCSIG clrf RTCCSIG1 goto main;*----SetHourmovlw 80hcall Selshow movlw d'24' subwf INTSIG,W btfsc STATUS,C goto $+4movf INTSIG,w movwf Hourgoto RtccS1clrf INTSIG movwf Hourgoto RtccS1;*----SetMinsmovlw 83hcall Selshow movlw d'60' subwf INTSIG,W btfsc STATUS,C goto $+4movf INTSIG,w movwf Minsgoto RtccS1clrf INTSIG movwf Minsgoto RtccS1;*=====RtccS2bcf STATUS,RP0 movlw 0c0hcall SendCmdcall Alarm movlw '1'call putcLCD movlw ' 'call putcLCDS2 movlw 80hcall SendCmdcall DisplayTime call DispTime call LongDelay bsf PCLATH,0 movf RTCCSIG1,W addwf PCL,1goto SetAlH2 goto SetAlM2 movf Hour1,w movwf ALRH1 movf Mins1,w movwf ALRM1clrf INTSIGclrf RTCCSIG1 incf RTCCSIG goto main;*---SetAlH2movlw 0c7hcall Selshow movf INTSIG,W btfss STATUS,Z bsf ALRSIG,1 movf INTSIG,W movwf Hour1 movlw d'24' subwf Hour1,W btfss STATUS,C goto S2clrf INTSIGclrf Hour1goto S2SetAlM2movlw 0cahcall Selshow movf INTSIG,W btfss STATUS,Z bsf ALRSIG,1 movf INTSIG,W movwf Mins1 movlw d'60' subwf Mins1,W btfss STATUS,C goto S2clrf INTSIGclrf Mins1goto S2;*----Alarm movlw 'A' call putcLCD movlw 'l'call putcLCD movlw 'a'call putcLCD ; movlw 'r'call putcLCD movlw 'm'call putcLCD ; return;*----Selshowcall SendCmd movlw ' 'call putcLCD movlw ' 'call putcLCD call LongDelay return;*=====Rtccs3bcf STATUS,RP0 movlw 0c0hcall SendCmd call Alarm movlw '2'call putcLCD movlw ' 'call putcLCDS3 movlw 80hcall SendCmdcall DisplayTime call DispTime call LongDelay bsf PCLATH,0 movf RTCCSIG1,w addwf PCL,1goto SetAlH3 goto SetAlM3 movf Hour1,w movwf ALRH2 movf Mins1,w movwf ALRM2clrf INTSIGclrf RTCCSIG1 incf RTCCSIG goto main;*---SetAlH3movlw 0c7hcall Selshow movf INTSIG,W btfss STATUS,Z bsf ALRSIG,2 movf INTSIG,W movwf Hour1 movlw d'24' subwf Hour1,W btfss STATUS,C goto S3clrf INTSIGclrf Hour1goto S3SetAlM3movlw 0cahcall Selshow movf INTSIG,W btfss STATUS,Z bsf ALRSIG,1 movf INTSIG,W movwf Mins1 movlw d'60' subwf Mins1,Wgoto S3clrf INTSIGclrf Mins1goto S3;*=====Rtccs4movlw 80hcall SendCmdcall DisplayTime bcf STATUS,RP0 movlw 0c0hcall SendCmdcall Alarm movlw '3'call putcLCD movlw ' 'call putcLCDS4 call DispTime call LongDelay bsf PCLATH,0 movf RTCCSIG1,w addwf PCL,1goto SetAlH4 goto SetAlM4 movf Hour1,w movwf ALRH3 movf Mins1,w movwf ALRM3clrf INTSIGclrf RTCCSIG1 incf RTCCSIG goto main;*---SetAlH4movlw 0c7hcall Selshow movf INTSIG,W btfss STATUS,Z bsf ALRSIG,3 movf INTSIG,W movwf Hour1 movlw d'24' subwf Hour1,Wgoto S4clrf INTSIGclrf Hour1goto S4SetAlM4movlw 0cahcall Selshowmovf INTSIG,Wbtfss STATUS,Zbsf ALRSIG,1movf INTSIG,Wmovwf Mins1movlw d'60'subwf Mins1,Wbtfss STATUS,Cgoto S4clrf INTSIGclrf Mins1goto S4;*=====ISRPushmovwf _WREG ; 存 WREG状态swapf STATUS,W ; 存 STATUS movwf _STATUS;*----bcf STATUS,RP0btfsc PIR1,TMR1IFcall TimeAdjbtfsc INTCON,INTFcall IntDealbtfsc INTCON,T0IFcall RtccDeal;*----Popswapf _STATUS,W ; Restore STATUS movwf STATUSswapf _WREG,F ; Restore WREG w/o swapf _WREG,W ; affecting STATUS retfie;*=====TimeAdjbcf PIR1,TMR1IFmovlw 00hmovwf TMR1Lmovlw 80hmovwf TMR1Hincf Secs,1movlw d'60'xorwf Secs,Wbtfss STATUS,Zgoto TEclrf Secsincf Mins,1movlw d'60'xorwf Mins,Wbtfss STATUS,Zgoto TEclrf Minsincf Hourmovlw d'24'xorwf Hour,Wbtfss STATUS,Zgoto TEclrf HourTEreturn;*=====IntDealbcf INTCON,INTFbsf PORTB,0btfsc PORTB,0 ;\goto $+5 ; \call Delaybsf PORTB,0 ; 按键去抖动btfsc PORTB,0goto $+2 ; /incf INTSIGreturn;*=====RtccDealbcf STATUS,RP0movlw 0ffh ;movwf TMR0bcf INTCON,T0IFbsf PORTA,4btfsc PORTA,4 ;\goto RtcWr ; \call Delaybsf PORTA,4 ; 按键去抖动btfsc PORTB,4goto RtcWr ; /movf RTCCSIG,Wsublw 04hbtfss STATUS,Cgoto WRONGmovf RTCCSIG1,Wsublw 03hbtfss STATUS,Cgoto WRONGmovf RTCCSIG,Waddwf RTCCSIG1,Wbtfsc STATUS,Zgoto $+3incf RTCCSIG1goto RtcWrincf RTCCSIGgoto RtcWrWRONGclrf RTCCSIGclrf RTCCSIG1RtcWr return;*=====BkLightbsf STATUS,RP0bcf ADCON1,ADFM ;ADRESH all 8-bit,H bcf STATUS,RP0movlw b'01010001'movwf ADCON0 ;select AD2,Fosc/8 decfsz BKMgoto $-1bsf ADCON0,GObtfss PIR1,ADIFgoto $-1bcf PIR1,ADIF;READ ADRES---movf ADRESH,Wmovwf ADRESBbsf STATUS,RP0bcf TRISE,0 ;SELECT RE0 OUTPUTbcf STATUS,RP0movlw b'10000000' ;critical value of lightness subwf ADRESB,Wbtfss STATUS,Cgoto $+4 ;c=0,ADRESB<criticalbcf STATUS,RP0bsf PORTE,0 ;c=1,backlight ongoto $+3bcf STATUS,RP0bcf PORTE,0movlw 20hmovwf BKMreturn;*=====TempM ;temprature measurebsf STATUS,RP0bcf ADCON1,ADFM ;ADRESH all 8-bitbcf STATUS,RP0movlw b'01001001' ;select AD1,FOSC/8movwf ADCON0decfsz BKMgoto $-1bsf ADCON0,GObtfss PIR1,ADIFgoto $-1bcf PIR1,ADIF;bsf STATUS,RP0movf ADRESH,W;bcf STATUS,RP0movwf Tempcall CalTablemovwf Tempcall Bin2BCDT ; 进行BCD码调整movlw 08ah ; 从第一行的第0A个位置开始call SendCmdmovf TempH,W ; 显示温度call putcLCDmovf TempL,Wcall putcLCDmovlw 'C' ; 显示“C”(表示摄氏度)call putcLCDmovlw 20hmovwf BKMreturn;************************************************ ;* Bin2BCDT - 将 Temp 寄存器内的二进制数转 *;* 换为相应的 ASCII 码并存为 TempH:TempL 的形式 * ;************************************************ Bin2BCDTbcf STATUS,RP0clrf TempH ; Initialize variablesmovf Temp,Wmovwf TempLTtenth ; Subtract 10 from low variablemovlw .10 ; until result is < 0. On eachsubwf TempL,W ; subtraction, increment thebtfss STATUS,C ; temperature high byte.goto Over0movwf TempLincf TempH,Fgoto TtenthOver0movlw 0x30 ; Make decimal ASCII by addingaddwf TempH,F ; '0' to high and low byteaddwf TempL,Freturn;************************************************* ;* DisplayTime - 将显示指针移至第一行,调用Bin2BCD* ;* 子程序将Secs 和 Mins寄存器内的数据转换为相应的* ;* ASCII 码, 然后送 LCD显示. *;************************************************* DisplayTimebcf STATUS,RP0call Bin2BCD ; 调用二进制与bcd码转换子程序movf HourH,W ; 显示小时高位call putcLCD ;movf HourL,W ; 显示小时低位call putcLCD ;movlw ':'call putcLCD ; 显示 ':'movf MinsH,W ; 显示分钟高位call putcLCD ;movf MinsL,W ; 显示分钟低位call putcLCD ;movlw ':' ; 显示 ':'call putcLCDmovf SecsH,W ; 显示秒钟高位call putcLCD ;movf SecsL,W ; 显示秒钟低位call putcLCD ;return;************************************************ ;* Bin2BCD - 将 Secs & Mins 寄存器内的二进制数转* ;* 换为相应的 ASCII 码并存为 SecsH:SecsL 及 *;* MinsH:MinsL,HourH:HourL的形式. *;************************************************ Bin2BCDbcf STATUS,RP0clrf HourH ; 初始化变量movf Hour,W ; 转换“时”movwf HourLHourth ; Loop to subtract 10movlw .10 ; from low byte andsubwf HourL,W ; increment high bytebtfss STATUS,C ; while low byte is > 0goto Nextmovwf HourLincf HourH,Fgoto HourthNextclrf MinsH ; 初始化变量movf Mins,W ; 转换“分”movwf MinsLMtenth ; Loop to subtract 10movlw .10 ; from low byte andsubwf MinsL,W ; increment high bytebtfss STATUS,C ; while low byte is > 0goto Next1movwf MinsLincf MinsH,Fgoto MtenthNext1clrf SecsH ; 初始化变量movf Secs,W ; 转换“秒”movwf SecsLStenth ; Loop to subtract 10movlw .10 ; from low byte andsubwf SecsL,W ; increment high bytebtfss STATUS,C ; while low byte is > 0goto Overmovwf SecsLincf SecsH,Fgoto StenthOvermovlw 0x30 ;addwf HourH,F ;addwf HourL,F ; Add 0x30 ('0') to all addwf MinsH,F ; variables to convertaddwf MinsL,F ; a number 0 - 9 to anaddwf SecsH,F ; ASCII equivalentaddwf SecsL,F ; '0' to '9'return;*====DispTimebcf STATUS,RP0movlw 0c7hcall SendCmdcall Bin2BCa ; 调用二进制与bcd码转换子程序movf HourH1,W ; 显示小时高位call putcLCD ;movf HourL1,W ; 显示小时低位call putcLCD ;movlw ':' ; 显示 ':'call putcLCDmovf MinsH1,W ; 显示分钟高位call putcLCD ;movf MinsL1,W ; 显示分钟低位call putcLCD ;return;*----Bin2BCabcf STATUS,RP0clrf HourH1 ; 初始化变量movf Hour1,W ; 转换“时”movwf HourL1Hourth1 ; Loop to subtract 10movlw .10 ; from low byte andsubwf HourL1,W ; increment high bytebtfss STATUS,C ; while low byte is > 0 goto Nextamovwf HourL1incf HourH1,Fgoto Hourth1Nextaclrf MinsH1 ; 初始化变量movf Mins1,W ; 转换“分”movwf MinsL1Mtenth1 ; Loop to subtract 10movlw .10 ; from low byte andsubwf MinsL1,W ; increment high bytebtfss STATUS,C ; while low byte is > 0goto Over1movwf MinsL1incf MinsH1,Fgoto Mtenth1Over1movlw 0x30 ;addwf HourH1,F ;addwf HourL1,F ; Add 0x30 ('0') to alladdwf MinsH1,F ; variables to convertaddwf MinsL1,F ; a number 0 - 9 to anreturn ; ASCII equivalent;******************************************************************* ;* LCD 模块子程序 *;******************************************************************* ;InitLCD——初始化LCD模块 *;******************************************************************* InitLCDbcf STATUS,RP0 ; Bank 0bcf STATUS,RP1clrf LCD_DATA ; 清 LCD 数据 & 控制位bsf STATUS,RP0 ; Bank 1movlw 0xc1 ; 设置RB1~RB5为输出movwf LCD_DATAbcf TRISA,5bcf STATUS,RP0 ;movlw 0x00 ;movwf LCD_DATAbsf LCD_CNTL2, Ebcf LCD_CNTL2, Emovlw 0x08 ;movwf LCD_DATAbsf LCD_CNTL2, Ebcf LCD_CNTL2, Ecall LongDelaycall LongDelaymovlw b'00101000'call SendCmdmovlw DISP_ON ; 开显示call SendCmdmovlw ENTRY_INC ; 设置指针移动方式call SendCmdmovlw DD_RAM_ADDR ; 设置起始地址call SendCmdInitLCDEnd ;bcf STATUS,RP0 ;movlw CLR_DISP ;call SendCmdreturn;******************************************************************* ;*putcLCD——将字符数据送入 LCD *;* 本程序将字符数据分成了高半字节和低半字节分别输入 *;* 先送入的是高半字节 *;******************************************************************* putcLCDbcf STATUS,RP0movwf Byte ; 存 WREG 到 Byte 寄存器swapf Byte,W ; 写入高半字节movwf LCD_DATA1rlf LCD_DATA1,1rlf LCD_DATA1,1movlw 0x3candwf LCD_DATA1,1movf LCD_DATA1,wmovwf LCD_DATAbsf LCD_CNTL1, RS ; 设置为送数据模式bsf LCD_CNTL2, E ; 发送数据信号bcf LCD_CNTL2, Emovf Byte,W ; 接着送低半字节movwf LCD_DATA1rlf LCD_DATA1,1rlf LCD_DATA1,1movlw 0x3candwf LCD_DATA1,1movf LCD_DATA1,wmovwf LCD_DATAbsf LCD_CNTL1, RS ; 设置为送数据模式bsf LCD_CNTL2, E ; 发送数据信号bcf LCD_CNTL2, Ecall Delayreturn;******************************************************************* ;* SendCmd - 送命令到 LCD *;* 本程序将命令数据分成了高半字节和低半字节分别输入 *;* 先送入的是高半字节 *;******************************************************************* SendCmdbcf STATUS,RP0movwf Byte ; 存 WREG 到 Byte 寄存器swapf Byte,W ; 送入命令的高字节movwf LCD_DATA1rlf LCD_DATA1,1rlf LCD_DATA1,1movlw 0x3candwf LCD_DATA1,1movf LCD_DATA1,wmovwf LCD_DATAbcf LCD_CNTL1,RS ; 设置为送命令模式bsf LCD_CNTL2,E ; 发送数据信号bcf LCD_CNTL2,Emovf Byte,W ; 接着送命令的低字节movwf LCD_DATA1rlf LCD_DATA1,1rlf LCD_DATA1,1movlw 0x3candwf LCD_DATA1,1movf LCD_DATA1,wmovwf LCD_DATAbcf LCD_CNTL1,RS ; 设置为送命令模式bsf LCD_CNTL2,E ; 发送数据信号bcf LCD_CNTL2,Ecall Delayreturn;******************************************************************* ;* Delay - 延时子程序 *;******************************************************************* Delay ; call指令占用2个指令周期bcf STATUS,RP0clrf Count ; 清 Count占用1个指令周期Dloopdecfsz Count,f ; 这两行指令将延时goto Dloop ; (256 * 3) -1 个指令周期return ; return占用2个指令周期;******************************************************************* ;* LongDelay - 长延时子程序 *;******************************************************************* LongDelaybcf STATUS,RP0clrf Countclrf Count1movlw 0x03movwf Count2LDloopdecfsz Count,fgoto LDloopdecfsz Count1,fgoto LDloopdecfsz Count2,fgoto LDloopreturn;*------END。
用C语言写的一个PIC16F877的时闹钟程序

用C语言写的一个PIC16F877的时闹钟程序单片机用16F877,主时钟用20MHz,用32768作定时时间。
可以实现2路定闹,每一路都可分别设置和开关,采用4x4键盘,16x2的字符型LCD显示。
连线在程序开头有说明。
程序的功能:(1)上电后LCD背光打开,并显示倒计时5秒,然后时钟开始工作。
(2)用模式键(*)切换模式,如显示时间、日期、闹钟1、闹钟2等,并且可以用上、下键控制加1、减1或是闹钟的On、Off。
(3)原程序有16个键,包括0~9数字键,可以直接输入要设置的时间值,但后来将数字键取消了,你仍然可以通过修改程序的部分注释恢复此功能。
(4)闹钟有2路,时间到后闹2分钟,可按任意键取消本次闹钟。
闹钟响时有2种音调,是用PIC的PWM实现的。
(5)按任意键可打开背光,1分钟后自动关闭背光。
(6)RA0~RA3为按键扫描输入,应接下拉电阻。
主程序// FileName: Main.c// MCU: Microchip PIC16F877// Tool: CCS-C compiler// Author: KingEDA, MSN:kingeda@, skype:kingeda, E-mail:kingeda@// Website: // Description:// A timer program// Ver 0.1: 2003-03-31, all clock function with date display, 2 way alarm.// Ver 0.2: 2003-05-05, (1) Alarm default is on,modify alarm1 time to 7:00:00,// and alarm2 to 13:30:00.// (2) Backlight will be enabled when alarming.// (3) Automatic adjust day(28,30,31).// (4) Automatic move cursor to next location when set item.// PIN Connection:// RC0~1 : 32768Hz crystal// RC2 : Buzzer// RC3 : LCD Back Light,drive a PNP BJT// RD0~RD7 : to LCD DB0~DB7// RA0~RA3 : keypad col in// RC4~RC7 : keypad line out// 7 8 9 #// 4 5 6 ↑// 1 2 3 ↓// 0 ←→*// RE0 : LCD RS// RE1 : LCD RW// RE2 : LCD E#include "my16f877.h"#device ICD=true//#fuses HS,NOWDT,NOPROTECT,PUT,BROWNOUT #use delay(clock = 24000000)//#use fast_io(C)#use fast_io(E)#define lcd_busy (lcd_read_addr()&0x80) == 0x80#define time_start_addr 0x80+0x04#define time_hourh_addr time_start_addr#define time_hourl_addr time_start_addr+1#define time_minuteh_addr time_start_addr+3#define time_minutel_addr time_start_addr+4#define time_secondh_addr time_start_addr+6#define time_secondl_addr time_start_addr+7#define key_0 0x11#define key_1 0x21#define key_2 0x22#define key_3 0x24#define key_4 0x41#define key_5 0x42#define key_6 0x44#define key_7 0x81#define key_8 0x82#define key_9 0x84#define key_left 0x12#define key_right 0x14#define key_up 0x48#define key_down 0x28#define key_mode 0x18#define key_cancel 0x88char StrPower1[] = " * Power on * ";char StrSetTime[] = " * Adjust time* ";char StrSetDate[] = " * Adjust date* ";char StrAlarm1[] = " * Set alarm 1* ";char StrAlarm2[] = " * Set alarm 2* ";unsigned char PORTC_MAP;#bit BackLightEn = PORTC_MAP.3unsigned char BackLightTimer;int1 led;#bit lcd_rs = PORTE.0#bit lcd_rw = PORTE.1#bit lcd_e = PORTE.2#byte lcd_bus = PORTD#byte lcd_dir = TRISD#define PWM_on 0x0c#define PWM_off 0x00#define PWM_period 200#define PWM_DC 100unsigned char lcd_addr;unsigned char KeyLine;unsigned char KeyOld;unsigned char KeyNew;struct mTime {unsigned char hourh; // hour,0~23unsigned char hourl;unsigned char minuteh; // minute,0~59unsigned char minutel;unsigned char secondh; // second,0~59unsigned char secondl;};struct mTime CurrentTime = {1,2,0,0,0,0};struct mTime AlarmTime1 = {0,7,0,0,0,0}; // 07:00:00 struct mTime AlarmTime2 = {1,3,3,0,0,0}; // 13:30:00 unsigned char AlarmStatus;#bit Alarm1Enable = AlarmStatus.0#bit Alarm2Enable = AlarmStatus.1#bit Alarm1Alarm = AlarmStatus.2#bit Alarm2Alarm = AlarmStatus.3unsigned char Alarm1Cnt; // alarm1 second count unsigned char Alarm2Cnt;unsigned char CurrentMode;#define mode_time 0#define mode_set_time 1#define mode_set_date 2#define mode_set_alarm1 3#define mode_set_alarm2 4unsigned char adjust_item;struct mDate {unsigned char year1; //unsigned char year2;unsigned char year3;unsigned char year4;unsigned char monthh;unsigned char monthl;unsigned char dayh;unsigned char dayl;};struct mDate CurrentDate = {2,0,0,3,0,1,0,1}; unsigned char *pStr;// ------------------------------------------------------- unsigned char lcd_read_addr(){unsigned char ch;lcd_dir = 0xff; // read from lcdlcd_rs = 0;lcd_rw = 1; // instlcd_e = 1;#asmnopnopnop#endasmch = lcd_bus;lcd_e = 0;lcd_dir = 0x00; // set write to lcdreturn ch;}// ------------------------------------------------------- unsigned char lcd_write_data(unsigned char ch) {while (lcd_busy){ restart_wdt(); }lcd_rs = 1; // datalcd_rw = 0; // writelcd_bus = ch; // write outlcd_e = 1;#asmnopnopnop#endasmlcd_e = 0;return 'Y';}// ------------------------------------------------------- unsigned char lcd_write_inst(unsigned char ch) {while (lcd_busy){ restart_wdt(); }lcd_rs = 0; // instlcd_rw = 0; // writelcd_bus = ch;lcd_e = 1;#asmnopnopnop#endasmlcd_e = 0;return 'Y';}// ------------------------------------------------------- unsigned char lcd_read_data(){unsigned char ch;while (lcd_busy){ restart_wdt(); }lcd_dir = 0xff; // read from lcdlcd_rs = 1; // datalcd_rw = 1; // readlcd_e = 1;#asmnopnopnop#endasmch = lcd_bus; // read inlcd_e = 0;lcd_dir = 0x00; // set write to lcdreturn ch;}// ------------------------------------------------------- void lcd_init(){unsigned char Tempch;lcd_addr = 0;delay_ms(100);Tempch = 0x38; // 1-line mode,5x8 dotslcd_write_inst(Tempch); // Function setTempch = 0x0f; // lcd on,cursor on,blink onlcd_write_inst(Tempch); // Display on/offTempch = 0x06; // Increment mode,Entire shift offlcd_write_inst(Tempch);Tempch = 0x01; // clear displaylcd_write_inst(Tempch);delay_ms(3);}// -------------------------------------------------------//#int_timer1//void timer1_interrupt(void)#int_ccp2void ccp2_interrupt(void){//TMR1H = 0x80;if (CurrentTime.secondl==9){CurrentTime.secondl=0;if (CurrentTime.secondh==5){CurrentTime.secondh=0;if (CurrentTime.minutel==9){CurrentTime.minutel=0;if (CurrentTime.minuteh==5){CurrentTime.minuteh=0;if (CurrentTime.hourl==9){CurrentTime.hourl=0;CurrentTime.hourh++;}else if((CurrentTime.hourl==3) && (CurrentTime.hourh==2)){CurrentTime.hourl=0;CurrentTime.hourh=0;if ((((CurrentDate.dayl == 8) || (CurrentDate.dayl == 9)) && (CurrentDate.dayh == 2) && (CurrentDate.monthl == 2) && (CurrentDate.monthh == 0)) ||((CurrentDate.dayl == 0) && (CurrentDate.dayh == 3) && ((((CurrentDate.monthl == 4) || (CurrentDate.monthl == 6)|| (CurrentDate.monthl == 9)) && (CurrentDate.monthh == 0)) || ((CurrentDate.monthl == 1) && (CurrentDate.monthh == 1)))) ||((CurrentDate.dayl == 1) && (CurrentDate.dayh == 3))){CurrentDate.dayl=1;CurrentDate.dayh=0;if ((CurrentDate.monthl == 2) && (CurrentDate.monthh == 1)){CurrentDate.monthl = 1;CurrentDate.monthh = 0;if (CurrentDate.year4 == 9){CurrentDate.year4 = 0;if (CurrentDate.year3 == 9){CurrentDate.year3 = 0;if (CurrentDate.year2 == 9){CurrentDate.year2 = 0;CurrentDate.year1++;}elseCurrentDate.year2++;}elseCurrentDate.year3++;}elseCurrentDate.year4++;}else if(CurrentDate.monthl == 9){CurrentDate.monthl = 0;CurrentDate.monthh++;}elseCurrentDate.monthl++;}else if(CurrentDate.dayl == 9){CurrentDate.dayl=0;CurrentDate.dayh++;}elseCurrentDate.dayl++;}elseCurrentTime.hourl++;}elseCurrentTime.minuteh++;}elseCurrentTime.minutel++;}elseCurrentTime.secondh++;}elseCurrentTime.secondl++;if ((Alarm1Alarm == false) & (Alarm2Alarm == false)){led = 0;CCP1CON = PWM_off;}else{if (led == 1){led = 0;PR2 = PWM_period; // set pwm periodCCPR1L = PWM_DC; // set pwm duty cycle//CCP1CON = PWM_on;}else{led = 1;PR2 = PWM_period/2; // set pwm periodCCPR1L = PWM_DC/2; // set pwm duty cycle//CCP1CON = PWM_off;}}Alarm1Cnt++;Alarm2Cnt++;if (BackLightEn == 0)if (((BackLightTimer++)>=60) & (Alarm1Alarm == false) & (Alarm1Alarm == false))BackLightEn = 1; // disable backlight PORTC = PORTC_MAP;//TMR1IF = 0;//PIR1 = PIR2 = 0x00;CCP2IF = 0;}// ------------------------------------------------------- unsigned char get_key(void){unsigned char key_in,tmp;TRISC = 0x03;KeyLine = 0xf0;PORTC = KeyLine | PORTC_MAP;#asmnopnopnop#endasmif ((PORTA & 0x0f) != 0){tmp = 0x10;for (KeyLine = tmp;KeyLine!=0;KeyLine = tmp){PORTC = KeyLine | PORTC_MAP;tmp = KeyLine <<1;#asmnopnopnop#endasmkey_in = PORTA & 0x0f;if (key_in != 0){return (key_in | KeyLine);}}return 0;}elsereturn 0;}// -------------------------------------------------------void set_mode(void){if (CurrentMode == mode_set_alarm2)CurrentMode = mode_time;else{CurrentMode++;adjust_item = 0;}lcd_write_inst(0x01); // clear LCD displaylcd_write_inst(time_start_addr); // set LCD line1 if (CurrentMode == mode_set_time){lcd_write_data(CurrentTime.hourh + '0');lcd_write_data(CurrentTime.hourl + '0');lcd_write_data(':');lcd_write_data(CurrentTime.minuteh + '0');lcd_write_data(CurrentTime.minutel + '0');lcd_write_data(':');lcd_write_data(CurrentTime.secondh + '0');lcd_write_data(CurrentTime.secondl + '0');pStr = StrSetTime;}else if(CurrentMode == mode_set_date){lcd_write_data(CurrentDate.year1 + '0');lcd_write_data(CurrentDate.year2 + '0');lcd_write_data(CurrentDate.year3 + '0');lcd_write_data(CurrentDate.year4 + '0');lcd_write_data('/');lcd_write_data(CurrentDate.monthh + '0');lcd_write_data(CurrentDate.monthl + '0');lcd_write_data('/');lcd_write_data(CurrentDate.dayh + '0');lcd_write_data(CurrentDate.dayl + '0');pStr = StrSetDate;}else if(CurrentMode == mode_set_alarm1){lcd_write_data(AlarmTime1.hourh + '0');lcd_write_data(AlarmTime1.hourl + '0');lcd_write_data(':');lcd_write_data(AlarmTime1.minuteh + '0');lcd_write_data(AlarmTime1.minutel + '0');lcd_write_data(':');lcd_write_data(AlarmTime1.secondh + '0');lcd_write_data(AlarmTime1.secondl + '0');lcd_write_data(' ');lcd_write_data('O');if (Alarm1Enable){lcd_write_data('n');}else{lcd_write_data('f');lcd_write_data('f');}pStr = StrAlarm1;Alarm1Cnt =0;}else if(CurrentMode == mode_set_alarm2) {lcd_write_data(AlarmTime2.hourh + '0');lcd_write_data(AlarmTime2.hourl + '0');lcd_write_data(':');lcd_write_data(AlarmTime2.minuteh + '0');lcd_write_data(AlarmTime2.minutel + '0');lcd_write_data(':');lcd_write_data(AlarmTime2.secondh + '0');lcd_write_data(AlarmTime2.secondl + '0');lcd_write_data(' ');lcd_write_data('O');if (Alarm2Enable){lcd_write_data('n');}else{lcd_write_data('f');lcd_write_data('f');}pStr = StrAlarm2;Alarm2Cnt = 0;}lcd_write_inst(0xc0); // set LCD line2 if (CurrentMode != mode_time){for (;*pStr!=0;pStr++){ // write hint messagelcd_write_data(*pStr);}lcd_write_inst(0x0f); // LCD cursor onlcd_write_inst(time_start_addr); // move cursor to start }else // time mode,write date to second line{lcd_write_inst(0x0c); // LCD sursor off/* lcd_write_inst(0xc0 + 3); // set date start address lcd_write_data(CurrentDate.year1 + '0');lcd_write_data(CurrentDate.year2 + '0');lcd_write_data(CurrentDate.year3 + '0');lcd_write_data(CurrentDate.year4 + '0');lcd_write_data('/');lcd_write_data(CurrentDate.monthh + '0');lcd_write_data(CurrentDate.monthl + '0');lcd_write_data('/');lcd_write_data(CurrentDate.dayh + '0');lcd_write_data(CurrentDate.dayl + '0');*/ }if (CurrentMode == mode_set_time){lcd_write_inst(time_start_addr); // move cursor to start }else if (CurrentMode == mode_set_date){lcd_write_inst(time_start_addr); // move cursor to start }else if (CurrentMode == mode_set_alarm1){lcd_write_inst(time_secondl_addr+3);adjust_item = 6;}else if (CurrentMode == mode_set_alarm2){lcd_write_inst(time_secondl_addr+3);adjust_item = 6;}else{lcd_write_inst(0x0c); // LCD cursor off}}// ------------------------------------------------------- void set_date(void){if (adjust_item == 0) // adjust year{if ((KeyNew >=0) & (KeyNew <= 9)){CurrentDate.year1 = KeyNew;lcd_write_data(CurrentDate.year1 + '0');//lcd_write_inst(time_start_addr);adjust_item ++;}else if (KeyNew == key_left){adjust_item = 7;lcd_write_inst(time_start_addr + 9);}else if(KeyNew == key_right){adjust_item ++;lcd_write_inst(time_start_addr + 1);}}else if(adjust_item == 1){if ((KeyNew >=0) & (KeyNew <= 9)){CurrentDate.year2 = KeyNew;lcd_write_data(CurrentDate.year2 + '0');//lcd_write_inst(time_start_addr + 1);adjust_item ++;}else if (KeyNew == key_left){adjust_item --;lcd_write_inst(time_start_addr + 0);}else if(KeyNew == key_right){adjust_item ++;lcd_write_inst(time_start_addr + 2);}}else if(adjust_item == 2){if ((KeyNew >=0) & (KeyNew <= 9)){CurrentDate.year3 = KeyNew;lcd_write_data(CurrentDate.year3 + '0');//lcd_write_inst(time_start_addr + 2);adjust_item ++;}else if (KeyNew == key_left){adjust_item --;lcd_write_inst(time_start_addr + 1);}else if(KeyNew == key_right){adjust_item ++;lcd_write_inst(time_start_addr + 3);}}else if(adjust_item == 3){if ((KeyNew >=0) & (KeyNew <= 9)){CurrentDate.year4 = KeyNew;lcd_write_data(CurrentDate.year4 + '0');//lcd_write_inst(time_start_addr + 3);adjust_item ++;lcd_write_inst(time_start_addr + 5);}else if (KeyNew == key_left){adjust_item --;lcd_write_inst(time_start_addr + 2);}else if(KeyNew == key_right){adjust_item ++;lcd_write_inst(time_start_addr + 5);}}else if(adjust_item == 4)if (((CurrentDate.monthl>2) & (KeyNew == 0)) | ((CurrentDate.monthl == 0) & (KeyNew == 1))| (((CurrentDate.monthl == 1) | (CurrentDate.monthl == 2)) & (KeyNew <2))) {CurrentDate.monthh = KeyNew;lcd_write_data(CurrentDate.monthh + '0');//lcd_write_inst(time_start_addr + 5);adjust_item ++;}else if (KeyNew == key_left){adjust_item --;lcd_write_inst(time_start_addr + 3);}else if (KeyNew == key_right){adjust_item ++;lcd_write_inst(time_start_addr + 6);}}else if(adjust_item == 5){if (((CurrentDate.monthh == 3) & (KeyNew <2)) | ((CurrentDate.monthh != 3) & (KeyNew >=0) & (KeyNew <=9))){CurrentDate.monthl = KeyNew;lcd_write_data(CurrentDate.monthl + '0');//lcd_write_inst(time_start_addr + 6);adjust_item ++;lcd_write_inst(time_start_addr + 8);}else if (KeyNew == key_left){adjust_item --;lcd_write_inst(time_start_addr + 5);}else if (KeyNew == key_right){adjust_item ++;lcd_write_inst(time_start_addr + 8);}}else if(adjust_item == 6)if (((CurrentDate.dayl>1) & ((KeyNew == 1) | (KeyNew == 2))) | ((CurrentDate.dayl == 0) & (KeyNew >0) & (KeyNew<4))| ((CurrentDate.dayl == 1) & (KeyNew <4))){CurrentDate.dayh = KeyNew;lcd_write_data(CurrentDate.dayh + '0');//lcd_write_inst(time_start_addr + 8);adjust_item ++;}else if (KeyNew == key_left){adjust_item --;lcd_write_inst(time_start_addr + 6);}else if (KeyNew == key_right){adjust_item ++;lcd_write_inst(time_start_addr + 9);}}else if(adjust_item == 7){if (((CurrentDate.dayh == 3) & (KeyNew <2)) | ((CurrentDate.dayh != 3) & (KeyNew >=0) & (KeyNew <=9))){CurrentDate.dayl = KeyNew;lcd_write_data(CurrentDate.dayl + '0');//lcd_write_inst(time_start_addr + 9);adjust_item ++;lcd_write_inst(time_start_addr + 0);}else if (KeyNew == key_left){adjust_item --;lcd_write_inst(time_start_addr + 8);}else if (KeyNew == key_right){adjust_item = 0;lcd_write_inst(time_start_addr + 0);}}}// -------------------------------------------------------void set_time(void){if (adjust_item == 0) // set hourh{if (((CurrentTime.hourl <4) & (KeyNew < 3)) | ((CurrentTime.hourl >3) & (KeyNew <2))){CurrentTime.hourh = KeyNew;lcd_write_data(CurrentTime.hourh + '0'); // refresh hourh//lcd_write_inst(0x10); // move cursor backadjust_item ++;}else if(KeyNew == key_left){adjust_item = 5;lcd_write_inst(time_secondl_addr);}else if(KeyNew == key_right){adjust_item ++;lcd_write_inst(time_hourl_addr);}}else if (adjust_item == 1) // set hourl{if (((CurrentTime.hourh == 2) & (KeyNew < 4)) | ((CurrentTime.hourh < 2) & (KeyNew <=9))){CurrentTime.hourl = KeyNew;lcd_write_data(CurrentTime.hourl + '0'); // refresh hourl//lcd_write_inst(0x10); // move cursor backadjust_item ++;lcd_write_inst(time_minuteh_addr);}else if(KeyNew == key_left){adjust_item --;lcd_write_inst(time_hourh_addr);}else if(KeyNew == key_right){adjust_item ++;lcd_write_inst(time_minuteh_addr);}}else if (adjust_item == 2) // set minuteh{if (KeyNew <6){CurrentTime.minuteh = KeyNew;lcd_write_data(CurrentTime.minuteh + '0');//lcd_write_inst(0x10); // move cursor backadjust_item ++;}else if(KeyNew == key_left){adjust_item --;lcd_write_inst(time_hourl_addr);}else if(KeyNew == key_right){adjust_item ++;lcd_write_inst(time_minutel_addr);}}else if (adjust_item == 3) // set minutel{if ((KeyNew >=0) & (KeyNew <=9)){CurrentTime.minutel = KeyNew;lcd_write_data(CurrentTime.minutel + '0');//lcd_write_inst(0x10); // move cursor backadjust_item ++;lcd_write_inst(time_secondh_addr);}else if(KeyNew == key_left){adjust_item --;lcd_write_inst(time_minuteh_addr);}else if(KeyNew == key_right){adjust_item ++;lcd_write_inst(time_secondh_addr);}}else if (adjust_item == 4) // set secondh{if (KeyNew <6){CurrentTime.secondh = KeyNew;lcd_write_data(CurrentTime.secondh + '0');//lcd_write_inst(0x10); // move cursor backadjust_item ++;}else if(KeyNew == key_left){adjust_item --;&nb, sp; lcd_write_inst(time_minutel_addr);}else if(KeyNew == key_right){adjust_item ++;lcd_write_inst(time_secondl_addr);}}else if (adjust_item == 5) // set secondl{if ((KeyNew >=0) & (KeyNew <=9)){CurrentTime.secondl = KeyNew;lcd_write_data(CurrentTime.secondl + '0');//lcd_write_inst(0x10); // move cursor backadjust_item = 0;lcd_write_inst(time_hourh_addr);}else if(KeyNew == key_left){adjust_item --;lcd_write_inst(time_secondh_addr);}else if(KeyNew == key_right){adjust_item = 0;lcd_write_inst(time_hourh_addr);}}}// -------------------------------------------------------void set_alarm1(void){if (adjust_item == 0) // set hourh{if (((AlarmTime1.hourl <4) & (KeyNew < 3)) | ((AlarmTime1.hourl >3) & (KeyNew <2))){AlarmTime1.hourh = KeyNew;lcd_write_data(AlarmTime1.hourh + '0'); // refresh hourh//lcd_write_inst(0x10); // move cursor backadjust_item ++;}else if(KeyNew == key_left){adjust_item = 6;lcd_write_inst(time_secondl_addr + 3);}else if(KeyNew == key_right){adjust_item ++;lcd_write_inst(time_hourl_addr);}}else if (adjust_item == 1) // set hourl{if (((AlarmTime1.hourh == 2) & (KeyNew < 4)) | ((AlarmTime1.hourh < 2) & (KeyNew <=9))){AlarmTime1.hourl = KeyNew;lcd_write_data(AlarmTime1.hourl + '0'); // refresh hourl//lcd_write_inst(0x10); // move cursor backadjust_item ++;lcd_write_inst(time_minuteh_addr);}else if(KeyNew == key_left){adjust_item --;lcd_write_inst(time_hourh_addr);}else if(KeyNew == key_right){adjust_item ++;lcd_write_inst(time_minuteh_addr);}}else if (adjust_item == 2) // set minuteh{if (KeyNew <6){AlarmTime1.minuteh = KeyNew;lcd_write_data(AlarmTime1.minuteh + '0');//lcd_write_inst(0x10); // move cursor backadjust_item ++;}else if(KeyNew == key_left){adjust_item --;lcd_write_inst(time_hourl_addr);}else if(KeyNew == key_right){adjust_item ++;lcd_write_inst(time_minutel_addr);}}else if (adjust_item == 3) // set minutel{if ((KeyNew >=0) & (KeyNew <=9)){AlarmTime1.minutel = KeyNew;lcd_write_data(AlarmTime1.minutel + '0');//lcd_write_inst(0x10); // move cursor backadjust_item ++;lcd_write_inst(time_secondh_addr);}else if(KeyNew == key_left){adjust_item --;lcd_write_inst(time_minuteh_addr);}else if(KeyNew == key_right){adjust_item ++;lcd_write_inst(time_secondh_addr);}}else if (adjust_item == 4) // set secondh{if (KeyNew <6){AlarmTime1.secondh = KeyNew;lcd_write_data(AlarmTime1.secondh + '0');//lcd_write_inst(0x10); // move cursor backadjust_item ++;}else if(KeyNew == key_left){adjust_item --;lcd_write_inst(time_minutel_addr);}else if(KeyNew == key_right){adjust_item ++;lcd_write_inst(time_secondl_addr);}}else if (adjust_item == 5) // set secondl{if ((KeyNew >=0) & (KeyNew <=9)){AlarmTime1.secondl = KeyNew;lcd_write_data(AlarmTime1.secondl + '0');//lcd_write_inst(0x10); // move cursor backadjust_item ++;lcd_write_inst(time_secondl_addr+3);}else if(KeyNew == key_left){adjust_item --;lcd_write_inst(time_secondh_addr);}else if(KeyNew == key_right){adjust_item ++;lcd_write_inst(time_secondl_addr+3);}}else if (adjust_item == 6) // set on/off{if ((KeyNew == key_up) | (KeyNew == key_down)){if (Alarm1Enable){Alarm1Enable =false; // disable alarm1lcd_write_data('f');lcd_write_data('f');}else{Alarm1Enable =true; // enable alarm1lcd_write_data('n');lcd_write_data(' ');}//lcd_write_inst(time_secondl_addr+3);adjust_item = 0;lcd_write_inst(time_hourh_addr);Alarm1Cnt = 0;}else if(KeyNew == key_left){adjust_item --;lcd_write_inst(time_secondl_addr);}else if(KeyNew == key_right){adjust_item = 0;lcd_write_inst(time_hourh_addr);}}}// -------------------------------------------------------void set_alarm2(void){if (adjust_item == 0) // set hourh{if (((AlarmTime2.hourl <4) & (KeyNew < 3)) | ((AlarmTime2.hourl >3) & (KeyNew <2))){AlarmTime2.hourh = KeyNew;lcd_write_data(AlarmTime2.hourh + '0'); // refresh hourh//lcd_write_inst(0x10); // move cursor backadjust_item ++;}else if(KeyNew == key_left){adjust_item = 6;lcd_write_inst(time_secondl_addr+3);}else if(KeyNew == key_right){adjust_item ++;lcd_write_inst(time_hourl_addr);}}else if (adjust_item == 1) // set hourl{if (((AlarmTime2.hourh == 2) & (KeyNew < 4)) | ((AlarmTime2.hourh < 2) & (KeyNew <=9))){AlarmTime2.hourl = KeyNew;lcd_write_data(AlarmTime2.hourl + '0'); // refresh hourl//lcd_write_inst(0x10); // move cursor backadjust_item ++;lcd_write_inst(time_minuteh_addr);}else if(KeyNew == key_left){adjust_item --;lcd_write_inst(time_hourh_addr);}else if(KeyNew == key_right){adjust_item ++;lcd_write_inst(time_minuteh_addr);}}else if (adjust_item == 2) // set minuteh{if (KeyNew <6){AlarmTime2.minuteh = KeyNew;lcd_write_data(AlarmTime2.minuteh + '0');//lcd_write_inst(0x10); // move cursor backadjust_item ++;}else if(KeyNew == key_left){adjust_item --;lcd_write_inst(time_hourl_addr);}else if(KeyNew == key_right){adjust_item ++;lcd_write_inst(time_minutel_addr);}}else if (adjust_item == 3) // set minutel{if ((KeyNew >=0) & (KeyNew <=9)){AlarmTime2.minutel = KeyNew;lcd_write_data(AlarmTime2.minutel + '0');//lcd_write_inst(0x10); // move cursor backadjust_item ++;lcd_write_inst(time_secondh_addr);}else if(KeyNew == key_left){adjust_item --;lcd_write_inst(time_minuteh_addr);}else if(KeyNew == key_right){adjust_item ++;lcd_write_inst(time_secondh_addr);}}else if (adjust_item == 4) // set secondh{if (KeyNew <6){AlarmTime2.secondh = KeyNew;lcd_write_data(AlarmTime2.secondh + '0');//lcd_write_inst(0x10); // move cursor backadjust_item ++;}else if(KeyNew == key_left){adjust_item --;lcd_write_inst(time_minutel_addr);}else if(KeyNew == key_right){adjust_item ++;lcd_write_inst(time_secondl_addr);}}else if (adjust_item == 5) // set secondl{if ((KeyNew >=0) & (KeyNew <=9)){AlarmTime2.secondl = KeyNew;lcd_write_data(AlarmTime2.secondl + '0');//lcd_write_inst(0x10); // move cursor backadjust_item ++;lcd_write_inst(time_secondl_addr+3);}else if(KeyNew == key_left){adjust_item --;lcd_write_inst(time_secondh_addr);}else if(KeyNew == key_right){adjust_item ++;lcd_write_inst(time_secondl_addr+3);}}else if (adjust_item == 6) // set on/off{if ((KeyNew == key_up) | (KeyNew == key_down)){if (Alarm2Enable){Alarm2Enable =false; // disable alarm2lcd_write_data('f');lcd_write_data('f');}else{Alarm2Enable =true; // enable alarm2lcd_write_data('n');lcd_write_data(' ');}//lcd_write_inst(time_secondl_addr+3);adjust_item = 0;lcd_write_inst(time_hourh_addr);Alarm2Cnt = 0;}else if(KeyNew == key_left){adjust_item --;lcd_write_inst(time_secondl_addr);}else if(KeyNew == key_right){adjust_item = 0;lcd_write_inst(time_hourh_addr);}}}// -------------------------------------------------------void main(void){unsigned char cnt;TRISC = 0x03; // PORTC.3 drive led,low activePORTC_MAP = 0x00;led = 0;BackLightEn = 0;BackLightTimer = 0;PORTC = PORTC_MAP;TRISA = 0xff; // low half byte as keyscan inTRISE = 0x00;ADCON0 = 0x00;ADCON1 = 0x06; // all digital I/Oslcd_init();INTCON = 0x00;lcd_write_inst(0x80); // set lcd ddram addressfor (pStr = StrPower1;*pStr!=0;pStr++){lcd_write_data(*pStr);}lcd_write_inst(0x0c); // LCD cursor offPIR1 = PIR2 = 0x00;T1CON = 0x0f; // T1CON: -- T1CKPS1 T1CPS0 T1OSCEN /T1SYNC TMR1CS TMR1ONTMR1H = 0x80;TMR1L = 0x00;。
PIC单片机-多功能万年历电子钟

PIC单片机-多功能万年历电子钟;*********************************************************************************LIST P=PIC16F72#INCLUDE<P16F72.INC>;********************************************************************************#DEFINE DIO_A PORTA ;RA端口寄存器#DEFINE DIO_B PORTB ;RB端口寄存器#DEFINE DIO_C PORTC ;RC端口寄存器#DEFINE SIO_A TRISA ;RA端口输入、输出设定#DEFINE SIO_B TRISB ;RB端口输入、输出设定#DEFINE SIO_C TRISC ;RC端口输入、输出设定;===============数码管共脚位定义=============================#DEFINE HOUH_LED PORTB,3 ;数码管位选#DEFINE HOUL_LED PORTB,2 ;数码管位选#DEFINE MINH_LED PORTB,1 ;数码管位选#DEFINE MINL_LED PORTB,0 ;数码管位选#DEFINE SEC_LED PORTB,4 ;LED位选;===============按键脚位定义=================================#DEFINE SETUP_KEY PORTA,3 ;时钟设置键#DEFINE INCREASE_KEY PORTA,4 ;时间加键#DEFINE DECREASE_KEY PORTA,5 ;时间减键;============== DS1302引脚定义==============================#DEFINE T_CLK PORTA,0 ;1302时钟->7#DEFINE T_IO PORTA,1 ;1302数据输入/输出->6#DEFINE T_RST PORTA,2 ;1302使能位->5#DEFINE SET_IO TRISA,1 ;设定1302I_O;========================================================================== #DEFINE FLAG_10S FLAG,7 ;#DEFINE FLAG_SETUP FLAG,6 ;#DEFINE FLAG_500MS FLAG,5 ;#DEFINE FLAG_250MS FLAG,4 ;#DEFINE FLAG_MINUTE FLAG,3 ;#DEFINE FLAG_HOUR FLAG,2 ;#DEFINE FLAG_TIME FLAG,1 ;#DEFINE FLAG_DATE FLAG,0 ;;========================================================================== #DEFINE FLAG_YEAR FLAG1,7 ;#DEFINE FLAG_DAY FLAG1,6 ;#DEFINE FLAG_DATA FLAG1,5 ;;*********************寄存器定义***************************ID_TEMP EQU 72HW_TEMP EQU 73HSTATUS_TEMP EQU 74HPCLATH_TEMP EQU 75HERRORLEVEL -302CBLOCK 020HSEC ;秒寄存器MINUTE ;分寄存器HOUR ;小时寄存器DATE ;日寄存器MONTH ;月寄存器DAY ;星期寄存器YEAR ;年寄存器WRITE_ENABLED ;写使能寄存器DS1302_RX ;保存接受的1个数据DS1302_TX ;准备写入到DS1302的一个数据BYTE_COUNT ;字节数寄存器BIT_COUNT ;BIT数寄存器TEMP1 ;转换进制用TIMER0 ;\TIMER1 ;定时用TIMER2 ;/;-------------------------------------FLAGFLAG1FSR_TEMPCOUNTCOUNT1 ;显示数据位数COUNT2 ;显示数据表中位置COUNT3 ;显示位置COUNT4CNTCNT0CNT1CNT2SHOW_MINSHOW_HOUDATA_INCDATEPC1 ;C2 ;C3 ;ENDC;*******************宏定义********************************* BANK1 MACRO ;体1BSR STATUS,RP0BCR STATUS,RP1ENDMBANK0 MACRO ;体0BCR STATUS,RP0BCR STATUS,RP1ENDM;-------------------------------------------------------------------;子程序名:;功能:中断服务主程序入口;功能说明:;----------------------------------------------------------------- INTERMIT_SERVE:;---------现场保护-----------------------STWR W_TEMP ;SWAPR STATUS,W ;CLRR STATUS ;STWR STATUS_TEMP ;LDR PCLATH,W ;STWR PCLATH_TEMP ;CLRR PCLATH ;;-------中断服务-------------------------INCR TIMER0,F ;\LDWI .100 ;\XORWR TIMER0,W ;判断是否到250MSBTSS STATUS,Z ;/LJUMP AAA ;ON,LDWI B'00010000' ;\每到250MS取反一次标志位1 XORWR FLAG,F ;/CLRR TIMER0INCR TIMER1,F ;\LDWI .2 ;\XORWR TIMER1,W ;判断是否到500MSBTSS STATUS,Z ;/LJUMP AAA ;ON,LDWI B'00100000' ;\每到500MS取反一次标志位1 XORWR FLAG,F ;/CLRR TIMER1 ;YES,INCR TIMER2,F ;\LDWI .20 ;\XORWR TIMER2,W ;判断是否到5SBTSS STATUS,Z ;/LJUMP $+3 ;/CLRR TIMER2 ;YES,BSR FLAG_10S ;DP_SECLCALL PLAY_SECANDWI 0F0HSTWR DIO_BCLRR DIO_CINCR COUNT,FLDWI 01H ;;;;;;;;;;;;;;;;;XORWR COUNT,WBTSC STATUS,ZLCALL PLAY_HOUR_H ;LDWI 02H ;;;;;;;;;;;;;;;;;;;XORWR COUNT,WBTSC STATUS,ZLCALL PLAY_HOUR_L ;LDWI 03H ;;;;;;;;;;;;;;;;;;XORWR COUNT,WBTSC STATUS,ZLCALL PLAY_MINUTE_H ;LDWI 04H ;;;;;;;;;;;;;;;;XORWR COUNT,WBTSS STATUS,ZLJUMP $+3CLRR COUNTLCALL PLAY_MINUTE_L ;LDWI 0D9H ;\STWR TMR0 ;/写入TMR0初始值BCR INTCON,T0IF ;清TMR0中断标志;-------恢复现场-------------------LDR PCLATH_TEMP,W ;STWR PCLATH ;SWAPR STATUS_TEMP,F ;STWR STATUS ;SWAPR W_TEMP,F ;SWAPR W_TEMP,W ;RTFI ;中断返回;............................................................. ;子程序名:;功能:清寄存器;功能说明: ;................................................................CLR_RAM:LDWI 20HSTWR FSRCLRR INDFINCR FSR,FLJUMP $-3RTIW 00H;--------------------------------------------------------------------------;子程序名:;功能:查表子程序;功能说明:用于显示0-9时钟数据字型码,共阳LED无小数点;--------------------------------------------------------------------------- TABLE:ADDWR PCL,FRTIW B'11001111' ;0RTIW B'00000101' ;1RTIW B'11011100' ;2RTIW B'10011101' ;3RTIW B'00010111' ;4RTIW B'10011011' ;5RTIW B'11011011' ;6RTIW B'00001101' ;7RTIW B'11011111' ;8RTIW B'10011111' ;9;...........Program Initialization........................................;子程序名: 单片机复位进入点;功能:;功能说明: ;............................................................................PORT_INIT:CLRR INTCON ;清除中断BANK1 ;\LDWI B'00000000' ;\STWR SIO_C ;\RC口设为输出LDWI B'11100000' ;\STWR SIO_B ;/RB口设为输入LDWI B'11111000' ;\STWR SIO_A ;LDWI 06H ;STWR ADCON1 ;A口配置为普通数字I/OLDWI B'10000101' ;\ 设TMR0分频1:64STWR OPTION_REG ;/RB口同时输入、出时不能上拉BANK0 ;;----------------------------------CLRR DIO_A ;清控制位CLRR DIO_BCLRR DIO_C ;\关闭显示LDWI 0DAH ;\写入TMR0初始值STWR TMR0 ;/2.5MS中断一次LDWI B'10100000' ;\开TMR0中断使能位STWR INTCON ;/LCALL CLR_RAM ;->清寄存器LCALL DS1302_INIT ;->初始化DS1302LCALL READ_DS1302 ;;CALL DATE_INIT ;\;CALL WRITE_DS1302 ;/写数据LCALL QINDON_INITMOVFW DATESTWR DATEP ;%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ;程序名:;功能:;功能说明: ;%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% MAIN_PROGRAM:BTSC FLAG_SETUPLJUMP $+3;NOP;NOPLCALL DELAY250MSLCALL READ_DS1302 ;BTSS FLAG_10S ;检测是否到5SLJUMP $+3 ;CLRR FLAG ;3S到,退出校正时间状态CLRR FLAG1 ;MOVFW DATEXORWR DATEP,WBTSC STATUS,ZLJUMP TEST_KEYLDWI 030HSUBWR SEC,WBTSS STATUS,ZLJUMP TEST_KEY ;->检测按键LDWI 005HSUBWR SEC,FLCALL WRITE_DS1302 ;写入设置的数据MOVFW DATESTWR DATEPLJUMP MAIN_PROGRAM ;循环;%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% TEST_KEY:NOP ;\LDR DIO_A,W ;\ANDWI B'00111000' ;\XORWI B'00111000' ;检测是否有按键按下?BTSC STATUS,Z ;/LJUMP MAIN_PROGRAM ;/BCR FLAG_10S ;YES,重新启动5S到标记CLRR TIMER2 ;/;------------------------------------------------------BTSC FLAG_DATA ;显示日期时禁止调整LJUMP MAIN_PROGRAM ;/BTSS SETUP_KEY ;检测是否按时间设置键?LJUMP SETUP ;YES,跳设置键处理程序BTSS INCREASE_KEY ;检测是否按增键?LJUMP INCREASE ;YES,BTSS DECREASE_KEY ;检测是否按减键?LJUMP DECREASE ;YES,LJUMP MAIN_PROGRAM ;;时间设置键处理--------------------SETUP:LCALL DELAY_10MS ;\BTSS SETUP_KEY ;检测设置键是否松开?LJUMP $-2 ;/LCALL DELAY_10MS ;LDWI SHOW_HOU ;STWR FSR ;第一个调整单元LDWI 24HSTWR DATA_INC ;调整最大值BSR FLAG_SETUPBSR FLAG_HOURBSR FLAG_TIMELJUMP TEST_KEYDEC_MIN:INCR COUNT2,FLDWI 01H ;;;;;;;;;;;;;;;;;;;;;;;XORWR COUNT2,WBTSS STATUS,ZLJUMP DEC_MON ;02HLDWI SHOW_MINSTWR FSR ;调整单元地址LDWI 60HSTWR DATA_INC ;调整最大值BSR FLAG_MINUTEBCR FLAG_HOURDEC_MONXORWR COUNT2,WBTSS STATUS,ZLJUMP DEC_DATE ;03HBSR FLAG_HOURBCR FLAG_MINUTEBSR FLAG_DATEBCR FLAG_TIMEDEC_DATELDWI 03H ;;;;;;;;;;;;;;;;;;;XORWR COUNT2,WBTSS STATUS,ZLJUMP DEC_YEAR ;04HLDWI SHOW_MINSTWR FSR ;调整单元地址LDWI 32HSTWR DATA_INC ;调整最大值BSR FLAG_MINUTEBCR FLAG_HOURDEC_YEARLDWI 04H ;;;;;;;;;;;;;;;;;;XORWR COUNT2,WBTSS STATUS,ZLJUMP DEC_DAY ;05HMOVFW SHOW_HOUSTWR MONTHMOVFW SHOW_MINBCR FLAG_MINUTEBSR FLAG_YEARBCR FLAG_DATEDEC_DAYLDWI 05H ;;;;;;;;;;;;;;;;;;;XORWR COUNT2,WBTSS STATUS,ZLJUMP DEC_END ;06HLDWI SHOW_MINSTWR FSR ;调整单元地址LDWI 08HSTWR DATA_INC ;调整最大值BSR FLAG_MINUTEBCR FLAG_HOURBSR FLAG_DAYBCR FLAG_YEARDEC_ENDXORWR COUNT2,WBTSS STATUS,ZLJUMP DEC1 ;MOVFW SHOW_HOUSTWR YEARMOVFW SHOW_MINSTWR DAYCLRR COUNT2 ;清BCR FLAG_SETUP ;清标示BCR FLAG_DAYBCR FLAG_MINUTELCALL WRITE_DS1302 ;写入设置的数据DEC1LJUMP TEST_KEY ;;增加键处理++++++++++++++++++++++++++++++++++++++++++++++++ INCREASE:LCALL DELAY_10MS ;\BTSS INCREASE_KEY ; 检测是否松开加键?LJUMP $-2 ;/LCALL DELAY_10MS ;BTSS FLAG_SETUP ;检测是否已进入设置状态?LJUMP $+8 ;YES,处理数据调整LCALL BCD_B ;先BCD数据转换成2进制,INCR INDF,F ;当前地址数据加1LCALL B_BCD ;再将2进制数据转换成BCD码,写如该单元;判断调整到上限?MOVFW DATA_INC ;\XORWR INDF,W ;\判断当前地址数据变量大小BTSC STATUS,Z ;/CLRR INDF ;/LJUMP MAIN_PROGRAM ;/;减少键处理================================================= DECREASE:LCALL DELAY_10MS ;\BTSS DECREASE_KEY ;检测是否松开减键?LJUMP $-2 ;/LCALL DELAY_10MS ;BTSS FLAG_SETUP ;检测是否已进入设置状态?LJUMP $+7 ;YES,处理数据调整LCALL BCD_B ;BCD码转2进制LDR INDF,W ;\BTSC STATUS,Z ;判断下限减到0?LJUMP MAIN_PROGRAM ;/DECR INDF,F ;LCALL B_BCD ;2进制转BCD码LJUMP MAIN_PROGRAM ;返回主程序;...........Program Initialization........................................;子程序名:;功能:启动DS1302开始计时;功能说明: ;............................................................................QINDON_INITBCR T_CLK ;\BCR T_RST ;先禁止LDWI B'10000000' ;发送写使能寄存器命令STWR DS1302_TX ;;B7必须为1BSR T_RST ;LCALL SEND_BYTE ;->发送一个字节数据BCR SEC,7MOVFW SEC ;\允许写使能命令STWR DS1302_TX ;/LCALL SEND_BYTE ;->发送一个字节的数据BCR T_RST ;->DS1302复位RET ;;...........Program Initialization........................................;子程序名:;功能:写DS1302初始数据;功能说明:写入10年09月19日10时05分00秒;............................................................................DATE_INIT:LDWI B'00000000' ;\B7=0表示启动时钟震荡,B7=1表示暂停时钟震荡STWR SEC ;/B6~B4表示秒十位,B3-B0表示秒个位;秒寄存器,BCD码格式,初始00秒LDWI 05H ;\STWR MINUTE ;/;分钟寄存器,BCD码格式,00-59LDWI B'00010000' ;B7=0表示24小时方式,B7=1表示12小时方式,当选12小时方式下STWR HOUR ;B6=未用,B5=1表示下午B5=0表示上午,B4=小时高位B3-B0小时低位;小时寄存器,BCD码格式,00-59LDWI 19HSTWR DATE ;日;日期寄存器,BCD码格式,00-31LDWI 09HSTWR MONTH ;月;月份寄存器,BCD码格式,00-12LDWI 07H;星期寄存器,BCD码格式,0-7LDWI 10H ;STWR YEAR ;年;年寄存器,BCD码格式,00-99RET;----------------------------------------------------------------------;子程序名::DS1302_INI;功能:初始化1302,先禁止RST,允许写使能;功能说明:;---------------------------------------------------------------------------DS1302_INIT:BCR T_CLK ;\BCR T_RST ;先禁止LDWI B'10001110' ;发送写使能寄存器命令STWR DS1302_TX ;;B7必须为1,B6=1表示对RAM进行操作B6=0表示读写时钟/日历数据;;B5~B1为寄存器地址位,B0为0表示写,为1表示读BSR T_RST ;LCALL SEND_BYTE ;->发送一个字节数据LDWI B'00000000' ;\允许写使能命令STWR DS1302_TX ;/;B7=1为写保护,B7=0为写允许,B0~B6=0固定为0LCALL SEND_BYTE ;->发送一个字节的数据BCR T_RST ;->DS1302复位;------------------------------LDWI B'10010000' ;\90H设定充电方式命令STWR DS1302_TX ;写入缓冲BSR T_RST ;->允许操作DS1302LCALL SEND_BYTE ;BCR T_RST ;->DS1302复位RET ;;----------------------------------------------------------------------;子程序名:SEND_BYTE;功能:调用一次发送一个字节的数据;功能说明:数据从低位开始发送,用于发送1302的控制命令或发送一个数据;---------------------------------------------------------------------------SEND_BYTE:LDWI D'8' ;\写入BIT数STWR BIT_COUNT ;/SEND_LOOP:BCR T_IO ;BCR T_CLK ;\->BIT数在T_CLK低电平时变化BTSC DS1302_TX,0 ;检测发送缓冲寄存器位0,是1就发1.是0就发0RRR DS1302_TX,F ;向右移1位,为发送下一个BIT准备BSR T_CLK ;确定发送有效DECRSZ BIT_COUNT,F ;检测是否发送完8个BIT?LJUMP SEND_LOOP ;<否>继续发送下一位BCR T_CLK ;<是>返回RTIW 00H ;发送完8BIT数返回;----------------------------------------------------------------------;子程序名:READ_BYTE;功能:调用一次读出一个字节的数据;功能说明:数据从低位开始发送,用于发送1302的控制命令或发送一个数据;---------------------------------------------------------------------------READ_BYTE:BANK1BSR SET_IO ;I_O 设置为输入BANK0NOPLDWI D'8' ;\读8个BIT数据STWR BIT_COUNT ;/READ_LOOP:BCR T_CLK ;下降沿读取BCR STATUS,C ;\BTSC T_IO ;接收一个BITBSR STATUS,C ;/RRR DS1302_RX,FBSR T_CLK ;恢复高电平DECRSZ BIT_COUNT,F ;检测是否读完8BIT?LJUMP READ_LOOP ;-><否>循环读出BANK1BCR SET_IO ;I_O恢复为输出BANK0BCR T_CLKRETNOP;**********************************************************;子程序名:READ_DS1302;功能:突发模式读DS1302;说明:1.FLAG_RAM=1 读RAM14个字节定时数据; 2.FLAG_RAM=0 读7个字节日历/时钟数据;**********************************************************READ_DS1302:BSR T_RST ;-启动DS1302LDWI B'10111111' ;->ON,读日历/时钟突发模式命令多字节STWR DS1302_TX ;->写入发送寄存器LCALL SEND_BYTE ;->发送LDWI SEC ;->ON,准备接收DS1302时钟数据的首地址STWR FSR ;写入间接寻址寄存器LDWI D'7' ;->,ON,1次读出7个字节日历/时钟数据STWR BYTE_COUNT ;->写入字节计数器READ_BITLCALL READ_BYTELDR DS1302_RX,W ;\<是>将8BIT数据写入数据保存处STWR INDF ;/INCR FSR,F ;数据保存处地址加1,为下一个数据提供地址DECRSZ BYTE_COUNT,F ;检测是否读完数据?LJUMP READ_BIT ;->否,循环BCR T_RST ;->DS1302复位,禁止操作RET ;读完7个日历/时钟数据,返回;**********************************************************;子程序名:WRITE_DS1302;功能:突发模式写DS1302;说明:1.定时标志FLAG_TIMER=1 写14个字节定时数据->RAM; 2.定时标志FLAG_TIMER=0 写7个字节日历/时钟数据/写使能命令;**********************************************************WRITE_DS1302:LDWI B'10111110' ;->ON,写时钟多字节命令STWR DS1302_TX ;\BSR T_RST ; 发送突发模式写时钟命令LCALL SEND_BYTE ;/;--------------------------------;BCF T_CLK ;;BCF T_IO ;LDWI SEC ;->ON,准备写时钟/日历数据首地址STWR FSR ;LDWI D'8' ;->ON,准备写时钟的字节数STWR BYTE_COUNT ;/WRITE_BYTE:LDR INDF,W ;\拷贝地址数据内容到发送缓冲STWR DS1302_TX ;/LCALL SEND_BYTEINCR FSR,F ;->数据发送地址加1,为下一个数据提供地址DECRSZ BYTE_COUNT,F ;检测是否写完数据?LJUMP WRITE_BYTE ;BCR T_RST ;->DS1302复位,禁止操作RET ;写完数据,返回;%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ;子程序名:显示LED;功能:;功能说明: ;%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%% PLAY_SEC:;显示秒闪烁~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~BTSS FLAG_500MS ;检测闪烁频率LJUMP $+3 ;/BSR SEC_LED ;RETBCR SEC_LED ;RET;====================================;显示分L位MLMLMLMLMLMLMLMLMLMLMLMLMLMLMLMLMMLMLMLMLMPLAY_MINUTE_L:BSR MINL_LED ;BTSS FLAG_MINUTE ;->检测是否要闪烁当前单元?LJUMP $+3 ;BTSS FLAG_250MS ;检测闪烁频率LJUMP $+0AH ;/LDR SHOW_MIN,W ;ANDWI 0FH ;LCALL TABLE ;STWR DIO_C ;ADDWR DIO_C,FRETBTSS FLAG_DAY ;指示灯不跟着闪烁LJUMP $+4MOVFW DIO_CXORWI B'00100000'STWR DIO_CRET;显示分H位MHMHMHMHMHMHMHMHMHMHMHMHMHMHMHPLAY_MINUTE_H:BSR MINH_LED ;BTSS FLAG_MINUTE ;->检测是否要闪烁当前单元?LJUMP $+3 ;BTSS FLAG_250MS ;检测闪烁频率LJUMP $+0AH ;/SWAPR SHOW_MIN,W ;ANDWI 0FH ;LCALL TABLE ;STWR DIO_C ;BTSS FLAG_YEARBTSS FLAG_YEARLJUMP $+4MOVFW DIO_CXORWI B'00100000'STWR DIO_CRET;显示时L位HLHLHLHLHLHLHLHLHLHLHLHLHLHLHLHLHLHLHLHLHLHLPLAY_HOUR_L:BSR HOUL_LED ;BTSS FLAG_HOUR ;->检测是否要闪烁当前单元?LJUMP $+3 ;BTSS FLAG_250MS ;检测闪烁频率LJUMP $+0AH ;/LDR SHOW_HOU,WANDWI 0FH ;LCALL TABLE ;STWR DIO_C ;MOVFW DIO_CXORWI B'00100000'STWR DIO_CRET;显示时H位HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH PLAY_HOUR_H:BSR HOUH_LED ;BTSS FLAG_HOUR ;->检测是否要闪烁当前单元?LJUMP $+3 ;BTSS FLAG_250MS ;检测闪烁频率LJUMP $+0AH ;/SWAPR SHOW_HOU,W ;ANDWI 0FH ;LCALL TABLE ;STWR DIO_C ;MOVFW DIO_CXORWI B'00100000'STWR DIO_CRETEND。
PIC单片机的最小系统及开发流程

; 设置RA口为IO口 ;选择数据存储器的体0
第三讲 5. PIC单片机的集成开发环境MPLAB 编译失败的原因1-拼写错误 学会看Output窗口的信息
第三讲 5. PIC单片机的集成开发环境MPLAB 编译失败的原因2-用中文输入法输入“;”“,”
DIP封装的 PIC16F877A
SOIC和SSOP封 装的PIC单片机
TQFP封装的 PIC6F877A
更加详细的封装信息在datasheet里面
第三讲 3,PIC单片机的封装
•
小知识点 • 环氧树脂聚合物 成本低,重量 轻 欣赏下黑胶芯片的内部 • 光照(包括紫外线)会影响晶 体管的工作性能,所以外壳不 能透光。
第三讲 5. PIC单片机的集成开发环境MPLAB 软件安装详见课本P32, 3.3节 安装程序,下课学习委员来找我拷贝
可官方免费下 载,但只支持 汇编编译,C 语言编译的话 需要安装其他 C编译器,而 且不同信号的 编译器不同
MPLAB 8.8 IDE (本课程讲解用)
MPLAB X IDE (最新版本)
asm文件第三讲pic单片机的集成开发环境mplab软件安装详见课本p3233节安装程序下课学习委员来找我拷贝mplab88ide本课程讲解用mplabide最新版本可官方免费下载但只支持汇编编译c语言编译的话需要安装其他c编译器而且不同信号的编译器不同第三讲pic单片机的集成开发环境mplabmplabide提供以下功能
TQFP封装的 PIC6F877A
集 成 电 路 的 封 装 ( Package ) 指 厂 商 对 由 集 成 电 路 的 核 心 —— 半 导 体硅片的包装方式,也即 芯片的载体。
第三讲 4,PIC单片机的烧写流程
用PIC单片机制作LED数字钟

该电路采用9v成品电源适配器供电输出电流为looma再通过三踹稳压模块78lo5降压给电路供电闹钟输出部分是低电平有效通过vt5输出驱动自带振荡电路的bc发声实现闹钟功能
用PIC单片机制作LED数字钟
本文介绍的LED数字钟是利用PICl6F84A单片机实现如下图所示,它走其电路图见图2。该电路采用9V成品电源适配器供电,输出电流为lOOmA,再通过三踹稳压模块78LO5降压给电路供电,闹钟输出部分是低电平有效,通过VT5输出驱动自带振荡电路的BC发声实现闹钟功能。如将BC换成继电器就可以实现对其他家用电器的控制。
PIC单片机实验报告

实验一循环点亮LED灯一、实验内容:将RE0-RE5配置为输出,连接6个LED灯;编写程序,调试并运行,下载到实验板上,实现循环点亮。
二、实验目的:学习PIC单片机I/O端口功能及特点,了解I/O端口引脚及连线,控制寄存器。
在开发板上实现循环点亮LED灯。
三、实验要求1.了解掌握PIC单片机的结构和功能。
2.应熟练掌握MPLAB开发环境的使用方法。
3.熟练掌握PIC单片机的程序编写方法。
4.掌握MPLAB IDE硬件调试的技巧。
四、实验准备:1、I/O引脚及连线:I/O端口特点:1、所有I/O 输入端口都是施密特触发器输入,以便增强抗干扰性。
2、外设复用:所有的器件引脚(除VDD、VSS、MCLR 和OSC1/CLKI之外),均为外设与I/O端口所共用。
3、如果外设使能,并且外设正在使用相关引脚时,该引脚将不再作为通用I/O 引脚使用。
4、优先级:I/O 与多个外设复用时I/O 引脚的名称定义了与该引脚相关的各个功能的优先级,如:I/O 引脚与两个外设复用(“外设A”和“外设B”)外设A 对引脚的控制具有最高优先权,若外设A 和外设B 同时使能,外设A将控制I/O 引脚5、电平变化通知引脚:电平变化通知引脚(CN)内接输入电平变化通知模块,使得dsPIC30F器件能够向处理器发出中断请求,以响应所选输入引脚上的状态变化。
I/O端口控制寄存器:所有的端口引脚,都有三个与端口引脚的操作直接相关的寄存器。
①TRISx:数据方向寄存器。
决定各个引脚是输入引脚还是输出引脚。
–若某个I/O 引脚的TRIS 位为“1”,则该引脚是输入引脚。
–某个I/O 引脚的TRIS 位为“0”,则该引脚被配置为输出引脚。
–复位以后,所有端口引脚被定义为输入。
②PORTx:I/O端口寄存器。
访问的是I/O引脚上的数据。
读的是端口引脚值;写端口引脚,写的是端口数据锁存器(LATx )。
③LATx:I/O端口锁存寄存器。
读的是数据锁存器里锁存的值;写锁存值,写的是端口数据锁存器(LATx )五、实验过程及结果:实验源程序:#include "p30f4011.h”int main(void){int led=0x01;unsigned long int i=0;TRISE =0x100;PORTE=led;while(1){PORTE =led;for (i=0;i<65000;i++){}; //延时led = led<<1; //当第6个LED灯亮后,重新从第1个LED灯点亮if (led == 0x40)led = 0x01;}return 0;}先编写程序,检验正确后,下载到实验板上并运行,实验板上6个LED灯开始循环点亮,通过修改程序,还可以改变延迟时间,即可控制LED灯点亮时间。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
#include <pic.h>__CONFIG (0x20F1); //运行用__CONFIG (0x3FFF);#define LCD_RS RD4 //LCD 寄存器选择数据H/指令L#define LCD_RW RD5 //LCD 读H/L写控制线#define LCD_E RD6 //LCD E 时钟//定义常数#define TC74_ADD 0b1001101 //TC74的7位地址#define RTR 0b00000000 //TC74的读温度命令#define COM 0 //在LCD_WRITE()中的第2参数为0表示写命令#define DA T 1 //在LCD_WRITE()中的第2参数为1表示写数据bank1 char DD[16]; //一行LCD显示数据暂存char SET=0,CK=0; //功能键判断,选着键#define YEAR LINE1+3 //年的显示位置(4位)#define MONTH LINE1+6 //月的显示位置(2位)#define DAY LINE1+9 //日的显示位置(2位)#define WEEK LINE1+15 //星期的显示位置(1位)#define HOUR LINE2+3 //时的显示位置(2位)#define MINUTE LINE2+6 //分的显示位置(2位)#define SECOND LINE2+9 //秒的显示位置(2位)#define TEMP LINE2+12 //温度的显示位置(4位)#define ADDR 0b11010000 //DS1307地址固定为0b11010000//宏定义,清屏#define CLR_LCD() \LCD_WRITE(0b00000001,COM); \DELAY(2)void CSH(void); //初始化void LCD_CSH(void); //LCD初始化void LCD_BUSY(void); //检测LCD是否忙char LCD_READ(void); //读LCD,忙检测用void LCD_WRITE(char,char); //LCD写1字节,命令或数据void DS1307(void); //DS1307显示程序void LCD_WRITE_4(char,char); //LCD写半字节void DISP_C(char); //在指定行中显示字符,字符在数组DD中void WRITE_DS1307(char,char); //写DS1307程序void READ_DS1307(char,char); //读DS1307程序void IIC_CSH(void);void IIC_SEND(char);signed char READ_TC74(void);void DISP_TC74(signed char);void DISP_MENU(const char *); //由常数数组显示整屏字符void BCD(unsigned int);void DELAY_US(char);void DELAY(unsigned int);void DELAY_I(unsigned int);void BCD_2(char,char); //2位BCD数转换成10进制void interrupt ISR(void);//修改中断void CHG_YEAR(void);//修改年void CHG_MONTH(void);//修改月void CHG_DAY(void);//修改日void CHG_WEEK(void);//修改星期void CHG_HOUR (void);//修改时void CHG_MINUTE(void);//修改分void CHG_SECOND(void);//修改秒//整屏界面,每行16个字符,最后加一个结束符const char MENU0[2][17]={{" WELCOME "},{" 010900411 "}};char SW,GW;#define LINE1 0b10000000#define LINE2 0b11000000const char LINE[2]={LINE1,LINE2};//定义结构体类型STRU的变量KEY//========主程序main(void){ signed char R1;DELAY(100);CSH();DISP_MENU(*MENU0); //显示整屏DELAY(2000);CLR_LCD();DS1307();while(1){R1=READ_TC74(); //读温度传感器的温度值DISP_TC74(R1); //显示温度值WRITE_DS1307(0x07,0b00010000); //OUT口输出方波,频率为1Hz READ_DS1307(0x00,7);BCD_2(SECOND,DD[0]); //显示时,分,秒BCD_2(MINUTE,DD[1]);BCD_2(HOUR,DD[2]);LCD_WRITE(WEEK,COM);LCD_WRITE(DD[3]+0x30,DA T); //WEEK就一位,可直接转换为ASCII 码BCD_2(DAY,DD[4]); //显示年,月,日BCD_2(MONTH,DD[5]);BCD_2(YEAR,DD[6]);if((DD[1]==0)&&DD[0]==0)//当整点时蜂鸣器响{ RC1=1;DELAY(200);}elseRC1=0;while(SET>=1) //功能键按下{ READ_DS1307(0x00,7);BCD_2(SECOND,DD[0]); //显示时,分,秒BCD_2(MINUTE,DD[1]);BCD_2(HOUR,DD[2]);LCD_WRITE(WEEK,COM);LCD_WRITE(DD[3]+0x30,DA T); //WEEK就一位,可直接转换为ASCII 码BCD_2(DAY,DD[4]); //显示年,月,日BCD_2(MONTH,DD[5]);BCD_2(YEAR,DD[6]);if(RB1==0){DELAY(150);CK++;if(CK>6)//总共7个数据,年...秒CK=0;}if(CK==0)CHG_YEAR();//修改年if(CK==1)CHG_MONTH();//修改月if(CK==2)CHG_DAY();//修改日if(CK==3)CHG_WEEK();//修改星期if(CK==4)CHG_HOUR();//修改时if(CK==5)CHG_MINUTE();//修改分if(CK==6)CHG_SECOND();//修改秒if(DD[0]&0x80==0x80) //判断CH=0?(且设定了初始值){ WRITE_DS1307(0x00,DD[0]); //秒WRITE_DS1307(0x01,DD[1]); //分WRITE_DS1307(0x02,DD[2]); //时WRITE_DS1307(0x03,DD[3]); //星期WRITE_DS1307(0x04,DD[4]); //号WRITE_DS1307(0x05,DD[5]); //月WRITE_DS1307(0x06,DD[6]); //年}}}}//========初始化端口void CSH(){ INTCON=0b10011000;TRISD=0b00000000; //控制LCD1604,全为输出TRISB=0b00000111; //键盘输入TRISC=0b00011000; //RC3,RC4为IIC接口,必须设置为输入,RC1为输出TRISA=0b00010000; //A4为输入口ANSEL=0b00000000; //A、E口为口做I/O口ANSELH=0b00000000; //B口为口做I/O口OPTION=0b00000000; //B口若上拉WPUB=0b11111111; //弱上拉使能LCD_CSH(); //LCD初始化IIC_CSH(); //IIC初始化RC1=0; //蜂鸣器不响RD7=1; //背光}void DS1307(void){ WRITE_DS1307(0x07,0b00010000); //OUT口输出方波,频率为1HzREAD_DS1307(0x00,7); //读取DS1307值(7个数据)if(DD[0]&0x80==0x80) //判断CH=0?(且设定了初始值){ WRITE_DS1307(0x00,0x00); //秒,55sWRITE_DS1307(0x01,0x59); //分,56minWRITE_DS1307(0x02,0x03); //时,23hWRITE_DS1307(0x03,0x04); //星期4WRITE_DS1307(0x04,0x27); //3号WRITE_DS1307(0x05,0x02); //5月WRITE_DS1307(0x06,0x08); //12年}LCD_WRITE(0b00001100,COM); //不闪LCD_WRITE(LINE1+1,COM); //第一行第1个字符LCD_WRITE(0x32,DA T); //在当前位置显示2LCD_WRITE(LINE1+2,COM); //第一行第2个字符LCD_WRITE(0x30,DA T); //在当前位置显示0LCD_WRITE(LINE1+5,COM); //第一行第5个字符LCD_WRITE('-',DA T); //在当前位置显示字符‘-’LCD_WRITE(LINE1+8,COM); //第一行第8个字符LCD_WRITE('-',DA T); //在当前位置显示字符‘-’LCD_WRITE(LINE1+11,COM); //第一行第11个字符LCD_WRITE('-',DA T); //在当前位置显示字符‘-’LCD_WRITE(LINE1+12,COM); //第一行第11个字符LCD_WRITE('W',DA T); //在当前位置显示字符‘W’LCD_WRITE(LINE1+13,COM); //第一行第11个字符LCD_WRITE('E',DA T); //在当前位置显示字符‘E’LCD_WRITE(LINE1+14,COM); //第一行第11个字符LCD_WRITE(':',DA T); //在当前位置显示字符‘:’LCD_WRITE(LINE2+5,COM); //第二行第5个字符LCD_WRITE(':',DA T); //在当前位置显示字符‘:’LCD_WRITE(LINE2+8,COM); //第二行第8个字符LCD_WRITE(':',DA T); //在当前位置显示字符‘:’LCD_WRITE(LINE2+14,COM); //第二行第14个字符LCD_WRITE(0xDF,DA T); //在当前位置显示字符‘°’LCD_WRITE(LINE2+15,COM); //第二行第15个字符LCD_WRITE('C',DA T); //在当前位置显示字符‘C’READ_DS1307(0x00,7);BCD_2(SECOND,DD[0]); //显示时,分,秒BCD_2(MINUTE,DD[1]);BCD_2(HOUR,DD[2]);LCD_WRITE(WEEK,COM);LCD_WRITE(DD[3]+0x30,DA T); //WEEK就一位,可直接转换为ASCII码BCD_2(DAY,DD[4]); //显示年,月,日BCD_2(MONTH,DD[5]);BCD_2(YEAR,DD[6]);}void DISP_TC74(signed char R1) //温度在R1{ LCD_WRITE(0b00001100,COM); //不闪LCD_WRITE(LINE2+12,COM); //DDRAM地址,第2行的第12个字符BCD(R1);LCD_WRITE(SW+0x30,DA T); //显示十位,数字加上0x30即为相应的ASCII码LCD_WRITE(GW+0x30,DA T); //显示个位,数字加上0x30即为相应的ASCII码}//LCD模块初始化void LCD_CSH(void){ DELAY(20); //延时20msLCD_WRITE_4(0b0011,COM); //发送控制序列DELAY_US(10); //延时100usLCD_WRITE_4(0b0011,COM); //发送控制序列DELAY_US(10); //延时100usLCD_WRITE_4(0b0011,COM); //发送控制序列DELAY_US(10); //延时100usLCD_WRITE_4(0b0010,COM); //4位数据格式LCD_BUSY(); //LCD忙检测LCD_WRITE(0b00101000,COM); //4位数据格式,4行,5×7点阵LCD_WRITE(0b00001100,COM); //D(d2)=1:打开显示,C(d1)=1:光标打开,B(d0)=1:光标闪烁LCD_WRITE(0b00000001,COM); //清除显示DELAY(2); //延时2msLCD_WRITE(0b00000110,COM); //输入模式,I/D(d1)=1:地址加1,S(d0)=1:显示移位关闭}//========读LCD状态char LCD_READ(void){ char R1;TRISD|=0x0F; //LCD数据线为输入LCD_RS=0; //寄存器选择LCD_RW=1;NOP(); //读为1LCD_E=1;NOP(); //使能R1=0; //短延时R1=PORTD&0x0F;LCD_E=0;NOP();LCD_E=1;NOP(); //使能R1=R1<<4; //读数据的高4位给R1高4位R1|= PORTD&0x0F; //读PORTD的0-3位,R1的高4位不变LCD_E=0;NOP(); //读数据结束LCD_RW=0;TRISD&=0xF0; //LCD数据线为输出return (R1);}//写一字节数R1,FLAG为写命令或数据选择,0为写命令,1为写数据//写之前先检查是否忙,写完后延时100us,分二次写4位数据/命令void LCD_WRITE(char R1,char FLAG){ char R2;LCD_BUSY();R2=R1&0xF0; //低4位清0R2=R2>>4; //取高4位LCD_WRITE_4(R2,FLAG); //先写高4位R2=R1 & 0x0F; //高4位清0,取低4位LCD_WRITE_4(R2,FLAG); //再写低4位DELAY_US(10); //延时100us}//写R1的低4位,FLAG为寄存器选择,1为命令,0为数据void LCD_WRITE_4(char R1,char FLAG){ LCD_RW=0; //写模式LCD_RS=FLAG; //寄存器选择PORTD&= 0xF0;; //RD的数据4位清0LCD_E=1; //使能PORTD|=R1; //送R1的低4位至RD口的高4位NOP();NOP(); //短延时LCD_E=0; //数据送入有效LCD_RS=0;PORTD&=0xF0; //RD的数据低4位清0}//========检测LCD是否忙void LCD_BUSY(void){ unsigned char R1;while(1){ R1=LCD_READ(); //读寄存器if ((R1 & 0x80)==0x00) //最高位为忙标志位break;};}//在line行显示整行,共16个字符,字符在数组DD中,注意显示字符直接将字符放入DD数组//而显示数字时则要将数值转换成显示的ASC码void DISP_C(char line){char i;LCD_WRITE(line,COM); //写行命令for (i=0;i<16;i++)LCD_WRITE(DD[i],DA T); //写16个数据,即显示1行}//完全按照数组中的字符显示整屏void DISP_MENU(const char *A){char i,j;for (i=0;i<2;i++){ for (j=0;j<16;j++)DD[j]=*A++;A++; //因为末尾还有结束字符!DISP_C(LINE[i]);}}//写DS1307,地址为address,数为datavoid WRITE_DS1307(char address,char data){ SEN=1;while(SEN==1); //起始位发送完成IIC_SEND(ADDR);IIC_SEND(address);IIC_SEND(data);PEN=1; //发送停止位while(PEN==1);}//读DS1307,读出的结果在START_ADDR,要读的数字节数位n //当START_ADDR=0,n=7时为时间void READ_DS1307(char START_ADDR,char n){ char i;SEN=1;while(SEN==1); //起始位发送完成IIC_SEND(ADDR); //写寄存器地址IIC_SEND(START_ADDR); //设定寄存器初始地址PEN=1; //发送停止位while(PEN==1);RSEN=1; //发送重新起始位while(RSEN==1); //发送重新起始位完成IIC_SEND(ADDR+1); //最后低位为1表示读for(i=0;i<n;i++) //共n个数{ RCEN=1; //读使能while(RCEN==1); //等待读完成DD[i]=SSPBUF; //读1字节if(i<n-1){ACKDT=0;ACKEN=1;while(ACKEN==1);}else{ACKDT=1;ACKEN=1;while(ACKEN==1);} //最后一个字节不应答}PEN=1; //发送停止位while(PEN==1);}//读TC74的温度值signed char READ_TC74(void){ signed char R1;SEN=1; //开始条件while (SEN==1); //检测开始条件是否完成?IIC_SEND(TC74_ADD<<1);//送TC74地址(写)IIC_SEND(RTR); //写RTR命令(写)RSEN=1; //重新开始条件while (RSEN==1); //等待重新开始条件结束IIC_SEND((TC74_ADD<<1)+1);//发送TC74地址(读)RCEN=1; //接收使能while (RCEN==1); //等待接收完成R1=SSPBUF; //接收数据存入R1PEN=1; //停止位while(PEN==0);return(R1);}//发送数R并等待发送完成,收到从机的应答信号void IIC_SEND(char R){ SSPBUF=R; //发送while (RW==1); //在主动模式下,判断发送是否完成while (SSPIF==0); //等待发送完成while (ACKSTA T==1); //等待从机发送应答信号}//IIC初始化void IIC_CSH(void){ TRISC&=0b00011000; //SDA,SCL设置为输入!SSPCON=0b00101000; //同步串口使能(SSPEN),主控方式SMP=0; //使能高速模式(400 kHz) 的压摆率控制SSPADD=4; //主控模式为波特率值,每位时间T=(SSPADD+1)/Tcy=5us}void BCD_2(char add,char dat) //两位数显示{char shi,ge;shi=dat>>4; //取高位ge=dat&0x0F; //取低位LCD_WRITE(add,COM);LCD_WRITE(shi+0x30,DA T);LCD_WRITE(ge+0x30,DA T);}//从R1双字节数转换为十进制数十位-个位:SW,GWvoid BCD(unsigned int R1){ SW=0;GW=0;while(R1>=10){R1-=10; SW++;}GW=R1;}//======延时(n)msvoid DELAY(unsigned int n){unsigned int j;char k;for (j=0;j<n;j++)for (k=246;k>0;k--) NOP();}//======延时(n)ms,中断专用void DELAY_I(unsigned int n){ unsigned int j;char k;for (j=0;j<n;j++)for (k=246;k>0;k--) NOP();}//======延时(n×10)usvoid DELAY_US(char n){ char j;for (j=0;j<n;j++){NOP();NOP();}}void interrupt ISR(void)//INT中断,统计功能键{if(INTF==1){DELAY_I(30);//躲过震荡INTF=0;//清中断标志位SET++;//按下一次if(SET>=2)//按下两次,清零SET=0;}}void CHG_YEAR(void){if(RA4==1){ LCD_WRITE(YEAR+1,COM);//修改年,显示空LCD_WRITE(' ',DA T);}if(RB2==0){DELAY(150);DD[6]++;if((DD[6]&0X0F)>9)//低位大于9{DD[6]=DD[6]+6;}if(DD[6]>0x99)DD[6]=0x00; //大于2099年,复位2000年BCD_2(YEAR,DD[6]);//显示修改后的值}BCD_2(YEAR,DD[6]);}void CHG_MONTH(void){if(RA4==1){LCD_WRITE(MONTH+1,COM);//修改年,显示空LCD_WRITE(' ',DA T);}if(RB2==0){DELAY(150);DD[5]++;if((DD[5]&0X0F)>9)//低位大于9{DD[5]=DD[5]+6;}if(((DD[5]&0X0F)>2)&&((DD[5]&0xF0)>0))//月份大于12DD[5]=0X01;BCD_2(MONTH,DD[5]);//显示修改后的值}BCD_2(MONTH,DD[5]);}void CHG_DAY(void){if(RA4==0){LCD_WRITE(DAY+1,COM);//修改年,显示空LCD_WRITE(' ',DA T);}if(RB2==0){DELAY(150);DD[4]++;if((DD[5]==1)||(DD[5]==3)||(DD[5]==5)||(DD[5]==7)||(DD[5]==8)||(DD[5]==0x10)||(DD[5]==0x 12))//大月{if((DD[4]&0x0F)>9) //低位大于9,进十位DD[4]=DD[4]+6;if(DD[4]>0x31)DD[4]=0x01; //大于31号,复位1号}if(DD[5]==2) //月份2{if((DD[4]&0x0F)>9) //低位大于9,进十位DD[4]=DD[4]+6;if(DD[6]%4==0||(DD[ 6]==0x12)||(DD[6]==0x16)||(DD[6]==0x32)||(DD[6]==0x36)||(DD[5]==0x 52)||(DD[5]==0x56)){if(DD[4]>0x29)DD[4]=0x01; //大于29号,复位1号}else{if(DD[4]>0x28)DD[4]=0x01; //大于28号,复位1号}}if((DD[5]==4)||(DD[5]==6)||(DD[5]==9)||(DD[5]==0x11))//小月{if((DD[4]&0x0F)>9) //低位大于9,进十位DD[4]=DD[4]+6;if(DD[4]>0x30)DD[4]=0x01; //大于30号,复位1号}BCD_2(DAY,DD[4]);//显示修改后的值}BCD_2(DAY,DD[4]);//显示修改后的值}void CHG_WEEK(void){if(RA4==0){LCD_WRITE(WEEK,COM);//修改年,显示空LCD_WRITE(' ',DA T);DELAY(300);}if(RB2==0){DELAY(150);DD[3]++;if(DD[3]>7)//星期大于7DD[3]=1;LCD_WRITE(WEEK,COM);LCD_WRITE(DD[3]+0x30,DA T);}LCD_WRITE(WEEK,COM);LCD_WRITE(DD[3]+0x30,DA T);}void CHG_HOUR(void){if(RA4==0){LCD_WRITE(HOUR+1,COM); //修改小时,显示空LCD_WRITE(' ',DA T);DELAY(300);}if(RB2==0){DELAY(150);DD[2]++;if((DD[2]&0X0F)>9) //低位大于9{DD[2]=DD[2]+6;}if(((DD[2]&0X0F)==4)&&((DD[2]&0xF0)==0x20))//时间大于24DD[2]=0X00;BCD_2(HOUR,DD[2]); //显示修改后的值}BCD_2(HOUR,DD[2]); //显示修改后的值}void CHG_MINUTE(void){if(RA4==1){LCD_WRITE(MINUTE+1,COM); //修改年,显示空LCD_WRITE(' ',DA T);DELAY(300);}if(RB2==0){DELAY(150);DD[1]++;if((DD[1]&0x0F)>9) //低位大于9{DD[1]=DD[1]+6;}if((DD[1]&0xF0)>0x59) //时间>=60DD[1]=0x00;BCD_2(MINUTE,DD[1]); //显示修改后的值}BCD_2(MINUTE,DD[1]); //显示修改后的值}void CHG_SECOND(void){if(RA4==1){LCD_WRITE(SECOND+1,COM); //修改年,显示空LCD_WRITE(' ',DA T);DELAY(300);}if(RB2==0){DELAY(150);DD[0]++;if((DD[0]&0x0F)>9) //低位大于9{DD[0]=DD[0]+6;}if(DD[0]>0x59) //时间>=60DD[0]=0x00;BCD_2(SECOND,DD[0]); //显示修改后的值}BCD_2(SECOND,DD[0]); //显示修改后的值}。