一个单片机C 程序 出租车计价器实现

最近面临找工作,经常会被问道曾经做过的项目,整理以前的资料,将自己曾经做过的一个单片机课设出租车计价器,整理如下:

  1. 硬件电路分为五个单元:单片机最小系统单元,指示灯电路单元,按键电路单元,路程时间与金额显示单元,转速信号接收单元。
  2. 软件系统分为五个模块:总初始化模块,按键扫描模块,中断与定时模块,数据计算模块,数码管显示模块。其中,键盘扫描和数码管显示采用查询方式,转速信号接收与等待记时采用中断方式。

系统采用了Atmel 公司生产的 AT89S52单片机,它含有256 字节数据存储器,内置8 KB 的电可擦除FLASH ROM,可重复编程。电路原理图实用Altium Designer设计,编程使用Keil C51开发环境,系统可以先用Proteus调试,然后烧入单片机调试即可。

功能:

  • 能显示里程,单位为公里,最后一位为小数位; 
  • 能显示金额数,单位为元,最后一位为小数位;
  • 可设定单程价格和往返价格,单程价格为2元/公里,往返价格为1.5元/公里;
  • 车速<5公里/小时的时间累积为总等待时间,每5分钟等待时间相当于里程数增加1公里;
  • 起步公里数为3公里,价格为5元,若实际距离大于3公里,按规则3计算价格;
  • 按暂停键,计价器可暂停计价,按查询键,可显示总等待时间;

电路:

一个单片机C 程序 出租车计价器实现_第1张图片

源代码:

#include<reg52.h>
#define uchar unsigned char
#define uint  unsigned int
uchar qianwei, baiwei, shiwei, gewei;	//显示数据各个位置数字的临时变量
char led_seg_code[10] = { 0x3f, 0x06, 0x05b, 0x04f, 0x66, 0x6d, 0x7d, 0x07,
		0x7f, 0x6f };	//段码表示0-9
uint tt, aa, round, distance, cost, price, wait;
uchar dengdai, second, minute;		//定义路程、价钱、等待时间等全局变量
unsigned long wait_ten_ms;	//记录等待多少个10ms
sbit key0 = P1 ^ 7;		//清零(按键的定义,所有键按下去为低电平)
sbit key1 = P1 ^ 4;		//切换路程与等待时间
sbit key2 = P1 ^ 5;		//单程还是往返设置
sbit key3 = P1 ^ 6;		//暂停按钮
sbit led1 = P1 ^ 2;		// 双程
sbit led2 = P1 ^ 1;		// 暂停
sbit led3 = P1 ^ 0;		// 堵车
sbit led4 = P1 ^ 3;		// 切换
bit key1_flag;			//由于按键会自动复位,这个为标志位
bit key2_flag;
bit key3_flag;
bit flag;

/** 初始化函数 */
void initial_data(void) {
	distance = 0;
	cost = 0;
	second = 0;
	minute = 0;
	wait_ten_ms = 0;
	key1_flag = 1;
	key2_flag = 0;   //单程or往返,接指示灯;
	key3_flag = 1;   //暂停,接指示灯;
	flag = 0;
	round = 0;
	dengdai = 0;
	led1 = 0;		 //双程指示
	led2 = 0;		 //暂停指示
	led3 = 0;		 //堵车指示
	led4 = 0;		 // 等待时间切换标志
}

/** 暂停 */
void zanting(void) {
	if (key3_flag) {
		EX0 = 0;	//关闭中断和定时器
		TR0 = 0;
	} else {
		EX0 = 1;
		TR0 = 1;
	}
	key3_flag = !key3_flag;
}

/** 计算数据处理 */
void jisuan() {
	distance = round / 57 + wait_ten_ms / 3000;		//车轮转57圈为100m,等待时间30s为100m
	if (distance <= 30)
		cost = 50;
	price = 20; 		//单程价格
	if (key2_flag)
		price = 15;		//往返价格
	if (distance > 30)
		cost = price * (distance - 30) / 10 + 50;
	wait = minute * 100 + second;
}

/** 分离一个数的各个数字 */
void fenli(uint temp) {
	if (temp > 9999)
		temp = 9999;
	qianwei = temp / 1000;
	baiwei = temp / 100 % 10;
	shiwei = temp % 100 / 10;
	gewei = temp % 10;
}

/** 延时约1ms */
void diplay_delay(void) {
	uint i;
	for (i = 0; i < 290; i++)
		;
}

/** 显示 */
void led_show() {
	if (key1_flag)
		fenli(distance);	//显示路程或者等待时间
	else
		fenli(wait);
	P2 = 0xfe;
	P0 = led_seg_code[gewei];
	diplay_delay();
	P2 = 0xfd;
	if (key1_flag)
		P0 = led_seg_code[shiwei] | 0x80;    //如果是路程,点亮小数点儿
	else
		P0 = led_seg_code[shiwei];   //如果是时间,不需要点亮小数点儿
	diplay_delay();
	P2 = 0xfb;
	if (key1_flag)
		P0 = led_seg_code[baiwei];
	else
		P0 = led_seg_code[baiwei] | 0x80;
	diplay_delay();
	P2 = 0xf7;
	P0 = led_seg_code[qianwei];
	diplay_delay();
	fenli(cost);	//价格
	P2 = 0xef;
	P0 = led_seg_code[gewei];
	diplay_delay();
	P2 = 0xdf;
	P0 = led_seg_code[shiwei] | 0x80;
	diplay_delay();
	P2 = 0xbf;
	P0 = led_seg_code[baiwei];
	diplay_delay();
	P2 = 0x7f;
	P0 = led_seg_code[qianwei];
	diplay_delay();
	P2 = 0xff;
}

/** 延时时基为1ms */
void delay(uint x) {
	int i, j;
	for (i = x; i > 0; i--)
		for (j = 340; j > 0; j--)
			;
}

/** 键盘的扫描 */
void keyscan() {
	if (key1 == 0) {
		delay(5);
		if (key1 == 0)
			key1_flag = !key1_flag;
		while (!key1)
			led_show();
		delay(5);
		while (!key1)
			led_show();
	} //按键消抖并判断按下去的次数为基数还是偶数

	if (key0 == 0) {
		delay(5);
		if (key0 == 0)
			initial_data();
	} //清零

	if (key3 == 0) {
		delay(5);
		if (key3 == 0)
			zanting();
		while (!key3)
			led_show();
		delay(5);
		while (!key3)
			led_show();
	} //暂停

	if (key2 == 0) {
		delay(5);
		if (key2 == 0)
			key2_flag = !key2_flag;
		while (!key2)
			led_show();
		delay(5);
		while (!key2)
			led_show();
	} //单程还是往返
	led1 = key2_flag;	//指示,单程还是往返,灯低电平点亮;往返亮;
	led2 = !key3_flag;	//指示,暂停时亮;
	led3 = !flag;		//指示是否等待;
	led4 = !key1_flag;	//切换指示,显示路程还是等待时间;
	diplay_delay();

}

/** 中断及定时器初始化 */
void initial_time() {
	TMOD = 0x01;	//工作在模式1
	TH0 = (65536 - 10000) / 256;
	TL0 = (65536 - 10000) % 256;
	IE = 0x83;
	IT0 = 1;	//外部边沿触发方式
	TR0 = 1;
}

/** 中断记录脉冲数 */
void zd() interrupt 0 {
	aa++;
	if(flag)
	round++;
}

/** 定时器 */
void time0() interrupt 1 {
	TH0=(65536-10000)/256;	//10ms
	TL0=(65536-10000)%256;
	tt++;
	if(tt>=100) {
		tt=0;
		aa=aa/5;	//速度(n*圈/s)
		if(aa<=5)
		flag=0;
		else
		flag=1;
		aa=0;
	} //1s采样

	if(!flag) {
		wait_ten_ms++;
		dengdai++;
		if(dengdai==100) {
			dengdai=0;
			second++;
			if(second==60) {
				minute++;
				second=0;
			}
		}
	} //1s采样
}

/** 主程序 */
void main(void) {
	initial_data();		//初始化数据
	initial_time();		//初始化定时器
	while (1) {
		keyscan();
		jisuan();
		led_show();
	}
}


你可能感兴趣的:(c,单片机)