|
霍尔测速元件清单
1) 9*15万用板
2) STC89C52单片机
3) 40脚IC座
4) 1602液晶
5) 16p母座
6) 16p排针
7) 10k电阻*3
8) 1k电阻
9) 3v直流电机
10) 3*1万用板
11) 磁铁*2
12) 201电位器
13) 3144霍尔传感器
14) 103排阻
15) 100uf电解电容
16) 10uf电解电容
17) 30pf瓷片电容*2
18) 12M晶振
19) 自锁开关
20) DC电源插口
21) 导线若干
22) 焊锡若干
23) USB电源线或电池盒
单片机程序源码:
- #include<reg52.h> //包含头文件
- #include <intrins.h>
- #define uchar unsigned char
- #define uint unsigned int //宏定义
- /*************STC89单片机EEPROM参数定义和声明********/
- #define RdCommand 0x01 //定义ISP的操作命令
- #define PrgCommand 0x02
- #define EraseCommand 0x03
- #define Error 1
- #define Ok 0
- #define WaitTime 0x01 //定义CPU的等待时间
- sfr ISP_DATA=0xe2;//寄存器申明
- sfr ISP_ADDRH=0xe3;
- sfr ISP_ADDRL=0xe4;
- sfr ISP_CMD=0xe5;
- sfr ISP_TRIG=0xe6;
- sfr ISP_CONTR=0xe7;
- char a_a;
- /********************************************/
- unsigned long temp=0;//报警上限转速参数定义
- uchar h_w,h_q,h_b,h_s,h_g;//报警上限转速的参数(万、千、百、十、个位)
- /**************************************************/
- sbit COUNT_IN=P3^2;//霍尔传感器信号输入
- /****************************************************/
- //定义1602液晶相关管脚
- sbit rs=P2^7;
- sbit en=P2^6;
- sbit rw=P2^5;
- uchar menu;//液晶设置界面菜单
- /****************************************************/
- sbit key1=P1^1;//报警转速参数设置按键
- sbit key2=P1^2;//加
- sbit key3=P1^3;//减
- sbit alarm=P1^0;//蜂鸣器报警
- /**************************************************/
- uint count,m,n; //定义计算速度变量
- unsigned long RPM=0; //定义速度变量
- unsigned long TT=0; //定义时间变量
- unsigned long sum=0; //计算平均值的总数
- unsigned char T_num=0; //平均值取值的次数
- unsigned long num=0; //单次转速
- unsigned int TT1=0; //定义定时器中断次数变量
- bit flag; //定义位变量,值只能是0或者1
- uchar p,sec;
- /********************************************************/
- //液晶初始化显示定义
- uchar code tab1[]={"R:"}; //一行显示的固定字符
- uchar code tab2[]={"r/min"}; //转速显示的固定字符
- uchar code tab3[]={"H:"}; //转速显示的固定字符
- /**************延时子函数定义************/
- void delay(uint x) //延时函数,大约延时1ms,不精确
- {
- uint i,j; //定义延时函数变量
- for(i=0;i<x;i++) //for循环延时
- for(j=0;j<110;j++);
- }
- void alarming()//蜂鸣器报警子函数
- {
- alarm=0;
- delay(50);
- alarm=1;
- delay(50);
- }
- /******************************STC89单片机 EERPROM函数******************/
- /*************打开 ISP,IAP 功能********************/
- void ISP_IAP_enable(void)
- {
- EA=0; //关中断
- ISP_CONTR=ISP_CONTR&0x18; // 0001,1000
- ISP_CONTR=ISP_CONTR|WaitTime; //写入硬件延时
- ISP_CONTR=ISP_CONTR|0x80; //ISPEN=1
- }
- /********************关闭 ISP,IAP 功能 ************/
- void ISP_IAP_disable(void)
- {
- ISP_CONTR=ISP_CONTR&0x7f; //ISPEN = 0
- ISP_TRIG=0x00;
- EA=1; //开中断
- }
- /************公用的触发代码**********************/
- void ISPgoon(void)
- {
- ISP_IAP_enable();//打开 ISP,IAP 功能
- ISP_TRIG=0x46; //触发ISP_IAP命令字节1
- ISP_TRIG=0xb9; //触发ISP_IAP命令字节2
- _nop_();
- }
- /****************字节读 *************************/
- unsigned char byte_read(unsigned int byte_addr)
- {
- EA=0;
- ISP_ADDRH=(unsigned char)(byte_addr>>8);//地址赋值
- ISP_ADDRL=(unsigned char)(byte_addr&0x00ff);
- ISP_CMD=ISP_CMD&0xf8;//清除低3位
- ISP_CMD=ISP_CMD|RdCommand;//写入读命令
- ISPgoon();//触发执行
- ISP_IAP_disable();//关闭ISP,IAP功能
- EA=1;
- return(ISP_DATA);//返回读到的数据
- }
- /*****************扇区擦除 ************************/
- void SectorErase(unsigned int sector_addr)
- {
- unsigned int iSectorAddr;
- iSectorAddr=(sector_addr&0xfe00); //取扇区地址
- ISP_ADDRH=(unsigned char)(iSectorAddr>>8);
- ISP_ADDRL=0x00;
- ISP_CMD=ISP_CMD&0xf8;//清空低3位
- ISP_CMD=ISP_CMD|EraseCommand; //擦除命令3
- ISPgoon();//触发执行
- ISP_IAP_disable();//关闭ISP,IAP功能
- }
- /************************字节写 *************************/
- void byte_write(unsigned int byte_addr, unsigned char original_data)
- {
- EA=0;
- ISP_ADDRH=(unsigned char)(byte_addr>>8);//取地址
- ISP_ADDRL=(unsigned char)(byte_addr & 0x00ff);
- ISP_CMD=ISP_CMD&0xf8;//清低3位
- ISP_CMD=ISP_CMD | PrgCommand;//写命令2
- ISP_DATA=original_data;//写入数据准备
- ISPgoon();//触发执行
- ISP_IAP_disable();//关闭IAP功能
- EA =1;
- }
- /********************内部eeprom写函数**************/
- void write_eeprom()
- {
- SectorErase(0x2000);//先把扇区清空
- delay(1);
- SectorErase(0x2c00);//先把扇区清空
- delay(1);
- SectorErase(0x2d00);//先把扇区清空
- delay(1);
- /**************写入参数******************/
- byte_write(0x2d00,h_w);//存万位
- delay(1);
- byte_write(0x2d01,h_q);//存千位
- delay(1);
- byte_write(0x2d02,h_b);//存百位
- delay(1);
- byte_write(0x2d03,h_s);//存十位
- delay(1);
- byte_write(0x2d04,h_g);//存个位
- delay(1);
-
- byte_write(0x2060,0x01);
- }
- /******************把数据从单片机内部eeprom中读出来*****************/
- void read_eeprom()
- {
- h_w=byte_read(0x2d00);//万位读回来
- delay(1);
- h_q=byte_read(0x2d01);//千位读回来
- delay(1);
- h_b=byte_read(0x2d02);//百位读回来
- delay(1);
- h_s=byte_read(0x2d03);//十位读回来
- delay(1);
- h_g=byte_read(0x2d04);//个位读回来
- delay(1);
- a_a=byte_read(0x2060);
- }
- /**************开机自检eeprom初始化*****************/
- void init_eeprom()
- {
- a_a=byte_read(0x2060);
- if(a_a!=1) //新的单片机初始单片机内问eeprom
- {
- a_a=1;
- write_eeprom();//保存数据
- delay(1);
- }
- }
- /********液晶写入指令函数与写入数据函数,以后可调用**************/
- void write_1602com(uchar com)//****液晶写入指令函数****
- {
- rs=0;//数据/指令选择置为指令
- P0=com;//送入数据
- delay(1);
- en=1;//拉高使能端,为制造有效的下降沿做准备
- delay(1);
- en=0;//en由高变低,产生下降沿,液晶执行命令
- }
- void write_1602dat(uchar dat)//***液晶写入数据函数****
- {
- rs=1;//数据/指令选择置为数据
- P0=dat;//送入数据
- delay(1);
- en=1; //en置高电平,为制造下降沿做准备
- delay(1);
- en=0; //en由高变低,产生下降沿,液晶执行命令
- }
- void lcd_init()//***液晶初始化函数****
- {
- uchar a;
- rw=0;
- write_1602com(0x38);//设置液晶工作模式,意思:16*2行显示,5*7点阵,8位数据
- write_1602com(0x0c);//开显示不显示光标
- write_1602com(0x06);//整屏不移动,光标自动右移
- write_1602com(0x01);//清显示
- write_1602com(0x80);//显示固定符号从第一行第1个位置之后开始显示
- for(a=0;a<2;a++)
- {
- write_1602dat(tab1[a]);//向液晶屏写固定符号部分
- }
- write_1602com(0x80+8);//显示固定符号写入位置,从第2个位置后开始显示
- for(a=0;a<5;a++)
- {
- write_1602dat(tab2[a]);//写显示固定符号
- }
- write_1602com(0x80+0x40);//显示固定符号写入位置,从第2个位置后开始显示
- for(a=0;a<2;a++)
- {
- write_1602dat(tab3[a]);//写显示固定符号
- }
- }
- void display() //显示函数
- {
- if(RPM<=99999) //范围内时
- {
- uchar gw,sw,bw,qw,ww;//定义拆字变量
- ww=RPM/10000; //转速/10000得到万位
- qw=RPM%10000/1000; //转速/10000的余数/1000得到千位
- bw=RPM%1000/100;//取得百位
- sw=RPM%100/10;//取得十位数字
- gw=RPM%10;//取得个位数字
- write_1602com(0x80+2); //选中第二行第二位
- if(ww==0) //万位为0时
- {
- write_1602dat(' '); //显示空格
- }
- else //万位不为0时
- {
- write_1602dat(0x30+ww); //显示万位的数据 +0x30是因为在液晶的字库中,0的地址是0x30,1的地址是0x31,以此类推
- }
- if((ww+qw)==0) //万位和千位都为0时
- {
- write_1602dat(' '); //千位显示空格
- }
- else //万位和千位不都为0时
- {
- write_1602dat(0x30+qw); //显示千位数据
- }
- if((ww+qw+bw)==0) //万位、千位和百位都是0时
- {
- write_1602dat(' '); //显示空格
- }
- else //万位、千位和百位不都为0时
- {
- write_1602dat(0x30+bw); //显示百位数据
- }
- if((ww+qw+bw+sw)==0) //万位、千位、百位和十位都为0时
- {
- write_1602dat(' '); //显示空格
- }
- else //万位、千位、百位和十位不都为0时
- {
- write_1602dat(0x30+sw); //显示十位数据
- }
- write_1602dat(0x30+gw); //显示个位数据 数字+0x30得到该数字的LCD1602显示码
- }
- else //超过范围时显示-----
- {
- write_1602com(0x80+2); //选中第二行第二列
- write_1602dat('-'); //显示‘-’
- write_1602dat('-'); //显示‘-’
- write_1602dat('-'); //显示‘-’
- write_1602dat('-'); //显示‘-’
- write_1602dat('-'); //显示‘-’
- }
- }
- /*********************报警转速参数转换函数************************/
- void conversion(unsigned long temp1)//数据转换出 个,十,百,千,万
- {
- h_w=temp1/10000;
- h_q=temp1%10000/1000;
- h_b=temp1%1000/100;
- h_s=temp1%100/10;
- h_g=temp1%10;
- }
- void key_shezhi()
- {
- if(key1==0)
- {
- delay(10);//延时消抖
- if(key1==0)
- {
- menu++;//切换液晶显示界面菜单
- if(menu>1)
- {
- menu=0;
- lcd_init();
- delay(5);
- }
- }
- while(!key1);
- }
- if(menu==0)
- {
- if(temp<RPM)//实际转速大于设置的上限,产生报警
- {
- alarming();//报警
- }
- else
- {
- alarm=1;
- }
- display();//返回初始化显示,显示当前的实时转速
- write_1602com(0x80+0x40+2);//刷新显示设置的报警参数
- write_1602dat(0x30+temp/10000);
- write_1602dat(0x30+temp%10000/1000);
- write_1602dat(0x30+temp%1000/100);
- write_1602dat(0x30+temp%100/10);
- write_1602dat(0x30+temp%10);
- temp=h_w*10000+h_q*1000+h_b*100+h_s*10+h_g;
- }
- if(menu==1)
- {
- if(key2==0)
- {
- delay(10);
- if(key2==0)
- {
- temp++;//参数加
- if(temp>29999)//最大值29999
- {
- temp=29999;
- }
- conversion(temp);//万、千、百、十、个位转换
- write_eeprom();//参数保存到EEPROM
- }
- }
- if(key3==0)//通过减按键
- {
- delay(10);
- if(key3==0)
- {
- if(temp>0)
- {
- temp--;//参数减
- }
- conversion(temp);//万、千、百、十、个位转换
- write_eeprom();//参数保存到EEPROM
- }
- }
- //conversion(temp);//万、千、百、十、个位转换
- //write_eeprom();//参数保存到EEPROM
- delay(30);//延时
- write_1602com(0x80+0x40+2);//在液晶上刷新参数显示
- write_1602dat(0x30+temp/10000);
- write_1602dat(0x30+temp%10000/1000);
- write_1602dat(0x30+temp%1000/100);
- write_1602dat(0x30+temp%100/10);
- write_1602dat(0x30+temp%10);
- /*************************************************/
- write_1602com(0x80+0x40+6);//将光标移动到上限参数的个位
- write_1602com(0x0e);
- }
- }
- void init() //系统初始化设置
- {
- IT0=1; //INT0负跳变触发
- TMOD=0x11;//定时器工作于方式1
- TH0=0;
- TL0=0;
- EA=1; //CPU开中断总允许
- ET0=1;
- EX0=1;//开外部INTO中断
- TR0=0;//启动定时
- TH1=0x3c;
- TL1=0xb0;
- ET1=1;
- TR1=1;
- }
- /*****************主函数*************************************/
- void main()
- {
- init(); //调用初始化函数
- lcd_init();//液晶初始化
- delay(5);
- init_eeprom();//初始化eeprom
- delay(10);
- read_eeprom();//读取eeprom数据
- delay(10);
- while(1) //进入while循环
- {
- key_shezhi();
- }
- }
- void EXINT0() interrupt 0 //外部中断函数,霍尔元件有信号,会进入此中断
- {
- if(TR0==0) //霍尔有信号输入时,定时器没有打开就打开定时器,准备计时
- {
- TH0=0;
- TL0=0; //定时器清零
- TT=0; //计时变量清零
- TT1=0; //定时器中断次数清零
- TR0=1; //打开定时器,开始计时
- p=0;
- sec=0;
- }
- else //第二次检测到信号时
- {
- p=0;
- sec=0;
- TR0=0; //关闭定时器
- TT=TT1*65536+TH0*256+TL0; //计算两次信号的时间差。中断次数*65536+TH0*256+TL0,得到时间差
- TH0=0;
- TL0=0; //计算完成后,将定时器清零
- num=60000000/TT; //根据时间计算1min中的速度。一分钟是60秒,一秒是1000毫秒,1毫秒是1000us,所以是60*1000*1000/时间,TT的单位是单片机的最快速度1微秒
- TT1=0; //计算完速度后,TT1清零
- if(num>1000) //转速超过1000时,取50次的平均值
- {
- sum=num+sum; //将数据加一起
- T_num++; //次数加
- if(T_num>=50) //加到50次
- {
- T_num=0; //次数清零
- RPM=sum/50; //总数除以50得到平均值
- sum=0; //计算完后总数清零
- }
- }
- else //转速小于1000时
- {
- sum=0; //总数清零
- RPM=num; //数据直接赋值给转速
- num=0; //数据清零
- T_num=0; //次数清零
- }
- }
- }
- void timeT0() interrupt 1 //两次信号中间,定时器有中断
- {
- TT1++; //说明达到一次65536,将TT1加1,计算时,将TT1乘以65536就是这个的时间了
- TH0=0;
- TL0=0; //定时器清零
- }
- void timeT1() interrupt 3 //两次信号中间,定时器有中断
- {
- TH1=0x3c;
- TL1=0xb0; //定时器清零
- p++;
- if(p>=20)
- {
- p=0;
- sec++;
- if(sec>=5)
- {
- sec=0;
- RPM=0;
- TR0=0;
- }
- }
- }
复制代码
|
|