AT89S52型单片机介绍
AT89S52是一个8位单片机,片内ROM全部采用FLASH ROM技术,与MCS-51系列完全兼容,它能以3V的超低电压工作,晶振时钟最高可达24MHz。AT89S52是标准的40引脚双列直插式集成电路芯片,有4个八位的并行双向I/O端口,分别记作P0、P1、P2、P3。第31引脚需要接高电位使单片机选用内部程序存储器;第9引脚是复位引脚,要接一个上电手动复位电路;第40脚为电源端VCC,接+5V电源,第20引脚为接地端VSS,通常在VCC和VSS引脚之间接0.1μF高频滤波电容。第18、19脚之间接上一个12MHz的晶振为单片机提供时钟信号。
AT89S52型单片机引脚功能
引脚说明
VCC:电源电压
GND:地
P0口:P0口是一组8位漏极开路型双向I/O口,作为输出口用时,每个引脚能驱动8个TTL逻辑门电路。当对0端口写入1时,可以作为高阻抗输入端使用。
当P0口访问外部程序存储器或数据存储器时,它还可设定成地址数据总线复用的形式。在这种模式下,P0口具有内部上拉电阻。
在EPROM编程时,P0口接收指令字节,同时输出指令字节在程序校验时。程序校验时需要外接上拉电阻。
P1口:P1口是一带有内部上拉电阻的8位双向I/O口。P1口的输出缓冲能接受或输出4个TTL逻辑门电路。当对P1口写1时,它们被内部的上拉电阻拉升为高电平,此时可以作为输入端使用。当作为输入端使用时,P1口因为内部存在上拉电阻,所以当外部被拉低时会输出一个低电流(IIL)。
P2口:P2是一带有内部上拉电阻的8位双向的I/O端口。P2口的输出缓冲能驱动4个TTL逻辑门电路。当向P2口写1时,通过内部上拉电阻把端口拉到高电平,此时可以用作输入口。作为输入口,因为内部存在上拉电阻,某个引脚被外部信号拉低时会输出电流(IIL)。
P2口在访问外部程序存储器或16位地址的外部数据存储器(例如MOVX @ DPTR)时,P2口送出高8位地址数据。在这种情况下,P2口使用强大的内部上拉电阻功能当输出1时。当利用8位地址线访问外部数据存储器时(例MOVX @R1),P2口输出特殊功能寄存器的内容。当EPROM编程或校验时,P2口同时接收高8位地址和一些控制信号。
P3口:P3是一带有内部上拉电阻的8位双向的I/O端口。P3口的输出缓冲能驱动4个TTL逻辑门电路。当向P3口写1时,通过内部上拉电阻把端口拉到高电平,此时可以用作输入口。作为输入口,因为内部存在上拉电阻,某个引脚被外部信号拉低时会输出电流(IIL)。
P3口同时具有多种特殊功能,具体如下表所示:
RST:复位输入。当振荡器工作时,RST引脚出现两个机器周期的高电平将使单片机复位。
ALE/PROG:当访问外部存储器时,地址锁存允许是一输出脉冲,用以锁存地址的低8位字节。当在Flash编程时还可以作为编程脉冲输出(PROG)。 一般情况下,ALE是以晶振频率的1/6输出,可以用作外部时钟或定时目的。但也要注意,每当访问外部数据存储器时将跳过一个ALE脉冲。
PSEN:程序存储允许时外部程序存储器的读选通信号。当AT89C52执行外部程序存储器的指令时,每个机器周期PSEN两次有效,除了当访问外部数据存储器时,PSEN将跳过两个信号。
EA/VPP:外部访问允许。为了使单片机能够有效的传送外部数据存储器从0000H到FFFH单元的指令,EA必须同GND相连接。需要主要的是,如果加密位1被编程,复位时EA端会自动内部锁存。当执行内部编程指令时,EA应该接到VCC端。
XTAL1:振荡器反相放大器以及内部时钟电路的输入端。 XTAL2:振荡器反相放大器的输出端。
电子秤的工作原理
当被称物体放置在秤体的秤台上时,其重量便通过秤体传递到称重传感器,传感器随之产生力-电效应,将物体的重量转换成与被称物体重量成一定函数关系(一般成正比关系)的电信号(电压或电流等)。此信号由放大电路进行放大、经滤波后再由模/数(A/D)器进行转换,数字信号再送到微处器的CPU处理,CPU不断扫描键盘和各种功能开关,根据键盘输入内容和各种功能开关的状态进行必要的判断、分析、由仪表的软件来控制各种运算。运算结果送到内存贮器,需要显示时,CPU发出指令,从内存贮器中读出送到显示器显示,或送打印机打印。一般地信号的放大、滤波、A/D转换以及信号各种运算处理都在仪表中完成。
电子秤设计的基本思路
将电子秤大致能划分为三大部分,数据采集模块、控制器模块和人机交互界面模块。其中数据采集模块由压力传感器、信号的前级处理和A/D转换部分组成。转换后的数字信号送给控制器处理,由控制器完成对该数字量的处理,驱动显示模块完成人机间的信息交换。此外添加了一个过载、欠量报警提示的特殊功能。
部分电路
双积分式A/D转换电路
(它由积分器、比较器、模拟电子开关,积分电阻、积分电容、自动回零电阻、电容组成。其中VG是模拟地,VFR是基准电压(相对于VG为负值),VX是检测电压)
主控电路的设计
P1口和P2.0~P2.6口作为地址总线,其中P1口作为低地址线和数据总线复用,P2.0~P2.6口做高地址线。P2.7作为62256的片选控制总线,ALE接锁存器74LS373的使能端。P3.6和P3.7作为外部数据存储器写/读选通信号输出端分别接62256的/WE和/OE端。
主控电路图如下:
信号处理电路
以下为滤波放大电路图:
电容C5、C6用来滤除采样信号电压中的高频噪声,电容C7、C84用来滤除采样信号电压中的低频噪声。
前端信号处理电路设计如下图
键盘输入控制电路及LCD显示电路
图中P1.5口接/CS;P1.6口接CLK;P1.0口接DIO;P3.2口接/KEY,利用中断0通知AT89S52读数。
键盘控制芯片ZLG7289 控制键盘的扫描,当监测到有键按下后ZLG7289 的9脚便产生一个低电平通知单片机,单片机可以采用查询或者中断方式将数据通过P3.0口以串行方式读入。
报警电路的设计
程序
1 主程序设计
uint max_weight;//最大称量
uchar dsel;//分度值
uchar dp;//小数点
float beilv;//倍率
ulong zero_save;//传感器零位值
}bdf;
uint code num_ten[4]={1,10,100,1000};
uchar code adcount2[4]={2,4,5};//数据处理进平均次数
uchar code tab_dsel[4]={1,2,5,10};//分度值表
//0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9
uchar code tab[]={0xB7,0x03,0xD6,0xC7,0x63,0xE5,0xF5,0x83,0xF7,0xE7,
//A , b , C , d , E , F , 暗, - , t , P
0xF3,0x75,0xB4,0x57,0xF4,0xF0,0x00,0x40,0x74,0xF2,
//H , L , o , J , r , n , U, =, - i
0x73,0x34,0x55,0x07,0x50,0x51,0x37,0x44,0x04,0x01};
//显示位码表
//0, 1, 2, 3, 4, 5, 6
uchar code digit[]={0xfe,0xdf,0xef,0xfd,0xfb,0xbf,0xF7};//显示位码表
sbit P_OE =P2^1;//显示控制
sbit P_LE =P2^0;
sbit buz0 =P3^6;//蜂鸣器
sbit buz1 =P3^7;
/******************************************************/
bit b_follow;//启动零位跟踪标记
bit b_serial;//串口发送完标记
bit b_followdelay;//第一次不进行零位跟踪
bit b_steady;//稳定标记
void (* data task)(void);//函数指针变量,接受下一步要做的任务
uint idata fendushu;//分度数
uchar weight_led[6] ;//重量窗显示缓存
uchar idata temp_var;
uchar weight_dp;//小数点位数
uchar fu_number;//负号显示位置
uchar wdcount;//稳定计数
uchar adup_count;//异常值计数
uchar addcount3;//累加次数
extern void key_scan(void);//按键扫描
extern void weight_disp(void);//重量计算,超载报警
extern void start_set(void);//单片机初始化设置
extern void adc (void);//读取AD值
extern void ad_processor(void);//AD数据滤波处理
extern void fun_weight(void);//正常称重状态
extern void bd_start(void);//重量或电压标定选择
extern void dy_disp(void);//电压显示
extern void led_disp(ulong temp,uchar num);
extern uchar get_jiaoyan(uchar *address,uchar num);//计算校验字
extern void neima(void);
void delay60ms(uchar time);//40ms延时
void fendu_val(void);//分度数运算
void check_canshu(void);//读参数,并校验是否正确
void ver_disp(void);//显示版本号
void seg_check(void);//笔画检测
/******************************************/
void main (void)
{
start_set(); //单片机初始化
beep_time=3; //开机鸣叫
flash_num=6; //没有闪烁位
spi_sys(); //ad芯片初始化
check_canshu(); //读参数,并校验是否正确
if(bdf.shuduval》2) //若是异常值,用默认值
bdf.shuduval=1;
addcount3=4;
bdf_dp_temp=bdf.dp; //保存小数点(标定修改参数时用)
bdf_dsel_temp=bdf.dsel;//保存分度值(标定修改参数时用)
key_scan(); //标定按键扫描
switch(key_temp) //功能键处理函数
case 0xc0:b_biaoding=1;task=bd_start ; break;//
default:
bdf.dp=0;
ver_disp();//显示版本号
seg_check();//笔画检测
fendu_val();//分度数运算
zero_current=ad_steady;//保存当前零位值
task=fun_weight;
break;
}
do
{ //主循环程序
adc(); //A/D采样
ad_processor();//数据处理
zero_follow(); //零位跟踪程序
neima(); //内码计算
weight_disp(); //重量显示
key_scan(); //按键扫描
(* task)(); //任务切换函数
while(1);
/*****************************************************************/
void fendu_val(void)//分度数运算
{ uchar i;
ulong temp;
temp=(ulong)bdf.max_weight*num_ten[bdf_dp_temp];
fendushu=temp/bdf.dsel;
i=fendushu/3000;
if (i==0)
i=1;
half_sel_bound=5/bdf.beilv;//半个分度的原始码
follow_bound=i*half_sel_bound;//计算零位跟踪时的原始码,按3000分度
time_weight=200;
void ver_disp(void)//显示版本号及最大量程
weight_led[0]=7;// 7
weight_led[1]=1;// 1
weight_led[2]=2;// 2
weight_led[3]=17;// -
weight_led[4]=0;// 0
weight_led[5]=5;// 5
fun_led=0xff;
delay60ms(15);//40ms延时
beep_time=3;
led_disp(bdf.max_weight,5);//显示最大量程
weight_led[0]=15;// F
delay60ms(20);//40ms延时
2、信号采样与A/D转换子程序的设计
extern uchar code adcount2[3];
extern bit bAd;//已产生AD值
extern bit b_warnled;
extern bit b_steady;
extern bit b_up_last;
extern uchar adup_count;
extern ulong idata ad_steady;//AD数据处理后的稳定值
extern uchar add_count;//AD累加计数器
extern ulong idata add_val;//AD累加值
extern uchar wdcount;
extern uchar adup_count;//AD异常值计数
extern uchar addcount3;
extern ulong idata up_val;
extern ulong idata adval;//AD芯片采样值
extern ulong idata lvbo[6];
extern uchar idata follow_time;//零位跟踪时间
extern uchar idata time_weight;//重量为0时,消隐时间
void time(void);
ulong buf_left(ulong temp);
/*******************************************/
//
void ad_processor(void)
{ ulong temp1;
ulong temp2;
uchar i;
bit b_up;
if(bAd)
bAd=0;
time();//时间计数器自减
//--------------------------------------------------------
adval=adval》》4;
add_val=add_val+adval;//传感器累加滤波
add_count++;
if(add_count《addcount3)
return;
temp1=add_val/addcount3; //累加n次平均
add_count=0;
add_val=0;//传感器累加清零
i=(uchar)(temp1》》16)+1;
3、键盘/显示子程序设计
extern bit b_keyok;//有按键产生标记
extern bit b_longdown;//长按下标记
extern uchar key_num;//键值
extern uchar key_temp;//临时键值
extern uchar key_count;//键长按计数
extern uchar key_dly;//键去抖动延时
extern uchar beep_time;//蜂鸣时间
void key_scan1();////按键松开或没有按下处理
/****************************************************/
oid disp_t1(void) interrupt 3 using 1//显示中断程序
uchar temp;
TR1 =0;
P_OE=1;//高阻态,禁止输出
if((disp_number==(5-bdf.dp))&(bdf.dp!=0))//这一位是否有小数点
temp=0x08;//小数点段码
else
temp=0;
if(disp_number==6)//指示灯显示不用查表
P0=fun_led;//
if((disp_number==fu_number)&&b_fuhao)
temp=temp|0x40;
if((disp_number==flash_num)&b_flash)//是否有闪烁位
P0=0x0;
P0=tab[weight_led[disp_number]]|temp;//查表取段码
P_LE=1;
P_LE=0;//573锁存段码
P0=digit[disp_number];//送位码
P_OE=0;//573输出有效
disp_number++;
if(disp_number==7)//是否显示最后一位
disp_number=0;
if(beep_time)//是否要鸣叫
if(!TR0)
{buz0=~buz1;TR0 =1;}
beep_time--;
{TR0=0;buz0=1;buz1=1;}//不鸣叫时置高,减小电流
if(key_dly)//按键去抖动延时
key_dly--;
if(flash_num《6)
if(flash_time)//闪烁计时
flash_time--;
{ b_flash=!b_flash;flash_time=20;}//时间到,置闪烁标记
TH1 =0xf8;
TL1 =0x18;
TR1 =1 ;