单片机学习之三:做一个自行车车速表
看到论坛里已经有人做过。原理都一样,利用霍尔元件感受自行车前轮转的圈数。统计时间,计算车速,里程,保留最高速度至DS1302的RAM,计量骑行的总时间。
不多说,上图。因为实物被朋友拿走了,这里上PCB图,原理图,并贴出代码。
代码肯定不专业,各位轻喷。
你这,能搭话的就少了啊;P我反正是看不明白 //这是一个用于测量自行车车速、里程的程序,需要专门设计的硬件支持。
//电路包含几大部分:脉冲采样、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
大侠水平高啊,机电通吃妥妥的。
谈不上啊,特备是电,真的业余水平,玩玩就好。
江东老歌 发表于 2023-9-4 08:25
专业技术贴,比我们以前用汇编语言方便多了!
我朋友仍然用汇编。汇编编译出来的,文件个头都比C小很多,运行效率也高。你们才是高手。
我问我那朋友,汇编可读性差,你编着不费劲?人家说习惯就好,就像平时说话一样了。
白无无 发表于 2023-9-4 07:46
你这,能搭话的就少了啊我反正是看不明白
咱们不是在讨论低矮歪吗?只要愿意去动手做的,肯迈出实践的第一步,就成功了一半。
不明觉历!
页:
[1]