本帖最后由 jianpu 于 2018-6-1 18:18 编辑
要求 51单片机使用,共用计时器 测距显示在左边四位数码管中 测速显示在右边四位数码管中 在测试成功之后 选择最佳答案
光电测速程序
#include <REG52.H>
#define uchar unsigned char
#define uint unsigned int
#define ulong unsigned long
char DisplayData[8];
typedef unsigned int u8; //对数据类型进行声明定义
typedef unsigned char u16;
#define LED_DAT P0
sbit pin_SpeedSenser = P3^5; //速度传感器脉冲信号输出端接在T1上
#define TIME_CYLC 100 //12M晶振,定时器10ms 中断一次 我们1秒计算一次转速,1000ms/10ms = 100
#define PLUS_PER 2 //码盘的齿数 ,这里假定码盘上有2个齿,即传感器检测到2个脉冲,认为1圈
#define K 1.0 //校准系数
sbit LSA=P2^2;
sbit LSB=P2^3;
sbit LSC=P2^4;
char code smgduan[17]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,
0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};//显示0~F的值
uint Tcounter = 0; //时间计数器
bit Flag_Fresh = 0; // 刷新标志
bit Flag_clac = 0; //计算转速标志
bit Flag_Err = 0; //超量程标志
//在数码管上显示一个四位数
void DigDisplay();
//计算转速,并把结果放入数码管缓冲区
void ClacSpeed();
//初始化定时器
void init_timer();
void it_timer0() interrupt 1 //定时器0中断的响应函数
{
TF0 = 0; //定时器 T0用于数码管的动态刷新
TH0 = 0xD8; //初始化
TL0 = 0xF0;
Flag_Fresh = 1;
Tcounter++;
if(Tcounter>TIME_CYLC)
{
Flag_clac = 1;//周期到,该重新计算转速了
}
}
void it_timer1() interrupt 3 //中断地址是0x001b
{
TF1 = 0; //定时器T1用于单位时间内收到的脉冲数,要速度不是很快,T1永远不会益处
Flag_Err = 1; //如果速度很高,我们应考虑另外一种测速方法:脉冲宽度算转速
}
/*******************************************************************************
* 函 数 名 : delay
* 函数功能 : 延时函数,i=1时,大约延时10us
*******************************************************************************/
void delay(u16 i)
{
while(i--);
}
void main(void)
{
init_timer();
while(1)
{
LSA=1;
LSB=0;
LSC=1;
delay(30);
LSC=0;
delay(170);
if(Flag_Fresh)
{
Flag_Fresh = 0;
DigDisplay(); // 定时刷新数码管显示
}
if(Flag_clac)
{
Flag_clac = 0;
ClacSpeed(); //计算转速,并把结果放入数码管缓冲区
Tcounter = 0;//周期定时清零
TH1=TL1 = 0x00;//脉冲计数清零
}
if(Flag_Err) //超量程处理
{
//数码管显示字母'EEEE',开机时初始化为0000
DisplayData[0] = 0x79;
DisplayData[1] = 0x79;
DisplayData[2] = 0x79;
DisplayData[3] = 0x79;
while(1)
{
DigDisplay();//等待复位,不再测速
}
}
}
}
/*******************************************************************************
* 函 数 名 : DigDisplay
* 函数功能 : 数码管动态扫描函数,循环扫描8个数码管显示
*******************************************************************************/
void DigDisplay()
{
u8 i;
for(i=0;i<8;i++)
{
switch(i) //位选,选择点亮的数码管,
{
case(0):
LSA=0;LSB=0;LSC=0; break;//显示第0位
case(1):
LSA=1;LSB=0;LSC=0; break;//显示第1位
case(2):
LSA=0;LSB=1;LSC=0; break;//显示第2位
case(3):
LSA=1;LSB=1;LSC=0; break;//显示第3位
}
P0=DisplayData;//发送段码
delay(100); //间隔一段时间扫描
P0=0x00;//消隐
}
}
//计算转速,并把结果放入数码管缓冲区
void ClacSpeed()
{
uint speed ;
ulong PlusCounter;
PlusCounter = TH1*256 + TL1;
speed = K*(PlusCounter/PLUS_PER);//K是校准系数,如速度不准,调节K的大小
DisplayData[3] = smgduan[speed/1000%10];
DisplayData[2] = smgduan[speed/100%10];
DisplayData[1] = smgduan[speed/10%10];
DisplayData[0] = smgduan[speed%10];
}
void init_timer() //初始化
{
TMOD = 0x51; //定时10毫秒,TOT1选择软件门方式1,T0定时,T1计数,96页可查
TH0 = 0xD8; //T0初始化
TL0 = 0xF0;
ET0=1; //T0中断允许
EA=1; //T0中断
TR0=1; //TO运行
TH1 = 0x00; //T1初始化
TL1 = 0x00;
ET1=1; //T1中断允许
TR1=1; //T1运行
LSA=1;
LSB=0;
}
超声波测距程序
/* 超声波模块的TRIG管脚接在单片机的P20口,ECHO管脚接在单片机的P21口 其他的电源管脚接在单片机
开发板上电源口即可。 */
#include"reg51.h"
#include <intrins.h>
sbit RX=P2^1;
sbit TX=P2^0;
unsigned int time=0;
unsigned int timer=0;
unsigned char posit=0;
unsigned long S=0;
typedef unsigned int u8; //对数据类型进行声明定义
typedef unsigned char u16;
bit flag =0;
//--定义使用的IO--//
#define GPIO_DIG P0
sbit LSA=P2^2;
sbit LSB=P2^3;
sbit LSC=P2^4;
//--定义全局变量--//
char code smgduan[17]={
0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,
0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};
//0、1、2、3、4、5、6、7、8、9、A、b、C、d、E、F的显示码
unsigned char disbuff[4] ={ 0,0,0,0,};
char DisplayData[8];
/*******************************************************************************
* 函 数 名 : delay
* 函数功能 : 延时函数,i=1时,大约延时10us
*******************************************************************************/
void delay(u16 i)
{
while(i--);
}
/*******************************************************************************
* 函 数 名 : DigDisplay
* 函数功能 : 使用数码管显示
* 输 入 : 无
* 输 出 : 无
*******************************************************************************/
void DigDisplay()
{
u8 i;
for(i=0;i<8;i++)
{
switch(i) //位选,选择点亮的数码管,
{
case(0):
LSA=0;LSB=0;LSC=0; break;//显示第0位
case(1):
LSA=1;LSB=0;LSC=0; break;//显示第1位
case(2):
LSA=0;LSB=1;LSC=0; break;//显示第2位
case(3):
LSA=1;LSB=1;LSC=0; break;//显示第3位
case(4):
LSA=0;LSB=0;LSC=1; break;//显示第4位
case(5):
LSA=1;LSB=0;LSC=1; break;//显示第5位
case(6):
LSA=0;LSB=1;LSC=1; break;//显示第6位
case(7):
LSA=1;LSB=1;LSC=1; break;//显示第7位
}
P0=DisplayData;//发送段码
delay(10); //间隔一段时间扫描
P0=0x00;//消隐
}
}
/********************************************************/
void Conut(void)
{
//time=TH0*256+TL0;
//TH0=0;
//TL0=0;
S= (long)(time*0.17); //算出来是CM
if(S>=4000)//||flag==1) //超出测量范围显示“ERR0”
{
flag=0;
DisplayData[7]=0x3f; //“-”
DisplayData[6]=0x50; //“-”
DisplayData[5]=0x50; //“-”
DisplayData[4]=0x79; //“-”
}
else
{
DisplayData[7]=smgduan[S%10000/1000];
DisplayData[6]=smgduan[S%1000/100];
DisplayData[5]=smgduan[S%100/10];
DisplayData[4]=smgduan[S%10/1];
}
}
/********************************************************/
// void zd0() interrupt 1 //T0中断用来计数器溢出,超过测距范围
// {
// flag=1; //中断溢出标志
// }
/********************************************************/
void zd3() interrupt 3 //T1中断用来扫描数码管和计800MS启动模块
{
TH1=0xf8;
TL1=0x30;
//DigDisplay();
timer++;
if(timer>=100)
{
timer=0;
TX=1; //800MS 启动一次模块
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
TX=0;
}
}
/*********************************************************/
void main( void )
{
TMOD=0x11; //设T0为方式1,GATE=1;
TH0=0;
TL0=0;
TH1=0xf8; //2MS定时
TL1=0x30;
ET0=1; //允许T0中断
ET1=1; //允许T1中断
TR1=1; //开启定时器
EA=1; //开启总中断
while(1)
{
while(!RX); //当RX为零时等待
TR0=1; //开启计数
while(RX); //当RX为1计数并等待
TR0=0; //关闭计数
Conut(); //计算
}
}
|