基于pic16f877a的车辆里程记录与速度测量
本文利用测速传感器模块对车轮的码盘进行计数,通过简单的数据处理可以转化成里程数与速度值。
首先是测速模块的硬件(窄体的槽型光耦测速模块,在陶包x信可以买到)
使用说明:
1、模块槽中无遮挡时,接收管导通,模块DO输出低电平,遮挡时,DO输出高电平;
2、DO输出接口可以与单片机IO口直接相连,检测传感器是否有遮档,如用电机码盘则可检测电机的转速。
3、模块DO可与继电器相连,组成限位开关等功能,也可以与有源蜂鸣器模块相连,组成报警器。
接线
1、VCC接电源正极3.3V-5V
2、GND接电源负极
3、D0(TTL开关信号输出)接单片机外部中断
4、A0无效
电机码盘的摆放位置 让码盘放在俩个柱子之间 通电后发现当光线被挡住时l开关指示的led灯将熄灭

代码部分
代码部分有俩个要处理的数据,一个时里程数,一个是速度值
1里程数(里程值被存放在eeprom中可以防止断电丢失)
我这款电机码盘上面有20个小孔,经过测量发现一个车轮的周长为20cm,测速模块每经过一个小孔输出一个跳变,也就是说一个跳变对应的里程为1cm,那么10个跳变则为1dm=10cm,
利用pic16f877a的RB0外部电平中断,每次收到一个跳变则进入中断并将计数值count_temp+1
我设置的分度值为1dm,进入10次中断后里程数就+1
2速度值
速度值的处理方式为一个俩个小孔之间是距离除以时间
简单来说就是在一个小孔到来时进入中断将定时器打开 下一个小孔到来进入中断将定时器关闭,为了防止定时器溢出,定时时器溢出时将n值+1,数据处理时(n*65535再加上定时器的数据)作为时间值
然后将俩个小孔之间对应车轮走过的距离1cm作为距离值
即 距离值/时间值 再进行简单的单位换算即可得出速度值
代码基本封装成函数了 可以直接看函数的注释
//from 793k
//基于pic16f877a编写代码
#include
__CONFIG(0xFF29);
__EEPROM_DATA(0,0,0,0,0,0,0,0);//eeprom寄存器一开始给一个0的值
static volatile char table[10]={0x30,0x31,0x32,0x33,
0x34,0x35,0x36,0x37,0x38,0x39} ;
#define rs RA5
#define rw RA2
#define e RA3
//lcd对应的使能引脚,看自己的原理图,有些RA2改成RA4
unsigned int count_temp,n,speed;
unsigned char shuju[6];
unsigned char speed_data[4],m;
unsigned int t_speed;
union
{ unsigned long count;char data[3]; }li_cheng;
//共用体
//========================lcd相关函数===============================
void delay()//延时函数
{unsigned int i;for(i=999;i>0;i--);}
void lcdml()//写入命令
{rs=0;rw=0;e=0;delay();e=1;}
void lcdx()//写入字
{rs=1;rw=0;e=0;delay();e=1;}
void lcd_Init()//lcd初始化
{TRISD=0;TRISA=0;ADCON1=7;PORTD=0;delay();PORTD=1;lcdml();PORTD=0x38;lcdml();PORTD=0x0c;lcdml();PORTD=0x06;lcdml(); }
//==========================数据处理部分========================================
void licheng_deal()//里程数的数据处理
{shuju[0]=li_cheng.count/100000;shuju[1]=li_cheng.count%100000/10000;shuju[2]=li_cheng.count%10000/1000;shuju[3]=li_cheng.count%1000/100;shuju[4]=li_cheng.count%100/10;shuju[5]=li_cheng.count%10;
}
void speed_deal()//速度的数据处理
{
//speed为最后的速度,speed_data为lcd显示做的数据处理speed=1000000/t_speed;speed_data[0]=speed/1000;speed_data[1]=speed%1000/100;speed_data[2]=speed%100/10;speed_data[3]=speed%10;
}
//========================================================================================
void interrupt int_serve()//中断服务函数
{if(TMR1IF==1){n++;TMR1IF=0;}//防止速度部分TMR1模块溢出if(INTF==1){ count_temp++;;if(count_temp==10){li_cheng.count++;count_temp=0;}//当收到100个高电平里程数+1,100个高电平相当于小车走了1m//====================================速度测量部分===============m++;if(m==0)//打开tmr1 清空定时器数据{n=0;TMR1IE=0;TMR1L=0;TMR1H=0;TMR1ON=1;TMR1IF=0;}if(m==1){TMR1ON=0;TMR1IE=0;t_speed=(n*65535)+(TMR1H*256)+TMR1L;TMR1IF=0;}//=============================================================== INTF=0;//清电平中断标志位,不清的话会一直进中断出不去}
}
void init()
{t_speed=0;TRISD=0;TRISA=0;ADCON1=7;m=250;n=0;TRISB0=1;count_temp=0;GIE=1;PEIE=1;TMR1IE=1;TMR1IF=0;INTE=1;INTF=0;T1CON=0B00000001;
}
void main()
{init();//中断&端口初始化函数调用lcd_Init();//lcd初始化函数调用 li_cheng.data[0]=eeprom_read(0x00);li_cheng.data[1]=eeprom_read(0x01);li_cheng.data[2]=eeprom_read(0x02);//从寄存器中调用上次存入的数据while(1){ speed_deal();licheng_deal();eeprom_write(0x02,li_cheng.data[2]);eeprom_write(0x01,li_cheng.data[1]);eeprom_write(0x00,li_cheng.data[0]);//将里程放到寄存体中 掉电不会丢失PORTD=0x80;lcdml();PORTD=table[shuju[0]];lcdx();PORTD=table[shuju[1]];lcdx();PORTD=table[shuju[2]];lcdx();PORTD=table[shuju[3]];lcdx();PORTD=table[shuju[4]];lcdx();PORTD=table[shuju[5]];lcdx();PORTD='d';lcdx();PORTD='m';lcdx();PORTD=0xc0;lcdml();//========================第二行速度的显示PORTD=table[speed_data[0]];lcdx();PORTD=table[speed_data[1]];lcdx();PORTD='.';lcdx();PORTD=table[speed_data[2]];lcdx();PORTD=table[speed_data[3]];lcdx();// PORTD='c';lcdx();PORTD='m';lcdx();PORTD='/';lcdx();PORTD='s';lcdx(); }
}
最后附上Proteus仿真(利用电源输入时钟信号代替测速模块的运行)

输入100hz的时钟,对应1s100个跳变即100cm,所以对应的速度为1m/s,仿真结果正确。
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
