WinFlash 强刷版
WinFlash2.exe 移除了BIOS类型判断,解决了改刷 DELL SYSTEM 后,再次刷机提示“OnBoard BIOS Not Award BIOS”问题!
由于移除了BIOS类型判断,开刷前请务必确认主板BIOS类型,避免酿成悲剧!
下载地址:
http://pan.baidu.com/share/link?shareid=1349327649&uk=1495204045
WinFlash2.exe 移除了BIOS类型判断,解决了改刷 DELL SYSTEM 后,再次刷机提示“OnBoard BIOS Not Award BIOS”问题!
由于移除了BIOS类型判断,开刷前请务必确认主板BIOS类型,避免酿成悲剧!
下载地址:
http://pan.baidu.com/share/link?shareid=1349327649&uk=1495204045
1、增加来去电归属地查询
2、支持音量键唤醒
3、移植CM9的Trebuchet启动器
4、移植CM9的DSP管理器
5、移植Apollo播放器
6、移植下拉快捷开关
7、修改为2%的环形电量指示器
8、增加MIUI文件管理(可以修改系统文件及FTP文件管理)
9、增加Superuser(ROOT管理)
a、增加拨号T9拼音检索联系人
b、移植CM9短信,改“添加联系人”为有手机号的联系人(原为常联系人)
c、精简掉 MusicFX.apk、Maps.apk、Music.apk、Talk.apk
刷机方法参照:小米手机6种刷机详细教程
文件名:mione_plus-ota-QDR68_20121202.signed.zip,访问地址:
http://pan.xiaomi.com/file/id_67101150238736728.htm
从10月份开始做,中间插入做了一个抢答器,走走停停搞到如今总算满意收工。
主要功能:可设置系统参数,可保存调用系统参数。电机通电记录时长,每通电一次自动换一次电压档,检测微动开关状态,检测从微动开关状态,判定时长,通过数码管和LED灯显示,蜂鸣器警报。
原理图:
程序:
//test.c*/
sfr WDT = 0xA6; // 89S52 Watchdog Timer */
#include <intrins.h>
#include <stdio.h>
#include<AT89X52.H>
#include<stdlib.H>
#include <AT24C16.h>
#define uchar unsigned char
#define WDTRST WDT=0x1E;WDT=0xE1;
#define LEDCode P0
#define LEDdisplay P2
#if 0
#define MENU_PIN P1_4
#define PLUS_PIN P1_3
#define REDUCE_PIN P1_2
#define MASTER_PIN P3_3
#define SLAVE_PIN P1_2
#define BOARD_PIN P1_4
#define L1_PIN P1_0
#define L2_PIN P1_1
#define L3_PIN P1_3
#else
#define MASTER_PIN P3_3 //定义通电端口
#define MENU_PIN P1_7 //定义设置按钮
#define PLUS_PIN P1_6 //定义加键按钮
#define REDUCE_PIN P1_5 //定义减键按钮
#define SLAVE_PIN P1_4 //定义从微动端口
#define BOARD_PIN P1_3 //定义安装板端口
#define L3_PIN P1_2 //定义档位端口
#define L2_PIN P1_1 //定义档位端口
#define L1_PIN P1_0 //定义档位端口
#endif
#define BELL P3_7 //蜂鸣器端口
static uchar code digital[]= {0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xd8,0x80,0x90,0xa0,0xa1,0xa3,0xc7,0x88,0x89,0x91}; //字库码"0,1,2,3,4,5,6,7,8,9,a,d,o,L,R,H,y"
static uchar code select[]={0xff,0xef,0xdf,0xbf,0x7f}; //选位字码
static uchar bod_led[]={0x00,0xfb}; //安装板指示灯 (开关[0],显示代码[1])
static uchar sla_led[]={0x01,0xf7}; //辅助触点指示灯(开关[0],显示代码[1])
static uchar relay[]={0x01,0xff,0xfc,0xfd,0x01}; //继电器三个档位(档位[0],档位代码[1]-[3],记忆上次档位)
static signed char SLa[]={0x01,0x01,0x0a,0x0d,0x05,0x00}; //定义从微动检测(闪动位[0],显示[1]-[4],小数点[5])
static signed char Bod[]={0x01,0x01,0x0b,0x0c,0x08,0x00}; //定义安装板检测
static signed char L1[]={0x03,0x05,0x09,0x00,0x0d,0x02}; //定义第1档最大容忍时间
static signed char L2[]={0x03,0x00,0x06,0x00,0x0e,0x02}; //定义第2档最大容忍时间
static signed char L3[]={0x03,0x00,0x04,0x00,0x0f,0x02}; //定义第3档最大容忍时间
static signed char dis[]={0x00,0x07,0x06,0x10,0x08,0x00}; //分配计时空间
static signed char led[]={0,0,0,0,0}; //计时数据临时存放
static signed char *p=dis; //显示指针
static bit write;//数据保存
static uchar index = 0x01; //起始显示位
static uchar delay; //等待时间,用于主从微动切换
static bit menu; //调用设置项
static bit changed; //选项切换
static unsigned int belltime; //蜂鸣器时长控制
//延迟时长大约为3us*x*/
void delay3xus(int unsigned x)
{
unsigned int i;
for(i=0;i<x;i++){WDTRST};
}
//参数读取*/
void read()
{
uchar i;
READ_BYTE(5,&SLa[1]);
READ_BYTE(10,&Bod[1]);
for(i=1;i<4;i++)
{
READ_BYTE(i+15,&L1[i]);
READ_BYTE(i+20,&L2[i]);
READ_BYTE(i+25,&L3[i]);
}
}
//参数保存*/
void save()
{
uchar i;
P3= 0xfe; //设置存储器可写
EA= 0x00; //禁止其他中断,优先处理此程序
P2 =0xff;
P0 = 0xff;
P1= 0xff;
WRITE_BYTE(5,SLa[1]);
delay3xus(500); //写操作需要等待存储器
WRITE_BYTE(10,Bod[1]);
delay3xus(500);
for(i=1;i<4;i++)
{
WRITE_BYTE(i+15,L1[i]);
delay3xus(500);
WRITE_BYTE(i+20,L2[i]);
delay3xus(500);
WRITE_BYTE(i+25,L3[i]);
delay3xus(500);
}
P3= 0xff; //设置存储器只读
EA= 0x01;
}
//初始化*/
void init()
{
P0 = 0xff;
P1 = 0xff;
P2 = 0xff;
P3 = 0xff;
EX0 = 0x00;
ET0 = 0x00;
EX1 = 0x00;
ES = 0x00;
TL0= 0xa0; //定时器T0=30ms
TH0= 0x15;
TL1= 0xbf; //定时器T1=4ms
TH1= 0xe0;
TMOD = 0x11; //设置定时器模式
ET1 = 0x01; //允许定时器T1中断
TR1= 0x01; // 启用定时器T1
TL2= 0xe0; //10ms
TH2= 0xb1;
RCAP2H=TH2; //中断溢出自动对TH2赋值(T2定时器为16位自动硬件赋值,故不必在中断产生后,再对寄存器再次赋值,但需要对TF2状态进行清零)
RCAP2L=TL2; //中断溢出自动对TL2赋值
T2MOD= 0x00; //设置为定时器
ET2 = 0x00; // 允许T2中断
TR2 = 0x00; // 启动定时器
EA = 0x01; //中断总开关
}
bit shift_voltage();
void clear();
void voltage_led(uchar tmp);
//按键数值加减处理*/
void plus_reduce()
{
if(!PLUS_PIN)
{
delay3xus(25000);
p[1]+=1;
if(p[1]>9)
{
p[2]+=1;
if(p[2]>9)
{
p[2]=0;
if(++p[3]>9) p[3]=0;
}
p[1]=0;
}
write =1;
}
else if(!REDUCE_PIN)
{
delay3xus(25000);
p[1]-=1;
if(p[1]<0)
{
p[2]-=1;
if(p[2]<0)
{
p[2]=9;
if(--p[3]<0) p[3]=9;
}
p[1]=9;
}
write =1;
}
}
//调用参数设置页
* menu、changed条件通过T1检测
*/
void setting(void)
{
if(menu)
{
P3= 0xff;
delay3xus(0xffff);
while(menu)
{
WDTRST
p=SLa; //从微动设置项
if(!PLUS_PIN)
{
delay3xus(25000);
p[1]=!p[1];
write =1; //数据改变,需要更新
}
else if(!REDUCE_PIN)
{
delay3xus(25000);
p[1]=!p[1];
write =1;
}
if(changed)
{
changed=0;
if(menu)
{
p=Bod; //安装板设置项
delay3xus(33333);
}
while(menu)
{
WDTRST
if(!PLUS_PIN)
{
delay3xus(25000);
p[1]=!p[1];
write =1;
}
else if(!REDUCE_PIN)
{
delay3xus(25000);
p[1]=!p[1];
write =1;
}
if(changed)
{
changed=0;
break;
}
}
if(menu)
{
p=L1; //第一档时间设置
delay3xus(33333);
}
while(menu)
{
WDTRST
plus_reduce();
if(changed)
{
changed=0;
break;
}
}
if(menu)
{
p=L2; //第二档时间设置
delay3xus(33333);
}
while(menu)
{
WDTRST
plus_reduce();
if(changed)
{
changed=0;
break;
}
}
if(menu)
{
p=L3; //第三档时间设置
delay3xus(33333);
}
while(menu)
{
WDTRST
plus_reduce();
if(changed)
{
changed=0;
break;
}
}
}
}
clear();
voltage_led(relay[0]);
}
p=dis; //退出设置菜单,回到计时状态
if(write)
{
save();
write=0; //已保存
relay[0]=3; //初始化继电器
shift_voltage(); //初始化继电器
clear(); //初始化计时器
voltage_led(relay[0]); //初始化继电器
}
}
//用于主从微动切换等待延迟*/
void start_t0(uchar t)
{
ET0 = 0x01;
TR0= 0x01;
delay=t;
}
//用于主从微动切换等待延迟*/
void stop_t0()
{
TL0= 0xa0;
TH0= 0x15;
TMOD = 0x11;
ET0 = 0x00;
TR0= 0x00;
}
//开始计时*/
void start_t2()
{
ET2 = 0x01;
TR2 = 0x01;
}
//停止计时*/
void stop_t2()
{
TL2= 0xe0;
TH2= 0xb1;
ET2 = 0x00;
TR2 = 0x00;
}
//主微动检测,去抖动*/
bit master()
{
uchar sum[]={100,300};
while(sum[0]&&sum[1]) //300*20us
{
MASTER_PIN=1;
_nop_();
if(MASTER_PIN)
{
sum[0]--;
}
else
{
sum[1]--;
}
WDTRST
}
return (bit)sum[0];
}
//从微动检测,去抖动*/
bit slave()
{
uchar sum[]={100,300};
while(sum[0]&&sum[1]) // 300*20us
{
SLAVE_PIN=1;
_nop_();
if(SLAVE_PIN)
{
sum[0]--;
}
else
{
sum[1]--;
}
WDTRST
}
return (bit)sum[0];
}
//报警蜂鸣*/
void bell()
{
if(!belltime)
{
BELL=0;
belltime=500; //蜂鸣时长控制
}
}
//清空计时*/
void clear()
{
dis[0]=0; //闪动位
dis[1]=0; //数值1
dis[2]=0; //数值2
dis[3]=0; //数值3
dis[4]=0; //数值4
dis[5]=3; //标点符号位
}
//处理时长警报*/
void time_chk()
{
bit overtime=0;
//超时报警处理 */
switch(relay[0])
{
case 0x01:
if(L1[3]>dis[4]) break;
else if((L1[3]==dis[4]))
{
if(L1[2]>dis[3]) break;
else if(L1[2]==dis[3])
{
if(L1[1]>dis[2]) break;
else if(L1[1]==dis[2]) break;
else overtime=1; break;
}else overtime=1; break;
}else overtime=1; break;
case 0x02:
if(L2[3]>dis[4]) break;
else if((L2[3]==dis[4]))
{
if(L2[2]>dis[3]) break;
else if(L2[2]==dis[3])
{
if(L2[1]>dis[2]) break;
else if(L2[1]==dis[2]) break;
else overtime=1; break;
}else overtime=1; break;
}else overtime=1; break;
case 0x03:
if(L3[3]>dis[4]) break;
else if((L3[3]==dis[4]))
{
if(L3[2]>dis[3]) break;
else if(L3[2]==dis[3])
{
if(L3[1]>dis[2]) break;
else if(L3[1]==dis[2]) break;
else overtime=1; break;
}else overtime=1; break;
}else overtime=1; break;
default:
;
}
if(overtime)
{
dis[0]=4; //计时器闪动
bell();
}
}
//换电压档位*/
bit shift_voltage()
{
char tmp=relay[0]; //程序过程不对继电器状态直接操作,避免继电器抖动
if(!(L1_PIN&&L2_PIN)) return 0; //人工操作电压档,不进行换挡操作,直接返回
if(++tmp>3) tmp=1; //换挡
//空档跳过*/
switch(tmp)
{
case 1:
if(!L1[1]&&!L1[2]&&!L1[3])
{
tmp++;
if(!L2[1]&&!L2[2]&&!L2[3])
{
tmp++;
if(!L3[1]&&!L3[2]&&!L3[3])
{
tmp=1;
}
}
}
break;
case 2:
if(!L2[1]&&!L2[2]&&!L2[3])
{
tmp++;
if(!L3[1]&&!L3[2]&&!L3[3])
{
tmp=1;
// if(!L1[1]&&!L1[2]&&!L1[3])
// {
// tmp=1;
// }
}
}
break;
case 3:
if(!L3[1]&&!L3[2]&&!L3[3])
{
tmp=1;
if(!L1[1]&&!L1[2]&&!L1[3])
{
tmp++;
if(!L2[1]&&!L2[2]&&!L2[3])
{
tmp=1;
}
}
}
break;
default:;
}
relay[4]=relay[0];
relay[0]=tmp; //处理换挡完毕,将档位数值写入继电器档位,换挡完成
return 1;
}
//档位指示灯*/
void voltage_led(uchar tmp)
{
switch(tmp)
{
case 1:
P3_4=1;P3_5=0;P3_6=1;break;
case 2:
P3_4=0;P3_5=1;P3_6=0;break;
default:
P3_4=0;P3_5=0;P3_6=0;break;
}
}
/
bit bod_open=0;//需要重新调节电压档,临时解除“电机拿出测试台,恢复到首档” ,计时过程开始恢复正常
void renew()
{
if(!MENU_PIN) bod_open=0; //按设置按钮解除“电机拿出测试台,恢复到首档”
if(Bod[1]&&BOARD_PIN&&L1_PIN&&L2_PIN&&L3_PIN&&bod_open)
{
if(L1[1]||L1[2]||L1[3])
{
relay[4]=relay[0]=1;
}
else if(L2[1]||L2[2]||L2[3])
{
relay[4]=relay[0]=2;
}
else if(L3[1]||L3[2]||L3[3])
{
relay[4]=relay[0]=3;
}
else relay[4]=relay[0]=1;
voltage_led(relay[0]) ;
}
}
// 人工操作电压档位*/
void manual_control()
{
char tmp=relay[0];
if(!L3_PIN) //档位端口3,设置为第三档
{
tmp=3;
relay[4]=relay[0]=tmp;
voltage_led(relay[0]) ;
}
else if(!L2_PIN) //档位端口2,设置为第二档
{
tmp=2;
relay[4]=relay[0]=tmp;
voltage_led(relay[0]) ;
}
else if(!L1_PIN) //档位端口1,设置为第一档
{
tmp=1;
relay[4]=relay[0]=tmp;
voltage_led(relay[0]) ;
}
else if(!PLUS_PIN)
{
delay3xus(25000);
shift_voltage();
tmp=relay[4]=relay[0];
voltage_led(relay[0]) ;
}
else if(!REDUCE_PIN)
{
delay3xus(25000);
if(--tmp<1) tmp=3;
switch(tmp)
{
case 1:
if(!(L1[1]||L1[2]||L1[3]))
{
tmp=3;
if(!(L3[1]||L3[2]||L3[3]))
{
tmp--;
if(!(L2[1]||L2[2]||L2[3]))
{
tmp=1;
}
}
}
break;
case 2:
if(!(L2[1]||L2[2]||L2[3]))
{
tmp--;
if(!(L1[1]||L1[2]||L1[3]))
{
tmp=3;
if(!(L3[1]||L3[2]||L3[3]))
{
tmp=1;
}
}
}
break;
case 3:
if(!(L3[1]||L3[2]||L3[3]))
{
tmp--;
if(!(L2[1]||L2[2]||L2[3]))
{
tmp--;
if(!(L1[1]||L1[2]||L1[3]))
{
tmp=1;
}
}
}
break;
default:;
}
relay[4]=relay[0]=tmp;
voltage_led(relay[0]) ;
}
}
//主函数入口,主要过程为控制计时和状态检测*/
void main()
{
unsigned int i;
init(); //初始化寄存器
read(); //读取设置参数
for(i=2500;i!=0;i--) delay3xus(0xff); //冷开机,比较器输入电容预充电,需要等待
relay[0]=3; //初始化继电器参数
shift_voltage(); //使继电器恢复到首参数档位
clear();
voltage_led(relay[0]) ;
while(1)
{
setting() ; //设置参数
WDTRST
renew(); //电机拿出测试台,恢复到首档
manual_control(); //手工操作电压档
//主微动闭合,通电开始*/
if(master())
{
start_t2(); //启动计时
voltage_led(relay[0]) ;
start_t0(35);
while(delay&&master())
{
if(!slave())
{
stop_t0();
break;
}
WDTRST
}
stop_t0();
if(!delay&&SLa[1])
{
bell();
}
//主微动闭合,从微动断开,通电过程*/
while(master())
{
if(slave())
{
start_t0(35);
while(delay)
{
if(!master())
{
break;
}
WDTRST
}
if(!delay&&SLa[1])
{
bell();
continue;
}
}
}
stop_t2();
if(!(led[2]||led[3]||led[4]))
{
for(i=1;i<5;i++) led[i]=0;
voltage_led(relay[4]);
continue;
}
//主微动断开,通电过程结束*/
start_t0(35);
while(delay)
{
WDTRST
if(slave())
{
start_t0(13);
while(delay)
{
if(!slave()||master())
{
stop_t0();
break;
}
WDTRST
}
if(master())
{
delay=1;
break;
}
else if(delay)
{
delay=0;
break;
}
else
{
delay=1;
break;
}
}
else if(master())
{
stop_t0();
break;
}
}
if(!delay&&SLa[1])
{
bell();
}
time_chk();
shift_voltage();
for(i=1;i<5;i++) led[i]=0; //清空临时计时
bod_open=1; //通电一次恢复“电机拿出测试台,恢复到首档 ”
if(Bod[1]) //安装板检测
{
if(BOARD_PIN) bell();
}
}
}
}
//定时器T0主要用于主从微动开关延迟等待用*/
void t0() interrupt 1 //30ms
{
TL0+= 0xa0;
TH0+= 0x15;
if(delay>0)
{
delay--;
}
else
{
ET0=0;
TR0=0;
TL0= 0xa0;
TH0= 0x15;
}
}
/
static uchar skip,count;
void t1() interrupt 3 //4ms
{
TL1+= 0xbf;
TH1+= 0xe0;
sla_led[0]=!SLAVE_PIN;
bod_led[0]=!BOARD_PIN;
if(belltime)
{
belltime--;
}else BELL=1;
if(index>p[0])
{
LEDCode = digital[p[index]]&(p[5]==index?0x7f:0xff);
LEDdisplay = select[index]&(bod_led[0]?bod_led[1]:0xff)&(sla_led[0]?sla_led[1]:0xff)&relay[relay[0]];
}
else if( skip >4 )
{
LEDCode = digital[p[index]]&(p[5]==index?0x7f:0xff);
LEDdisplay = select[index]&(bod_led[0]?bod_led[1]:0xff)&(sla_led[0]?sla_led[1]:0xff)&relay[relay[0]];
if(index==p[0]) skip=0;
}
else
{
LEDCode = p[5]==index?0x7f:0xff;
LEDdisplay = select[index]&(bod_led[0]?bod_led[1]:0xff)&(sla_led[0]?sla_led[1]:0xff)&relay[relay[0]];
}
if(++index>4)
{
index=0x01;
skip++;
}
if(!MENU_PIN)
{
if(count<200) count++;
}
else
{
if(count==200)
{
menu=!menu;
count=0;
}
else if(count>10)
{
changed=1;
}
count=0;
}
}
//AT89S52特有的16位中断自动载入TH2、TL2计时器,用于通电时长计时*/
void t2() interrupt 5 //10ms
{
uchar i;
TF2 = 0; // 溢出标志必须由软件清零
EXF2 = 0; // 捕获标志必须由软件清零
menu=0;//测试过程不可设置
if(++led[1]>9)
{
led[1]=0;
if(++led[2]>9)
{
led[2]=0;
if(++led[3]>9)
{
led[3]=0;
if(++led[4]>9)
{
led[4]=0;
}
}
}
}
if(led[4]||led[2]||led[3])
{
dis[0]=0;
dis[5]=3;
for(i=1;i<5;i++)
{
dis[i]=led[i];
}
}
}
//AT24C16.H*/
#ifndef __AT24C16_H__
#define __AT24C16_H__
#include <intrins.h>
#define uchar unsigned char
#define Delay1us() _nop_();_nop_()
#define Delay2us() _nop_();_nop_();_nop_();_nop_()
#define Delay5us() _nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_()
sbit SDA=P3^2; //模拟数据线
sbit SCL=P3^1; //模拟时钟线
//sbit WC=P3^0; //读写控制线
//开始信号
void START_I2C(void)
{
SCL=1; //空闲状态
Delay5us();
SDA=0; // 1->0跳变,开始
Delay5us();
SCL=0; //准备发送数据
Delay1us();
}
//结束信号
void STOP_I2C(void)
{
SDA=0;
SCL=1;
Delay5us();
SDA=1; // 0->1跳变,结束
Delay2us();
}
//
//应答信号
void ACK_I2C(bit ack)
{
SDA=ack?1:0; //发出应答或非应答
Delay2us();
SCL=1; //保持一个高电平周期
Delay5us();
SCL=0;
Delay2us();
}
*/
//发送一个字节
bit SEND_BYTE(uchar byte)
{
uchar i;
bit ack;
SDA = 1;
for(i=0;i<8;i++)
{
SDA=((byte<<i)&0x80)?1:0; //赋值发送位
Delay1us();
SCL=1; //保持一个高电平周期
Delay5us();
SCL=0;
Delay2us();
}
Delay2us();
SDA=1; //准备接收应答位
Delay2us();
SCL=1;
Delay2us();
ack=SDA?1:0; //判断应答位
SCL=0;
return(ack); //返回应答位
}
//接收一个字节
uchar RECEIVE_BYTE(void)
{
uchar i;
uchar byte=0;
SDA=1; //输入方式,等待接收
for(i=0;i<8;i++)
{
SCL=1;
Delay2us();
byte=byte<<1;
if(SDA) //读数据位,存入byte
byte+=1;
Delay5us();
SCL=0; //提供一个低电平周期
}
Delay2us();
return(byte); //返回接收字节
}
//向从机写一个字节
bit WRITE_BYTE(uchar address, uchar byte)
{
START_I2C();
if(SEND_BYTE(0xa0))
return 1; //非应答,返回
if(SEND_BYTE(address))
return 1; //非应答,返回
if(SEND_BYTE(byte))
return 1; //非应答,返回
STOP_I2C();
return 0;
}
//读取从机一个字节
uchar READ_BYTE(uchar address, uchar *byte)
{
START_I2C();
if(SEND_BYTE(0xa0))
return 1; //非应答,返回
if(SEND_BYTE(address))
return 1; //非应答,返回
START_I2C();
if(SEND_BYTE(0xa1))
return 1; //非应答,返回
*byte=RECEIVE_BYTE();
// ACK_I2C(0); //应答信号
STOP_I2C();
return 0;
}
成品:
1、流程
裁判按下复位键,抢答器进入抢答模式,各组人员才可以通过抢答按钮进行抢答,抢答结果显示在抢答器上。
2、实现
使用单片机对输入的电平信号处理(低电平有效):1路为复位,8路为抢答。复位前对8路抢答状态进行判断,防止作弊。一次性对8路抢答器状态进行采样,将结果存储在num数组内,最大可存储4路同时抢答结果。LED显示部分由T0定时器每3ms动态将num数组的结果点亮。蜂鸣器的时长由T0定时器控制
3、原理图
4、代码
#include<AT89X51.H>
#include<stdio.H>
#include<stdlib.H>
sfr WDTRST = 0xA6;
#define OUTPORT1 P0
#define OUTPORT2 P2
#define BELL P3_5
#define CLR P3_4
#define INPORT P1
Static unsigned char code digital[]= {0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xd8,0x80,0xe1,0x91,0x88,0x86,0xa0,0xa1,0x40,0x79,0x24,0x30,0x19,0x12,0x02,0x58,0x00}; //字库码"0,1,2,3,4,5,6,7,8,j,y,r,e,a,d,0.,1.,2.,3.,4.,5.,6.,7.,8."
static unsigned char code select[]={0xff,0xfb,0xf7,0xef,0xdf}; //选位字码
static unsigned char rycle=0x00; //当前数码管显示位控制
static unsigned char data num[5]={0x4,0x0e,0x09,0x0A,0x09};//检测结果
static unsigned char data i,j;
static unsigned char data count;//蜂鸣器警报时长
static unsigned char bdata temp; //8位取样数据
static bit state=0x00 ;//复位状态保存
static unsigned int sum[]={0x00,0x00}; //复位键检测时间/自动复位的时长
static bit timeCLR=0x00;//自动复位状态
static bit stateCLR=0x00; //首次状态保留
void delay(char t);
void ready();
void init()
{
P0 = 0xff;
P1 = 0xff;
P2 = 0xff;
P3 = 0xFF;
EX0 = 0x00;
EX1 = 0x00;
ET1 = 0x00;
ES = 0x00;
ET2 = 0x00;
WDTRST = 0x1E;
WDTRST = 0xE1;
BELL = 0;
TMOD=0x11;
EA=0x01;
TR0=0x00;
ET0=0x00;
TL0=0x18; //T0=130ms
TH0=0x02;
count=0;
TL1=0x24; //T1=4.5ms
TH1=0xfa;
TR1=0x01;
ET1=0x01;
}
void belltime() interrupt 1
{
TL0+=0x18;
TH0+=0x02;
if(!count--)
{
BELL=0x00;
ET0=0x00;
TR0=0x00;
}
}
void display() interrupt 3
{
TL1+=0x24;
TH1+=0xFA;
if(rycle<=num[0])
{
OUTPORT1 = digital[num[rycle]];
OUTPORT2 = select[rycle];
++rycle;
}else rycle=0x00;
if(!CLR)
{
sum[0]++;
if(sum[0]>666&&stateCLR)
{
timeCLR=!timeCLR;
stateCLR=0;
state=!state; //避免按复位键超时,导致状态重复反转
}
}else
{
sum[0]=0;
stateCLR=1; //复位键退出,将状态设置为可复位状态
}
if(timeCLR&&!state)
{
if(sum[1]++>2333) //在有抢答结果的情况下,等待复位
{
if(temp==0xff) //防作弊
{
ready();
}else
{
sum[1]=2167-(int)666*rand(); //延迟0.5-2.5S
}
}
}else sum[1]=0;
}
void delay(char t)
{
count=t;
TL0=0x18;
TH0=0x02;
ET0=0x01;
TR0=0x01;
}
void main()
{
init();
while(1){
WDTRST=0x1E;
WDTRST=0xE1;
temp = INPORT; //对8个连接器同时采样
if(!CLR&&temp==0xff)
{
ready();
}
for(i=1,j=0;i<=8&&state;i++) //8个连接器状态检测
{
if(!(temp & 0x01))
{
j++;
num[0]=j; //num[0]存放首批按下的连接器个数
num[j]=(j>1?i+0x0f:i); //存放按下状态的连接器序列
BELL=0x01;
delay(1);
}
temp >>= 1;
}
if(j>0) state=0; //判断是否抢答成功,成功就禁止再次抢答
}
}
void ready()
{
num[0]=0x04;
num[4]=0x0b;
num[3]=0x0c;
num[2]=0x0e;
num[1]=0x0a;
state=0x01;
BELL=0x01;
delay(1);
}
5、成品效果
月底CO开关就要送样,上个月底答应小郑要把非独立的检测方式改为独立的方式,总不能食言。利用周末两天时间在家搞这个电路:12个微动开关(24根线)、12组LED,24+12超出89S51总的32个IO口,故增加一片74LS138进行IO扩展。通过对IO口动态扫描电平状态,检测其相对应的微动开关的状态,再将检测的结果写到相对应的LED,LED使用ULN2803进行扩流,弥补单片机驱动能力不足的弱点。
原理图
焊接完成的PCB板
由于只是扫描和写出,故程序没啥难度,这也是我写的最快的一个程序
#include "AT89X51.H"
sfr WDTRST = 0xA6;
static unsigned char code write_data[12]={0x0f,0x8f,0x4f,0xcf,0x2f,0xaf,0x6f,0xef,0xfe,0xfd,0xf9,0xf7};
unsigned char i;
void init()
{
P0 = 0x00;
P1 = 0xff;
P2 = 0xff;
P3 = 0x0f;
EX0 = 0x00;
ET0 = 0x00;
EX1 = 0x00;
ET1 = 0x00;
ES = 0x00;
ET2 = 0x00;
WDTRST = 0x1E;
WDTRST = 0xE1;
}
void main()
{
init();
while(1){
WDTRST=0x1E;
WDTRST=0xE1;
for (i=0;i<12;i++)
{
P2=write_data[i] ;
switch(i)
{
case 0: P0_0=!P1_0; break;
case 1: P0_1=!P1_1; break;
case 2: P0_2=!P1_2; break;
case 3: P0_3=!P1_3; break;
case 4: P0_4=!P1_4; break;
case 5: P0_5=!P1_5; break;
case 6: P0_6=!P1_6; break;
case 7: P0_7=!P1_7; break;
case 8: P3_4=!P3_0; break;
case 9: P3_5=!P3_1; break;
case 10: P3_6=!P3_2; break;
case 11: P3_7=!P3_3; break;
default: break;
}
}
}
}
把程序编译成HEX格式,烧录到89S51中即可,有了躯干和灵魂的PCB板就跑了起来。
组装到箱子里,替换原电路板
密麻麻的线,其实很多都是相同信号线(不想再去大费周折的精简重焊,就按原本的电气特性,重新做的这个PCB兼容电路)
原电路板为立林做的,就留着做应急备用