[学习资料]

基于pic16f877a的车辆里程记录与速度测量

[复制链接]
246|9
手机看帖
扫描二维码
随时随地手机跟帖
花间一壶酒sd|  楼主 | 2024-2-27 11:57 | 显示全部楼层 |阅读模式

本文利用测速传感器模块对车轮的码盘进行计数,通过简单的数据处理可以转化成里程数与速度值。

首先是测速模块的硬件(窄体的槽型光耦测速模块,在陶包x信可以买到)


7142965dd5dad10b3a.png


使用说明:

1、模块槽中无遮挡时,接收管导通,模块DO输出低电平,遮挡时,DO输出高电平;

2、DO输出接口可以与单片机IO口直接相连,检测传感器是否有遮档,如用电机码盘则可检测电机的转速。

3、模块DO可与继电器相连,组成限位开关等功能,也可以与有源蜂鸣器模块相连,组成报警器。


使用特权

评论回复
评论
花间一壶酒sd 2024-2-27 11:58 回复TA
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。 原文链接:https://blog.csdn.net/z793kelvins/article/details/130760893 
花间一壶酒sd|  楼主 | 2024-2-27 11:59 | 显示全部楼层
接线
1、VCC接电源正极3.3V-5V

2、GND接电源负极

3、D0(TTL开关信号输出)接单片机外部中断

4、A0无效

电机码盘的摆放位置 让码盘放在俩个柱子之间 通电后发现当光线被挡住时l开关指示的led灯将熄灭

8179465dd5e0d030ec.png

使用特权

评论回复
花间一壶酒sd|  楼主 | 2024-2-27 11:59 | 显示全部楼层
代码部分

代码部分有俩个要处理的数据,一个时里程数,一个是速度值

1里程数(里程值被存放在eeprom中可以防止断电丢失)

我这款电机码盘上面有20个小孔,经过测量发现一个车轮的周长为20cm,测速模块每经过一个小孔输出一个跳变,也就是说一个跳变对应的里程为1cm,那么10个跳变则为1dm=10cm,

利用pic16f877a的RB0外部电平中断,每次收到一个跳变则进入中断并将计数值count_temp+1

我设置的分度值为1dm,进入10次中断后里程数就+1

2速度值

速度值的处理方式为一个俩个小孔之间是距离除以时间

简单来说就是在一个小孔到来时进入中断将定时器打开 下一个小孔到来进入中断将定时器关闭,为了防止定时器溢出,定时时器溢出时将n值+1,数据处理时(n*65535再加上定时器的数据)作为时间值

然后将俩个小孔之间对应车轮走过的距离1cm作为距离值

即 距离值/时间值 再进行简单的单位换算即可得出速度值

使用特权

评论回复
花间一壶酒sd|  楼主 | 2024-2-27 11:59 | 显示全部楼层
代码基本封装成函数了 可以直接看函数的注释

//from 793k
//基于pic16f877a编写代码
#include <pic.h>
__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();       
        }
}

使用特权

评论回复
花间一壶酒sd|  楼主 | 2024-2-27 12:00 | 显示全部楼层
最后附上Proteus仿真(利用电源输入时钟信号代替测速模块的运行)
3495865dd5e4dc00f7.png

输入100hz的时钟,对应1s100个跳变即100cm,所以对应的速度为1m/s,仿真结果正确。

使用特权

评论回复
在线DIY23| | 2024-2-27 12:03 | 显示全部楼层
这个原理应该是自行车的码表原理一样的。

使用特权

评论回复
1134209200| | 2024-2-27 12:06 | 显示全部楼层
可以的

使用特权

评论回复
CarterERO| | 2024-2-28 21:51 | 显示全部楼层
这个还可以测速啊

使用特权

评论回复
LOVEEVER| | 2024-2-28 22:49 | 显示全部楼层
这个是码表原理

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

76

主题

971

帖子

1

粉丝