標題: 51單片機自行車里程表設計C程序看不懂,求指教 [打印本頁]
作者: 劉珍 時間: 2021-5-9 23:41
標題: 51單片機自行車里程表設計C程序看不懂,求指教
基于單片機的自行車里程表設計(有原理圖 仿真電路 源程序 pcb) - 單片機DIY制作 (51hei.com)
上面帖子上的這段程序沒看懂,有人可以幫忙講解下嗎,尤其是下面兩句,速度和里程是怎么計算的呢,速度除以40 的意思是?
count參數是500ms產生的脈沖數,是這個意思嗎,希望幫忙解釋下,謝謝或者有別的里程速度計算公式可以用在這個程序中實現功能的嗎?
Mileage=Mileage+10*(Velocity/3.6)/2; //里程m=里程+速度km/h/3.6/2
Velocity=count *2*3.14*RADIUS /100000*2*3600 /40;//將500ms的距離經過運算得到km/h,將速度/100,方便顯示
完整程序如下:
#include<reg52.h>
#define uchar unsigned char
#define uint unsigned int
#include "Data.h"
#include "DS1302.h"
#include "AT24C02.h"
sbit COUNT_IN=P3^2;
//定義1602相關管腳
sbit rs=P1^4; //寄存器選擇位
sbit en=P1^0; //使能信號位
//鍵盤定義
sbit K1=P3^4; //設置時間
sbit K3=P3^6; //減按鍵
sbit K2=P3^5; //加按鍵
sbit K4=P3^7; //設置半徑安全距離
sbit BEEP=P3^0;
uint count;
unsigned long Velocity,Mileage;
uchar code tab1[]={" / / : "};
uchar code tab2[]={" 0.000km 00km/h"};
uchar code tab3[]={"Wheel Radius cm"};
uchar code tab4[]={"Safe Speed km/h"};
uchar code tab5[]={"Sec : "};
uchar Mode=0;
uchar bike_set=0;
uchar a;
char RADIUS,SAFE_SPEED;
bit LED_SEC;
uchar before_sec;
uchar code num[]={
0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x00,//1
0x1f,0x01,0x01,0x1f,0x10,0x10,0x1f,0x00,//2
0x1f,0x01,0x01,0x1f,0x01,0x01,0x1f,0x00,//3
0x11,0x11,0x11,0x1f,0x01,0x01,0x01,0x00,//4
0x1f,0x10,0x10,0x1f,0x01,0x01,0x1f,0x00,//5
0x1f,0x10,0x10,0x1f,0x11,0x11,0x1f,0x00,//6
0x1f,0x01,0x01,0x01,0x01,0x01,0x01,0x00,//7 //自定義字符
};
void READS();
void SETS();
void delay(uint x)
{
uint i,j;
for(i=0;i<x;i++)
for(j=0;j<110;j++);//延時
}
void init()
{
IT0=1; //INT0負跳變觸發
TMOD=0x01;//定時器工作于方式1
TH0=0x3c; //50ms
TL0=0xb0;
EA=1; //CPU開中斷總允許
ET0=1;//開定時中斷
EX0=1;//開外部INTO中斷
TR0=1;//啟動定時
}
/********液晶寫入指令函數與寫入數據函數,以后可調用**************/
void write_1602com(uchar com)//****液晶寫入指令函數****
{
rs=0;//數據/指令置為指令
P0=com;//送入數據
delay(1);
en=1;//拉高使能端,為制造有效的下降沿做準備
delay(1);
en=0;//en由高變低,產生下降沿,液晶執行命令
}
void write_1602dat(uchar dat)//***液晶寫入數據函數****
{
rs=1;//數據/指令置為數據
P0=dat;//送入數據
delay(1);
en=1; //en置高電平,為制造下降沿做準備
delay(1);
en=0; //en由高變低,產生下降沿,液晶執行命令
}
void Lcd_ram() //自定義字符集
{
uint i,j,k=0,temp=0x40;
for(i=0;i<7;i++)
{
for(j=0;j<8;j++)
{
write_1602com(temp+j); //寫地址
write_1602dat(num[k]); //寫數據
k++;
}
temp=temp+8; } }
void lcd_init()//***液晶初始化函數****
{
Lcd_ram();
write_1602com(0x38);//設置液晶工作模式,意思:16*2行顯示,5*7點陣,8位數據
write_1602com(0x0c);//開顯示不顯示光標
write_1602com(0x06);//整屏不移動,光標自動右移
write_1602com(0x01);//清顯示
write_1602com(0x80);//顯示固定符號從第一行第1個位置之后開始顯示
for(a=0;a<16;a++)
{
write_1602dat(tab1[a]);//向液晶屏寫固定符號部分
}
write_1602com(0x80+0x40);//顯示固定符號寫入位置,從第2個位置后開始顯示
for(a=0;a<16;a++)
{
write_1602dat(tab2[a]);//寫顯示固定符號
}
}
void display()
{
// 1km/h=100m/0.1h 360s
// 10km/h=100m/0.01h 36s
// 100km/h=100m/0.001h 3.6s
if(Mode==0&&bike_set==0)
{
//讀時間
Ds1302_Read_Time();
//顯示時間
write_1602com(0x80);
write_1602dat(0x30+time_buf1[1]/10);
write_1602dat(0x30+time_buf1[1]%10);
write_1602com(0x80+3);
write_1602dat(0x30+time_buf1[2]/10);
write_1602dat(0x30+time_buf1[2]%10);
write_1602com(0x80+6);
write_1602dat(0x30+time_buf1[3]/10);
write_1602dat(0x30+time_buf1[3]%10);
write_1602com(0x80+9);
write_1602dat(0x30+time_buf1[4]/10);
write_1602dat(0x30+time_buf1[4]%10);
write_1602com(0x80+12);
write_1602dat(0x30+time_buf1[5]/10);
write_1602dat(0x30+time_buf1[5]%10);
write_1602com(0x80+15);
write_1602dat(time_buf1[7]-1);
if(before_sec!=time_buf1[6])
{
before_sec=time_buf1[6];
write_1602com(0x80+11);
write_1602dat(':');
LED_SEC=1;
}
if(LED_SEC==0)
{
write_1602com(0x80+11);
write_1602dat(' ');
}
write_1602com(0x80+0x40);
if(Mileage/1000000==0)
write_1602dat(' ');
else
write_1602dat(0x30+Mileage/1000000);//數字+0x30得到該數字LCD顯示碼
if(Mileage%1000000/100000==0)
write_1602dat(' ');
else
write_1602dat(0x30+Mileage%1000000/100000);//數字+0x30得到該數字LCD顯示碼
write_1602dat(0x30+Mileage%1000000%100000/10000);
write_1602com(0x80+0x40+4);
write_1602dat(0x30+Mileage%1000000%100000%10000/1000);
write_1602dat(0x30+Mileage%1000000%100000%10000%1000/100);
write_1602dat(0x30+Mileage%1000000%100000%10000%1000%100/10); SETS();
write_1602com(0x80+0x40+10);
write_1602dat(0x30+Velocity/10);
write_1602dat(0x30+Velocity%10);//數字+30得到該數字的LCD1602顯示碼
}
else if(Mode!=0)
{
switch(Mode)
{
case 1:
write_1602com(0x80+0x40);//顯示固定符號寫入位置
for(a=0;a<16;a++)
{
write_1602dat(tab5[a]);//寫顯示固定符號
}
write_1602com(0x80+0x40+14);
write_1602dat(0x30+time_buf1[6]/10);
write_1602dat(0x30+time_buf1[6]%10);
write_1602com(0x0F); //打開閃爍
write_1602com(0x80+1);
break;
case 2:
write_1602com(0x80+4);
break;
case 3:
write_1602com(0x80+7);
break;
case 4:
write_1602com(0x80+10);
break;
case 5:
write_1602com(0x80+13);
break;
case 6:
write_1602com(0x80+0x40+15);
break;
case 7:
write_1602com(0x80+15);
break;
case 8:
write_1602com(0x0c);
write_1602com(0x80);//顯示固定符號第1行第1個位置后顯示
for(a=0;a<16;a++)
{
write_1602dat(tab1[a]);//向液晶屏寫固定符號部分
}
write_1602com(0x80+0x40);//顯示固定符號寫入位置,從第2個位置后開始顯示
for(a=0;a<16;a++)
{
write_1602dat(tab2[a]);//寫顯示固定符號
}
break;
}
}
else if(bike_set!=0)
{
switch(bike_set)
{
case 1:
write_1602com(0x80);//顯示固定符號寫入位置
for(a=0;a<16;a++)
{
write_1602dat(tab3[a]);//寫顯示固定符號
}
write_1602com(0x80+0x40);//顯示固定符號寫入位置
for(a=0;a<16;a++)
{
write_1602dat(tab4[a]);//寫顯示固定符號
}
write_1602com(0x80+12);
write_1602dat(0x30+RADIUS/10); //車輪半徑
write_1602dat(0x30+RADIUS%10);
write_1602com(0x80+0x40+10);
write_1602dat(0x30+SAFE_SPEED/10); //安全速度
write_1602dat(0x30+SAFE_SPEED%10);
write_1602com(0x0F); //打開閃爍
write_1602com(0x80+13);
break;
case 2:
write_1602com(0x80+0x40+11);
break;
case 3:
write_1602com(0x0c);
write_1602com(0x80);/
for(a=0;a<16;a++)
{
write_1602dat(tab1[a]);//向液晶屏寫固定符號部分
}
write_1602com(0x80+0x40);//從第2個位置后顯示
for(a=0;a<16;a++)
{
write_1602dat(tab2[a]);//寫顯示固定符號
}
break;
}
}
}
void KEY()
{
if(bike_set==0&&K1==0)
{
delay(20);
if(bike_set==0&&K1==0)
{
BEEP=0;
delay(50);
BEEP=1;
Mode++;
display();
if(Mode>=8)
{
Mode=0;
Ds1302_Write_Time();
}
}
while(bike_set==0&&K1==0);
}
if(K4==0&&Mode==0)
{
delay(20);
if(K4==0&&Mode==0)
{
BEEP=0;
delay(50);
BEEP=1;
bike_set++;
display();
if(bike_set>=3)
{
bike_set=0;
SETS();
}
}
while(Mode==0&&K4==0);
}
//+
if(K2==0&&(Mode!=0||bike_set!=0))
{
delay(20);
//調時
if(K2==0&&(Mode!=0||bike_set!=0))
{
BEEP=0;
delay(50);
BEEP=1;
switch(Mode)
{
case 1:
time_buf1[1]++;
if(time_buf1[1]>=100)
time_buf1[1]=0;
write_1602com(0x80);
write_1602dat(0x30+time_buf1[1]/10);
write_1602dat(0x30+time_buf1[1]%10);
write_1602com(0x80+1);
break;
case 2:
time_buf1[2]++;
if(time_buf1[2]>=13)
time_buf1[2]=1;
write_1602com(0x80+3);
write_1602dat(0x30+time_buf1[2]/10);
write_1602dat(0x30+time_buf1[2]%10);
write_1602com(0x80+4);
break;
case 3:
time_buf1[3]++;
if(time_buf1[3]>=YDay(time_buf1[1],time_buf1[2])+1)
time_buf1[3]=1;
write_1602com(0x80+6);
write_1602dat(0x30+time_buf1[3]/10);
write_1602dat(0x30+time_buf1[3]%10);
write_1602com(0x80+7);
break;
case 4:
time_buf1[4]++;
if(time_buf1[4]>=24)
time_buf1[4]=0;
write_1602com(0x80+9);
write_1602dat(0x30+time_buf1[4]/10);
write_1602dat(0x30+time_buf1[4]%10);
write_1602com(0x80+10);
break;
case 5:
time_buf1[5]++;
if(time_buf1[5]>=60)
time_buf1[5]=0;
write_1602com(0x80+12);
write_1602dat(0x30+time_buf1[5]/10);
write_1602dat(0x30+time_buf1[5]%10);
write_1602com(0x80+13);
break;
case 6:
time_buf1[6]++;
if(time_buf1[6]>=60)
time_buf1[6]=0;
write_1602com(0x80+0x40+14);
write_1602dat(0x30+time_buf1[6]/10);
write_1602dat(0x30+time_buf1[6]%10);
write_1602com(0x80+0x40+15);
break;
case 7:
time_buf1[7]++;
if(time_buf1[7]>=8)
time_buf1[7]=1;
write_1602com(0x80+15);
write_1602dat(time_buf1[7]-1);
write_1602com(0x80+15);
break;
}
switch(bike_set)
{
case 1:
RADIUS++;
if(RADIUS>=71)
RADIUS=0;
write_1602com(0x80+12);
write_1602dat(0x30+RADIUS/10);
write_1602dat(0x30+RADIUS%10);
write_1602com(0x80+13);
break;
case 2:
SAFE_SPEED++;
if(SAFE_SPEED>=100)
SAFE_SPEED=0;
write_1602com(0x80+0x40+10);
write_1602dat(0x30+SAFE_SPEED/10);
write_1602dat(0x30+SAFE_SPEED%10);
write_1602com(0x80+0x40+11);
break;
}
}
while(K2==0);
}
if(K3==0&&(Mode!=0||bike_set!=0))
{
delay(20);
//調時
if(K3==0&&(Mode!=0||bike_set!=0))
{
BEEP=0;
delay(50);
BEEP=1;
switch(Mode)
{
case 1:
time_buf1[1]--;
if(time_buf1[1]<0)
time_buf1[1]=99;
write_1602com(0x80);
write_1602dat(0x30+time_buf1[1]/10);
write_1602dat(0x30+time_buf1[1]%10);
write_1602com(0x80+1);
break;
case 2:
time_buf1[2]--;
if(time_buf1[2]<=0)
time_buf1[2]=12;
write_1602com(0x80+3);
write_1602dat(0x30+time_buf1[2]/10);
write_1602dat(0x30+time_buf1[2]%10);
write_1602com(0x80+4);
break;
case 3:
time_buf1[3]--;
if(time_buf1[3]<=0)
time_buf1[3]=YDay(time_buf1[1],time_buf1[2]);
write_1602com(0x80+6);
write_1602dat(0x30+time_buf1[3]/10);
write_1602dat(0x30+time_buf1[3]%10);
write_1602com(0x80+7);
break;
case 4:
time_buf1[4]--;
if(time_buf1[4]<0)
time_buf1[4]=23;
write_1602com(0x80+9);
write_1602dat(0x30+time_buf1[4]/10);
write_1602dat(0x30+time_buf1[4]%10);
write_1602com(0x80+10);
break;
case 5:
time_buf1[5]--;
if(time_buf1[5]<0)
time_buf1[5]=59;
write_1602com(0x80+12);
write_1602dat(0x30+time_buf1[5]/10);
write_1602dat(0x30+time_buf1[5]%10);
write_1602com(0x80+13);
break;
case 6:
time_buf1[6]--;
if(time_buf1[6]<0)
time_buf1[6]=59;
write_1602com(0x80+0x40+14);
write_1602dat(0x30+time_buf1[6]/10);
write_1602dat(0x30+time_buf1[6]%10);
write_1602com(0x80+0x40+15);
break;
case 7:
time_buf1[7]--;
if(time_buf1[7]<1)
time_buf1[7]=7;
write_1602com(0x80+15);
write_1602dat(time_buf1[7]-1);
write_1602com(0x80+15);
break;
}
switch(bike_set)
{
case 1:
RADIUS--;
if(RADIUS<0)
RADIUS=70;
write_1602com(0x80+12);
write_1602dat(0x30+RADIUS/10);
write_1602dat(0x30+RADIUS%10);
write_1602com(0x80+13);
break;
case 2:
SAFE_SPEED--;
if(SAFE_SPEED<0)
SAFE_SPEED=99;
write_1602com(0x80+0x40+10);
write_1602dat(0x30+SAFE_SPEED/10);
write_1602dat(0x30+SAFE_SPEED%10);
write_1602com(0x80+0x40+11);
break;
}
}
while(K3==0);
}
if(K2==0&&K3==0&&Mode==0&bike_set==0)
{
BEEP=0;
delay(100);
BEEP=1;
delay(100);
BEEP=0;
delay(100);
BEEP=1;
delay(100);
Mileage=0;
SETS();
while(K2==0&&K3==0);
}
}
void BJ_SAFE()
{
if(Velocity>SAFE_SPEED)
{
BEEP=0;
}
else
{
BEEP=1;
}
}
void main()
{
//初始化
Ds1302_Init();
lcd_init();
initeeprom();
//讀取初始參數
READS();
//定時器初始化
// InitTimer0();
init();
lcd_init();
before_sec=time_buf1[6];
while(1)
{
if(Mode==0&&bike_set==0)
{
display();
BJ_SAFE();
}
KEY();
}
void EXINT0() interrupt 0
{
count++;
}
void time0() interrupt 1
{
uchar m,n;
TH0=0x3c;
TL0=0xb0; //50ms
m++;
if(LED_SEC==1)
{
n++;
if(n>=10)
{
n=0;
LED_SEC=0;
}
}
if(m>=10)
{
m=0;
Mileage=Mileage+10*(Velocity/3.6)/2; //里程m=里程+速度km/h/3.6/2
Velocity=count *2*3.14*RADIUS /100000*2*3600 /40;//將500ms的距離經過運算得到km/h,將速度/100,方便顯示
count=0;
}
}
//讀初值
void READS()
{
uchar Mileage_H,Mileage_M,Mileage_L;
delay(10);
RADIUS=read_add(0x01);
delay(10);
SAFE_SPEED=read_add(0x02);
delay(10);
Mileage_H=read_add(0x03);
delay(10);
Mileage_M=read_add(0x04);
delay(10);
Mileage_L=read_add(0x05);
Mileage=Mileage_H*100000+Mileage_M*1000+Mileage_L*10;
}
//寫初值
void SETS()
{
delay(10);
write_add(0x01,RADIUS);
delay(10);
write_add(0x02,SAFE_SPEED);
/* Mileage_H=Mileage/10000; //123.4560
Mileage_M=Mileage%10000/100;
Mileage_L=Mileage%10000%100; */
delay(10);
write_add(0x03,Mileage/100000);
delay(10);
write_add(0x04,Mileage%100000/1000);
delay(10);
write_add(0x05,Mileage%100000%1000/10);
作者: xll_9527 時間: 2021-5-10 10:59
單獨對下面的這兩行代碼進行解釋:
Mileage=Mileage+10*(Velocity/3.6)/2; //里程m=里程+速度km/h/3.6/2
Velocity=count *2*3.14*RADIUS /100000*2*3600 /40;//將500ms的距離經過運算得到km/h,將速度/100,方便顯示
1、首先是500ms里程數和速度刷新一次;
2、里程數計算:之前的里程數+根據500ms前的速度與500ms的乘積計算得來。
Mileage(當前總里程數)=Mileage(500ms前的里程數)+10*(Velocity/3.6)/2; 這里除以2可以理解為乘以0.5秒(500ms),乘以10是為了方便顯示;
3、速度計算:
Velocity=count *2*3.14*RADIUS /100000*2*3600 /40
(1)count/40是自行車轉動的圈數(可能大于1,也可能小于1,速度快大于1,速度慢可能小于1),也就是在500ms內,自行車輪胎滾了幾圈,乘以輪胎的周長(2*3.14*RADIUS),也就是自行車前進的距離。
(2)為啥count要除以40,count是500ms內總的接收到信號的次數,車輪一周應該有40個傳感器或者車輪轉動一周會產生40個脈沖信號,所以要除以40,才是自行車真正的轉動圈數;
(3)100000=100*1000,除以100是為了方便顯示,除以1000是將M轉化成KM;
(4)后面那個乘以2,實際是除以0.5s(500ms),乘以3600是將秒轉成小時,以便得到速度是KM/H
作者: 劉珍 時間: 2021-5-10 17:47
你好,請問車輪轉一圈產生40個脈沖這個是固定的嗎
這個設計的測試方法可以用在實際自行車上使用嗎?我師傅問此設計實際意義有嗎?麻煩解答下,謝謝。測量的精度能滿足要求嗎?
作者: w1179benp 時間: 2022-3-14 10:54
我理解這個“40”取決于輪子轉一周遮光(采集信號)的次數
作者: man1234567 時間: 2022-3-14 11:37
先從原理上搞,然后就清楚了:
在車架上安裝一個觸發裝置,車輪轉動一周計一次數,累加;
單片機開個定時器,累加到一定時間時,與車輪上的計數器通過以下公式:
里程=計數×車輪周長;速度=計數×車輪周長÷一定時間
所以在程序中找相關的項目就可以,自己寫比讀可能更方便。計數器常用霍爾之類的 
作者: youlinys 時間: 2022-3-15 11:55
輪子是多大的?
歡迎光臨 (http://www.raoushi.com/bbs/) |
Powered by Discuz! X3.1 |