找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 3895|回复: 4
收起左侧

单片机霍尔测速设计最终版程序与元件清单

[复制链接]
ID:470473 发表于 2019-1-19 11:30 | 显示全部楼层 |阅读模式
霍尔测速元件清单
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电源线或电池盒

单片机程序源码:

  1. #include<reg52.h>                        //包含头文件
  2. #include <intrins.h>
  3. #define uchar unsigned char
  4. #define uint unsigned int        //宏定义

  5. /*************STC89单片机EEPROM参数定义和声明********/
  6. #define RdCommand 0x01 //定义ISP的操作命令
  7. #define PrgCommand 0x02
  8. #define EraseCommand 0x03
  9. #define Error 1
  10. #define Ok 0
  11. #define WaitTime 0x01 //定义CPU的等待时间
  12. sfr ISP_DATA=0xe2;//寄存器申明
  13. sfr ISP_ADDRH=0xe3;
  14. sfr ISP_ADDRL=0xe4;
  15. sfr ISP_CMD=0xe5;
  16. sfr ISP_TRIG=0xe6;
  17. sfr ISP_CONTR=0xe7;
  18. char a_a;
  19. /********************************************/
  20. unsigned long temp=0;//报警上限转速参数定义
  21. uchar h_w,h_q,h_b,h_s,h_g;//报警上限转速的参数(万、千、百、十、个位)
  22. /**************************************************/
  23. sbit COUNT_IN=P3^2;//霍尔传感器信号输入
  24. /****************************************************/
  25. //定义1602液晶相关管脚
  26. sbit rs=P2^7;
  27. sbit en=P2^6;
  28. sbit rw=P2^5;
  29. uchar menu;//液晶设置界面菜单
  30. /****************************************************/
  31. sbit key1=P1^1;//报警转速参数设置按键
  32. sbit key2=P1^2;//加
  33. sbit key3=P1^3;//减
  34. sbit alarm=P1^0;//蜂鸣器报警
  35. /**************************************************/
  36. uint count,m,n;                                //定义计算速度变量
  37. unsigned long RPM=0;                        //定义速度变量
  38. unsigned long TT=0;                                //定义时间变量
  39. unsigned long sum=0;                        //计算平均值的总数
  40. unsigned char T_num=0;                        //平均值取值的次数
  41. unsigned long num=0;                        //单次转速
  42. unsigned int TT1=0;                                //定义定时器中断次数变量
  43. bit flag;                                        //定义位变量,值只能是0或者1
  44. uchar p,sec;
  45. /********************************************************/
  46. //液晶初始化显示定义
  47. uchar code tab1[]={"R:"};         //一行显示的固定字符
  48. uchar code tab2[]={"r/min"};                //转速显示的固定字符
  49. uchar code tab3[]={"H:"};                //转速显示的固定字符

  50. /**************延时子函数定义************/
  51. void delay(uint x)                //延时函数,大约延时1ms,不精确
  52. {
  53. uint i,j;                        //定义延时函数变量
  54. for(i=0;i<x;i++)        //for循环延时
  55. for(j=0;j<110;j++);
  56. }
  57. void alarming()//蜂鸣器报警子函数
  58. {
  59. alarm=0;
  60. delay(50);
  61. alarm=1;
  62. delay(50);
  63. }
  64. /******************************STC89单片机 EERPROM函数******************/
  65. /*************打开 ISP,IAP 功能********************/
  66. void ISP_IAP_enable(void)
  67. {
  68. EA=0;       //关中断
  69. ISP_CONTR=ISP_CONTR&0x18;       // 0001,1000
  70. ISP_CONTR=ISP_CONTR|WaitTime; //写入硬件延时
  71. ISP_CONTR=ISP_CONTR|0x80;      //ISPEN=1
  72. }
  73. /********************关闭 ISP,IAP 功能 ************/
  74. void ISP_IAP_disable(void)
  75. {
  76. ISP_CONTR=ISP_CONTR&0x7f; //ISPEN = 0
  77. ISP_TRIG=0x00;
  78. EA=1;   //开中断
  79. }
  80. /************公用的触发代码**********************/
  81. void ISPgoon(void)
  82. {
  83. ISP_IAP_enable();//打开 ISP,IAP 功能
  84. ISP_TRIG=0x46; //触发ISP_IAP命令字节1
  85. ISP_TRIG=0xb9; //触发ISP_IAP命令字节2
  86. _nop_();
  87. }
  88. /****************字节读 *************************/
  89. unsigned char byte_read(unsigned int byte_addr)
  90. {
  91. EA=0;
  92. ISP_ADDRH=(unsigned char)(byte_addr>>8);//地址赋值
  93. ISP_ADDRL=(unsigned char)(byte_addr&0x00ff);
  94. ISP_CMD=ISP_CMD&0xf8;//清除低3位  
  95. ISP_CMD=ISP_CMD|RdCommand;//写入读命令
  96. ISPgoon();//触发执行  
  97. ISP_IAP_disable();//关闭ISP,IAP功能
  98. EA=1;
  99. return(ISP_DATA);//返回读到的数据
  100. }
  101. /*****************扇区擦除 ************************/
  102. void SectorErase(unsigned int sector_addr)
  103. {
  104. unsigned int iSectorAddr;
  105. iSectorAddr=(sector_addr&0xfe00); //取扇区地址
  106. ISP_ADDRH=(unsigned char)(iSectorAddr>>8);
  107. ISP_ADDRL=0x00;
  108. ISP_CMD=ISP_CMD&0xf8;//清空低3位  
  109. ISP_CMD=ISP_CMD|EraseCommand; //擦除命令3  
  110. ISPgoon();//触发执行
  111. ISP_IAP_disable();//关闭ISP,IAP功能
  112. }
  113. /************************字节写 *************************/
  114. void byte_write(unsigned int byte_addr, unsigned char original_data)
  115. {
  116. EA=0;
  117. ISP_ADDRH=(unsigned char)(byte_addr>>8);//取地址
  118. ISP_ADDRL=(unsigned char)(byte_addr & 0x00ff);
  119. ISP_CMD=ISP_CMD&0xf8;//清低3位
  120. ISP_CMD=ISP_CMD | PrgCommand;//写命令2
  121. ISP_DATA=original_data;//写入数据准备
  122. ISPgoon();//触发执行  
  123. ISP_IAP_disable();//关闭IAP功能
  124. EA =1;
  125. }
  126. /********************内部eeprom写函数**************/
  127. void write_eeprom()
  128. {
  129. SectorErase(0x2000);//先把扇区清空
  130. delay(1);
  131. SectorErase(0x2c00);//先把扇区清空
  132. delay(1);
  133. SectorErase(0x2d00);//先把扇区清空
  134. delay(1);

  135. /**************写入参数******************/
  136. byte_write(0x2d00,h_w);//存万位
  137. delay(1);
  138. byte_write(0x2d01,h_q);//存千位
  139. delay(1);
  140. byte_write(0x2d02,h_b);//存百位
  141. delay(1);
  142. byte_write(0x2d03,h_s);//存十位
  143. delay(1);
  144. byte_write(0x2d04,h_g);//存个位
  145. delay(1);
  146.                                    
  147. byte_write(0x2060,0x01);
  148. }
  149. /******************把数据从单片机内部eeprom中读出来*****************/
  150. void read_eeprom()                                                                                                                                 
  151. {
  152. h_w=byte_read(0x2d00);//万位读回来
  153. delay(1);
  154. h_q=byte_read(0x2d01);//千位读回来
  155. delay(1);
  156. h_b=byte_read(0x2d02);//百位读回来
  157. delay(1);
  158. h_s=byte_read(0x2d03);//十位读回来
  159. delay(1);
  160. h_g=byte_read(0x2d04);//个位读回来
  161. delay(1);
  162. a_a=byte_read(0x2060);         
  163. }
  164. /**************开机自检eeprom初始化*****************/
  165. void init_eeprom()
  166. {
  167. a_a=byte_read(0x2060);
  168. if(a_a!=1)                //新的单片机初始单片机内问eeprom
  169. {
  170.   a_a=1;
  171.   write_eeprom();//保存数据
  172.   delay(1);
  173. }        
  174. }

  175. /********液晶写入指令函数与写入数据函数,以后可调用**************/
  176. void write_1602com(uchar com)//****液晶写入指令函数****
  177. {
  178. rs=0;//数据/指令选择置为指令
  179. P0=com;//送入数据
  180. delay(1);
  181. en=1;//拉高使能端,为制造有效的下降沿做准备
  182. delay(1);
  183. en=0;//en由高变低,产生下降沿,液晶执行命令
  184. }
  185. void write_1602dat(uchar dat)//***液晶写入数据函数****
  186. {
  187. rs=1;//数据/指令选择置为数据
  188. P0=dat;//送入数据
  189. delay(1);
  190. en=1; //en置高电平,为制造下降沿做准备
  191. delay(1);
  192. en=0; //en由高变低,产生下降沿,液晶执行命令
  193. }
  194. void lcd_init()//***液晶初始化函数****
  195. {
  196. uchar a;
  197. rw=0;
  198. write_1602com(0x38);//设置液晶工作模式,意思:16*2行显示,5*7点阵,8位数据
  199. write_1602com(0x0c);//开显示不显示光标
  200. write_1602com(0x06);//整屏不移动,光标自动右移
  201. write_1602com(0x01);//清显示

  202. write_1602com(0x80);//显示固定符号从第一行第1个位置之后开始显示
  203. for(a=0;a<2;a++)
  204. {
  205.   write_1602dat(tab1[a]);//向液晶屏写固定符号部分
  206. }
  207. write_1602com(0x80+8);//显示固定符号写入位置,从第2个位置后开始显示
  208. for(a=0;a<5;a++)
  209. {
  210.   write_1602dat(tab2[a]);//写显示固定符号
  211. }
  212. write_1602com(0x80+0x40);//显示固定符号写入位置,从第2个位置后开始显示
  213. for(a=0;a<2;a++)
  214. {
  215.   write_1602dat(tab3[a]);//写显示固定符号
  216. }
  217. }

  218. void display()                         //显示函数
  219. {
  220. if(RPM<=99999)                 //范围内时
  221. {
  222.   uchar gw,sw,bw,qw,ww;//定义拆字变量
  223.   ww=RPM/10000;                //转速/10000得到万位
  224.   qw=RPM%10000/1000;        //转速/10000的余数/1000得到千位
  225.   bw=RPM%1000/100;//取得百位
  226.   sw=RPM%100/10;//取得十位数字
  227.   gw=RPM%10;//取得个位数字
  228.   write_1602com(0x80+2);         //选中第二行第二位

  229.   if(ww==0)                                         //万位为0时
  230.   {
  231.    write_1602dat(' ');                         //显示空格
  232.   }
  233.   else                                                 //万位不为0时
  234.   {
  235.    write_1602dat(0x30+ww);                 //显示万位的数据        +0x30是因为在液晶的字库中,0的地址是0x30,1的地址是0x31,以此类推
  236.   }

  237.   if((ww+qw)==0)                                 //万位和千位都为0时
  238.   {
  239.    write_1602dat(' ');                         //千位显示空格
  240.   }
  241.   else                                                 //万位和千位不都为0时
  242.   {
  243.    write_1602dat(0x30+qw);                 //显示千位数据
  244.   }

  245.   if((ww+qw+bw)==0)                         //万位、千位和百位都是0时
  246.   {
  247.    write_1602dat(' ');                         //显示空格
  248.   }
  249.   else                                                 //万位、千位和百位不都为0时
  250.   {
  251.    write_1602dat(0x30+bw);                 //显示百位数据
  252.   }

  253.   if((ww+qw+bw+sw)==0)                 //万位、千位、百位和十位都为0时
  254.   {
  255.    write_1602dat(' ');                         //显示空格
  256.   }
  257.   else                                                 //万位、千位、百位和十位不都为0时
  258.   {
  259.    write_1602dat(0x30+sw);                 //显示十位数据
  260.   }               
  261.   write_1602dat(0x30+gw);                 //显示个位数据    数字+0x30得到该数字的LCD1602显示码
  262. }
  263. else                  //超过范围时显示-----
  264. {
  265.   write_1602com(0x80+2);         //选中第二行第二列
  266.   write_1602dat('-');                         //显示‘-’
  267.   write_1602dat('-');                         //显示‘-’
  268.   write_1602dat('-');                         //显示‘-’
  269.   write_1602dat('-');                         //显示‘-’
  270.   write_1602dat('-');                         //显示‘-’
  271. }
  272. }

  273. /*********************报警转速参数转换函数************************/
  274. void conversion(unsigned long temp1)//数据转换出 个,十,百,千,万
  275. {  
  276. h_w=temp1/10000;
  277. h_q=temp1%10000/1000;
  278. h_b=temp1%1000/100;
  279. h_s=temp1%100/10;
  280. h_g=temp1%10;        
  281. }

  282. void key_shezhi()
  283. {
  284. if(key1==0)
  285. {
  286.   delay(10);//延时消抖
  287.   if(key1==0)
  288.   {
  289.    menu++;//切换液晶显示界面菜单
  290.    if(menu>1)
  291.    {
  292.         menu=0;
  293.         lcd_init();
  294.         delay(5);
  295.    }
  296.   }
  297.   while(!key1);
  298. }

  299. if(menu==0)
  300. {
  301.    if(temp<RPM)//实际转速大于设置的上限,产生报警
  302.    {
  303.     alarming();//报警
  304.    }
  305.    else
  306.    {
  307.     alarm=1;
  308.    }

  309.    display();//返回初始化显示,显示当前的实时转速
  310.    write_1602com(0x80+0x40+2);//刷新显示设置的报警参数
  311.    write_1602dat(0x30+temp/10000);
  312.    write_1602dat(0x30+temp%10000/1000);
  313.    write_1602dat(0x30+temp%1000/100);
  314.    write_1602dat(0x30+temp%100/10);
  315.    write_1602dat(0x30+temp%10);

  316.    temp=h_w*10000+h_q*1000+h_b*100+h_s*10+h_g;
  317. }
  318. if(menu==1)
  319. {
  320.   if(key2==0)
  321.   {
  322.    delay(10);
  323.    if(key2==0)
  324.    {
  325.     temp++;//参数加
  326.         if(temp>29999)//最大值29999
  327.         {
  328.          temp=29999;
  329.         }
  330.         conversion(temp);//万、千、百、十、个位转换
  331.     write_eeprom();//参数保存到EEPROM
  332.    }
  333.   }
  334.   if(key3==0)//通过减按键
  335.   {
  336.    delay(10);
  337.    if(key3==0)
  338.    {
  339.     if(temp>0)
  340.         {
  341.          temp--;//参数减
  342.         }
  343.         conversion(temp);//万、千、百、十、个位转换
  344.     write_eeprom();//参数保存到EEPROM
  345.    }
  346.   }
  347.   //conversion(temp);//万、千、百、十、个位转换
  348.   //write_eeprom();//参数保存到EEPROM

  349.   delay(30);//延时
  350.   write_1602com(0x80+0x40+2);//在液晶上刷新参数显示
  351.   write_1602dat(0x30+temp/10000);
  352.   write_1602dat(0x30+temp%10000/1000);
  353.   write_1602dat(0x30+temp%1000/100);
  354.   write_1602dat(0x30+temp%100/10);
  355.   write_1602dat(0x30+temp%10);
  356.   /*************************************************/
  357.   write_1602com(0x80+0x40+6);//将光标移动到上限参数的个位
  358.   write_1602com(0x0e);
  359. }
  360. }

  361. void init()                                //系统初始化设置
  362. {
  363. IT0=1;        //INT0负跳变触发        
  364. TMOD=0x11;//定时器工作于方式1
  365. TH0=0;         
  366. TL0=0;
  367. EA=1; //CPU开中断总允许
  368. ET0=1;
  369. EX0=1;//开外部INTO中断
  370. TR0=0;//启动定时

  371. TH1=0x3c;
  372. TL1=0xb0;
  373. ET1=1;
  374. TR1=1;
  375. }
  376. /*****************主函数*************************************/
  377. void main()                  
  378. {
  379. init();        //调用初始化函数
  380. lcd_init();//液晶初始化
  381. delay(5);
  382. init_eeprom();//初始化eeprom
  383. delay(10);
  384. read_eeprom();//读取eeprom数据
  385. delay(10);
  386. while(1)          //进入while循环
  387. {
  388.   key_shezhi();
  389. }
  390. }

  391. void EXINT0() interrupt 0 //外部中断函数,霍尔元件有信号,会进入此中断
  392. {
  393. if(TR0==0)                                           //霍尔有信号输入时,定时器没有打开就打开定时器,准备计时
  394. {
  395.   TH0=0;
  396.   TL0=0;                                           //定时器清零
  397.   TT=0;                                           //计时变量清零
  398.   TT1=0;                                           //定时器中断次数清零
  399.   TR0=1;                                           //打开定时器,开始计时
  400.   p=0;
  401.   sec=0;
  402. }
  403. else                                                   //第二次检测到信号时
  404. {
  405.   p=0;
  406.   sec=0;
  407.   TR0=0;                                           //关闭定时器
  408.   TT=TT1*65536+TH0*256+TL0;  //计算两次信号的时间差。中断次数*65536+TH0*256+TL0,得到时间差
  409.   TH0=0;
  410.   TL0=0;                                           //计算完成后,将定时器清零
  411.   num=60000000/TT;                   //根据时间计算1min中的速度。一分钟是60秒,一秒是1000毫秒,1毫秒是1000us,所以是60*1000*1000/时间,TT的单位是单片机的最快速度1微秒
  412.   TT1=0;                                           //计算完速度后,TT1清零
  413.   if(num>1000)                           //转速超过1000时,取50次的平均值
  414.   {
  415.    sum=num+sum;                   //将数据加一起
  416.    T_num++;                           //次数加
  417.    if(T_num>=50)                   //加到50次
  418.    {
  419.         T_num=0;                   //次数清零
  420.     RPM=sum/50;                   //总数除以50得到平均值
  421.         sum=0;                           //计算完后总数清零
  422.    }
  423.   }
  424.   else                                           //转速小于1000时
  425.   {
  426.    sum=0;                                   //总数清零
  427.    RPM=num;                           //数据直接赋值给转速
  428.    num=0;                                   //数据清零
  429.    T_num=0;                           //次数清零
  430.   }
  431. }
  432. }

  433. void timeT0() interrupt 1                   //两次信号中间,定时器有中断
  434. {
  435. TT1++;                                                   //说明达到一次65536,将TT1加1,计算时,将TT1乘以65536就是这个的时间了
  436. TH0=0;
  437. TL0=0;                                                   //定时器清零
  438. }

  439. void timeT1() interrupt 3                   //两次信号中间,定时器有中断
  440. {
  441. TH1=0x3c;
  442. TL1=0xb0;                                                   //定时器清零
  443. p++;
  444. if(p>=20)
  445. {
  446.   p=0;
  447.   sec++;
  448.   if(sec>=5)
  449.   {
  450.    sec=0;
  451.    RPM=0;
  452.    TR0=0;
  453.   }
  454. }
  455. }


复制代码

元件清单.doc

27.5 KB, 下载次数: 9, 下载积分: 黑币 -5

回复

使用道具 举报

ID:1 发表于 2019-1-19 13:43 | 显示全部楼层
补全原理图或者详细说明一下电路连接即可获得100+黑币
回复

使用道具 举报

ID:470473 发表于 2019-2-16 15:07 | 显示全部楼层
admin 发表于 2019-1-19 13:43
补全原理图或者详细说明一下电路连接即可获得100+黑币

你好,要怎么补全,再发一个帖子吗
回复

使用道具 举报

ID:517235 发表于 2019-5-4 18:23 | 显示全部楼层
袁继辉 发表于 2019-2-16 15:07
你好,要怎么补全,再发一个帖子吗

原贴修改上传原理图
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表