字體:小 中 大 | |
|
|
2019/02/04 17:00:14瀏覽657|回應0|推薦0 | |
鬧鐘3精簡版實作程式說明(W/O PCF8574T/AT) 鬧鐘3精簡版實作程式說明(W/O PCF8574T/AT) 過年假期,突然想到可以將原先"單晶片MCU STC12C5608AD的時鐘程式"一文中的I2C_LCM使用之PCF8574AT/T加以省去,直接用MCU剩餘的I/O腳來控制,最早期在LCD的介面完全用I/O腳時,總共需8個DATA+3個控制信號=11支I/O腳,算起來在小型MCU來說是很佔用數量不多的I/O腳,,之後利用PCF8974AT/T的I2C介面將LCM介面精簡至2個I/O腳就可以控制的程度,當然就是使用I2C_LCM介面板,如此成本也就增加百餘元之多,幾乎佔了LCM模組成本的1/3之多,有機會用到STC15C5608AD後有23個I/O腳,比原先的ATMEL 89C4052的I/O腳只有15腳,足足多出8個I/O腳,因此才想到如果用I2C_LCM的4BIT傳送模式的話,I/O只需要7支腳即可,而"單晶片MCU STC12C5608AD的時鐘程式"一文中有足足一個P1未使用,正可以用來給LCM的4BIT介面,如此就可以省下一個I2C_LCM介面板的成本,所以就動手修改線路與程式,來分享給各位同好。 基本上此次的修改是使用"鬧鐘2.0加強版功能說明"一文中的基礎加以修改的,還好一切尚稱順利,將LCM的4個DATA+3個控制腳與一只20K偏壓的可變電阻焊上後,就直接修改之前的 I2CPCF8574.c 與主程式,沒想到還很順利在短短3個小時就搞定,雖然尚未利用示波器與LA量測整個LCM介面的信號波形與量測時序,來確認時序是否符合規格,就先行將修改之部份撰文分享之。 本文將敘述的部份有2個部份,第一部份是主程式部份,這部份在解釋修改後之LCD顯示指令與I/O腳定義而已,而第2部份則重點在介紹 LCD4.c 的副程式,這是在此次實驗中最主要的部份,將來如果有進一步修改LCM時序時,會不定時再更新。 線路圖
照片#1
照片#2
照片#3
照片#4
<<程式說明:>> (本文所列之程式,將會不定時的更新或修改,各位同好可視檔案抬頭所註明之更新日期分辨之,不便之處,尚請原諒。) /*----------------------------------------------- 檔案名稱:LT-TEST_06.c @2019/02/04 PM 12:00 程式說明: 此程式在撰寫一個由MCU內部的 Timmer 0 計時器來實現時鐘, 而重點在構思不使用 RTC DS1302 晶片下, 只利用計時器定時中斷的功能, 並且在程式責寫時加入三個 CTx,CTy,CTz變數,來修正石英振盪晶體的頻率 之差異,而且可以利用UART指令來設定修正的數值. 附註 : STC12C5608AD 單晶片MCU @2019/01/24 STC12C5608AD, XTALL=22.1184MHZ,I2C-LCM @2019/01/25 added BUZZ & ALARM command @2019/01/26 added SW1~SW4 functions @2019/01/26 ALARM array had 11 sets, @2019/01/28 added 1 more ALARM array @2019/01/31 added ALARM for the UART checksum error & UART command error @2019/02/04 拿去 PCF8574T/AT ------------------------------------------------*/ #include "reg52.h" #include "stdio.h" #include "stdlib.h" #include "intrins.h" #include "string.h" #include "delay.c" #include "LCD4.c"
unsigned char* RC ="TEST_06 2019-02-04\r\n"; unsigned char* SPC=" "; #define XTAL 22118400 //XTAL 外部石英晶體 22.1184 Mhz #define BAUDRATE 115200 //UART BAUDRATE 115200,8,N,1 #define UARTSIZE 12 //Uart buffer size #define BS 0x08 //\b backspace code #define WAIT 10 #define WAIT5 5 #define IEPROM 0x1ff9 typedef unsigned char BYTE; typedef unsigned int WORD; typedef unsigned long DWORD;
sbit CDS = P3^2; //CDS sensor input //sbit = P3^3; // //sbit LCM_SDA = P3^4; //PCF8574AT SDA //sbit LCM_SCL = P3^5; //PCF8574AT SCL sbit ALARM = P3^7; //ALARM out
sbit RS = P1^0; //LCD4 RS sbit RW = P1^1; //LCD4 RW sbit EN = P1^2; //LCD4 EN sbit OUT3 = P1^3; // sbit OUT4 = P1^4; //LCD D4 sbit OUT5 = P1^5; //LCD D5 sbit OUT6 = P1^4; //LCD D6 sbit OUT7 = P1^5; //LCD D7
sbit LED_GRN =P2^7; sbit LED_YEW =P2^6; sbit LED_BLU =P2^5; sbit LED_RED =P2^4; sbit SW4 =P2^3; sbit SW3 =P2^2; sbit SW2 =P2^1; sbit SW1 =P2^0; /*------------------------------------------------ 整體變數宣告 ------------------------------------------------*/ bit Turn_flag=0,SetFlag=0,busy=0,LCD_flag,DISP_flag=0,BUZZ=0,CDS_flag,CT_flag=0;
unsigned char temp[40]; unsigned char UART_buf[UARTSIZE]; //UART RCV Buffer unsigned char ALM[12][2]= {{0,7},{5,7},{10,7},{15,7},{20,7},{25,7},{30,7},{35,7},{40,7},{45,7},{50,7},{55,7}}; //ALARM array unsigned xdata AC_ms=0,Rcv_idx,AC_sec,AC_min,AC_hrs,AC_day,AC_mth,AC_yer,CTx,CTy,CTz; unsigned xdata ALM_no; //ALARM set no. unsigned short CT,CDS_cnt; /*------------------------------------------------ 函數聲明 ------------------------------------------------*/ void Init_Timer0(void); void Init_Timer1(void); void Uart_SendStr(unsigned char *value,unsigned int leng); void Uart_PutChar(unsigned char dat); void Uart_ISR_Handle(void); void Uart_cmd(void); // UART接收指令處理副程式 void Sent_Uart(void); // UART送出訊息 void CHECK_year(void); // 萬年曆檢查副程式 void LED_flash(void); // LED閃爍 /*------------------------------------------------ 主程式 ------------------------------------------------*/ void main(void) { unsigned char i=0,k; //
P1 = P2 = P3 =0xff; AUXR &= 0xbf; CT=58921; // Timer 0 count down參數基值 Init_Timer0(); // 計時器初始化 Init_Timer1(); // UART baus rate LCD4_Device_Init(); //啟動LCM介面板與 1602液晶螢幕 DelayMs(WAIT5); //需延遲待待LCD螢幕內部運作 CDS_cnt=0;DISP_flag=0; for(i=0;i SetFlag=0; // 完成 LCM 的初啟程式.清除旗號 LCD4_Write_Command(0x01); //清除螢幕內容, DelayMs(WAIT5); AC_sec=AC_min=0,AC_hrs=12;AC_day=4;AC_mth=2;AC_yer=19; ET0=1; TR0=1; ES=1; EA=1; //打開總中斷 //********************************** Uart_SendStr(RC,22); //system start, sent the system information to UART DelayMs(WAIT5); sprintf(temp,"%2d/%d/%d ",(int)AC_yer,(int)AC_mth,(int)AC_day); // 顯示 年/月/日 時間; if(RI==0) { LCD4_Write_String(0,0,temp); } Rcv_idx=0; CDS_flag=0; while(1) //主程式 { BUZZ=1;ALM_no=0;CTx=0;CTy=50;CTz=0; START: //************************** ES=1;LED_YEW=~BUZZ;
if(SetFlag==1) //UART HAD COMMAND RECIVED { DISP_flag=0;LED_BLU=0; k=0; //****** UART CHECKSUM for(i=0;i<10;i++) k="k%256+(int)UART_buf[i];}" p=""> if((int)UART_buf[11] == k) //比對CHECKSUM值 { Uart_cmd(); } else { BUZZ=1;DelayMs(100);BUZZ=0;BUZZ=1;DelayMs(100);BUZZ=0; } //CHECKSUM ERROR //顯示接收到的 UART DATA if(DISP_flag==0) { sprintf(temp,"%02x%02x%02x%02x",(int)UART_buf[2],(int)UART_buf[3],(int)UART_buf[4],(int)UART_buf[5]); LCD4_Write_String(0,1,temp); sprintf(temp,"%02x %02x<%02x",(int)uart_buf[6],(int)uart_buf[11],(int)k); p=""> LCD4_Write_String(8,1,temp); } SetFlag=0;Rcv_idx=0;LED_BLU=1; } //**************************** if(Turn_flag==1 ) { LED_GRN=~LED_GRN; if(AC_min>=60 ) // 是否時間"分"已滿60分 { AC_min=0;AC_hrs++; if(CTz >= AC_hrs) // 判斷是否需要補加"秒"數 { AC_sec++; } } if(AC_hrs>=24 ) // 判斷是否已滿24小時 { AC_hrs=0;AC_day++; CHECK_year(); // 萬年曆檢核 } if((AC_sec/3)>11 ) // 顯示 ALARM時間 lister { sprintf(temp,"%d/%d/%2d ",(int)AC_yer,(int)AC_mth,(int)AC_day); } // 顯示 年/月/日 時間; else { LCD4_Write_String(0,0," "); sprintf(temp,"%d %d:%d ",(int)AC_sec/3,(int)ALM[AC_sec/3][1],(int)ALM[AC_sec/3][0]); } if(RI==0) { LCD4_Write_String(0,0,temp); } sprintf(temp,"%2d:%2d:%2d",(int)AC_hrs,(int)AC_min,(int)AC_sec); //顯示 CLOCK 時間 if(RI==0) { LCD4_Write_String(8,0,temp); } for(i=0;i<12;i++) vertify="" the="" alarm="" set="" current="" time="" p=""> { if(ALM[i][1]==AC_hrs && ALM[i][0]==AC_min && (AC_sec%2)==0) { BUZZ=1;goto AAA; } // 比對 ALARM時間是否吻合 if(ALM[i][1]!=AC_hrs || ALM[i][0]!=AC_min ) { BUZZ=0; } } AAA: if(CDS==0 && CDS_flag==0) { CDS_cnt++;LED_RED=0;CDS_flag=~CDS_flag;CT_flag=1;BUZZ=1;DelayMs(100); BUZZ=0;} //check CDS detector ON else { if(CDS==1 && CDS_flag==1) { LED_RED=1;CDS_flag=~CDS_flag; } } //check CDS detector OFF if(SW1==0 ) //check SW1 for display CDS_cnt, CTx, CTy, CTz data { while(SW1==0) { LED_flash(); } LCD4_Write_String(0,1,SPC); CT_flag=1; sprintf(temp,"CDS_cnt=%5d, CTx=%2x, CTy=%2x, CTz=%2x\r\n",(short)CDS_cnt,(int)CTx,(int)CTy,(int)CTz); //列印 CDS_cnt, CTx, CTy與 CTz 的數值 Uart_SendStr(temp,strlen(temp)); } if(SW2==0) // auto set the alarm by 5 minters { while(SW2==0) { LED_flash(); } for(i=0;i<12;i++) p=""> { ALM[i][1]=AC_hrs; } } if(SW3==0) // 設定5分鐘後蜂鳴器提醒 { while(SW3==0) { LED_flash(); } ALM[0][1]=AC_hrs; ALM[0][0]=AC_min+5; if( ALM[0][0]>=60) {ALM[0][0]=ALM[0][0]-60;ALM[0][1]++; } if( ALM[0][1]>=24) {ALM[0][1]=ALM[0][1]-24; } } if(SW4==0) // 設定10分鐘後蜂鳴器提醒 { while(SW4==0) { LED_flash(); } ALM[0][1]=AC_hrs; ALM[0][0]=AC_min+10; if( ALM[0][0]>=60) {ALM[0][0]=ALM[0][0]-60;ALM[0][1]++; } if( ALM[0][1]>=24) {ALM[0][1]=ALM[0][1]-24; } } if(CT_flag==1) { LCD4_Write_String(0,1,SPC); sprintf(temp,"%5d ",(short)CDS_cnt); if(RI==0) {LCD4_Write_String(0,1,temp);} sprintf(temp,"%2d %2d %2d ",(int)CTx,(int)CTy,(int)CTz); //顯示 CDS_cnt, CTx, CTy與 CTz 的數值 if(RI==0) {LCD4_Write_String(7,1,temp);} CT_flag=0; } Turn_flag=0; } goto START; } } //******************************** void LED_flash(void) { LED_RED=LED_GRN=LED_BLU=LED_YEW=0;DelayMs(100); LED_RED=LED_GRN=LED_BLU=LED_YEW=1;DelayMs(100); } void CHECK_year(void) { if((AC_mth==4 || AC_mth==6 || AC_mth==9 || AC_mth==11) && AC_day>=31) {AC_day=1;AC_mth++;goto C0;} //判斷有31日的月份 else { if(AC_mth==2 && AC_day>=29 && (AC_yer%4)!=0) {AC_day=1;AC_mth++;goto C0;} //判斷是否閏年之2月28日 else { if(AC_mth==2 && AC_day>=30 && (AC_yer%4)==0) {AC_day=1;AC_mth++;goto C0;} //判斷是否閏年之2月29日 else { if((AC_mth==1 || AC_mth==3 || AC_mth==5 || AC_mth==7 || AC_mth==8 || AC_mth==10 || AC_mth==12) && AC_day>=32) {AC_day=1;AC_mth++;goto C0;} } //判斷有30日的月份 } } C0: if(AC_mth>=13) {AC_yer++;AC_mth=1;} // 判斷月份是否已滿12月 return; } //****************** void Uart_cmd(void) { switch((int)UART_buf[2]) { case 0x80: //WIFI下傳時間. AC_hrs=(UART_buf[5]/16)*10+(UART_buf[5]%16); //16進制轉為10進制 AC_min=(UART_buf[4]/16)*10+(UART_buf[4]%16); AC_sec=(UART_buf[3]/16)*10+(UART_buf[3]%16); break; case 0x81: //WIFI下傳日期 AC_yer=(UART_buf[5]/16)*10+(UART_buf[5]%16); //16進制轉為10進制 AC_mth=(UART_buf[4]/16)*10+(UART_buf[4]%16); AC_day=(UART_buf[3]/16)*10+(UART_buf[3]%16); sprintf(temp,"%2d/%d/%d ",(int)AC_yer,(int)AC_mth,(int)AC_day); // 顯示 年/月/日 時間; if(RI==0) { LCD4_Write_String(0,0,temp); } break; //******************* case 0x82: CTx=(UART_buf[3]/16)*10+(UART_buf[3]%16); // CTx參數, 補正差 CTy=(UART_buf[4]/16)*10+(UART_buf[4]%16); // CTy參數, 扣負差 CTz=(UART_buf[5]/16)*10+(UART_buf[5]%16); // CTz參數, 補秒數 CT_flag=1; break; case 0x83: CT_flag=1; DISP_flag=1; //設定顯示時間修正參數值 break; case 0x84: ALM_no=UART_buf[3]; //ALARM 編組 NO if(ALM_no>=12) break; ALM[ALM_no][1]=(UART_buf[5]/16)*10+(UART_buf[5]%16); // ALARM 小時 ALM[ALM_no][0]=(UART_buf[4]/16)*10+(UART_buf[4]%16); // ALARM 分鐘 break; default: { BUZZ=1;DelayMs(100);BUZZ=0;BUZZ=1;DelayMs(100);BUZZ=0; }break; } } /*------------------------------------------------ 計數器0的初始化 for w/o RTC ------------------------------------------------*/ void Init_Timer0(void) // 計數器0的初始化 { TMOD |= 0x01; // 選擇為計時器0模式,工作方式 1,僅用TR0打開啟動。 AUXR &= ~0x80; TH0 = (65536-(CT+CTx-CTy))>>8; // 設置計時器初始值, 4ms TL0 = (65536-(CT+CTx-CTy)); //
TR0 = 1; //打開計時器 } /*------------------------------------------------ 計時器 TIMER0 中斷處理 for w/o RTC ------------------------------------------------*/ void TIMER0(void) interrupt 1 using 1 { unsigned int i; TH0 = (65536-(CT+CTx-CTy))>>8; // 重設計時器初始值 TL0 = (65536-(CT+CTx-CTy)); // i++; if(BUZZ==1) ALARM= ~ALARM; // 如何ALARM旗號被啟動,就輸出 BUZZL信號 else ALARM=0; if(i>=250) // 確認是否滿足1秒鐘 { AC_sec++;if(AC_sec>=60) {AC_sec=0;AC_min++;} i=0;Turn_flag=1; // 設定足秒旗號 } } /*------------------------------------------------ 計數器 1 的初始化 115200,8,N,1 @ 1T / 22.1184Mhz ------------------------------------------------*/ void Init_Timer1(void) { SCON = 0x5a; AUXR |= 0x40; TMOD = 0x20; // setting Timer1 to 8bits autoload TL1 = (256-(XTAL/32/BAUDRATE)); // @22.1184Mhz, for 115200bps TH1 = (256-(XTAL/32/BAUDRATE)); TR1 = 1; // Timer1 running enable ES = 1; // serial port interrupt enable EA = 1; // interrupt enable } /*------------------------------------------------ 發送一個位元組 ------------------------------------------------*/ void Uart_PutChar(unsigned char dat) { while(busy); busy=1; SBUF = dat; } /*------------------------------------------------ 發送一個字串 ------------------------------------------------*/ void Uart_SendStr(unsigned char *value,unsigned int leng) { while(leng>0) // { Uart_PutChar(*value); value++; leng--; } } /*------------------------------------------------ 串口中斷程式 ---------------------------------------------*/ void Uart_ISR_Handle (void) interrupt 4 { if(RI==1) { UART_buf[Rcv_idx]=SBUF; if(UART_buf[Rcv_idx-1]==0x20 && UART_buf[Rcv_idx]==0xa5) {Rcv_idx=1;UART_buf[0]=0x20;UART_buf[1]=0xa5;} Rcv_idx++; if(Rcv_idx>=UARTSIZE) //連續接收16個字元資訊 { Rcv_idx=0; SetFlag=1; //接收完成,標誌旗號設定 1 } RI = 0; } if(TI==1) //如果是發送標誌位元,清零 { TI=0; busy=0; //清除傳送旗號 } } //*********************************
//*** FILE:LCD4.c
unsigned xdata LCD4temp=0; bit LCD4_flag2=0; //應答標誌位元
/*------------向LCD1602寫入指令---------------------------- 函數名稱:void LCD4_Write_Command(unsigned char command) 向LCD4寫入指令 函數參數:unsigned char command //準備寫入的指令 函數說明:向LCD4的指令寄存器寫入一個指令 ---------------------------------------------------------------*/ void LCD4_Write_Command(unsigned char command) //向LCD4寫入指令 { DelayMs(5); //此處插入一個等待很重要,小於這個時間會導致連續寫時出現錯誤 //先寫入高4位 LCD4temp = command & 0xf0 | 0x08; //先處理高4位,EN=0,RW=0,RS=0 P1=LCD4temp; LCD4temp |= 0x0c; //拉高EN P1=LCD4temp; LCD4temp &= 0xfb; //EN置低,下降沿寫入液晶 P1=LCD4temp; //接下來寫入低4位 if(LCD4_flag2==0) return; //判斷是否是冷開機 LCD4temp = command<<4; p=""> P1=LCD4temp; LCD4temp |= 0x0c; //拉高EN P1=LCD4temp; LCD4temp &= 0xfb; //EN置低,下降沿寫入液晶 P1=LCD4temp; } /*------------向LCD1602寫入資料---------------------------- 函數名稱:void LCD1602_Write_Data(unsigned char data) 向LCD4寫入資料 函數參數:unsigned char data //準備寫入的資料 函數說明:向LCD4的指令寄存器寫入一個資料 ---------------------------------------------------------------*/ void LCD4_Write_Data(unsigned char Data) //向LCD4寫入資料 { DelayMs(5); //此處插入一個等待很重要,小於這個時間會導致連續寫時出現錯誤 //先寫入高4位 LCD4temp = (Data & 0xf0) | 0x09; //先處理高4位,EN=0,RW=0,RS=1 P1=LCD4temp; LCD4temp |= 0x0c; //拉高EN P1=LCD4temp; LCD4temp &= 0xfb; //EN置低,下降沿寫入液晶 P1=LCD4temp; //接下來寫入低4位 LCD4temp = (Data<<4) 0x09="" p=""> P1=LCD4temp; LCD4temp |= 0x0c; //拉高EN P1=LCD4temp; LCD4temp &= 0xfb; //EN置低,下降沿寫入液晶 P1=LCD4temp; } /*------------------------------------------------------------------ 函數名稱:void LCD4_Init(void) //LCD4初始化函數 函數參數:無 函數說明:參考LCD4液晶說明手冊,請特別留意LCD4_flag2 ------------------------------------------------------------------*/ void LCD4_Device_Init(void) //LCD1602初始化函數 { DelayMs(50); //冷開機 LCD4_Write_Command(0x38); DelayMs(50); LCD4_Write_Command(0x28); DelayMs(5); LCD4_Write_Command(0x28); DelayMs(5); LCD4_Write_Command(0x28); DelayMs(50); //先等待50毫秒VDD上電穩定 LCD4_flag2=1; LCD4_Write_Command(0x28); //先進行功能設置,四位元資料介面,兩行顯示,5′7點陣字元。 DelayMs(25); //等待上條指令完成 LCD4_Write_Command(0x08); //Display On/Off Control,顯示開關:D=1打開,游標開關:C=1打開,閃爍開關:B=1打開 DelayMs(5); LCD4_Write_Command(0x01); //清屏 DelayUs2x(5); LCD4_Write_Command(0x06); //AC位址遞增模式 DelayUs2x(5); LCD4_Write_Command(0x01); //清屏 DelayUs2x(5); LCD4_Write_Command(0x02); //HOME DelayMs(5); LCD4_Write_Command(0x0f); //Display On/Off Control,顯示開關:D=1打開,游標開關:C=1打開,閃爍開關:B=1打開 DelayMs(5); } /*--------設置AC地址-------------------------------------------------- 函數名稱:void LCD4_Set_Position(unsigned char x, unsigned char y) 向LCD4設置下一個準備寫入的字元位置 函數參數:unsigned char x 行地址 0~F unsigned char y 列地址 0~1 函數說明:設置AC地址, ---------------------------------------------------------------------*/ void LCD4_Set_Position(unsigned char x, unsigned char y) { //向LCD4設置下一個準備寫入的字元位置 unsigned char address = (y * 0x40) + (0x80 + x) ; LCD4_Write_Command(address); DelayUs2x(150); } /*--------向指定的位置開始寫字串 --------------------------------------- 函數名稱:LCD4_Write_String(unsigned char X, unsigned char Y, char *s) 向指定的位置開始寫字串 函數參數:unsigned char X //列位置 unsigned char Y //行位置 char *String //要顯示的字串 函數說明:向指定的位置開始寫字串 ------------------------------------------------------------------------*/ void LCD4_Write_String(unsigned char X, unsigned char Y, char *String) { //向指定的位置開始寫字串 LCD4_Set_Position(X,Y); while(*String) { LCD4_Write_Data(*String++); DelayUs2x(50); } } @2019/02/05 修改之程式說明 一) LT-TEST_06.c主程式部份: 在主程式有修改之處, 在原先的LCM顯示的指令修改為本次的新指令,其仔的部份大致上未做任何異動。 新指令部份 #include "LCD4.c" LCD4_Device_Init(); //啟動LCM介面板與 1602液晶螢幕 LCD4_Write_Command(0x01); //清除螢幕內容, LCD4_Write_String(0,1,temp); 舊指令部份 #include "I2CPCF8574.c" //I2C LCM 副程式 LCD1602_Device_Init(XIO_ID); //啟動I2C LCD介面板與 1602液晶螢幕 LCD1602_Write_Command(XIO_ID,0x01); //清除螢幕內容, XIO_ID 需依 I2C //PCF8574T(0x40) 或 PCF8574AT(0x70) LCD1602_Write_String(XIO_ID,0,1,temp); 舊指令因為需要有分辨, 使用何者的I2C 介面IC PCF8574T 或 PCF8574T,所以需帶入XIO_ID的變數, 而新指令部份,因為已不再使用I2C元件, 所以就不需帶入I2C PORT位址變數。 二)FILE:LCD4.c是副程式 在此程式的修改,最大的是LCD4.C的副程式,總共有5個子程式被修改,當然是移除了XIO_ID的變數,同時也不再需要I2C的一干BYTE轉BIT的子程式,同好可以比對"I2C LCD介面應用於STC89C516RD+之溫度與濕度計"一文中的舊程式,因為副程式之行數甚多,就不在此逐條解說,相信同好應有足夠的程度了解,就不在此一一說明,請見諒。
|
|
( 興趣嗜好|電腦3C ) |