成品最终检测设备
从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;
}
成品: