该代码是基于STC单片机的双工位塑料瓶检测系统程序,主要功能包括:
- 采用12864液晶显示工位A和B的工作状态与计时数据
- 通过4个独立按键实现两个工位时间参数的加减设置(0-999可调)
- 具有EEPROM存储功能,可保存设定的时间参数
- 包含两个工位的独立检测控制逻辑:
- 通过外部中断检测启动信号
- 定时器0中断实现精确计时
- 超时报警功能(蜂鸣器+指示灯)
- 采用硬件消抖算法处理按键和传感器信号
系统通过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