吹塑塑料瓶工位检测

该代码是基于STC单片机的双工位塑料瓶检测系统程序,主要功能包括:

  1. 采用12864液晶显示工位A和B的工作状态与计时数据
  2. 通过4个独立按键实现两个工位时间参数的加减设置(0-999可调)
  3. 具有EEPROM存储功能,可保存设定的时间参数
  4. 包含两个工位的独立检测控制逻辑:
    • 通过外部中断检测启动信号
    • 定时器0中断实现精确计时
    • 超时报警功能(蜂鸣器+指示灯)
  5. 采用硬件消抖算法处理按键和传感器信号

系统通过IAP方式读写内部EEPROM,实现工作参数的掉电保存,并具有完善的异常处理机制。程序结构包含初始化、显示驱动、按键处理、中断服务和主控制循环等模块,实现了双工位的独立控制和状态监测功能。



/*塑料瓶检测2021 11 2 **/

/*****L609 CODE2211 **/

/*****-------------------***********/

/*****| 工位A 000 |**********/

/*****| 工位B 000 |**********/

/*****| |**********/

/*****| |**********/

/*****-------------------***********/

/***********************************/

#include <REG52.H>

#include <intrins.H>

#define uint unsigned int

#define uchar unsigned char

uchar code disdt11={0xb0,0xb1,0xb2,0xb3,0xb4,0xb5,0xb6,0xb7,0xb8,0xb9,0xa3}; //

uchar code disds10={0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39}; //

#define IAP_ADDRESS 0x0800 //EEPROM首地址

typedef unsigned char BYTE;

typedef unsigned int WORD;

#define CMD_IDLE 0 //空闲模式

#define CMD_READ 1 //IAP字节读命令

#define CMD_PROGRAM 2 //IAP字节编程命令

#define CMD_ERASE 3 //IAP扇区擦除命令

#define ENABLE_IAP 0x82 //if SYSCLK<20MHz

sfr INT_CLKO=0x8f; //外部中断与时钟输出控制寄存器

uint val1,val2,val3,vala,valb; /**/

sbit Bp=P2^3; //Bp

sbit CS=P2^6; //12864PIN4 vala显示缓冲valb加减时间处理缓冲

sbit SID=P2^7; //12864PIN5

sbit SCLK=P1^0; //12864PIN6

sbit A_Up=P3^2; // A工位加按键

sbit A_Down=P3^3; // A工位减按键

sbit B_Up=P1^3; // B工位加按键

sbit B_Down=P1^2; // B工位减按键

uchar kcounter,kstatus; //按键计数标志 按键状态标志

bit Sign; /*低电平标志01*/

bit Flag_A,Flag_B; //AB工位运行标志

sbit IntPut1=P3^6;

sbit IntPut2=P3^7;

sbit IntPut3=P2^0;

sbit IntPut4=P2^1;

sbit OUT1=P3^0;

sbit OUT2=P3^1;

sbit OUT3=P3^4;

// sbit OUT4=P3^5;

sbit OUT5=P3^5;

uint l,m,n,k; /****个十百代码缓冲**/

uint aa=0; /****RUN FLAG****/

/*------------------延时子程序------------------------*/

void delay_1ms(uint x)

{

int i, j;

for(i=0;i<x;i++)

for(j=0;j<1500;j++);

}

/*----关闭IAP----------------------------*/

void IapIdle()

{

IAP_CONTR=0; //关闭IAP功能

IAP_CMD=0; //清除命令寄存器

IAP_TRIG=0; //清除触发寄存器

IAP_ADDRH=0x80; //将地址设置到非IAP区域

IAP_ADDRL=0;

}

/*-从ISP/IAP/EEPROM区域读取一字节-*/

BYTE IapReadByte(WORD addr)

{

BYTE dat; //数据缓冲区

IAP_CONTR=ENABLE_IAP; //使能IAP

IAP_CMD=CMD_READ; //设置IAP命令

IAP_ADDRL=addr; //设置IAP低地址

IAP_ADDRH=addr>>8; //设置IAP高地址

IAP_TRIG=0x5a; //写触发命令(0x5a)

IAP_TRIG=0xa5; //写触发命令(0xa5)

nop(); //等待ISP/IAP/EEPROM操作完成

dat=IAP_DATA; //读ISP/IAP/EEPROM数据

IapIdle(); //关闭IAP功能

return dat; //返回

}

/*-写一字节数据到ISP/IAP/EEPROM区域-*/

void IapProgramByte(WORD addr, BYTE dat)

{

IAP_CONTR=ENABLE_IAP; //使能IAP

IAP_CMD=CMD_PROGRAM; //设置IAP命令

IAP_ADDRL=addr; //设置IAP低地址

IAP_ADDRH=addr>>8; //设置IAP高地址

IAP_DATA=dat; //写ISP/IAP/EEPROM数据

IAP_TRIG=0x5a; //写触发命令(0x5a)

IAP_TRIG=0xa5; //写触发命令(0xa5)

nop(); //等待ISP/IAP/EEPROM操作完成

IapIdle();

}

/*---扇区擦除---------------*/

void IapEraseSector(WORD addr)

{

IAP_CONTR=ENABLE_IAP; //使能IAP val=IapReadByte(IAP_ADDRESS+1);

IAP_CMD=CMD_ERASE; //设置IAP命令

IAP_ADDRL=addr; //设置IAP低地址

IAP_ADDRH=addr>>8; //设置IAP高地址

IAP_TRIG=0x5a; //写触发命令(0x5a)

IAP_TRIG=0xa5; //写触发命令(0xa5)

nop(); //等待ISP/IAP/EEPROM操作完成

IapIdle();

}

/*******************************************/

void write_eeprom(void)

{

IapEraseSector(IAP_ADDRESS); //扇区擦除

l=vala/100;

m=(vala-l*100)/10;

n=vala-l*100-m*10;

IapProgramByte(IAP_ADDRESS+1,l); //百位

IapProgramByte(IAP_ADDRESS+2,m); //十位

IapProgramByte(IAP_ADDRESS+3,n); //个位

l=valb/100;

m=(valb-l*100)/10;

n=valb-l*100-m*10;

IapProgramByte(IAP_ADDRESS+4,l);//百位

IapProgramByte(IAP_ADDRESS+5,m);//十位

IapProgramByte(IAP_ADDRESS+6,n);//个位

}

/*******************************************/

void red_eeprom(void)

{

l=IapReadByte(IAP_ADDRESS+1); //

m=IapReadByte(IAP_ADDRESS+2); //

n=IapReadByte(IAP_ADDRESS+3); //

vala=l*100+m*10+n; //A工位时间

l=IapReadByte(IAP_ADDRESS+4); //

m=IapReadByte(IAP_ADDRESS+5); //

n=IapReadByte(IAP_ADDRESS+6); //

valb=l*100+m*10+n; //B工位时间

}

/****************按键计数器状态寄存器归零*************/

void RstKey()

{

kcounter=0; //按键计数器归零

kstatus=0; //状态寄存器归零

}

/*****************按键低电平检测函数*****************/

void LowVoltKey(void) //按键计数器状态标志加一

{

kcounter++;

kstatus++;

}

/*****************按键高电平检测函数*****************/

void HighVoltKey(void) //按键计数器加一 状态标志归零

{

kcounter++; //按键计数器加一

kstatus=0; //按键状态标志归零

}

/*------------------写命令到LCD-----------------------*/

void write_com(unsigned char cmdcode)

{

uchar i;

uchar i_data,temp_data1,temp_data2;

EA=0;

i_data=0xf8;

delay_1ms(10);

CS=1;

SCLK=0;

for(i=0;i<8;i++)

{

SID=(bit)(i_data&0x80);

SCLK=0;

SCLK=1;

i_data=i_data<<1;

}

i_data=cmdcode;

i_data&=0xf0;

for(i=0;i<8;i++)

{

SID=(bit)(i_data&0x80);

SCLK=0;

SCLK=1;

i_data=i_data<<1;

}

i_data=cmdcode;

temp_data1=i_data&0xf0;

temp_data2=i_data&0x0f;

temp_data1>>=4;

temp_data2<<=4;

i_data=temp_data1|temp_data2;

i_data&=0xf0;

for(i=0;i<8;i++)

{

SID=(bit)(i_data&0x80);

SCLK=0;

SCLK=1;

i_data=i_data<<1;

}

CS=0;

EA=1;

}

/*-------------------写数据到LCD----------------------*/

void write_data(unsigned char Dispdata)

{

uchar i;

uchar i_data,temp_data1,temp_data2;

EA=0;

i_data=0xfa;

delay_1ms(10);

CS=1;

for(i=0;i<8;i++)

{

SID=(bit)(i_data&0x80);

SCLK=0;

SCLK=1;

i_data=i_data<<1;

}

i_data=Dispdata;

i_data&=0xf0;

for(i=0;i<8;i++)

{

SID=(bit)(i_data&0x80);

SCLK=0;

SCLK=1;

i_data=i_data<<1;

}

i_data=Dispdata;

temp_data1=i_data&0xf0;

temp_data2=i_data&0x0f;

temp_data1>>=4;

temp_data2<<=4;

i_data=temp_data1|temp_data2;

i_data&=0xf0;

for(i=0;i<8;i++)

{

SID=(bit)(i_data&0x80);

SCLK=0;

SCLK=1;

i_data=i_data<<1;

}

CS=0;

EA=1;

}

/*------------------初始化LCD屏-----------------------*/

void lcd_init()

{

uchar comdata;

delay_1ms(100);

comdata=0x30;

write_com(comdata); /*功能设置:一次送8位数据,基本指令集*/

comdata=0x04;

write_com(comdata); /*点设定:显示字符/光标从左到右移位,DDRAM地址加1*/

comdata=0x0f;

write_com(comdata); /*显示设定:开显示,显示光标,当前显示位反白闪动*/

comdata=0x01;

write_com(comdata); /*清DDRAM*/

comdata=0x02;

write_com(comdata); /*DDRAM地址归位*/

comdata=0x80;

write_com(comdata); /*把显示地址设为0X80,即为第一行的首位*/

}

/*--------------X位置数据显示------------------------*/

void Dis_Xdata() //A3B0

{

l=vala/100; /**/

m=(vala-l*100)/10; /*减t1x1000再减t2X100*/

n=vala-l*100-10*m; /*分离千 百 十 个三位*/

write_com(0x84);

write_data(0xA3); /*半个字符*/

write_data(disdsl); /*百位半个字符*/

write_com(0x85);

write_data(0xA3); /*半个字符*/

write_data(disdsm); /*十位半个字符*/

write_com(0x86);

write_data(0xA3); /*半个字符*/

write_data(disdsn); /*个位半个字符*/

}

/*--------------Y位置数据显示------------------------*/

void Dis_Ydata()

{

l=valb/100; /**/

m=(valb-l*100)/10; /*减t1x1000再减t2X100*/

n=valb-l*100-10*m; /*分离千 百 十 个三位*/

write_com(0x94);

write_data(0xA3); /*半个字符*/

write_data(disdsl); /*百位半个字符*/

write_com(0x95);

write_data(0xA3); /*半个字符*/

write_data(disdsm); /*十位半个字符*/

write_com(0x96);

write_data(0xA3); /*半个字符*/

write_data(disdsn); /*个位半个字符*/

}

/*--------------X位置数据显示------------------------*/

void Dis_XTime(uint val) //A3B0

{

l=val/100; /**/

m=(val-l*100)/10; /*减t1x1000再减t2X100*/

n=val-l*100-10*m; /*分离千 百 十 个三位*/

write_com(0x88);

write_data(0xA3); /*半个字符*/

write_data(disdsl); /*百位半个字符*/

write_com(0x89);

write_data(0xA3); /*半个字符*/

write_data(disdsm); /*十位半个字符*/

write_com(0x8A);

write_data(0xA3); /*半个字符*/

write_data(disdsn); /*个位半个字符*/

}

/*--------------Y位置数据显示------------------------*/

void Dis_YTime(uint val)

{

l=val/100; /**/

m=(val-l*100)/10; /*减t1x1000再减t2X100*/

n=val-l*100-10*m; /*分离千 百 十 个三位*/

write_com(0x98);

write_data(0xA3); /*半个字符*/

write_data(disdsl); /*百位半个字符*/

write_com(0x99);

write_data(0xA3); /*半个字符*/

write_data(disdsm); /*十位半个字符*/

write_com(0x9A);

write_data(0xA3); /*半个字符*/

write_data(disdsn); /*个位半个字符*/

}

/*------------------开机广告-----------------------*/

void displayAdvertising() //B9 A4 CEBB A6AA A6AB

{

write_com(0x80); /*--工---*/

write_data(0xB9);

write_data(0xA4);

write_com(0x81); /*--位---*/

write_data(0xCE);

write_data(0xBB);

write_com(0x82);

write_data(0xA3);

write_data(0xC1); /*--A----*/

write_com(0x90); /*--工---*/

write_data(0xB9);

write_data(0xA4);

write_com(0x91); /*--位---*/

write_data(0xCE);

write_data(0xBB);

write_com(0x92);

write_data(0xA3);

write_data(0xC2); /*--B----*/

}

/**************定时中断*************************/

void timer0() interrupt 1

{

aa=aa+1;

TH0=0X53;

TL0=0X32;

if(aa==2)

{

OUT5=!OUT5,

aa=0;

if(Flag_A==1) //气缸下位开关未到位

val1++; //标志未复位工位A计时

if(Flag_B==1) //气缸下位开关未到位

val2++; //标志未复位工位B计时

}

}

//中断服务程序 P3.6

void exint2() interrupt 10 //INT2中断入口

{

RstKey();

if(!IntPut1&&Flag_A==0) //启动信号键

{

for(;kcounter<3;) //按键循环5次

{

if(!IntPut1) //按键低电平

{

LowVoltKey();

}

else if(~!IntPut1) //按键高电平

{

HighVoltKey();

}

}

if(kstatus>=2) /*按键状态标志大于等于3为有效值*/

{ /*循环检测 */

Flag_A=1; //启动气缸A计数

OUT1=0; //A工位启动指示

}

}

}

//中断服务程序 P3.7

void exint3() interrupt 11 //INT3中断入口

{

RstKey(); /*开始kcounter,kstatus*/

if(!IntPut2&&Flag_B==0) //启动信号键

{

for(;kcounter<3;) //按键循环5次

{

if(!IntPut2) //按键低电平

{

LowVoltKey();

}

else if(~!IntPut2) //按键高电平

{

HighVoltKey();

}

}

if(kstatus>=2) /*按键状态标志大于等于3为有效值*/

{ /*循环检测 */

Flag_B=1; //启动气缸B计数

OUT2=0; //B工位启动指示

}

}

}

/*------------------主循环程序----------------*/

void main( ) /*主程序开始*/

{

Flag_A=0;

Flag_B=0;

lcd_init() ; /*液晶复位*/

k=0;

AUXR=0X80; //STC系列的1T 设置

TMOD=0X01;

TH0=0X53;

TL0=0X32;

INT_CLKO|=0x10; //(EX2 = 1)使能INT2中断

INT_CLKO|=0x20; //(EX3 = 1)使能INT3中断

ET0=1;

TR0=1;

displayAdvertising(); /*开机广告*/

OUT5=0;

red_eeprom(); /*读EEPROM数据*/

Dis_Xdata();

Dis_Ydata();

EA=1;

while(1) /*主函数循环*/

{

RstKey(); /*开始kcounter,kstatus*/

if(!A_Up) //启动信号键

{

for(;kcounter<5;) //按键循环5次

{

if(!A_Up) //按键低电平

{

LowVoltKey();

}

else if(~!A_Up) //按键高电平

{

HighVoltKey();

}

}

if(kstatus>=4) /*按键状态标志大于等于3为有效值*/

{ /*循环检测 */

vala=vala+1; /**加一**/

if(vala>999)

vala=0; /*大于999归零*/

Dis_Xdata();

write_eeprom();

}

}

/************************************/

RstKey(); /*开始kcounter,kstatus*/

if(!A_Down) //启动信号键

{

for(;kcounter<5;) //按键循环5次

{

if(!A_Down) //按键低电平

{

LowVoltKey();

}

else if(~!A_Down) //按键高电平

{

HighVoltKey();

}

}

if(kstatus>=4) /*按键状态标志大于等于3为有效值*/

{ /*循环检测 */

vala=vala-1; /**减一**/

if(vala==0)

vala=999; /*等于零赋值999*/

Dis_Xdata();

write_eeprom();

}

}

/************************************/

RstKey(); /*开始kcounter,kstatus*/

if(!B_Up) //启动信号键

{

for(;kcounter<5;) //按键循环5次

{

if(!B_Up) //按键低电平

{

LowVoltKey();

}

else if(~!B_Up) //按键高电平

{

HighVoltKey();

}

}

if(kstatus>=4) /*按键状态标志大于等于3为有效值*/

{ /*循环检测 */

valb=valb+1; /**加一**/

if(valb>999)

valb=0; /*大于999归零*/

Dis_Ydata();

write_eeprom();

}

}

/************************************/

RstKey(); /*开始kcounter,kstatus*/

if(!B_Down) //启动信号键

{

for(;kcounter<5;) //按键循环5次

{

if(!B_Down) //按键低电平

{

LowVoltKey();

}

else if(~!B_Down) //按键高电平

{

HighVoltKey();

}

}

if(kstatus>=4) /*按键状态标志大于等于3为有效值*/

{ /*循环检测 */

valb=valb-1; /**减一**/

if(valb==0)

valb=999; /*等于零赋值999*/

Dis_Ydata();

write_eeprom();

}

}

/****************工位A检测********************/

RstKey(); /*开始kcounter,kstatus*/

if(!IntPut3) //启动信号键

{

for(;kcounter<5;) //按键循环5次

{

if(!IntPut3) //按键低电平

{

LowVoltKey();

}

else if(~!IntPut3) //按键高电平

{

HighVoltKey();

}

}

if(kstatus>=4) /*按键状态标志大于等于3为有效值*/

{ /*循环检测 */

Flag_A=0; //关工位A运行标志

val1=0; //关工位A定时器计数

OUT1=1; //关闭A工位指示

}

}

/****************工位B检测********************/

RstKey(); /*开始kcounter,kstatus*/

if(!IntPut4) //启动信号键

{

for(;kcounter<5;) //按键循环5次

{

if(!IntPut4) //按键低电平

{

LowVoltKey();

}

else if(~!IntPut4) //按键高电平

{

HighVoltKey();

}

}

if(kstatus>=4) /*按键状态标志大于等于3为有效值*/

{ /*循环检测 */

Flag_B=0; //关工位B运行标志

val2=0; //关工位B定时器计数

OUT2=1; //关闭B工位指示

}

}

Dis_XTime(val1); //工位A计时显示

Dis_YTime(val2); //工位B计时显示

if(val1>vala)

{

EA=0;

Bp=0;

OUT3=0;

delay_1ms(100);

Bp=1;

delay_1ms(100);

Bp=0;

delay_1ms(100);

Bp=1;

delay_1ms(100);

Bp=0;

delay_1ms(100);

Bp=1;

val1=0;

Flag_A=0;

OUT3=1;

EA=1;

}

if(val2>valb)

{

EA=0;

Bp=0;

OUT3=0;

delay_1ms(100);

Bp=1;

delay_1ms(100);

Bp=0;

delay_1ms(100);

Bp=1;

delay_1ms(100);

Bp=0;

delay_1ms(100);

Bp=1;

val2=0;

Flag_B=0;

OUT3=1;

EA=1;

}

} //

} //L609 CODE2211