网上采购的LED点阵时钟散件,所有贴片都焊好了,只有一些分立的器件需要自己焊接。
----------------------------------------------------------
不过其毛病还是不少的,硬件方面:器件基本都是比较便宜的,时钟晶振偏差大,温度检测BS18B20使用的是1820,比18B20低了一个档次,安装在LED附近,受其发热影响大。软件方面,点阵刷新不是使用定时中断,因此略带闪烁,显示亮度不可调整。没有亮度传感器,IO口基本都用上了,也不好加了。 硬件改装:晶振并联自制双绞线电容,微调时钟快慢,可调至每天误差1秒以内;换上BS18B20,将其引到背板外,背板里再衬铝箔反射热辐射。
软件方面:程序全部抛弃重写,写了20多年代码,这点事情小意思。修改点阵字形,改进显示扫描方法,换成定时中断触发,点阵横向有22线,连接22个IO口,排列顺序竟然不连续,因此原扫描程序用了22个case语句,就是一次显示扫描最多可能经过22次判断,太蠢笨了,改成查表式,几条语句就办了。通过改变端口输出的占空比,可以调整LED显示亮度,分成亮、暗两档,在不同时间段自动切换,这样晚上就不会太刺眼。改进显示切换方法,显示时间几秒后自动滚出温度、日期、星期。23日下面的七个点代表星期日,星期一到六各有不同点的图案组合,容易辨别。
中心下方的点代表有一个闹钟开启,闹钟可设置工作日响,休息日不响。 虽然硬件提高了时钟精度,但软件可以进一步校准。可设定一定时间内加减的秒数。例如一个月下来快20秒,可设定每三十天减去20秒,一个月的误差缩小到1秒以内,一年就是12秒,或正负六秒。当然温飘无法控制,完成一年的周期后再对数值具体调整吧。还有温度偏高的问题,减少温度测量频率,降低传感器自身发热,再对温度数值自动加以补偿。 可惜IO口不够,Flash 24K的空间也没法加太多功能,为了节省内存绞尽脑汁,自己设计了根据日期判断星期的算法,两行语句就解决了,这个世纪不会有问题。不重要的功能只能省去了,否则可以加wifi或电波钟模块进行自动校时,把蜂鸣器换成小扬声器可以把闹钟改成音乐的,加光敏器件可以自动调整亮度等。
【程序示例】原先的点阵扫描版本,col1-col22对应P0、P1、P2端口各位: sbit col1 = P0^0;//点阵上第22脚
sbit col2 = P0^1;//点阵上第21脚
sbit col3 = P0^2;//点阵上第2脚
sbit col4 = P0^3;//点阵上第19脚
sbit col5 = P0^4;//点阵上第5脚
sbit col6 = P0^5;//点阵上第6脚或17脚
sbit col7 = P0^6;//点阵上第16脚
sbit col8 = P0^7;//点阵上第8脚
sbit col9 = P2^0;//点阵上第13脚
sbit col10 = P2^1;//点阵上第10脚
sbit col11= P2^2;//点阵上第11脚
sbit col12 = P1^0;//点阵上第22脚
sbit col13 = P1^1;//点阵上第21脚
sbit col14 = P1^2;//点阵上第2脚
sbit col15 = P1^3;//点阵上第19脚
sbit col16 = P1^4;//点阵上第5脚
sbit col17 = P1^5;//点阵上第6脚或17脚
sbit col18 = P1^6;//点阵上第16脚
sbit col19 = P1^7;//点阵上第8脚
sbit col20 = P2^4;//点阵上第13脚
sbit col21 = P2^5;//点阵上第10脚
sbit col22 = P2^6;//点阵上第11脚
.....
switch(k+1)
{
case 1: col1=0; break;
case 2: col2=0; break;
case 3: col3=0; break;
case 4: col4=0; break;
case 5: col5=0; break;
case 6: col6=0; break;
case 7: col7=0; break;
case 8: col8=0; break;
case 9: col9=0; break;
case 10: col10=0; break;
case 11: col11=0; break;
case 12: col12=0; break;
case 13: col13=0; break;
case 14: col14=0; break;
case 15: col15=0; break;
case 16: col16=0; break;
case 17: col17=0; break;
case 18: col18=0; break;
case 19: col19=0; break;
case 20: col20=0; break;
case 21: col21=0; break;
case 22: col22=0; break;
default:break;
}
....
---------------------------------------------------
改进后的:
//端口掩码表
code BYTE P0Map[] = {0xFE,0xFD,0xFB,0xF7,0xEF,0xDF,0xBF,0x7F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF};
code BYTE P1Map[] = {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFE,0xFD,0xFB,0xF7,0xEF,0xDF,0xBF,0x7F,0xFF,0xFF,0xFF};
code BYTE P2Map[] = {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFE,0xFD,0xFB,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xEF,0xDF,0xBF};
// 二十二个列的掩码,每次只有一列中一个位为0
P0 = P0Map[k];
P1 = P1Map[k];
P2 = (P2 | 0x77) & P2Map[k];
虽然第一个好理解,但第二个编译后字节数少多了,效率平均提高10倍。
下面这个是计算星期的,原创。
//---------------------------------------------------------------
// 函数名称:intWeekDay(int year, int month, int day)
// 函数功能:由日期计算今天为星期几
// 入口参数:int year, int month, int day
// 出口参数:星期1 - 7 7为星期日
//-----------------------------------------------------------------
char ReturnWeekDay( char iYear, char iMonth, char iDay )
{
static code BYTE day1[] = { 0, 0, 0, 4, 0, 2, 5, 0, 3, 6, 1, 4, 6, 2, 5 }; // 2013年 3-12月的一日 与2014年1-2月 一日,0=星期1,6= 星期日
// -,-,-,3月,4月,5月,6月,7月,8月,9月,10月,11月,12月,次年1月,次年2月
if (iMonth <= 2){ iYear--; iMonth += 12;}
return (int)(day1[iMonth] + (iYear - 13) + (iYear - 13 + 1) / 4 + iDay - 1) % 7 + 1; // Fox自创公式,适合2013年以后,未加400年修正
}
代码,Keil uVision4编译:
[ 此帖被fox69在2017-04-23 18:51重新编辑 ]