1、 生产实习报告 班 级: 电信 12-2 姓 名: 李 猛 学 号: 1206110207 成 绩: 电子与信息工程学院 信息与通信工程系 基于单片机的计步器设计 摘要 随着社会的发展,生活方式的改变,现代人的生活越来越远离运动,都市的白领们在享受着汽车、互联网等科学技术为生活带来便利的同时,身体的活动机会也在不断
2、的减少。高强度的脑力劳动,长时间的办公室作业,让许多人的身体处于亚健康状态,更有不少人患上了肥胖、失眠等疾病。本文基于IAP15F2K61S2单片机,利用常开型振动传感器模块检测人体行走的步数,通过数码管显示出来。并具有清零、存储记录和查看历史记录的功能。使人们时刻掌握着自己的健身强度和运动水平。 关键词:IAP15F2K61S2、常开型振动传感器模块、计步器 1 设计任务 计步器主要由振动传感器和电子计数器组成。人在步行时重心都要有一点上下移动。以腰部的上下位移最为明显,所以计步器挂在腰带上最为适宜。 计步器的工作核心就是振动传感器,通过振动传感器对日常锻炼进度监控器,可以计算人
3、们行走的步数,估计行走距离、消耗的卡路里,方便人们随时监控自己的健身强度和运动水平。 通过设计实现的功能有: 1) 利用振动传感器来实现对计步器功能的模拟; 2) 可以记录行走的步数,可以显示记录的步数; 3) 通过按键实现归零功能,可以存储历史记录,并断电不丢失; 4) 通过按键实现了历史记录的查看。 2 设计思路 计步器由振荡电路、复位电路、数码管显示模块以及按键模块和传感器模块等几个部分组成(如图2-1)。振荡电路是给单片机提供外部时钟信号,使单片机工作。复位电路是使单片机恢复初始状态。数码管显示模块是受单片机控制显示步数。按键模块是通过相应的按键控制单片机实现相应的功
4、能。传感器模块是检测人体行走时的振动,若检测到振动则传感器给出低电平,来告诉单片机记录步数。 图2-1 计步器系统框图 3 电路原理图 图3-1 计步器电路原理图 4 硬件设计及器件清单 4.1 振荡电路 单片机内设有一个由反向放大器所构成的振荡电路,振荡电路是单片机系统正常工作的保证,如果振荡器不起振,系统将会不能工作。假如振荡器运行不规律,系统执行程序的时候就会出现时间上的误差。单片机内部时钟不精确,尤其是在高频时,添加外部振荡电路[3],时钟电路中的两个电容用作抗干扰,使得晶振频率更加稳定(如图4-1)。 图4-1 时钟振荡电路
5、 4.2 复位电路 为确保单片机电路稳定可靠工作,复位电路是必不可少的一部分,复位电路的第一功能是上电复位[3]。按键放开时,电容充满电后相当于断路,RST通过电阻接地为低电平。按键按下时,RST通过电阻链接到VCC为高电平,按键松开后,电容充电保持一定时间高电平,系统复位(如图4-2)。 图4-2 系统复位电路 4.3 显示电路 计步器设计采用4位LED共阳极数码管显示做为系统的显示界面(如图4-3)。常用的LED数码管为8段或7段(8段比7段多了一个小数点“dp”段)。每一个段对应一个发光二极管,数码管有共阳极和共阴极两种。共阳极LED数码管的发光二极管的阳极连接在一起,通
6、常是共阳极接VCC。为了使LED数码管显示不同的符号和数字,就要把不同段的发光二极管点亮,这样就要为LED数码管提供代码,因为这些代码可使LED相应的 段发光,从而显示不同字型,该代码称之为段码。当某些发光二极管的阴极为低电平时,发光二极管点亮,相应的段被显示,这些段组合成字型[2]。 图4-3 数码管显示电路 4.4 按键电路 本次设计通过按键的按下来实现步数的存储、步数的清零、查看存储的上一条记录和查看下一条记录(如图4-4)。 图4-4 系统按键电路 4.5 传感器模块 振动传感器的基本工作原理是当检测到机械振动信号后,它在电路的配合下,将机械振动信号转换为电信号
7、输出[1]。 模块使用说明 1) 用于各种振动触发作用,报盗报警,智能小车,电子积木等; 2) 模块在感应到小的振动时触发时间会很短,不够驱动继电器,有些人的资料显示可以直接和继电器模块相连,实际运用效果不佳; 3) 产品不振动时,振动开关呈断开状态,输出端输出高电平,黄色指示灯不亮; 4) 产品振动时,振动开关瞬间导通,输出端输出低电平,黄色指示灯亮; 5) 输出端可以与单片机直接相连,通过单片机来检测高低电平,由此来检测环境是否有振动,起到报警作用。 4.6 器件清单 表4-1 计步器元器件列表 序号 器件 数量 1 IAP15F2K61S2单片机 1片
8、2 常开型振动传感器模块 1块 3 4位共阳数码管 1块 4 晶振11.0592 1块 5 三极管NPN 4个 6 四角开关 4个 7 电阻10K 5个 8 电阻470R 9个 9 电阻300R 4个 10 电解电容10uF 1个 11 电容47pF 2个 12 发光二极管红色 1个 13 开关 1个 14 排针、导线 若干 5 PCB图 5.1 计步器PCB正面图 图5-1计步器PCB正面图 5.2计步器PCB背面图 图5-2计步器PCB背面图 6 程序流程图
9、 7 部分程序代码 7.1 数码管显示程序 循环语句实现数码管的动态扫描,显示对应的位,利用人眼的视觉惰性实现显示。主程序调用数码管段显示子程序,显示字型[4]。 while(1) { qian=num/1000;bai=(num/100)%10;shi=(num/10)%10;ge=num%10; sel1=0; sel2=0; sel3=0; sel4=1; seg(qian); delay(1); sel1=0; sel2=0; sel3=1; sel4=0; seg(bai); delay(1); sel1=0; sel2=1; sel3=0; sel4=0; s
10、eg(shi); delay(1); sel1=1; sel2=0; sel3=0; sel4=0; seg(ge); delay(1); } void seg(uint n) { switch(n) { case 0:P0 = 0xC0; break; case 1:P0 = 0xF9; break; case 2:P0 = 0xA4; break; case 3:P0 = 0xB0; break; case 4:P0 = 0x99; break; case 5:P0 = 0x92; break; case 6:P0 = 0x82;
11、 break; case 7:P0 = 0xF8; break; case 8:P0 = 0x80; break; case 9:P0 = 0x90; break; default:P0 = 0xC0; break; } } 7.2 记录存储程序 存储记录要先擦除扇区,在写入数据,写入数据前要对命令触发寄存器写入0x5A,再写入0xA5,才能写如数据。 //===============写字节数据=============== void write(uint addr,uchar dat) { iap_contr = eniap;
12、 iap_cmd = 0x02; iap_addrl = addr; iap_addrh = addr>>8; iap_data = dat; iap_trig = 0x5A; iap_trig = 0xA5; _nop_(); uniap(); } //===============擦除扇区=============== void erase(uint addr) { iap_contr = eniap; iap_cmd = 0x03; iap_addrl = a
13、ddr; iap_addrh = addr>>8; iap_trig = 0x5A; iap_trig = 0xA5; _nop_(); uniap(); } 8 设计总结及学习FPGA感想 为期两周的生产实习渐渐的结束了,在这次实习过程中,我选择了计步器设计。在实习过程中,我先是对硬件电路进行了设计,之后要进行焊接操作,由于之前很少使用电烙铁进行焊接,所以导致刚开始焊接时对焊点焊的不够饱满,有时甚至出现了虚焊的情况,但慢慢地熟悉了之后,焊接起来也就快了不少。而在后面的程序设计的阶段,我选择的C语言进行设计,在经过数百次
14、的修改和调试之后,最终顺利完成了设计。同时,这次生产实习是一次很好的把理论应用到实践中去的锻炼,通过实习,我更加认识到了理论知识的重要性,也对自己所学知识的长处与不足有了一定的认识,锻炼了动手能力。最后看着自己努力设计出来的成果,心里有了一丝的成就感。 感谢至芯科技,无私地给我们带来一个星期的FPGA培训。经过一周的培训,我收获颇丰。有技能的提高,思维的扩展还有生活的充实。技能的提升对我来说非常明显。培训一开始,老师教我们用熟这些软件,这些软件的熟练掌握,加速了进一步设计电路的速度。老师根据我们薄弱的底子和对Verilog HDL的一无所知的基本情况,从简单的显数、计数,再到RAM、ROM、
15、串行通信的设计,逐步深入,设计合适的万用框架体系让我们更容易上手,化繁为简,局部分模块化逐步设计到后来顶层文件做关联形成一个看起来功能很复杂的程序体系。最后能够轻松完成一个复杂功能的电路。体现了硬件描述语言能够模块化设计关联的强大特性。也使我们对Verilog HDL编程有了浓厚的兴趣。 学习的一周过的十分充实,坐在实验室里写程序看似单调,但有条不紊,忙忙碌碌,脑子里是如何用语言描述一个功能,如何处理时序还有各个功能块之间的关系。现在我能能感觉到自己的提高,自然会感觉无限充实。经过培训和实习,大大增强了我的自学能力和独立能力。更重要的是,我拓展了思路,开阔了视野,活跃了思想,对以后的学习工作
16、起到了很大的帮助作用。
参考文献
[1] 胡向东.传感器与检测技术.机械工业出版社.2015,01(2):303~314.
[2] 童诗白,华成英.模拟电子技术基础.高等教育出版社.2013,12(19):74~115.
[3] 姜志海,黄玉清,刘连鑫.单片机原理与应用.电子工业出版.2014,07(2):27~32.
[4] 谭浩强.C程序设计(第四版).清华大学出版社.2012,10(10):37~140.
附录
计步器完整程序:
#include
17、signed char #define uint unsigned int #define iapaddr 0x4A00 #define endaddr 0x4800 #define eniap 0x82 sfr iap_data = 0xC2; //iap数据寄存器 sfr iap_addrh = 0xC3; //iap地址寄存器高字节 sfr iap_addrl = 0xC4; //iap地址寄存器低字节 sfr iap_cmd = 0xC5; //iap命令寄存器 sfr iap_trig = 0xC6; //iap命令触发寄存器
18、 sfr iap_contr = 0xC7; //iap控制寄存器 sbit led = P2^7; sbit key0 = P2^0; sbit key1 = P2^6; sbit key2 = P2^5; sbit key3 = P2^4; sbit sel1 = P1^0; sbit sel2 = P1^1; sbit sel3 = P1^2; sbit sel4 = P1^3; void delay(uint z); //延时程序 void seg(uint n); //数码管段显示 void uniap(void);
19、 //关闭IAP功能 uint read(uint addr); //读字节数据 void write(uint addr,uchar dat); //写字节数据 void erase(uint addr); //擦除扇区 //===============主程序=============== void main(void) { uint num=0,n,m,i; uchar qian,bai,shi,ge; n=iapaddr; m=iapaddr-4; led=1; while(1) { qian=num/1000;b
20、ai=(num/100)%10;shi=(num/10)%10;ge=num%10; sel1=0; sel2=0; sel3=0; sel4=1; seg(qian); delay(1); sel1=0; sel2=0; sel3=1; sel4=0; seg(bai); delay(1); sel1=0; sel2=1; sel3=0; sel4=0; seg(shi); delay(1); sel1=1; sel2=0; sel3=0; sel4=0; seg(ge); delay(1); if(num==9999) //计数等于99
21、99灯闪烁两下 { sel1=1; sel2=1; sel3=1; sel4=1; led=0; delay(50); led=1; delay(50); led=0; delay(50); led=1; } if((key1==0)||(num==9999)) //按键按下存储数据并归零 { if(num!=0) { erase(endaddr); if(!(n%512)) erase(n); for(i=0;i<4;i++) {
22、 switch(i) { case 0:write(n,qian); break; case 1:write(n,bai); break; case 2:write(n,shi); break; case 3:write(n,ge); break; } n++; } m=n; if(n==0xFDFF) n=iapaddr; write((uint)endaddr,(uchar)(n>>8)); write((uint)endaddr
23、1,(uchar)n); } num=0; } if(key2==0) //按键按下显示下一条记录 { m=m+4; if(m>=((read((uint)endaddr)<<8)+read((uint)endaddr+1))||m==iapaddr) { sel1=1; sel2=1; sel3=1; sel4=1; m=iapaddr; led=0; delay(36); led=1; } for(i=0;i<200;i++) { sel1=0;
24、 sel2=0; sel3=0; sel4=1; seg(read(m)); delay(1); sel1=0; sel2=0; sel3=1; sel4=0; seg(read(m+1)); delay(1); sel1=0; sel2=1; sel3=0; sel4=0; seg(read(m+2)); delay(1); sel1=1; sel2=0; sel3=0; sel4=0; seg(read(m+3)); delay(1); } } if(key3==0) //按键按下显示上一条记录
25、
{
m=m-4;
if(m 26、sel3=1; sel4=0;
seg(read(m+1)); delay(1);
sel1=0; sel2=1; sel3=0; sel4=0;
seg(read(m+2)); delay(1);
sel1=1; sel2=0; sel3=0; sel4=0;
seg(read(m+3)); delay(1);
}
}
if(key0==0)
num++;
}
}
//===============延时程序===============
void delay(uint z)
{
uint i,j 27、
for(i=z;i>0;i--)
for(j=1300;j>0;j--);
}
//===============数码管段显示===============
void seg(uint n)
{
switch(n)
{
case 0:P0 = 0xC0; break;
case 1:P0 = 0xF9; break;
case 2:P0 = 0xA4; break;
case 3:P0 = 0xB0; break;
case 4:P0 = 0x99; break;
case 5:P0 = 0x92; break;
case 28、6:P0 = 0x82; break;
case 7:P0 = 0xF8; break;
case 8:P0 = 0x80; break;
case 9:P0 = 0x90; break;
default:P0 = 0xC0; break;
}
}
//===============关闭IAP功能===============
void uniap(void)
{
iap_contr = 0;
iap_cmd = 0;
iap_trig = 0;
iap_addrh = 0x80;
i 29、ap_addrl = 0;
}
//===============读字节数据===============
uint read(uint addr)
{
uint dat;
iap_contr = eniap;
iap_cmd = 0x01;
iap_addrl = addr;
iap_addrh = addr>>8;
iap_trig = 0x5A;
iap_trig = 0xA5;
_nop_();
dat = iap_data;
uniap();
re 30、turn dat;
}
//===============写字节数据===============
void write(uint addr,uchar dat)
{
iap_contr = eniap;
iap_cmd = 0x02;
iap_addrl = addr;
iap_addrh = addr>>8;
iap_data = dat;
iap_trig = 0x5A;
iap_trig = 0xA5;
_nop_();
uniap();
}
//===============擦除扇区===============
void erase(uint addr)
{
iap_contr = eniap;
iap_cmd = 0x03;
iap_addrl = addr;
iap_addrh = addr>>8;
iap_trig = 0x5A;
iap_trig = 0xA5;
_nop_();
uniap();
}
20






