/*
程序名:?  ?LCD1602,4位數據總線液晶屏時鐘,STC12C5A60S2的10位ADC功能程序
編寫時間:  2015年10月4日
硬件支持:  LCD1602液晶屏??STC12C5A60S2 外部12MHZ晶振?
接線定義:???DB7?-->?P1^7DB6?-->?P1^6DB5?-->?P1^5DB4?-->?P1^5RS??-->?P3^2;RW??-->?P3^3;E???-->?P3^4;ADC?-->?P1^0;?給0--5V的電位器調電壓*/#include?<STC12C5A60S2.H>?//單片機頭文件
#include?<intrins.h>?//51基本運算(包括_nop_空函數)
typedef?unsigned?char??????uint8;??????????//?無符號8位整型變量?//
#define?LCM2402_DB0_DB7?P1??//?定義LCM2402的數據總線
sbit?LCM2402_RS???=?P3?^?2;???//?定義LCM2402的RS控制線
sbit?LCM2402_RW???=?P3?^?3;???//?定義LCM2402的RW控制線
sbit?LCM2402_E????=?P3?^?4;???//?定義LCM2402的E控制線
sbit?LCM2402_Busy?=?P1?^?7;???//?定義LCM2402的測忙線(與LCM2402_DB0_DB7關聯)
data?unsigned?char?TIME_DD,TIME_MO,TIME_YY,TIME_WW,TIME_HH,TIME_MM,TIME_SS;//設置日、月、年、周、時、分、秒和溫度存放區
data?bit?DAY_BIT?=?0;//天數增加標志位(用于日期進位的啟動)
data?unsigned?char?DIS_BIT?=?0;?//多種信息的切換顯示
data?unsigned?char?cou??=?0;?????//?軟計數器,對10ms時基信號累加到1s?//?定義LCM2402指令集?//?(詳細請見技術手冊)
#define??CMD_clear?0x01????????????//?清除屏幕
#define??CMD_back?0x02?????????????//?DDRAM回零位
#define??CMD_dec1?0x04?????????????//?讀入后AC(指針)減1,向左寫
#define??CMD_add1?0x06?????????????//?讀入后AC(指針)加1,向右寫
#define??CMD_dis_gb1?0x0f??????????//?開顯示_開光標_開光標閃爍
#define??CMD_dis_gb2?0x0e??????????//?開顯示_開光標_關光標閃爍
#define??CMD_dis_gb3?0x0c??????????//?開顯示_關光標_關光標閃爍
#define??CMD_OFF_dis?0x08??????????//?關顯示_關光標_關光標閃爍
#define??CMD_set82?0x38????????????//?8位總線_2行顯示
#define??CMD_set81?0x30????????????//?8位總線_1行顯示(上邊行)
#define??CMD_set42?0x28????????????//?4位總線_2行顯示
#define??CMD_set41?0x20????????????//?4位總線_1行顯示(上邊行)
#define??lin_1??0x80???????????????//?4位總線_1行顯示(上邊行)
#define??lin_2??0xc0???????????????//?4位總線_1行顯示(上邊行)
#define??ct???2????????????????????//?寫入命令,寫入數據?E能端?持續的毫秒void?DELAY_MS?(unsigned?int?a){unsigned?int?i;while(?--a?!=?0){for(i?=?0;?i?<?600;?i++);}
}//?LCM2402測忙,若LCM2402處于忙狀態,本函數將等待至非忙狀態?//
void?LCM2402_TestBusy(void){LCM2402_DB0_DB7?=?0xff;?//設備讀狀態LCM2402_RS?=?0;LCM2402_RW?=?1;LCM2402_E?=?1;while(LCM2402_Busy);?//等待LCM不忙LCM2402_E?=?0;??//
}//?寫指令程序?//
//?向LCM2402寫命令?本函數需要1個指令集的入口參數?//
void?LCM2402_WriteCMD(uint8?LCM2402_command)?{?LCM2402_TestBusy();LCM2402_RS?=?0;LCM2402_RW?=?0;LCM2402_DB0_DB7?=?(LCM2402_command/16)<<4;//0x45?0x40??LCM2402_E?=?1;DELAY_MS(ct);?LCM2402_E?=?0;LCM2402_DB0_DB7?=?(LCM2402_command%16)<<4;//0x45?0x50LCM2402_E?=?1;DELAY_MS(ct);?LCM2402_E?=?0;
}//?向LCM2402寫數據?//
void?LCM2402_WriteData(uint8?LCM2402_data){?LCM2402_TestBusy();LCM2402_RS?=?1;LCM2402_RW?=?0;LCM2402_DB0_DB7?=?(LCM2402_data/16)<<4;LCM2402_E?=?1;DELAY_MS(ct);?LCM2402_E?=?0;LCM2402_DB0_DB7?=?(LCM2402_data%16)<<4;LCM2402_E?=?1;DELAY_MS(ct);?LCM2402_E?=?0;
}?//?向LCM發送一個字符串,長度48字符之內?
void?print(uint8?a,uint8?*str){LCM2402_WriteCMD(a?|?0x80);while(*str?!=?'\0'){LCM2402_WriteData(*str++);}*str?=?0;
}//?打印單字符程序?//?
void?print2(uint8?a,uint8?t){LCM2402_WriteCMD(a?|?0x80);LCM2402_WriteData(t);
}//?定義小漢字??可寫入16個自字義字符,寫入后可用其CGRAM代碼直接提取顯示。
uint8?code?Xword[]={0x18,0x18,0x07,0x08,0x08,0x08,0x07,0x00,????????//℃,代碼?0x000x00,0x00,0x00,0x00,0xff,0x00,0x00,0x00,????????//一,代碼?0x010x00,0x00,0x00,0x0e,0x00,0xff,0x00,0x00,????????//二,代碼?0x020x00,0x00,0xff,0x00,0x0e,0x00,0xff,0x00,????????//三,代碼?0x030x00,0x00,0xff,0xf5,0xfb,0xf1,0xff,0x00,????????//四,代碼?0x040x00,0xfe,0x08,0xfe,0x0a,0x0a,0xff,0x00,????????//五,代碼?0x050x00,0x04,0x00,0xff,0x00,0x0a,0x11,0x00,????????//六,代碼?0x060x00,0x1f,0x11,0x1f,0x11,0x11,0x1f,0x00,????????//日,代碼?0x07
};
void?CgramWrite(void)?{?//?裝入CGRAM?//uint8?i;LCM2402_WriteCMD(0x06);??//?CGRAM地址自動加1LCM2402_WriteCMD(0x40);??//?CGRAM地址設為00處for(i=0;i<64;i++)?{LCM2402_WriteData(Xword[i]);//?按數組寫入數據}
}//?LCM2402初始化?//(使用者可自定義,加?*?號程序行必須保留但可修改)
void?LCM2402_Init(void){LCM2402_WriteCMD(CMD_set42);?//*?顯示模式設置:顯示2行,每個字符為5*7個像素LCM2402_WriteCMD(CMD_set42);?//*?顯示模式設置:顯示2行,每個字符為5*7個像素LCM2402_WriteCMD(CMD_clear);?//??顯示清屏LCM2402_WriteCMD(CMD_back);?//*?數據指針指向第1行第1個字符位置LCM2402_WriteCMD(CMD_add1);?//??顯示光標移動設置:文字不動,光標右移LCM2402_WriteCMD(CMD_dis_gb3);??//??顯示開及光標設置:顯示開,光標開,閃爍開CgramWrite();???//??向CGRAM寫入自定義字符
}bit?IsLeapYear(void){????//計算本年是否是潤年?unsigned?int?a;a?=?2000+TIME_YY;//加2000表示成完整的年if((a%4==0?&&?a%100!=0)||(a%400==0)){?//潤年的計算公式return?1;//是潤年返回1?}else{?return?0;//不是潤年返回0?}
}?void?month_day(void){??unsigned?char?mon_day[]={31,28,31,30,31,30,31,31,30,31,30,31};TIME_DD++;//天加1TIME_WW++;//星期值加1if(TIME_WW?>?7){TIME_WW?=?1;//時期值限定}if(TIME_DD?>?mon_day[TIME_MO-1]){//檢查天是否大于當月的最大值if(IsLeapYear()&&TIME_MO==2){?//計算本月是否是潤年的2月份?TIME_DD?=?29;//如果是潤年又是2月,則天為29}else{TIME_DD?=?1;?//否則就等于1TIME_MO++;//月加1if(TIME_MO?>?12){TIME_MO?=?1;?//如果月大于12則月等于1TIME_YY++;//年加1?(公歷年無限積加)}}}
}?void?init?(void){?//上電初始化TMOD?=?0x11;?????????//?定時/計數器0,1工作于方式1???TH0?=?0x3c;??????????//?預置產生50ms時基信號???TL0?=?0xb0;???EA?=?1;??????????????//?開總中斷???ET0?=?1;?????????????//?定時/計數器0允許中斷???TR0?=?1;?????????????//?開閉定時/計數器0???TIME_DD?=?4;?//時間在首次使用的值,之后會在EEPROM自動記錄上一天的值TIME_MO?=?10;?//初始時間:2009年5月18日周一,20時13分40秒TIME_YY?=?15;TIME_WW?=?1;TIME_HH?=?0;TIME_MM?=?35;TIME_SS?=?0;
}//顯示項目?時間部分?在第一行全行顯示時間
void?RealTime_Display(void){print(0x80,"20");print2(0x82,TIME_YY/10+0x30);print2(0x83,TIME_YY%10+0x30);print(0x84,"/");????????????//?顯示年print2(0x85,TIME_MO/10+0x30);print2(0x86,TIME_MO%10+0x30);print(0x87,"/");????????????//?顯示月print2(0x88,TIME_DD/10+0x30);print2(0x89,TIME_DD%10+0x30);print(0x8b,"[");????????????//?顯示[print2(0x8c,TIME_WW%10);?//星期print(0x8d,"]");????????????//?顯示]print2(0x40,TIME_HH/10+0x30);//小時print2(0x41,TIME_HH%10+0x30);print(0x42,":");????????????//?顯示cgram第一個字模":"print2(0x43,TIME_MM/10+0x30);//分鐘print2(0x44,TIME_MM%10+0x30);print(0x45,".");????????????//?顯示cgram第一個字模"."print2(0x46,TIME_SS/10+0x30);//秒print2(0x47,TIME_SS%10+0x30);
}/***
函數名:10位A/D轉換初始化函數
調??用:Read_init?(?);
參??數:輸入的端口(0000?0XXX?其中XXX是設置輸入端口號,可用十進制0~7表示,0表示P1.0,7表示P1.7)
返回值:無
結??果:開啟ADC功能并設置ADC的輸入端口
備??注:使用ADC功能時需要將對應的IO接口設置為高阻輸入方式(例如:P1M1?=?0x01;)
***/
void?Read_init?(unsigned?char?CHA){unsigned?char?AD_FIN=0;?//存儲A/D轉換標志CHA?&=?0x07;????????????//選擇ADC的8個接口中的一個(0000?0111?清0高5位)ADC_CONTR?=?0x40;?//ADC轉換的速度(0XX0?0000?其中XX控制速度,請根據數據手冊設置)_nop_();ADC_CONTR?|=?CHA;???????//選擇A/D當前通道_nop_();ADC_CONTR?|=?0x80;??????//啟動A/D電源DELAY_MS(1);????????????//使輸入電壓達到穩定(1ms即可)
}/***
函數名:10位A/D轉換函數
調??用:??=?ADC_Read();
參??數:無
返回值:10位ADC數據高(從0到1023(十進制))
結??果:讀出指定ADC接口的A/D轉換值,并返回數值
備??注:適用于STC12C5A60S2系列單片機(必須使用STC12C5A60S2.h頭文件)
***/
unsigned?int?ADC_Read?(void){?//?int?2個字節,16位unsigned?char?AD_FIN=0;?//存儲A/D轉換標志ADC_CONTR?|=?0x08;??????//啟動A/D轉換(0000?1000?令ADCS?=?1)_nop_();_nop_();_nop_();_nop_();while?(AD_FIN?==0){?????//等待A/D轉換結束AD_FIN?=?(ADC_CONTR?&?0x10);?//0001?0000測試A/D轉換結束否}ADC_CONTR?&=?0xE7;??????//1111?0111?清ADC_FLAG位,?關閉A/D轉換,?
return?(ADC_RES*4+ADC_RESL);//返回A/D轉換結果(10位ADC數據高8位在ADC_RES中,低2位在ADC_RESL中)//內部寄存器ADC_RES返回的值,在反給int時,左移兩位,空兩位出來給低兩位ADC_RESL
}void?main?(void){
unsigned?int?m;??//?m必須是16位的數據類型!init();//初始化???????????????????????????LCM2402_Init();//LCM2402初始化P1M1?=?0x01;//??高阻會有感應,用哪一個就開啟哪一個???????????????????????????Read_init?(0);??//?選取P1^0引腳while(1){??RealTime_Display();?
m?=?ADC_Read?();//m必須是16位的數據類型!
print2(0x4A,m/1000+0x30);
print2(0x4B,(m%1000)/100+0x30);
print2(0x4C,(m%100)/10+0x30);
print2(0x4D,m%10+0x30);if(DAY_BIT?==?1){?//檢查天數是否更新,是則計算公歷month_day();//計算公歷日期?DAY_BIT?=?0;//計算完成后將日期變更標志位置0}}
}void?tiem0(void)?interrupt?1{???//?T/C0中斷服務程序(產生50ms時基信號)???cou++;??????????????????????//?軟計數器加1???if(cou?>?19){?????????????????//?計數值到100(1s)???cou?=?0;???????????????//?軟計數器清零???TIME_SS++;?????????????????//?秒計數器加1(進位10ms*100=1s)???if(TIME_SS?>?59){??????????//?秒計數值到60???TIME_SS?=?0;???????????//?秒計數器清零???TIME_MM++;?????????????//?分計數器加1(進位60s=1m)??if(TIME_MM?>?59){??????//?分計數到60???TIME_MM?=?0;???????//?分計數器清零???TIME_HH++;?????????//?時計數器加1(進位60m=1h)???if(TIME_HH?>?23){??//?時計數到23???TIME_HH?=?0;???//?時計數器清零DAY_BIT?=?1;?//天增加標志位?}??}???}???}???TH0?=?0x3c;????????????????//?重置定時常數???TL0?=?0xb0;???
}



wKioL1YRIB2zgJzlAAKuRZMP6c4875.jpg