光电式速度计课程设计 报告
课程设计
题目光电式速度计
二级学院
专业
班级
学生姓名
学号
指导教师
考核项目设计50分平时成绩20分答辩30分得分
总分考核等级教师签名
光电式传感器,是基于光电效应的传感器,在受到可见光照射后即产生光电效应,将光信号转换成电信号输出。它除能测量光强之外,还能利用光线的透射、遮挡、反射、干涉等测量多种物理量,如尺寸、位移、速度、温度等,因而是一种应用极广泛的重要敏感器件。光电测量时不与被测对象直接接触,光束的质量又近似为零,在测量中不存在摩擦和对被测对象几乎不施加压力。因此在许多应用场合,光电式传感器比其他传感器有明显的优越性。其缺点是在某些应用方面,光学器件和电子器件价格较贵,并且对测量的环境条件要求较高。而光电式速度计就是基于光电传感器将速度的变化转变成光通量的变化,在通过光电转换元件将光通量的变化转换成电量变化,即利用光电脉冲变成电脉冲,通过对电脉冲的一系列计数,换算,即可实现光电式计算速度。
一、概述
二、硬件电路设计及描述
1.阐述方案选择及设计思想
2.绘制原理框图
3.简述工作原理
4.绘制原理电路图
三、软件设计流程及描述
1.绘制系统模块层次结构图
2.程序流程图
3.源程序代码
四、测试
五、总结
参考文献
元器件清单一览表
个人总结
一、概述
本次课程设计我们所做的是光电式速度计,它主要是利用光电式传感器收到光照射后产生的光电效应,将光信号转换成电信号输出。通过对输出的电信号计时,就可计算出在这期间的平均速度。
系统利用光电式传感器设计速度计量系统,具有计数功能,且系统工作满足速度计的一般要求。
二、硬件电路设计及描述
1.阐述方案选择及设计思想
我们在选择方案的时候选择了用外部中断0和51的T0定时/计数器。因为这样会让电路更加简洁,直接用外部中断0的H/L 来判定是否进入中断。由于外部中断0的是L 触发,所以当外部中断0开始输入L 时,T0定时/计数器开始计时。当外部中断0重新输入H 时,T0定时/计数器结束计时,就得到在INT0期间的时间,因为已知转盘的弧长或者木条的长度l ,由v=l/t,就可以得到在INT0期间的平均速度。再通过LCD1602将所得的时间t 和速度v 输出到液晶屏上。
2.绘制原理框图
89C51 P0.0 XTAL1
XTAL2
P0.7
P2.5 RST P2.7
P3.2/INT0
复位电路 晶振电路 1602液晶显示器 D0---D7 控制位
红外光电传感器
3.简述工作原理
如上图所示,上图是硬件原理框图。可以看到硬件是由几大模块主成的。晶振电路主要是为51内部产生时钟信号。复位电路是为51回到初始化的状态的一种操作,它可以在1602显示乱码,或者电路其它部分的上电状态与预期不一样时,按下复位按钮就可以使51回到初始化的状态。1602液晶显示器是一块16*2的液晶显示,它会显示两行16个字符或数字。1602有3个控制位。RS为寄存器选择,高电平1时选择数据寄存器,低电平0时选择指令寄存器。RW为读写信号线,高电平时进行读操作,低电平时进行写操作。E(或EN)端为使能(enable)端,写操作时,下降沿使能;读操作时,E高电平有效。VSS一般接地,VDD接电源(+5V),V0液晶显示器对比度调整端,接正电源时对比度最弱,接地电源时对比度最高(对比度过高时会产生“鬼影”,使用时可以通过一个10K的电位器调整对比度)。红外光电传感器是将利用光电式传感器收到光照射后产生的光电效应,将光信号转换成电信号输出。当转盘或者木条经过时,挡住了红外光电传感器一直输给INT0的高电平,触发了INT0,T0就开始计时了,当INT0再次接受到H时,T0计时结束。由v=l/t,就得到了速度。
4.绘制原理电路图
5.绘制器件清单列表
元器件清单列表见附页。
三、软件设计流程及描述
1.绘制系统模块层次结构图
2.程序流程图
开始
LCD初始化
T0初始化
LCD清屏
LCD显示:
no interrupt 0
开总中断
While(1)
If(int0_flag==2)
计算v和t
把v和t的浮点数转成字
符串,保留小数点后4位
LCD清屏,
LCD第一行显示t=xxx.xxxx s
第二行显示v=xxx.xxxx m/s
t0_num=0(T0计数器置0)
int0_flag=0(INT0标志置0)
EA=1(开总中断)
如上图所示,上图是主函数程序流程图。可以看到程序开始后,先进行LCD的初始化,再对T0进行初始化。然后是对LCD的清屏,在没有INT0的时候,LCD显示no interrupt 0,让EA=1开外部总中断。判断int0_flag==2,计算在INT0期间的时间t,由已知转盘的弧长或者小木条的长度l,故v=l/t。当然在程序中要注意单位的转换,让最后时间t的单位为s,最后v的单位为m/s。再把v和t的浮点数转成字符串,保留小数点后4位。令LCD清屏,1602的第一行显示t=xxx.xxxx s,第二行显示v=xxx.xxxx m/s。对t0_num置0,int0_flag置0,EA置1(开总中断),等待下一次INT0。
3.源程序代码
#include
#define uchar unsigned char #define uint unsigned int
T0初始化
EA=0(关总中断)EX0=1(允许INT0中断)IT0=1(INT0边沿触发)
TMOD=0x01;
初始化T0,工作方式一,16位计数器
计数器设初值
TH0=(65536-1000)/256;
TL0=(65536-1000)%256;
t0_num 每1ms计一次
EA=1(开总中断)
uchar code table0[]="no interrupt 0";
uchar code table1[]="counting";
sbit lcden=P2^6;
sbit lcdrs=P2^5;
sbit lcdrw=P2^7;
uchar num;
unsigned int t0_num=0;
unsigned int tt;
float aa;
float v;
unsigned int l=10; //10cm
unsigned char int0_flag=0; //INT0的中断标志位unsigned char t0_max=65000; //T0的最大中断次数void delay(uint z)
{
uint x,y;
for(x=z;x>0;x--)
for(y=110;y>0;y--);
}
void write_com(uchar com) //1602写命令函数
{
lcdrs=0;
lcden=0;
P0=com;
delay(5);
lcden=1;
delay(5);
lcden=0;
}
void write_data(uchar date) //1602写数据函数
{
lcdrs=1;
lcden=0;
P0=date;
delay(5);
lcden=1;
delay(5);
lcden=0;
}
void ftostr1(double fNum, unsigned char str[],unsigned int dotsize)//将浮点数转字符串{
int iSize=0; //记录字符串长度的数
int n=0; //用作循环的临时变量
unsigned long int i_predot;//小数点前的数
unsigned long int i_afterdot;//小数点后的数
float f_afterdot;//实数型的小数部分
unsigned char *p=str;//做换向时用的指针
unsigned char *s=str;//做换向时用的指针
i_predot=(unsigned long int)fNum;//将小数点之前的数变为整数
f_afterdot=fNum-i_predot;//单独取出小数点之后的数
//根据设定的要保存的小数点后的位数,将小数点后相应的位数变到小数点之前for(n=dotsize+1;n!=0;n--)
{
f_afterdot=f_afterdot*10;
}
i_afterdot=(unsigned long int)f_afterdot;//将小数点后相应位数的数字变为整数
n=i_afterdot%10;
n/=5;
i_afterdot/=10;//将i_afterdot恢复到实际要求的小数位数
if(n!=0)//判断最后一位是否大于或者等于5,并进行四舍五入处理
{
//i_afterdot/=10;//将i_afterdot恢复到实际要求的小数位数i_afterdot++;
n=i_afterdot;
}
//先将小数点后的数转换为字符串
n=dotsize;
while(n!=0)
{
n--;
str[iSize++]=i_afterdot%10+'0';//对10取余并变为ASCII码i_afterdot=i_afterdot/10;//对10取商
}
if(dotsize!=0)//小数点位数大于零的情况下
str[iSize++] ='.';//加上小数点
//处理小数点前为0的情况。
if(i_predot==0)
str[iSize++]='0';
//再将小数点前的数转换为字符串
while(i_predot!=0)
{
str[iSize++]=i_predot%10+'0';//对10取余并变为ASCII码i_predot=i_predot/10;//对10取商
}
if(fNum<0)
str[iSize++]='-';
str[iSize] ='\0'; //加上字符串结束标志
p=str+iSize-1; //将P指针指向字符串结束标志之前for(;(p-s)>0;p--,s++) //将字符串中存储的数调头
{
*s^=*p;
*p^=*s;
*s^=*p;
}
}
void init()
{
lcdrw=0; //写
lcden=0;
write_com(0x38);
write_com(0x0c);
write_com(0x06);
write_com(0x01);
write_com(0x80);
}
uint i,j;
void int0_fun() interrupt 0 //INT0中断处理函数{
//uint i,j;
if(int0_flag==0)
{
TR0=1;
}
int0_flag++;
if(int0_flag==1)
{
write_com(0x01);
write_com(0x80);
for(j=0;j<8;j++)
{
write_data(table1[j]);
}
}
if(int0_flag==2)
{
TR0=0;
EA=0;
}
}
void t0_fun() interrupt 1
{
TH0=(65536-1000)/256;
TL0=(65536-1000)%256;
t0_num++;
if(T0==t0_max)
{
int0_flag=2;
TR0=0;
EA=0;
}
}
//主函数
void main ()
{
uchar str1[10];
uchar str2[10];
uint i,j;
init();
EA=0; //初始化中断
IT0=1; //外部中断0,边沿触发
EX0=1; //允许外部中断0中断
TMOD=0X01; //初始化T0,方式一,16位计数器
ET0 = 1 ;
TH0=(65536-1000)/256;
TL0=(65536-1000)%256; //t0_num --1ms计一次(即每1mst0_num++)//EA=1; //开总中断
write_com(0x01);
write_com(0x80);
for(i=0;i<14;i++)
{
write_data(table0[i]);
}
EA=1;
while(1)
{
if(int0_flag==2)
{
tt=t0_num;
aa=tt/1000.0;
v=(10.0*l)/tt;
ftostr1(aa,str1,4); //小数点后保留4位
ftostr1(v,str2,4);
write_com(0x01);
write_com(0x80);
write_data('t');
write_com(0x80+1);
write_data('=');
for(i=0;i<10;i++)
{
write_data(str1[i]);
}
write_com(0x80+0x0a);
write_data('s');
write_com(0x80+0x40);
write_data('v');
write_com(0x80+0x40+1);
write_data('=');
for(j=0;j<10;j++)
{
write_data(str2[j]);
}
write_com(0x80+0x40+0x0a);
write_data('m');
write_com(0x80+0x40+0x0b);
write_data('/');
write_com(0x80+0x40+0x0c);
write_data('s');
t0_num=0;
int0_flag=0;
EA=1;
}
}
}
四、测试
上电后若没有触发INT0时,显示的是no interrupt 0(没有外部中断0),当触发INT0时,显示counting(正在计数、计算),当INT0再次回到H(高电平)时,显示INT0触发期间的时间t、速度v的结果。
INT0没有触发。
INT0触发,计数中。
INT0触发结束,显示结果。
五、总结
本次课程设计从最开始的方案设定,到采购器件,自己制版,到最后的电路调试,我们对单片机又有了更深一步的认识。在本次课程设计中,我们也更深一步的了解到仿真跟实物完全是两回事,我们对1602也有了更深的认识。
在软件方面,我们最开始的方向不对,一直都没有想到给定长度,导致进度很慢。最后经过老师的指点解决了。其次就是我们对定时器的初始化不熟悉,翻阅了以前的书,还去查了很多关于定时器初始化的例子,解决了定时器的问题。还有就是我们的显示,最开始因为没有接触过1602,后来通过同学和老师我们对它有了一点了解,解决了显示上的问题。
在硬件方面,我们在最后调试的时候1602始终都还是不显示,跟仿真完全不一样,电脑上仿真的时候显示都没有问题,可是做到实物上就不出显示。我们尝试写入最简单的程序就只显示一个1、2,它还是会显示,可是写入我们自己的程序时,1602还是没反应。还有值得注意的是,在往51烧程序的时候,一定要确保烧程序的软件跟硬件都是好的。在烧程序的时候,有天我们就是一直不知道烧程序的那个硬件是坏的,一直找不到原因。在做硬件的时候不管是做万能板,还是PCB,我们发现用排针接线会减少接线短路,或是其他故障的几率。
这次课程设计唯一的遗憾就是我们把程序烧进51后,1602不显示,仿真上都可以,找了两周始终找不到问题。但是如果烧其他程序LCD又有显示,因为课程设计的时间有限,我们也只能做到这里,但是我们下来后还是会继续研究程序的问题,最终希望它能实现功能。
参考文献
1.51单片机技术与应用系统开发案例精选(清华大学出版社)
2.例说51单片机(人民邮电出版社)
3.51单片机开发与应用技术详解(电子工业出版社)
4.51单片机应用系统典型模块开发大全(中国铁道出版社)
5.51单片机应用开发范例大全(人民邮电出版社)
6.单片机原理及应用(重庆大学出版社)
课程设计元器件清单一览表
题目名称:光电式速度计
组员名单:
序号品名型号规格参数封装数量参考价金额
1 51单片机AT89C51 1 5.5 5.5
2 液晶显示器LCD1602 1 10 10
3 按键常开 2 1 1
4 电容30pF 2 2 2
5 电容10uF 1 1 1
6 电阻1KΩ 1 2 2
7 排阻9脚 1 1 1
8 晶振12MHz 1 0.5 0.5
9 电位器10kΩ 1 0.5 0.5
10 底座40脚 1 3 3
11 面包板面包板 1 1 1
12 烙铁烙铁、松香 1 18 18
13 锡丝 1 1.5 1.5
14 导线若干 1 1
15 红外光电传感器 1 1 1
16 电阻220Ω 1 1 1
合计50