wryp 发表于 2023-9-3 17:37:45

单片机学习之三:做一个自行车车速表

看到必威APP精装版下载里已经有人做过。
原理都一样,利用霍尔元件感受自行车前轮转的圈数。统计时间,计算车速,里程,保留最高速度至DS1302的RAM,计量骑行的总时间。
不多说,上图。因为实物被朋友拿走了,这里上PCB图,原理图,并贴出代码。
代码肯定不专业,各位轻喷。

白无无 发表于 2023-9-4 07:46:35

你这,能搭话的就少了啊;P我反正是看不明白

wryp 发表于 2023-9-3 17:38:21

//这是一个用于测量自行车车速、里程的程序,需要专门设计的硬件支持。

//电路包含几大部分:脉冲采样、DS1302以及89S52,5位LED数码管显示。

#include <reg52.h>
#include<intrins.h>


//                                  0    1    2    3    4    5    6    7    8   9    空               //码表,不带小数点,最后两位为显示空和-
unsigned char code table[]   ={0x77,0x14,0xb3,0xb6,0xd4,0xe6,0xe7,0x34,0xf7,0xf6,0x00,0x80};
unsigned char code table_D[] ={0x7f,0x1c,0xbb,0xbe,0xdc,0x6d,0xee,0x3c,0xff,0xfe,0x00,0x02,0x82,0xa2,0x80};//码表,带小数点。



unsigned long z=4294967295;                                          //          2毫秒的个数
unsigned int time=65535,dc = 0;
unsigned int maxg,maxs,maxb,maxq,maxw,v,max;                         //             最后两个是速度   和最高车速
unsigned char gn = 1;                                                //             功能切换
unsigned char g,s,b,q,w,temp,xhcs;                                 //显示推送位
unsigned long sg,ss,sb,sq,sw,ssw;


sbit ACC0 = ACC^0;
sbit ACC7 = ACC^7;

sbit T_CLK = P1^6; //实时时钟时钟线引脚
sbit T_IO = P1^5; //实时时钟数据线引脚
sbit T_RST = P1^7; //实时时钟复位线引脚

sbit p11 = P1^1;
sbit p10 = P1^0;

bit dw=1;



//      **************************************************************************************************************
//      *   名称:delay(void)                                                                                                                            *
//      *   功能:延迟                                                                                                                               *
//      *   输入:无                                                                                                                                        *
//      *   输出:无                                                                                                                                                         *
//      **************************************************************************************************************
void delay(void)
{
        unsigned char x,j;
        for(j=0;j<2;j++)
        for(x=0;x<=148;x++);       
}




//      **************************************************************************************************************
//      *   名称:v_RTInputByte()                                                                                                                         *
//      *   功能:往DS1302写入1Byte数据                                                                                                                 *
//      *   输入:ucDa 写入的数据                                                                                                                             *
//      *   输出:无                                                                                                                                                         *
//      **************************************************************************************************************
void v_RTInputByte(unsigned char ucDa)
{
        unsigned char i;
        ACC = ucDa;
        T_RST = 1;
        for(i=8; i>0; i--)
        {
                T_IO = ACC0;
                T_CLK = 1;
                T_CLK = 0;
                ACC = ACC >> 1;
        }
}




//      **************************************************************************************************************
//      *   名称:uc_RTOutputByte()                                                                                                                         *
//      *   功能:从DS1302读取1Byte数据                                                                                                                   *
//      *   输入:无                                                                                                                                                         *
//      *   返回值:ACC                                                                                                                                                         *
//      **************************************************************************************************************
unsigned char uc_RTOutputByte(void)
{
        unsigned char i;
        T_RST = 1;
        for(i=8; i>0; i--)
        {
                ACC = ACC >>1;
                T_IO=1;
                ACC7 = T_IO;
                T_CLK = 1;
                T_CLK = 0;
        }
        return(ACC);
}





//      **************************************************************************************************************
//      *   名称:v_W1302(unsigned char ucAddr, unsigned char ucDa)                                                *
//      *   功能:往DS1302写入数据                                                                                 *
//      *   输入:ucAddr: DS1302地址, ucDa: 要写的数据                                                             *
//      *   返回值:无                                                                                             *
//      **************************************************************************************************************
void v_W1302(unsigned char ucAddr, unsigned char ucDa)
{
        T_RST = 0;
        T_CLK = 0;
        T_RST = 1;
        v_RTInputByte(ucAddr);   // 写地址
        _nop_();
        _nop_();
        v_RTInputByte(ucDa);   // 写1Byte数据
        T_CLK = 1;
        T_RST = 0;
}





//      **************************************************************************************************************
//      *   名称:uc_R1302(unsigned char ucAddr)                                                                                             *
//      *   功能:读取DS1302某地址的数据                                                                                                     *
//      *   输入:ucAddr: DS1302地址                                                                                                             *
//      *   返回值:ucDa :读取的数据                                                                                                             *
//      **************************************************************************************************************
unsigned char uc_R1302(unsigned char ucAddr)
{
        unsigned char ucDa;
        T_RST = 0;
        T_CLK = 0;
        T_RST = 1;
        v_RTInputByte(ucAddr);    //写地址,命令
        _nop_();
        _nop_();
        ucDa = uc_RTOutputByte(); //读1Byte数据
        T_CLK = 1;
        T_RST = 0;
        return(ucDa);
}






//      **************************************************************************************************************
//      *   名称 : bcdtodec(unsigned char bcd)                                                                     *
//      *   功能 : BCD码转换为DEC码                                                                                  *
//      *   输入 : bcd码                                                                                             *
//      *   输出 : dec码                                                                                             *
//      **************************************************************************************************************
unsigned char bcdtodec(unsigned char bcd)
{
        unsigned char data1;
        data1 = bcd & 0x0f;   //取BCD低4位
        bcd = bcd & 0x70;       //剔除BCD的最高位和低4位。
        data1 += bcd >> 1;
        data1 += bcd >> 3;      //用位移代替乘法运算
        return data1;
}


void lc()
{
        unsigned long x,y;

        x = sg + ss*10 + sb*100 + sq*1000 + sw*10000 + ssw*100000;
        x = x*41/200;
        if(x == 487805)
        {
                x=0;
                xhcs++;
        }

        x = x % 100000;
        w = x / 10000;
        if (x < 10000)w=10;
        y = x % 10000;
        q = y / 1000; //求四位数的千位
        if (x < 1000)q=10;
        y = y % 1000; //求四位数去除千位的值
        b = y / 100; //求四位数的百位
        y = y % 100; //求四位数去除千位后再去除百位的值
        s = y / 10; //求四位数的十位
        g = y % 10; //求四位数的个位
}







void dlc()
{
        unsigned long x,y;

        x = dc*41/200;

        x = x % 100000;
        w = x / 10000;
        if (x < 10000)w=10;
        y = x % 10000;
        q = y / 1000; //求四位数的千位
        if (x < 1000)q=10;
        y = y % 1000; //求四位数去除千位的值
        b = y / 100; //求四位数的百位
        y = y % 100; //求四位数去除千位后再去除百位的值
        s = y / 10; //求四位数的十位
        g = y % 10; //求四位数的个位
}



void ljlc(void)
{
        if(sg > 9)
        {
                sg = 0;
                ss++;
        }

        if(ss == 10)
        {
                ss = 0;
                sb++;
        }

        if(sb == 10)
        {
                sb = 0;
                sq++;
        }

        if(sq == 10)
        {
                sq = 0;
                sw++;
        }

        if(sw == 10)
        {
                sw = 0;
                ssw++;
        }

        if(ssw == 10)
        {
                ssw = 0;
        }
}




void readdata()
{
//*******************************************************************
//最高速

        v_W1302(0x8f,0);
        maxg = bcdtodec(uc_R1302(0xc1));           //读出DS1302中的maxg

        v_W1302(0x8f,0);
        maxs = bcdtodec(uc_R1302(0xc3));           //读出DS1302中的maxs

        v_W1302(0x8f,0);
        maxb = bcdtodec(uc_R1302(0xc5));           //读出DS1302中的maxb

        v_W1302(0x8f,0);
        maxq = bcdtodec(uc_R1302(0xc7));           //读出DS1302中的maxq

        v_W1302(0x8f,0);
        maxw = bcdtodec(uc_R1302(0xc9));           //读出DS1302中的maxw

//*******************************************************************
//总里程

        v_W1302(0x8f,0);
        sg = bcdtodec(uc_R1302(0xcb));           //读出DS1302中的sg

        v_W1302(0x8f,0);
        ss = bcdtodec(uc_R1302(0xcd));           //读出DS1302中的ss

        v_W1302(0x8f,0);
        sb = bcdtodec(uc_R1302(0xcf));           //读出DS1302中的sb

        v_W1302(0x8f,0);
        sq = bcdtodec(uc_R1302(0xd1));           //读出DS1302中的sq

        v_W1302(0x8f,0);
        sw = bcdtodec(uc_R1302(0xd3));           //读出DS1302中的sw

        v_W1302(0x8f,0);
        ssw = bcdtodec(uc_R1302(0xd5));           //读出DS1302中的ssw

//*******************************************************************
//循环次数
        v_W1302(0x8f,0);
        xhcs = bcdtodec(uc_R1302(0xd7));           //读出DS1302中的xhcs
}

void savedata(void)
{
//*****************************************************************************
//最高车速
        v_W1302(0x8e,0);
        v_W1302(0xc0,maxg);

        v_W1302(0x8e,0);
        v_W1302(0xc2,maxs);

        v_W1302(0x8e,0);
        v_W1302(0xc4,maxb);

        v_W1302(0x8e,0);
        v_W1302(0xc6,maxq);

        v_W1302(0x8e,0);
        v_W1302(0xc8,maxw);


//*****************************************************************************
//总里程
        v_W1302(0x8e,0);
        v_W1302(0xca,sg);

        v_W1302(0x8e,0);
        v_W1302(0xcc,ss);

        v_W1302(0x8e,0);
        v_W1302(0xce,sb);

        v_W1302(0x8e,0);
        v_W1302(0xd0,sq);

        v_W1302(0x8e,0);
        v_W1302(0xd2,sw);

        v_W1302(0x8e,0);
        v_W1302(0xd4,ssw);


//*****************************************************************************
//循环次数
        v_W1302(0x8e,0);
        v_W1302(0xd6,xhcs);
}


void ql()
{
//*****************************************************************************
//最高车速
        v_W1302(0x8e,0);
        v_W1302(0xc0,0);

        v_W1302(0x8e,0);
        v_W1302(0xc2,0);

        v_W1302(0x8e,0);
        v_W1302(0xc4,0);

        v_W1302(0x8e,0);
        v_W1302(0xc6,0);

        v_W1302(0x8e,0);
        v_W1302(0xc8,0);


//*****************************************************************************
//总里程
        v_W1302(0x8e,0);
        v_W1302(0xca,0);

        v_W1302(0x8e,0);
        v_W1302(0xcc,0);

        v_W1302(0x8e,0);
        v_W1302(0xce,0);

        v_W1302(0x8e,0);
        v_W1302(0xd0,0);

        v_W1302(0x8e,0);
        v_W1302(0xd2,0);

        v_W1302(0x8e,0);
        v_W1302(0xd4,0);


//*****************************************************************************
//循环次数
        v_W1302(0x8e,0);
        v_W1302(0xd6,0);
}








void clock()
{
        unsigned char min, hour;

        v_W1302(0x8f, 0);
        min = bcdtodec(uc_R1302(0x83));           //读出DS1302中的分

        v_W1302(0x8f, 0);
        hour = bcdtodec(uc_R1302(0x85));   //读出DS1302中的小时

        w = hour/10;
        q = hour%10;
        b = 14;
        s = min/10;
        g = min%10;
}



void xh(void)
{
        g = xhcs%100;
        if(g<10)s = 10;else s = g / 10;
        g = g % 10;
        b = 10;
        q = 10;
        w = 10;
}





void display(void)
{
        P2=0x01;
        P0=table;
        delay();
        P0=0x00;

        P2=0x02;
        P0=table;
        delay();
        P0=0x00;

        P2=0x04;
        P0=table_D;
        delay();
        P0=0x00;

        P2=0x08;
        P0=table;
        delay();
        P0=0x00;

        P2=0x10;
        P0=table;
        delay();
        P0=0x00;
}


void tim(void) interrupt 1 using 1
{
        TH0=0xf0;//重新赋值,定时2毫秒
        TL0=0x5f;
        time++;//计时,数2毫秒的个数zs();
}


void ISR_INT0(void) interrupt 0 using 1
{
        sg++;
        dc++;
        z=time;//车轮转动1圈所用的时间--------多少个2毫秒
        time=0;//计时复零
}

void adjust(void)
{
        unsigned char min,sec;
        v_W1302(0x8f, 0);
        sec = bcdtodec(uc_R1302(0x81));           //读出DS1302中的秒

        v_W1302(0x8f, 0);
        min = bcdtodec(uc_R1302(0x83));           //读出DS1302中的分

        w = min/10;
        q = min%10;
        b = 10;
        s = sec/10;
        g = sec%10;

           if(p10 == 0)
           {
                if(sec > 29)
                {
                        v_W1302(0x8e,0);
                        v_W1302(0x80,0x59);        //写入秒sec = 59;
                }
      else
                {
                        v_W1302(0x8e,0);
                        v_W1302(0x80,0x00);        //写入秒sec = 00;
                }
        }
}


void jscs(void)
{
        unsigned long ls;
        v = 369000/z;
        if(v > max)max = v;
        if(v < 6)v = 0;
        maxw = max/10000;
        ls = max%10000;
        maxq = ls/1000;
        ls = ls%1000;
        maxb = ls/100;
        ls = ls%100;
        maxs = ls/10;
        maxg =ls%10;
}




void cs(void)
{
        unsigned long ls;
        if(v > 9999)w = v/10000;else w=10;
        ls = v%10000;
        if(ls > 999)q = ls/1000;else q=10;
        ls = ls%1000;
        b = ls/100;
        ls = ls%100;
        s= ls/10;
        g= ls%10;
}


void maxcs(void)
{
        unsigned long ls;
        if(max > 9999)w = max/10000;else w=10;
        ls = max%10000;
        if(ls > 999)q = ls/1000;else q=10;
        ls = ls%1000;
        b= ls/100;
        ls = ls%100;
        s= ls/10;
        g= ls%10;
}


/********************************************************************
* 名称 : Write_DS1302Init()
* 功能 : 往DS1302中写入数据。最开始显示的数据就是在这里设置的。
* 输入 : 无
* 输出 : 无
***********************************************************************/
void Write_DS1302Init(void)
{
        v_W1302(0x8e,0);
        v_W1302(0x80,0x00);        //写入秒
        v_W1302(0x8e,0);
        v_W1302(0x82,0x09);        //写入分
        v_W1302(0x8e,0);
        v_W1302(0x84,0x18);        //写入小时
        v_W1302(0x8e,0);
        v_W1302(0x86,0x18);        //写入日
        v_W1302(0x8e,0);
        v_W1302(0x88,0x06);        //写入月
        v_W1302(0x8e,0);
        v_W1302(0x8a,0x01);        //写入星期
        v_W1302(0x8e,0);
        v_W1302(0x8c,0x18);        //写入年       
}









void ljsj(void)
{}












void main(void)
{
        unsigned char xd=0,q;

        EX0 = 1;//外部中断0设置
        IT0 = 1;

        EX1 = 1;//外部中断1设置
        IT1 = 1;

//定时器设置 2ms in 24M crystal,工作方式1,16位计数器,2毫秒4000个脉冲故(65536-4000)的16进制为f05f。
        TMOD |= 0x01;
        TH0 = 0xf0;
        TL0 = 0x5f;
        ET0 = 1;//打开中断
        TR0 = 1;
        EA = 1;

        v_W1302(0x8e,0);//打开写保护
//        v_W1302(0x90,0x00);        //   TCS 4位                  DS 2位            TS 2位
                                                //   xxxx                     xx                  xx
                        //   1010可以充电             01一个二极管      00无电阻
                                                //   其他禁止充电             10两个二极管      01    2K电阻
                                                //                              其他禁止充电      10    4K电阻
                                                //                                                11    8K电阻
                                                //如果以1个二极管串联4K电阻充电,则为:10100110    十六进制为:0xa6

//        Write_DS1302Init();


        if (p11 == 0)                                                    //检测是否按下按钮,在系统加电时按下按钮,则执行清零程序
        {
                ql();
                for(q=0;q<255;q++) delay();
                for(q=0;q<255;q++) delay();
        }




        readdata();                                                      //读出DS1302内的数据
        max = maxg + maxs*10 + maxb*100 + maxq*1000 + maxw*10000;          //计算以前的最高车速

        while(1)
        {
                if (p11 == 0&xd == 0)                                                    //检测是否按下按钮
                {
                        gn++;                                                                  //如果按下按键则转换功能

                        if(gn > 7)gn = 1;
                        xd = 1;                                                                  //如果没有松开按键不允许继续转换
                        for(q=0;q<255;q++) delay();
                        for(q=0;q<255;q++) delay();
                        if(p11 == 1)xd = 0;
                }

                jscs();                                                                      //计算车速
                ljlc();                                                                      //累计里程

                if(time < 2500)ljsj();                                                       //如果时间小于5秒(行车中)则执行累积时间
                else if(time <3000)
                {
                        time = 65530;
                        savedata();                                                            //否则认为已停车,保存数据
                        z = time;
                }
                else time = 65530;                                                               //保持time=3500,不至于育溢出

                switch(gn)
                {
                        case 1:clock();break;      //时钟
                        case 2:cs();break;         //车速
                        case 3:dlc();break;          //当前里程
                        case 4:lc();break;         //总里程
                        case 5:xh();break;         //总里程数
                        case 6:maxcs();break;      //最高车速
                        case 7:adjust();break;       //对表
                }
                display();
        }
}

DianGongN 发表于 2023-9-4 08:10:55

大侠水平高啊,机电通吃妥妥的。

江东老歌 发表于 2023-9-4 08:25:38

         专业技术贴,比我们以前用汇编语言方便多了!

wryp 发表于 2023-9-4 08:26:18

DianGongN 发表于 2023-9-4 08:10
大侠水平高啊,机电通吃妥妥的。

谈不上啊,特备是电,真的业余水平,玩玩就好。

wryp 发表于 2023-9-4 08:29:12

江东老歌 发表于 2023-9-4 08:25
专业技术贴,比我们以前用汇编语言方便多了!

我朋友仍然用汇编。汇编编译出来的,文件个头都比C小很多,运行效率也高。你们才是高手。
我问我那朋友,汇编可读性差,你编着不费劲?人家说习惯就好,就像平时说话一样了。

wryp 发表于 2023-9-4 08:55:46

白无无 发表于 2023-9-4 07:46
你这,能搭话的就少了啊我反正是看不明白

咱们不是在讨论低矮歪吗?只要愿意去动手做的,肯迈出实践的第一步,就成功了一半。

fanxx2000 发表于 2023-9-4 13:04:53

不明觉历!
页: [1]
查看完整版本: 单片机学习之三:做一个自行车车速表