查看: 17957
回复: 40
参赛作品《多功能遥控电子时钟》 (已完成)

主题

回复
发表于2017-06-03 16:01:44 | 显示全部楼层
1# 电梯直达

【报名阶段需要填写的内容】


1. 参赛者姓名(必填项):
易军平/易博智

2. 单位或学校名称(必填项):
长沙市晶通物控电子科技有限公司

3. 当前职务或职称(必填项):
工程师/学生

4. 参赛作品的名字(必填项):
多功能遥控电子时钟

5. 简要陈述您的idea和作品(必填项):
单片机通过读取DS1302时钟芯片数据,将之显示在数码管上。并与FLASH内部存储的数据进行比较,匹配则闹钟一分钟。相关调置可以通过遥控器操作

6. 拟用到的立创商城在售物料(必填项):
1、C18615 STM8S003F3P6 管装
2、C14334 DS1302Z+T&R 编带
3、C8696  STC12C5A60S2-35I 托盘  
4、C5126  HS0038A 管装
5、C12189 1英寸红色共阳数码管 盒装
6、C57395 MC74HC164ADR2G 编带

7. 拟用到的非立创商城物料或其它补充(必填项):
电阻、电容、二三极管及其它配料根据实际需要选择。


【作品正式发表(报名成功后进入设计阶段)需要填写的内容】


一、作品简介

例如,可以包括但不局限于以下内容:

1.作品的整机外观图片或焊接组装好的PCBA图片;

2.作品的研究背景、目的和功能、市场应用前景;

3.作品在创新性、趣味性、实用性甚至公益性方面,有哪些亮点可体现?

3.1.1 设计效果:

 


3.1.2 实际效果

 


3.1.3 运行效果

 





二、系统构架图

用流程图或思维导图等形式,描述您的作品的组成构架,即方案图。


三、硬件部分的描述

1.附上原理图&PCB实物图的图片或者源文件(官方建议大家尽量用源文件上传),如果是图片,请确保图片是清晰可辨的;

2.用文字把该作品的实现原理、系统的工作过程大致讲解一下。


显示电路部份,采用模块结构。多片串行显示,可以不局限于线路板大小,而可以将产品尺寸做大;

 点击查看大图

 点击查看大图

2、主板电路

 点击查看大图

以前做过一个版本是IR的,现在IR的遥控器手上难找,且IR的有方向性不能穿墙。将原IR部份电路改成RF方式的。另外增加了485的总线接口。可以与485总线的智能家居系统等实现系统对接。实现一定的模块功能。

主板到显示模块,输出外围了一个NMOS,可以实现PWM亮度调节,夜晚时分,可以自动调低亮度。

 点击查看大图

 点击查看大图



四、材料清单(BOM列表)

列出您这个作品所用到的主要器件(关键器件即可),比如单片机&ARM芯片、专用集成芯片(ASIC)、传感器、功能模块等。

如果所列出的芯片是来自我们立创商城上的,最好能写出该器件的商品编号或附上对应购买链接。

 点击查看大图

 点击查看大图

失误更正:

显示板BOM清单内,数码显示器LED1,正确型号为:FJ11001AH, 编号:C10687,购买链接:http://www.szlcsc.com/product/details_11231.html


五、软件部分的描述(选填)

如果您的作品涉及到软件,请列出作品对应的软件工作流程图,及关键部分的例程、源码(如果您想开源的话请上传全部源码)。

5.1、按键处理流程:

 



5.2 按键部份处理代码:

#include "Config.h"

extern DATE date;
extern TIME time;
extern volatile Alam_t on_Alam; 
#if OPT_COUNTER
extern volatile Counter_t on_Ct; 
#endif 
extern volatile uCHAR dis_buffer[11];
extern volatile WatchSet_t WatchSet; 
extern volatile WatchCfg_t WatchCofing; 
extern volatile XTIMER Timer[e_Timer_Max];


//-------------------------------
//Function: Key Adjust Process
//-------------------------------
void Key_Adjust_Value(u8 dig, s8 v) 
{ 
	if(!WatchSet.in.item.set) return; 
	if(!WatchSet.in.item.adj) return; 

	dig = dig?10:0; 
	v += dig; 
	//己进入调整状态
	switch(WatchSet.item){
	case MENUMOD_ITEM_TIME:
		Watch_Set_Time(WatchSet.sub, v);
		break;
	case MENUMOD_ITEM_DATE:
		Watch_Set_Date(WatchSet.sub, v);
		break;
#if OPT_COUNTER
	case MENUMOD_ITEM_COUNT:
		Watch_Set_Count(WatchSet.sub, v);
		break;
#endif 
	case MENUMOD_ITEM_ALAM0:
	case MENUMOD_ITEM_ALAM1:
	case MENUMOD_ITEM_ALAM2:
	case MENUMOD_ITEM_ALAM3:
	case MENUMOD_ITEM_ALAM4:
	case MENUMOD_ITEM_ALAM5:
	case MENUMOD_ITEM_ALAM6:
	case MENUMOD_ITEM_ALAM7:
	case MENUMOD_ITEM_ALAM8:
	case MENUMOD_ITEM_ALAM9:
		Watch_Set_Alam(WatchSet.item-MENUMOD_ITEM_ALAM0, WatchSet.sub, v);
		break;
	default:
		break;
	}
} 

//-------------------------------
//Function: Key action Process
//-------------------------------
void KeyProcess(void)
{
	uCHAR Keytemp,Out = 200,i;
	
	Keytemp = IR_KeyB();
	if(Keytemp==KEY_SEL_NOSEL)return; 
	
	Beeper(TRUE, 100, 0); 
	if(IS_TIMERSTART(e_Timer_SET)) { 
		RESET_TIMER(e_Timer_SET); 
	} else {  
		START_TIMER(e_Timer_SET, 25000); 
	} 

	if(on_Alam.inw) { 
		memclr(&on_Alam, sizeof(Alam_t)); 
		return; 
#if OPT_COUNTER
	} else if(on_Ct.full && on_Ct.use) { 
		on_Ct.use = FALSE; 
		on_Ct.full = FALSE; 
		return; 
#endif 
	} 

	switch(Keytemp) { 
	case KEY_SEL_DIG0: 
	case KEY_SEL_DIG1: 
	case KEY_SEL_DIG2: 
	case KEY_SEL_DIG3: 
	case KEY_SEL_DIG4: 
	case KEY_SEL_DIG5: 
	case KEY_SEL_DIG6: 
	case KEY_SEL_DIG7: 
	case KEY_SEL_DIG8: 
	case KEY_SEL_DIG9: 
		//己进入调整状态
		Keytemp -= KEY_SEL_DIG0; 
		Key_Adjust_Value(TRUE, Keytemp); 
		if(!WatchSet.in.item.set) break; 
		if(!WatchSet.in.item.adj) break; 
	case KEY_SEL_SET: 
		if(WatchSet.in.item.show) { 
			Alert_t* alam = WatchCofing.alart+WatchSet.sub; 
			if(WatchSet.item==MENUSHOW_ITEM_ALAM) { 
				if(alam->on) { 
					alam->on = FALSE; 
					if(on_Alam.id==WatchSet.sub) { 
						memclr(&on_Alam, sizeof(Alam_t)); 
					} 
				} else { 
					alam->on = TRUE; 
				} 
				Watch_Show_Alam(WatchSet.sub);  
				WatchCofing.dirty = TRUE; 
			} 
			break; 
#if OPT_COUNTER
		} else if(on_Ct.use) { 
			on_Ct.use = FALSE; 
			break; 
#endif 
		} 
		
		if(WatchSet.in.item.set) { 
			if(WatchSet.in.item.adj) { 
				//调整设置项目
				//WatchSet.in.item.adj = FALSE; 
				WatchSet.sub++; 
				if(WatchSet.item==MENUMOD_ITEM_DATE){ 
					if(WatchSet.sub>=7) { 
						ExitMenu(TRUE); 
						break;
					} 
				} else { 
					if(WatchSet.sub>=6) { 
						ExitMenu(TRUE); 
						break;
					} 
				} 
			} else { 
				WatchSet.sub = 0; 
				WatchSet.item++; 
				if(WatchSet.item>=MENUMOD_ITEM_MAX) { 
					ExitMenu(TRUE); 
					break;
				} 
			} 
			Watch_Show_SetItem(WatchSet.item, WatchSet.sub);
			break; 
			//WatchSet.in.item.adj = TRUE; 
		} 
		WatchSet.in.items = 0; 
		WatchSet.in.item.set = TRUE; 
		WatchSet.sub = 0; 
		WatchSet.item = MENUMOD_ITEM_TIME; 
		Watch_Show_SetItem(MENUMOD_ITEM_TIME, 0); 
		break; 
	case KEY_SEL_INC: 
		if(WatchSet.in.item.set) { 
			Key_Adjust_Value(FALSE, 1); 
			break; 
#if OPT_COUNTER
		} else if(on_Ct.use && on_Ct.pause) { 
			on_Ct.base = SecondsToTime(TimeToSeconds(time)+on_Ct.run); 
			on_Ct.pause = FALSE; 
			break; 
#endif 
		} 

		//显示闹钟
		if(WatchSet.in.item.show) { 
			WatchSet.sub++; 
			if(WatchSet.sub>9) { 
				WatchSet.in.item.show = FALSE; 
			} 
		} else { 
			WatchSet.in.item.show = TRUE; 
			WatchSet.item = MENUSHOW_ITEM_ALAM; 
			WatchSet.sub = 0; 
		} 
		Watch_Show_Alam(WatchSet.sub); 
		break; 
	case KEY_SEL_DEC: 
		if(WatchSet.in.item.set) { 
			//己进入调整状态
			if(WatchSet.in.item.adj) { 
				Key_Adjust_Value(FALSE, -1); 
			} else { 
				WatchSet.sub = 0; 
				WatchSet.in.item.adj = TRUE; 
				Watch_Show_SetItem(WatchSet.item, 0); 
			} 
			break; 
		} 
		if(WatchSet.in.item.show ) { 
			ExitMenu(TRUE); 
#if OPT_COUNTER
		} else if(on_Ct.use){ 
			on_Ct.pause = TRUE; 
			break; 
#endif 
		} else { 
			//显示日期
			WatchSet.in.items = 0; 
			WatchSet.in.item.show = TRUE; 
			WatchSet.item = MENUSHOW_ITEM_DATE; 
			Watch_Display_Date(date);
		} 
		break; 
	}
}


void ExitMenu(char force) 
{ 
	if(IS_TIMEROVER(e_Timer_SET)||force) { 
		if(WatchSet.in.item.modify) { 
			switch(WatchSet.item) { 
			case MENUMOD_ITEM_TIME: 
				Watch_Save_Time();
				break; 
			case MENUMOD_ITEM_DATE: 
				Watch_Save_Date();
				break; 
#if OPT_COUNTER
			case MENUMOD_ITEM_COUNT: 
				Watch_Save_Count();//show the countdown time
				break; 
#endif 
			case MENUMOD_ITEM_ALAM0:
			case MENUMOD_ITEM_ALAM1:
			case MENUMOD_ITEM_ALAM2:
			case MENUMOD_ITEM_ALAM3:
			case MENUMOD_ITEM_ALAM4:
			case MENUMOD_ITEM_ALAM5:
			case MENUMOD_ITEM_ALAM6:
			case MENUMOD_ITEM_ALAM7:
			case MENUMOD_ITEM_ALAM8:
			case MENUMOD_ITEM_ALAM9:
				Save_WatchCofing();
				break; 
			default: 
				WatchSet.in.items = 0; 
				break; 
			} 
		} 
		
		WatchSet.sub = 0; 
		WatchSet.item = 0; 
		WatchSet.temp = 0; 
		WatchSet.in.items = 0; 
		STOP_TIMER(e_Timer_SET); 
	} 
} 




5.3 按键/遥控读取部份代码

#include "Config.h"


extern volatile _Bool Synch; 
extern volatile  u8 RF_data; 
extern volatile XTIMER Timer[e_Timer_Max];
const u8 rfcodes[] = { 
	0XCC, 0X03, 0X0C, 0X0F, 0X30, 0X33, 
	0X3C, 0X3F, 0XC0, 0XC3, 0XCF, 0XF0
}; 

void Key_Init(void) 
{ 
	set_io_isinput(PORT_KEY_SET, BIT_KEY_SET); 
	set_io_isinput(PORT_KEY_INC, BIT_KEY_INC); 
	set_io_isinput(PORT_KEY_DEC, BIT_KEY_DEC); 
	
	set_io_pushpull(PORT_KEY_SET, BIT_KEY_SET); 
	set_io_pushpull(PORT_KEY_INC, BIT_KEY_INC); 
	set_io_pushpull(PORT_KEY_DEC, BIT_KEY_DEC); 
} 

uCHAR GetKeyVal(void)
{
	char temp, i;
	static key_bak, key_temp=KEY_SEL_NOSEL; 	
	
	temp = 0; 
	if(!get_bit(PORT_KEY_SET, BIT_KEY_SET)) { 
		temp |= BIT(0); 
	} 
	if(!get_bit(PORT_KEY_INC, BIT_KEY_INC)) { 
		temp |= BIT(1); 
	} 
	if(!get_bit(PORT_KEY_DEC, BIT_KEY_DEC)) { 
		temp |= BIT(2); 
	} 
	
	if(temp == KEY_SEL_NOSEL) { 
		//unpressed 
		key_temp = KEY_SEL_NOSEL; 
		return KEY_SEL_NOSEL; 
	} 
	//the last key event not free
	if(key_temp==temp) return KEY_SEL_NOSEL;	//key noise filter
	if(!IS_TIMERSTART(e_Timer_KeyFilter)) { 
		key_bak = temp; 
		START_TIMER(e_Timer_KeyFilter, 10); 
	} else if(key_bak!=temp) { 
		//key changed in filter 
		STOP_TIMER(e_Timer_KeyFilter); 
		return KEY_SEL_NOSEL; 
	} 

	if(!IS_TIMEROVER(e_Timer_KeyFilter)) return KEY_SEL_NOSEL; 
	STOP_TIMER(e_Timer_KeyFilter); 
	key_temp = temp; 

	if(temp==0x01) { 
		return KEY_SEL_SET;
	} else if(temp==0x02) { 
		return KEY_SEL_INC;
	} else if(temp==0x04) { 
		return KEY_SEL_DEC;
	} else { 
		//KEY_SEL_MOV,KEY_SEL_POW 
		if(temp==0x03) { 
			return KEY_SEL_MOV;
		} else if(temp==0x05) { 
			return KEY_SEL_POW;
		}
	} 
	return KEY_SEL_NOSEL;
}

uCHAR IR_KeyB(void)
{
	uCHAR Keytemp;
	static uCHAR RF_Temp = 0xFF;
	
	if(!Synch) { 
		Keytemp = GetKeyVal(); 
	} else { 
		Synch = FALSE; 
		if(IS_TIMERSTART(e_Timer_Remote)) { 
			if(!IS_TIMEROVER(e_Timer_Remote)) { 
				return KEY_SEL_NOSEL; 
			} 
			STOP_TIMER(e_Timer_Remote); 
		} 
		//遥控解码间隙超时
		START_TIMER(e_Timer_Remote, 300); 
		
		for(Keytemp=0; Keytemp<12; Keytemp++) { 
			if(rfcodes[Keytemp]==RF_data) { 
				Synch = TRUE; 
				break; 
			} 
		} 
		if(Synch) { 
			switch(Keytemp) { 
			case 10: 
				Keytemp = KEY_SEL_SET; 
				break; 
			case 11:
				Keytemp = KEY_SEL_DEC; 
				break; 
			} 
		} 
		Synch = FALSE; 
	} 
	
	return Keytemp;
}



5.4 电子表核心处理代码

#include "Config.h"

#if OPT_COUNTER
volatile Counter_t on_Ct = {0}; 
#endif 
volatile Alam_t on_Alam = {0, 0, 0, 0}; 
volatile uCHAR dis_buffer[11];
volatile WatchSet_t WatchSet; 

extern DATE date;
extern TIME time;
extern volatile WatchCfg_t WatchCofing; 
extern volatile XTIMER Timer[e_Timer_Max];

//-----------------------------------

#define isLeampyear(year) ((year%4==0&&year%100!=0)||(year%400==0))  
	
//-----------------------------------

//led show codes
//0~9, ' ', -, A, C, H
const uCHAR LED[] = {
	0XDE,0X06,0XEC,0XAE,0X36, //0~4
	0XBA,0XFA,0X0E,0XFE,0XBE, //5~9
	0x00, //String - ' '
	0X20, //String - '-'
	0X7E, //String - 'A'
	0XD8, //String - 'C'
	0X76, //String - 'H'
	0XD6, //String - 'U'
	0X5E, //String - 'N'
	0XF0, //String - 't'
	0XD0, //String - 'L'
	0X01  //String - '.'
}; 

const uCHAR SEGMENT[] = { 
	0x08,0x04,0x02,0x80,0x40,0x10,0x20,0x01
}; 

//-----------------------------------
//FUNCTION: DISPLAY THE DATA
//-----------------------------------
static void Watch_Update_Display(void)
{
	uCHAR i; 
	uCHAR v; 
	
	for(i=0; i<11; i++) { 
		v = *(dis_buffer+i); 
		if(v>=LEDWORD_USEDEF) { 
			MC74HC595_Shift(v-LEDWORD_USEDEF); 
		} else { 
			MC74HC595_Shift(LED[v]); 
		} 
	} 
	MC74HC595_Update(); 
}

void write_DisBuffer(u8 ID, u8 v) 
{ 
	*(dis_buffer+ID) = v; 
} 

u8 read_DisBuffer(u8 ID) 
{ 
	return *(dis_buffer+ID); 
} 

//----------------------------------
//FUNCTION: display the year
//----------------------------------
void Watch_Display_Date(DATE date)
{
	write_DisBuffer(LEDITEM_MAIN_1, math_div(date.year, 10));	//year ten
	write_DisBuffer(LEDITEM_MAIN_2, math_mod(date.year, 10));			//year signed
	write_DisBuffer(LEDITEM_MAIN_3, LEDWORD_LINE);						//"-"
	write_DisBuffer(LEDITEM_MAIN_4, math_div(date.month, 10));	//month ten
	write_DisBuffer(LEDITEM_MAIN_5, math_mod(date.month, 10));		//month signed
	write_DisBuffer(LEDITEM_MAIN_6, LEDWORD_LINE);						//"-"
	write_DisBuffer(LEDITEM_MAIN_7, math_div(date.day, 10));	//date ten
	write_DisBuffer(LEDITEM_MAIN_8, math_mod(date.day, 10));			//date signed
	write_DisBuffer(LEDITEM_WEEK, math_mod(date.week, 10));		//week
	if(WatchSet.in.item.show) { 
		write_DisBuffer(LEDITEM_TEMP_H, LEDWORD_WORDA); 
		write_DisBuffer(LEDITEM_TEMP_L, LEDWORD_WORDT); 
	} 
	
	Watch_Update_Display(); 
}


//----------------------------------
//Function: display the date
//----------------------------------
void Watch_Display_Time(TIME time)
{
	uCHAR temp;
	static u8 scrow = TRUE; 
	
	write_DisBuffer(LEDITEM_MAIN_1, math_div(time.hour, 10));	//Hour ten
	write_DisBuffer(LEDITEM_MAIN_2, math_mod(time.hour, 10));		//Hour signed
	write_DisBuffer(LEDITEM_MAIN_3, LEDWORD_LINE);			//"-"
	write_DisBuffer(LEDITEM_MAIN_4, math_div(time.min, 10));	//minute ten
	write_DisBuffer(LEDITEM_MAIN_5, math_mod(time.min, 10));		//minute signed
	write_DisBuffer(LEDITEM_MAIN_6, LEDWORD_LINE);			//"-"
	write_DisBuffer(LEDITEM_MAIN_7, math_div(time.sec, 10));	//second ten
	write_DisBuffer(LEDITEM_MAIN_8, math_mod(time.sec, 10));		//second signed
	if(!WatchSet.in.items) { 
#if OPT_COUNTER
		if(on_Ct.use) { 
			if(!on_Ct.full) { 
				on_Ct.segLeds |= SEGMENT[on_Ct.sCount++]; 
				if(on_Ct.sCount>=6) { 
					on_Ct.sCount = 0; 
				} 
				on_Ct.segLeds &= ~SEGMENT[on_Ct.sCount]; 
				
				write_DisBuffer(LEDITEM_TEMP_H, LEDWORD_WORDC); 
				write_DisBuffer(LEDITEM_TEMP_L, LEDWORD_DIG0); 
				write_DisBuffer(LEDITEM_WEEK, LEDWORD_USEDEF+on_Ct.segLeds);
			} else { 
				if(scrow) { 
					write_DisBuffer(LEDITEM_TEMP_H, LEDWORD_BLANK); 
					write_DisBuffer(LEDITEM_TEMP_L, LEDWORD_BLANK); 
					write_DisBuffer(LEDITEM_WEEK, LEDWORD_BLANK);
				} else { 
					write_DisBuffer(LEDITEM_TEMP_H, LEDWORD_WORDC); 
					write_DisBuffer(LEDITEM_TEMP_L, LEDWORD_DIG0); 
					write_DisBuffer(LEDITEM_WEEK, LEDWORD_LINE);
				} 
				scrow = !scrow; 
			} 
		} else 
#endif 
		if(on_Alam.inw) { 
			if(scrow) { 
				write_DisBuffer(LEDITEM_TEMP_H, LEDWORD_WORDA); 
				write_DisBuffer(LEDITEM_TEMP_L, on_Alam.id); 
				write_DisBuffer(LEDITEM_WEEK, LEDWORD_LINE);
			} else { 
				write_DisBuffer(LEDITEM_TEMP_H, LEDWORD_BLANK); 
				write_DisBuffer(LEDITEM_TEMP_L, LEDWORD_BLANK); 
				write_DisBuffer(LEDITEM_WEEK, LEDWORD_BLANK);
			} 
			scrow = !scrow; 
		} else { 
			temp = Temperature_Read(); 
			if(temp>=100) { 
				write_DisBuffer(LEDITEM_TEMP_H, LEDWORD_LINE); 
				write_DisBuffer(LEDITEM_TEMP_L, LEDWORD_LINE); 
			} else { 
				write_DisBuffer(LEDITEM_TEMP_H, math_div(temp, 10)); 
				write_DisBuffer(LEDITEM_TEMP_L, math_mod(temp, 10)); 
			} 
			write_DisBuffer(LEDITEM_WEEK, math_mod(date.week, 10));		//week 
		} 
	} 
	Watch_Update_Display(); 
}

void Watch_Display_Temp(s8 temp) 
{ 
	if(temp>=0) { 
		write_DisBuffer(LEDITEM_TEMP_H, math_div(temp, 10));
		write_DisBuffer(LEDITEM_TEMP_L, math_mod(temp, 10)); 
	} else { 
		write_DisBuffer(LEDITEM_TEMP_H, LEDWORD_LINE);
		write_DisBuffer(LEDITEM_TEMP_L, (0-temp));
	} 
	Watch_Update_Display(); 
} 


//----------------------------------
//Function: Adjust the time
//----------------------------------
void setv(uCHAR ID, s8 v, const char min, const char max) 
{ 
	s8 ss = -1; 

	if(v>=10) { 
		ss = v-10; 
		if((ss>=min)&&(ss<=max))write_DisBuffer(ID, ss); 
	} else { 
		ss = (char)(read_DisBuffer(ID)+v); 
		if(ss > max) {  
			write_DisBuffer(ID, min); 
		} else if(ss < min) { 
			write_DisBuffer(ID, max); 
		} else { 
			write_DisBuffer(ID, (uCHAR)ss); 
		} 
	} 
	if(v!=0)WatchSet.in.item.modify = TRUE; 
} 

void setCV(uCHAR ID, s8 v, const char min, const char max) 
{ 
	setv(ID, v, min, max); 
	//更新闪烁缓存数值
	WatchSet.temp = read_DisBuffer(ID); 
} 

static TIME Watch_Adjust_Time(char AdjItem, s8 val)
{	
	TIME new_time; 
	
	switch(AdjItem){
	case 0: 
		setCV(LEDITEM_MAIN_1, val, 0, 2); 
		if(read_DisBuffer(LEDITEM_MAIN_1)==2){
			setv(LEDITEM_MAIN_2, val, 0, 3); 
		}
		break;
	case 1:
		if(read_DisBuffer(LEDITEM_MAIN_1)==2){
			setCV(LEDITEM_MAIN_2, val, 0, 3); 
		} else { 
			setCV(LEDITEM_MAIN_2, val, 0, 9); 
		}
		break;
	case 2:
		setCV(LEDITEM_MAIN_4, val, 0, 5); 
		break;
	case 3:
		setCV(LEDITEM_MAIN_5, val, 0, 9); 
		break;
	case 4:
		setCV(LEDITEM_MAIN_7, val, 0, 5); 
		break;
	case 5:
		setCV(LEDITEM_MAIN_8, val, 0, 9); 
		break;
	default: 
		break;
	} 
	 
	new_time.hour = math_mux(read_DisBuffer(LEDITEM_MAIN_1),10) + read_DisBuffer(LEDITEM_MAIN_2);
	new_time.min  = math_mux(read_DisBuffer(LEDITEM_MAIN_4),10) + read_DisBuffer(LEDITEM_MAIN_5);
	new_time.sec  = math_mux(read_DisBuffer(LEDITEM_MAIN_7),10) + read_DisBuffer(LEDITEM_MAIN_8);
	Watch_Update_Display(); 
	
	return new_time; 
}



//---------------------------------
//Function: Adjust date
//---------------------------------
void Adjust_Date_Value(u8 ID)
{
	u8 month, x; 
	u16 year = 2000; 
	uCHAR lagermonth[] = {1,3,5,7,8,10,12};

	year += read_DisBuffer(LEDITEM_MAIN_1)*10 + read_DisBuffer(LEDITEM_MAIN_2); 
	month = read_DisBuffer(LEDITEM_MAIN_4)*10 + read_DisBuffer(LEDITEM_MAIN_5); 
	if(month==2) { 
		if(read_DisBuffer(LEDITEM_MAIN_7)==2) { 
			if(isLeampyear(year)) { 
				setv(LEDITEM_MAIN_8, 0, 0,  8); 
			} else { 
				setv(LEDITEM_MAIN_8, 0, 0,  9); 
			} 
		} 
	} else if(read_DisBuffer(LEDITEM_MAIN_7)==3) { 
		for(x=0; x<sizeof(lagermonth); x++) { 
			if(month==lagermonth[x]) { 
				setv(LEDITEM_MAIN_8, 0, 0,  1); 
				break; 
			} 
		} 
		if(x>=sizeof(lagermonth)) { 
			write_DisBuffer(LEDITEM_MAIN_8, 0); 
		} 
	} 
	//更新闪烁缓存数值
	if(ID==LEDITEM_MAIN_8) { 
		WatchSet.temp = read_DisBuffer(LEDITEM_MAIN_8); 
	} 
}

static DATE Watch_Adjust_Date(char AdjItem, s8 val)
{
	u8 month; 
	DATE new_date;  
	

	switch(AdjItem){
	case 0:
		//Year-H
		setCV(LEDITEM_MAIN_1, val, 0, 9); 
		break;
	case 1:
		//Year-L
		setCV(LEDITEM_MAIN_2, val, 0, 9); 
		break; 
	case 2: 
		//Month-H
		setCV(LEDITEM_MAIN_4, val, 0, 1); 
		if(read_DisBuffer(LEDITEM_MAIN_4)) { 
			setv(LEDITEM_MAIN_5, val, 0, 2); 
		} else { 
			setv(LEDITEM_MAIN_5, val, 1, 9); 
		}
		Adjust_Date_Value(LEDITEM_MAIN_4); 
		break;
	case 3:
		//Month-L
		if(read_DisBuffer(LEDITEM_MAIN_4)) { 
			setCV(LEDITEM_MAIN_5, val, 0, 2); 
		} else { 
			setCV(LEDITEM_MAIN_5, val, 1, 9); 
		} 
		Adjust_Date_Value(LEDITEM_MAIN_5); 
		break;
	case 4: 
		//DAY-H 
		month = read_DisBuffer(LEDITEM_MAIN_4)*10 + read_DisBuffer(LEDITEM_MAIN_5); 
		if(month==2) { 
			setCV(LEDITEM_MAIN_7, val, 0, 2); 
		} else { 
			setCV(LEDITEM_MAIN_7, val, 0, 3); 
		} 
		Adjust_Date_Value(LEDITEM_MAIN_7); 
		break;
	case 5:
		if(read_DisBuffer(LEDITEM_MAIN_7)==3) { 
			setCV(LEDITEM_MAIN_8, val, 0, 1); 
		} else { 
			setCV(LEDITEM_MAIN_8, val, 0, 9); 
		} 
		Adjust_Date_Value(LEDITEM_MAIN_8); 
		break;
	case 6:
		setCV(LEDITEM_WEEK, val, 0, 6); 
		break;
	default: 
		break;
	} 

	
	new_date.year   = math_mux(read_DisBuffer(LEDITEM_MAIN_1),10) + read_DisBuffer(LEDITEM_MAIN_2);
	new_date.month  = math_mux(read_DisBuffer(LEDITEM_MAIN_4),10) + read_DisBuffer(LEDITEM_MAIN_5);
	new_date.day   = math_mux(read_DisBuffer(LEDITEM_MAIN_7),10) + read_DisBuffer(LEDITEM_MAIN_8);
	new_date.week   = read_DisBuffer(LEDITEM_WEEK);
	Watch_Update_Display(); 
	return new_date; 
}



//---------------------------------
//Check alam time 
//---------------------------------
void Watch_Start_Alam(void)
{
	u8 i; 
	u16 nowtime; 
	Alert_t alam; 
	static u8 beepn = 0; 

	nowtime = (time.hour<<8)+time.min; 
	if((nowtime>=0x0700)&&(nowtime<0x1200)) { //7:00~18:00
		MC74HC595_Light_Set(80); 
	} else { 
		MC74HC595_Light_Set(30); 
	} 
	if(WatchSet.in.item.set) return; 

	if(on_Alam.enb) { 
		if(on_Alam.inw) { 
			if(on_Alam.time==nowtime) { 
				if(IS_TIMERSTART(e_Timer_Beep)) { 
					if(!IS_TIMEROVER(e_Timer_Beep)) return; 
				}
				if(++beepn<3) { 
					Beeper(TRUE, 150, 150); 
				} else { 
					beepn = 0; 
					Beeper(TRUE, 150, 250); 
				} 
			} else { 
				on_Alam.inw = FALSE; 
				if(on_Alam.cnt==0) on_Alam.enb = FALSE; 
			} 
		} else { 
			if((nowtime-on_Alam.time)>=3) { 
				on_Alam.inw = TRUE; 
				on_Alam.cnt--; 
				on_Alam.time = nowtime; 
			} 
		} 
	}

	
	if(time.sec) return; 
	for(i=0; i<10; i++) { 
		alam = WatchCofing.alart[i]; 
		if(!alam.on) continue; 
		if((alam.begin>alam.end)&&(date.week>alam.end)&&(date.week<alam.begin)) continue; 
		if((alam.begin<alam.end)&&((date.week<alam.begin)||(date.week>alam.end))) continue; 
		if((alam.begin==alam.end)&&(date.week!=alam.begin))continue; 
		if(nowtime==alam.time) { 
			on_Alam.inw = TRUE; 
			on_Alam.enb = TRUE; 
			on_Alam.cnt = 2; 
			on_Alam.id = i; 
			on_Alam.time = nowtime; 
			beepn = 0; 
			return; 
		} 
	} 
} 


void Watch_Show_SetItem(MENUMOD_ITEM mi, char sub)
{ 
	switch(mi) { 
	case MENUMOD_ITEM_TIME: 
		write_DisBuffer(LEDITEM_TEMP_H, LEDWORD_WORDC); 
		write_DisBuffer(LEDITEM_TEMP_L, LEDWORD_WORDH); 
		write_DisBuffer(LEDITEM_WEEK, LEDWORD_BLANK); 
		Watch_Display_Time(time); 
		Watch_Adjust_Time(sub, 0); 
		break; 
	case MENUMOD_ITEM_DATE: 
		write_DisBuffer(LEDITEM_TEMP_H, LEDWORD_WORDC); 
		write_DisBuffer(LEDITEM_TEMP_L, LEDWORD_WORDU); 
		Watch_Display_Date(date);
		Watch_Adjust_Date(sub, 0); 
		break; 
#if OPT_COUNTER
	case MENUMOD_ITEM_COUNT: 
		write_DisBuffer(LEDITEM_TEMP_H, LEDWORD_WORDC); 
		write_DisBuffer(LEDITEM_TEMP_L, 0); 
		write_DisBuffer(LEDITEM_WEEK, LEDWORD_LINE); 
		Watch_Display_Time(on_Ct.set); 
		Watch_Adjust_Time(sub, 0); 
		break; 
#endif 
	case MENUMOD_ITEM_ALAM0:
	case MENUMOD_ITEM_ALAM1:
	case MENUMOD_ITEM_ALAM2:
	case MENUMOD_ITEM_ALAM3:
	case MENUMOD_ITEM_ALAM4:
	case MENUMOD_ITEM_ALAM5:
	case MENUMOD_ITEM_ALAM6:
	case MENUMOD_ITEM_ALAM7:
	case MENUMOD_ITEM_ALAM8:
	case MENUMOD_ITEM_ALAM9:
		Watch_Show_Alam(mi-MENUMOD_ITEM_ALAM0); 
		Watch_Adjust_Time(sub, 0); 
		break; 
	} 
}


//++++++++++++++++++++++++++++++++++ 
//+                         Grounp: time                           +
//++++++++++++++++++++++++++++++++++ 

//---------------------------------
//Function:Watch_Set_ time
//---------------------------------
void Watch_Set_Time(char item, char val)
{
	Watch_Display_Time(time);
	time = Watch_Adjust_Time(item, val);
}

//---------------------------------
//---------------------------------
void Watch_Save_Time(void)
{
	Writetime(time);
}


//+++++++++++++++++++++++++++++++++Grounp: Count down++++++++++++++++++++++++++
#if OPT_COUNTER 
//---------------------------------
//Function: Watch_Set_ count down
//---------------------------------
void Watch_Set_Count(char item, char val)
{ 
	Watch_Display_Time(on_Ct.set); 
	on_Ct.set = Watch_Adjust_Time(item, val);
}

//---------------------------------
//---------------------------------
void Watch_Start_Count(void)
{
	u32 setV; 

	if(!on_Ct.use) return; 

	setV = TimeToSeconds(on_Ct.set); 
	if(on_Ct.pause) { 
		Watch_Display_Time(SecondsToTime(setV-on_Ct.run)); 
		return; 
	} 
	
	if(!on_Ct.full) { 
		if(math_Time(time, on_Ct.base)==0) goto COUNT_DISPLAY; 
		
		on_Ct.run += math_Time(time, on_Ct.base); 
		on_Ct.base = time; 
		if(on_Ct.run>=setV) { 
			on_Ct.run = setV; 
			on_Ct.full = TRUE; 
			STOP_TIMER(e_Timer_Count); 
			START_TIMER(e_Timer_Alam, 30000); 
		} 
	} else { 
		if(IS_TIMEROVER(e_Timer_Alam)) { 
			on_Ct.use = FALSE; 
			on_Ct.full = FALSE; 
			STOP_TIMER(e_Timer_Alam); 
			STOP_TIMER(e_Timer_Count); 
			return; 
		} else { 
			Beeper(TRUE, 300, 500); 
			if(IS_TIMERSTOP(e_Timer_Count)) { 
				START_TIMER(e_Timer_Count, 400); 
			} 
		} 
	} 
COUNT_DISPLAY: 
	if(IS_TIMEROVER(e_Timer_Count)) {
		RESET_TIMER(e_Timer_Count); 
		Watch_Display_Time(SecondsToTime(setV-on_Ct.run)); 
	} 
}


void Watch_Save_Count(void) 
{ 
	time = Readtime(); 
	
	on_Ct.run = 0; 
	on_Ct.sCount = 0; 
	on_Ct.segLeds= 0; 
	on_Ct.full = FALSE; 
	on_Ct.pause = FALSE; 
	on_Ct.use = TRUE; 
	on_Ct.base = time; 
	START_TIMER(e_Timer_Count, 150); 
}
#endif 


//++++++++++++++++++++++++++++++++++Grounp: Alam++++++++++++++++++++++++++++++++
//---------------------------------
//Function: show the alam time
//---------------------------------
void Watch_Show_Alam(char alamID)
{
	u8 s; 
	Alert_t alam; 
	
	alam = WatchCofing.alart[alamID]; 
	
	write_DisBuffer(LEDITEM_TEMP_H, LEDWORD_WORDA); 
	write_DisBuffer(LEDITEM_TEMP_L, alamID); 

	s = (u8)(alam.time>>8); 
	write_DisBuffer(LEDITEM_MAIN_1, math_div(s, 10));	        //Hour ten
	write_DisBuffer(LEDITEM_MAIN_2, math_mod(s, 10));	        //Hour signed
	write_DisBuffer(LEDITEM_MAIN_3, LEDWORD_LINE);   //"-"
	s = (u8)(alam.time); 
	write_DisBuffer(LEDITEM_MAIN_4, math_div(s, 10));	         //minute ten
	write_DisBuffer(LEDITEM_MAIN_5, math_mod(s, 10));		     //minute signed
	write_DisBuffer(LEDITEM_MAIN_6, LEDWORD_BLANK);  //"."
	write_DisBuffer(LEDITEM_MAIN_7, alam.begin); 
	write_DisBuffer(LEDITEM_MAIN_8, alam.end); 
	if(alam.on) { 
		write_DisBuffer(LEDITEM_WEEK, LEDWORD_LINE); 
	} else { 
		write_DisBuffer(LEDITEM_WEEK, LEDWORD_BLANK); 
	} 
	
	Watch_Update_Display(); 
}

//---------------------------------
//Funtion: Watch_Set_ Alam time
//---------------------------------
void Watch_Set_Alam(char alamID, char item, char val)
{ 
	u8 v; 
	Alert_t* alam; 
	TIME alamTime; 
	
	Watch_Show_Alam(alamID);
	switch(item) { 
	case 0: 
		setCV(LEDITEM_MAIN_1, val, 0, 2); 
		if(read_DisBuffer(LEDITEM_MAIN_1)==2){
			setv(LEDITEM_MAIN_2, val, 0, 3); 
		}
		break;
	case 1:
		if(read_DisBuffer(LEDITEM_MAIN_1)==2){
			setCV(LEDITEM_MAIN_2, val, 0, 3); 
		} else { 
			setCV(LEDITEM_MAIN_2, val, 0, 9); 
		}
		break;
	case 2:
		setCV(LEDITEM_MAIN_4, val, 0, 5); 
		break;
	case 3:
		setCV(LEDITEM_MAIN_5, val, 0, 9); 
		break;
	case 4: 
		setCV(LEDITEM_MAIN_7, val, 0, 6); 
		break; 
	case 5: 
		setCV(LEDITEM_MAIN_8, val, 0, 6); 
		break; 
	} 	
	WatchCofing.dirty = TRUE; 
	
	alam = WatchCofing.alart+alamID; 
	alam->on = TRUE; 
	alam->time  = (read_DisBuffer(LEDITEM_MAIN_1)*10+read_DisBuffer(LEDITEM_MAIN_2))<<8; 
	alam->time += (read_DisBuffer(LEDITEM_MAIN_4)*10+read_DisBuffer(LEDITEM_MAIN_5)); 
	alam->begin = read_DisBuffer(LEDITEM_MAIN_7); 
	alam->end   = read_DisBuffer(LEDITEM_MAIN_8); 
	write_DisBuffer(LEDITEM_WEEK, LEDWORD_LINE); 
	
	Watch_Update_Display(); 
}

//---------------------------------
//---------------------------------
void Watch_Save_Alam(void)
{ 
}
//++++++++++++++++++++++++++++++++Grounp: Date+++++++++++++++++++++++++++++++++

//---------------------------------
//Function: set the date
//---------------------------------
void Watch_Set_Date(char item, char val)
{
	Watch_Display_Date(date);
	date = Watch_Adjust_Date(item, val);
}

//---------------------------------
//---------------------------------
void Watch_Save_Date(void)
{
	Writedaliy(date);
}


//---------------------------------
//---------------------------------
void Watch_Flash_SetItem(void)
{
	uCHAR i, item;
 	static char scrow = TRUE;

	if(WatchSet.in.item.adj) { 
		switch(WatchSet.sub) { 
		case 0: 
			item = LEDITEM_MAIN_1; 
			break; 
		case 1: 
			item = LEDITEM_MAIN_2; 
			break; 
		case 2: 
			item = LEDITEM_MAIN_4; 
			break; 
		case 3: 
			item = LEDITEM_MAIN_5; 
			break; 
		case 4: 
			item = LEDITEM_MAIN_7; 
			break; 
		case 5: 
			item = LEDITEM_MAIN_8; 
			break; 
		default: 
			item = LEDITEM_WEEK; 
			break; 
		} 
		
		if(scrow) { 
			WatchSet.temp = *(dis_buffer+item); 
			*(dis_buffer+item) = LEDWORD_BLANK;
		} else { 
			*(dis_buffer+item) = WatchSet.temp;
		} 
	} 
	scrow = !scrow;
	Watch_Update_Display(); 
}


//---------------------------------
//---------------------------------

void Watch_Init(void) 
{ 
	uCHAR i; 
	
	MC74HC595_Init(); 
	for(i=0; i<11; i++) { 
		dis_buffer[i] = LEDWORD_LINE; 
	} 
	
	Watch_Update_Display(); 
	Ds1302_Init();
} 



5.5 电子表核心数据结构

typedef struct {
	uCHAR hour;
	uCHAR min;
	uCHAR sec;
}TIME;

typedef struct {
	uCHAR year;
	uCHAR month;
	uCHAR day;
	uCHAR week;
}DATE;

typedef struct { 
	u8 on:1;    //响闹开关 
	u8 begin:6; //响闹周期开始
	u8 end;     //响闹周期结束
	u16 time;   //响闹时间
}Alert_t;  

typedef struct { 
	u8 dirty; 
	u8 leddute; 
	u16 rfaddr; 
	//====================
	//Alert Set
	//====================
	Alert_t alart[10]; 
}WatchCfg_t; 

typedef struct { 
	u8 enb:1; //闹钟已经打开 
	u8 inw:1; //闹钟正在运行
	u8 id:6;  //闹钟编号 
	u8 cnt;   //重复提醒次数
	u16 time; //最后一次响闹时间
}Alam_t; 

#if OPT_COUNTER
typedef struct { 
	u8 use:1; 
	u8 full:1; 
	u8 pause:1; 
	u8 sCount:5; 
	u8 segLeds; 
	TIME run; 
	TIME set; 
	TIME base; 
}Counter_t;  
#endif 

typedef struct { 
	union { 
		struct { 
			u8 set:1;    //in set statu 
			u8 adj:1;    //in adjust statu 
			u8 show:1;   //in show alam item or date 
			u8 modify:1; //item is modify 
		}item; 
		u8 items; 
	}in; 
	u8 item; //main set item 
	u8 sub;  //sub set item 
	u8 temp; //backup digtal value 
}WatchSet_t; 



5.6  主任务程序

Main.c


/* MAIN.C file
 * 
 * Copyright (c) 2002-2005 STMicroelectronics
 */

#include "Config.h"

DATE date;
TIME time;
extern volatile _Bool Synch; 
extern volatile Alam_t on_Alam; 
#if OPT_COUNTER
extern volatile Counter_t on_Ct; 
#endif 
extern volatile WatchSet_t WatchSet; 
extern volatile WatchCfg_t WatchCofing; 
extern volatile XTIMER Timer[e_Timer_Max];


void memclr(void* src, u8 len)
{
	while(len--){ *((u8*)src+len) = 0x00; }
}

void RESTART(void) 
{ 
	WWDG_CR |= BIT(7); 
	WWDG_CR &= ~BIT(6); 
}

#if OPT_WATCHDOGDEMON 
void Watchdog_Init(void)
{ 
	WWDG_CR &= ~BIT(7); //Stop Window watchdog 
	WWDG_CR = 0x7F; 
	
	IWDG_KR = 0xCC; //启动IWDG
	IWDG_KR = 0x55; //解除 PR 及 RLR 的写保护
	IWDG_RLR = 0xff; //看门狗计数器重装载数值 	  
	IWDG_PR = 0x06; //分频系数为256,最长超时时间为:1.02S
	IWDG_KR = 0xAA; //刷新IDDG,避免产生看门狗复位,同时恢复 PR 及 RLR 的写保护状态
}
#else 
void Watchdog_Init(void) {_asm("nop"); }
#endif 

/*********************************************
函数功能:系统内部时钟配置
*********************************************/
void Init_SystemClock(void)
{
	//时钟配置为内部RC,16M
	CLK_CKDIVR &= ~(BIT(4)|BIT(3));
}

void Ready(void) 
{
	START_TIMER(e_Timer_RunTick, 500);  //in 800mS
}

//_Bool on = FALSE;
void doTaskScheduler(void) 
{ 
	static s8 taskID = -1, c=0;  
	
	Decode_Task(); 
	switch(taskID) { 
	case 0: 
		Beeper_Task(); 
		break; 
	case 1: 
		KeyProcess();//Countflag 
		break; 
	case 2: 
		if(c)Watch_Start_Alam();
		break; 
	case 3: 
		Temperature_Task();  
		break; 
	case 4: 
		ExitMenu(FALSE); 
		break; 
	case 5: 
#if OPT_COUNTER
		if(!WatchSet.in.items && on_Ct.use) { 
			Watch_Start_Count();  
		}
		break; 
#endif 
	default: 
		taskID = -1; 
		if(!IS_TIMEROVER(e_Timer_RunTick)) break; 
		RESET_TIMER(e_Timer_RunTick); 
		if(WatchSet.in.items) { 
			if(WatchSet.in.item.adj) { 
				Watch_Flash_SetItem(); 
			} 
		} else { 
			c = 1; 
			date = Readdaliy();
			time = Readtime();
#if OPT_COUNTER
			if(!on_Ct.use) 
#endif 
			{ 
				Watch_Display_Time(time); 
			} 
		} 
		break; 
	} 
	++taskID; 
}

void InitDeviceConfig(void) 
{
	memclr((void*)0, 1024); 
	Load_WatchCofing(); 
	Watch_Init(); 
	//TimerInit();
	Key_Init(); 
	Beeper_Init(); 
	Decode_Init(); 
	Temperature_Init(); 

	SystemTimer_Init();  //初始化系统定时器,软定时器时钟源
	Watchdog_Init();
	_asm("rim");    //开总中断
}

int main(void)
{ 	
	Init_SystemClock();
	//Init Device Hardware 
	InitDeviceConfig();
	
	Ready();
	for(;;) {
		RESETWDT();
		doTaskScheduler(); 
	}
}


单帖长度限制,部份代码,后面跟贴附上


本来计划做一个倒计时功能,功能也调好接近80%,但是因为程序空间限制,只好做罢。当前代码使用空间看STVP截图,刚刚好。


 


六、作品演示

请上传您的作品的功能演示到腾讯视频,并编辑到本楼(或附上视频链接)。按要求上传视频可获得5分,具体详见活动规则。

     演示视频: https://v.qq.com/x/page/i0541pw1mvs.html



七、总结

例如您在完成该作品过程中的一些体会、碰到的技术问题或调试经验、作品的未来规划,及对我们主办方的建议和意见等。

小朋友的暑假快结束了,这个项目的时间也所剩无几。因为工作的原因,也因为小朋友磨蹭的原因,这个项目过程中也耽误了不少的时间,只到在距结束不到一周的时间才开始写代码。还好因为这个项目是十多年之前做过的,只需要做一些移植。但是因为电路结构的变化,以前对十年前水平的不满意,还是对代码进行了大手术。在暑假中带孩子完成这个项目还是挺有成就感的。孩子在过程中焊接了全部的电路,而我只做一些指导,进行程序调试。以及明天22号还需要演示,我只负责录象以及视频的剪辑等等。希望通过这样的项目可以让孩子了解并喜欢发明(开发)这个行业。培养他的动手能力等。
当然设计中也有许多不足,比如外观设计时没有考虑到数码管本身的黑底,将它装在淡蓝色的亚克力板上而显得有些突兀。在电路中没有布置测温电路,最后取消了485通讯电路面改接了测温电路等。亚克力板上的文字想用贴纸盖住再喷白漆,但因为字体只有7MM高,而割字机割不出来,最后用激光机雕刻而字迹并没那么明显。为了美观,孩子还专门找做木工的爷爷做了一个木质的外框,但因为时间有限没有时间来给外框来进行装饰,油漆木框,给蓝色亚克力喷上黑色,描出白字等。但作为一个启蒙项目,所有的目的都己达到了。虽然做这个项目还是花了一些代价的。全部算下来,已经超出了500元。但是这些付出还是值得的。中间对孩子的严厉,责骂,都是想让他做得更好,希望孩子也能理解。
这个项目的部份代码涉及到公司的部份代码,就不全部开源,但是将相关部份的代码已经贴在第五项内,有意思的可以参考下。十年前的源代码及原理图,将附件在文后,有兴趣的请自己下载DIY


想重制的请下载资料:重制资料.rar 



主题

回复
发表于2017-08-26 13:52:21   |  显示全部楼层
41#
恭喜楼主获得了第二届立创商城电子制作节入围奖,虽然距离30强还有些小差距,30强&入围奖名单:http://club.szlcsc.com/article/details_8910_1.html
但到明年的第三届电子制作节,带上您更成熟的作品参赛时,也许就能一举夺冠了呢,现在,有众多优秀作品让你参考,投票:http://club.szlcsc.com/article/details_8913_1.html

主题

回复
  • 温馨提示: 标题不合格、重复发帖、发布广告贴,将会被删除帖子或禁止发言。 详情请参考: 社区发帖规则
  • 您当前输入了 0 个文字。还可以输入 8000 个文字。 已添加复制上传图片功能,该功能目前仅支持chrome和火狐

禁言/删除

X
请选择禁言时长:
是否清除头像:
禁言/删除备注:
昵 称:
 
温馨提示:昵称只能设置一次,设置后无法修改。
只支持中文、英文和数字。

举报

X
请选择举报类型:
请输入详细内容:

顶部