基于51单片机的PC机控制系统

整理电脑里面资料的时候,发现以前大二结束的时候写的一个小项目,贴出来吧,回味下曾经倒腾硬件方面的日子,那些年和几个小伙伴一起逛电子商城,边吐槽玩硬件就是烧钱,还时不时的往那跑,用Altium Designer 画电路图和PCB图,一起大热天的手持电烙铁焊板子,拿着万用表测电压,接着串口线板级调试程序。现在回想起来觉得也挺充实的,转眼间研究生三年又要过去了,以后工作了,回想起研究生的生活也应该是这样子吧。

这个小项目是基于51单片机的,电子类专业孩子的入门玩意。实现一个多任务的控制系统,采用模块化编程,通过键盘输入控制读取电压,环境温度值,时间等基本功能。开发环境 Keil 4。

        51单片机作为入门级,后面陆续接触了ARM和FPGA,主要是FPGA,当时用的开发软件是Altea 公司的 Quartus II,用 Verilog HDL 编写,用的芯片是 Altera 公司的 Cyclone II,后来由于实习和考研,就没倒腾FPGA了,中间由于某些原因,想走软件这条路,又重新拾起了C/C++,汇编语言,微机原理,数据结构和基本算法等,而后开始学习 Linux,回想起来,要是一开始是学ARM,不是FPGA,恐怕那时候早就接触Linux了,FPGA就当扩展下视野吧。硕士阶段主要是软件开发了,可以说是没碰过这些硬件了,研究方向是图像处理。额外之余研究下了计算机网络(TCP/IP),Linux 内核(很浅)。并研究了一些开源项目,开源代码,如 STL,Linux Kernel(网络栈),TinyHTTPd 等。一路走来有硬件也有软件。至于哪个好玩些,硬件调试成功,和软件编译无bug带来的感觉是一样一样的,硬件那部分也要写程序。

main.c

/***************************************************************************************************
**----------------历史版本信息----------------------------------------------------------------------
**创建人:**
**版  本:v0.1
**日  期:2011年8月
**描  述:基于前后台的PC机控制系统
**		 平台:PL-51单片机控制系统,晶振为11.0592MHZ
**
**-----------------功能描述-------------------------------------------------------------------------
**
**		本设计为——基于前后台的PC机控制系统。
**		该系统可以通过超级终端控制LED的亮灭,蜂鸣器唱歌及报警,
**		控制DS18B20读取当前环境温度并显示在超级终端和LCD1602上,
**		控制数码管连续显示相应终端输入数字,
**		控制DS1302读取当前时间并显示在LCD1602上,可通过终端修改当前时间,
**		具备整点报时,闹钟提醒功能,并将闹钟状态显示在LCD1602上,
**		控制ADC0804读取测点电压值,并显示在终端上,
**		该系统支持终端可退格输入操作,//并支持可在线计算功能(简易计算器)(该功能待完善)。
**
**-----------------当前版本修订---------------------------------------------------------------------
**修改人:
**版  本:
**日  期:
**描  述:
**
**--------------------------------------------------------------------------------------------------
***************************************************************************************************/
#include"terminal.h"
#include"beep.h"

void main(void)
{
	Init_Terminal();
	Terminal_Temper();
	while (1)
	{
		Terminal();
	}
}

terminal.h

#ifndef __TERMINAL_H__
#define __TERMINAL_H__

void Init_Terminal(void);
void Send(char *add);
void Sendbyte(char dat);
void Rec_Terminal(char size);
void Clear_Terminal(char size);
void Terminal(void);
void Terminal_Temper(void);
void Help(void);
void Display_Terminal(void);
void Wenqian(void);
void Reboot(void);
void Clear(void);
void Buzzer_Timer(void);
void Buzzer_Music(void);
void Buzzer_Time(void);
void Temper_Display(void);
void Dataled_On(void);
void Dataled_Off(void);
void Led_On(void);
void Led_Off(void);
void Compute_Terminal(void);
void Terminal_Voltage(void);
void Voltage_Display(void);
void Display_Lcd1602(void);
void Write_Time(void);

/*前景色*/
#define    F_BLACK 			"\033[30m" 			/* 黑色 */
#define    F_RED 			"\033[31m" 			/* 红色 */
#define    F_GREEN 			"\033[32m" 			/* 绿色 */
#define    F_YELLOW 		"\033[33m" 			/* 黄色 */
#define    F_BLUE 			"\033[34m" 			/* 蓝色 */
#define    F_MAGENTA 		"\033[35m" 			/* 紫色 */
#define    F_CYAN 			"\033[36m" 			/* 青色 */
#define    F_WHITE 			"\033[37m" 			/* 白色 */
#define    F_LIGHTRED 		"\033[1;31m"    	/* 亮红 */
#define    F_LIGHTGREEN 	"\033[1;32m"    	/* 亮绿 */
#define    F_LIGHTYELLOW 	"\033[1;33m"    	/* 亮黄 */
#define    F_LIGHITBLUE 	"\033[1;34m"    	/* 亮蓝 */
#define    F_LIGHTMAGENTA	"\033[1;35m"    	/* 亮紫 */
#define    F_LIGHTCYAN 		"\033[1;36m"    	/* 亮青 */
#define    F_LIGHTWHITE 	"\033[1;37m"    	/* 亮白 */

/*背景色*/
#define    B_BLACK 			"\033[40m" 			/* 黑色 */
#define    B_RED 			"\033[41m" 			/* 红色 */
#define    B_GREEN 			"\033[42m" 			/* 绿色 */
#define    B_YELLOW 		"\033[43m" 			/* 黄色 */
#define    B_BLUE 			"\033[44m" 			/* 蓝色 */
#define    B_MAGENTA 		"\033[45m" 			/* 紫色 */
#define    B_CYAN 			"\033[46m" 			/* 青色 */
#define    B_LIGHTRED 		"\033[41;1m" 		/* 亮红 */
#define    B_LIGHTGREEN		"\033[42;1m" 		/* 亮绿 */
#define    B_LIGHTYELLOW 	"\033[43;1m" 		/* 亮黄 */
#define    B_LIGHTBLUE 		"\033[44;1m" 		/* 亮蓝 */
#define    B_LIGHTMAGENTA 	"\033[45;1m" 		/* 亮紫 */
#define    B_LIGHTCYAN 		"\033[46;1m" 		/* 亮青 */
#define    B_LIGHTWHITE 	"\033[47;1m" 		/* 亮白 */


#define    BOLDFONT 		"\033[1m" 			/* Set blod font */
#define    UNDERLINEFONT 	"\033[4m" 			/* Set underline font */
#define    CLEARSCREEN 		"\033[2J" 			/* Clear screen */
#define    CURSORHOME 		"\033[H" 			/* Restore cursor to home */
#define    SAVECURSOR		"\033[s" 			/* Save cursor position */
#define    RESTORECURSOR	"\033[u" 			/* Restore cursor to saved position */
#define    SINGLEWIDTH 		"\033#5" 			/* Normal, single-width characters */
#define    DOUBLEWIDTH 		"\033#6" 			/* Creates double-width characters */

#define	   FREEZETOP		"\033[2;25r" 		/* Freeze top line */
#define    FREEZEBOTTOM		"\033[1;24r" 		/* Freeze bottom line */
#define    UNFREEZE_TB		"\033[r" 			/* Unfreeze top line and bottom line */

#define    BLINKTEXT		"\033[5m" 			/* Blink text */		
#define    REVERSEMODE		"\033[7m" 			/* Set hyper terminal to reverse mode */
#define    LIGHTREVERSEMODE	"\033[1,7m" 		/* Set hyper terminal to light reverse mode */

#endif
terminal.c
#include"terminal.h"					 //包含头文件
#include"beep.h"
#include"ds18b20.h"
#include"led.h"
#include"dataled.h"
#include"delay.h"
#include"lcd1602.h"
#include"adc0804.h"
#include"ds1302.h"
//#include"at24c02.h"

#define  TURE   1						 //宏定义参数值
#define  FALSE  0
 
uint temperature,voltage;
uchar input_size = 0;						
uchar i,Taddr;

//***定义各类命令操作符
//uchar Operation[] = "wenqian";
uchar Operation_music[] = "music";
//uchar Operation_stop[] = "stop";
uchar Operation_temper[] = "temper";
uchar Operation_ledon[] = "ledon";
uchar Operation_ledoff[] = "ledoff";
uchar Operation_dataledon[] = "dataledon";
uchar Operation_dataledoff[] = "dataledoff";
uchar Operation_writetime[] = "writetime";
uchar Operation_compute[] = "compute";
uchar Operation_voltage[] = "voltage";
uchar Operation_clear[] = "clear";
uchar Operation_reboot[] = "reboot";
uchar Operation_help[] = "help";
uchar Operation_F_color[] = "bule";
//uchar Operation_B_color[] = "green";

uchar rec[20];
uchar code num_to_char[] = {"0123456789ABCDEF"}; 	   /*定义数字跟ASCII码的关系*/
uchar temper[] = {"00.00\r\n"};                       /*定义温度值ASCII码*/
uchar result[] = {"00000"};						     /*定义计算值ASCII码*/
uchar vol[] = {"0.00"};							    /*定义电压值ASCII码*/

			   /*终端修改时间操作命令*/

uchar data ds1302_time[] = {0x00,0x00,0x16,0x10,0x06,0x01,0x13};/*格式为: 秒 分 时 日 月 星期 年 */
uchar data lcd1602_line1[] = {"00/00/00  00.00℃"};   /*1602第一行显示数据初始化*/
uchar data lcd1602_line2[] = {"00:00:00  Monday"};   		/*1602第二行显示数据初始化*/
uchar data time_buzzer[9];

/*
**************************************************************************************************	
**					     超级终端设置函数
**
** 		Init_Terminal()    :超级终端设置初始化
**		Send()         	   : 发送函数设定,用来发送字符串
**		Sendbyte()         :发送单个字符
**		Rec_Terminal()     :接收函数设定,用来接收字符串
**		Compare_Terminal() :比较函数设定,带返回值(TURE or FALSE)
**		Clear_Terminal()   :清除缓存函数,即清除接收数组中的数据
**
**************************************************************************************************
*/

void Init_Terminal(void)
{
	WELA = 0;					//关闭数码管锁存端
	DULA = 0;
	TMOD |= 0x21;				//选择定时器1工作模式2,不影响定时器的其他设置
	SCON = 0x50;				//选择10位异步通信
	PCON = 0x80; 			    //波特率设置加倍 
	TH1  = 0xFF;			    //波特率为57600,fOSC=11.0592MHZ
	TL1  = 0xFF;
//	frq  = 0x00;					//蜂鸣器PWM调节
	TH0  = 0x00;	              //定时器0中断初值
	TL0  = 0xff;	
	TR0  = 0;
	TR1  = 1;
  	RI   = 0; 		
    TI   = 0;					
	Send(CLEARSCREEN);
	Send(F_BLUE);
	Wenqian();
	Send(">> Please Operate \r\n\r\n");
 	Set1302(ds1302_time);
	Init_Lcd1602();
	IE   = 0x92; 		//EA、ET0、ES =1;  
//	IP   = 0X10; 		//串行口中断定义为高优先级中断

}

//***----send:发送函数设定,用来发送字符串
//***----输入用于发送的字符串或字符串地址
void Send(char *add)
{
	while(*add != '\0')
	{
		SBUF = *add++;        //发送字符串           
		while(!TI);
			TI = 0;
	}	
}

///***发送单个字符
void Sendbyte(char dat)
{
	SBUF = dat;
	while(!TI);
	TI = 0;
}

//***----receive:接收函数设定
//***----接收字符串和存放字符串
void Rec_Terminal(char size)
{
	uchar temp;
	do
	{
		while(!RI);
		RI = 0;
		temp = SBUF;

		if((temp == 0x08) && (input_size > 0))				    //退格指令
		{
			input_size = input_size - 1;
			Sendbyte(0x08);
			Sendbyte(' ');
		}
	
		SBUF = temp;
		while(!TI);
			TI = 0;	 	

		if(temp != 0x08)						 //当输入退格键(0x08)时,数据不存入存储数组
	   {
		rec[input_size] = temp;
		input_size ++;
	   }
	   if(input_size >= size)     //当接收数组存放的数目大于设定值时,跳出循环
				break;
	}
	while(temp != '\r');    //当操作回车键时,不进入循环
}

//***----compare比较函数设定,带返回值(0 or 1)
//***----输入两个字符串的地址
uchar Compare_Terminal(char *i,char *j)
{
	while(*i != '\0')
		{
			if(*i++ != *j++)		  //字符串逐个字符进行比较,若不相同,返回值为0
				return FALSE;
		}
 	if(*j != '\r')				  //没有操作回车键,返回值为0
 		return FALSE;
		    
	return TURE;
}

//***----clear清除缓存函数
void Clear_Terminal(char size)
{
	char n;
	for(n=0; n<=size; n++)		   
	{
		rec[n] = 0;			   //清零
	}
	input_size = 0;			   //清零
}

/*
**************************************************************************************************	
**						终端信息显示函数
**
**		描述:显示文字内容,在该系统中,执行清屏操作后,会显示该信息内容
**
**************************************************************************************************
*/

void Display_Terminal(void)
{
	Send("--------------------------今天心情不错--------------------------\r\n");
	Send("    \r\n");
	Send("    \r\n");
	Send("    \r\n");
	Send("   人生自古谁无死,留取丹心照汗青 \r\n");
	Send("    \r\n");
	Send("    \r\n\r\n");	
}

/*
**************************************************************************************************	
**					     功能函数
**
**		功能:为终端提供相应操作函数,键入以下对应命令行,即可实现相应的操作
** 		
**		help    : 获得该控制系统的所有命令行提示
**		wenqian :获得该系统额外信息
**		reboot	:软件复位MCU
**		clear   :清除当前屏幕内容
**
**************************************************************************************************
*/

void Help(void)
{
	Send(">> help -- Command help \r\n>> dataledon/dataledoff -- Operate dataled on/off \r\n");
	Send(">> ledon/ledoff -- Operate led on/off \r\n>> temper -- Read temperature \r\n");
	Send(">> sos -- Operate buzzer speak \r\n>> music -- Buzzer sing music \r\n");
	Send(">> voltage -- Display voltage \r\n>> writetime -- Change time \r\n");
	Send(">> clear -- Clear screen \r\n>> reboot -- Reboot the MCU \r\n\r\n");
//	Send(">> wenqian -- Welcome \r\n\r\n");	
}

////****欢迎函数*****//
void Wenqian(void)
{
	Send("-->> wenqian -- welcome ! \r\n");
	Send("-->> hello world -- \r\n");
//	Display_Terminal();
}

///****复位函数*****////
void Reboot(void)
{
	(*(void(*)())0)();							 //调用保存在首地址为0 的一段区域内的函数			
	Send("\r\n\r\n");							     //即MCU复位		
}

///****清屏函数******////
void Clear(void)
{
	Send(CLEARSCREEN);										//清除屏幕
	Display_Terminal();								   //显示
}

/*
**************************************************************************************************	
**						1602显示函数
**
**		功能:将从DS1302读取的时间数据显示在LCD1602上
**
**************************************************************************************************
*/

void Display_Lcd1602(void)
{
	Terminal_Temper();
 
	//***闹钟状态扫描
	Buzzer_Timer();

	//***ds1302读取当前时间
 	Get1302(ds1302_time);
		
	//***lcd1602显示数据读取***//
	//-----第一行数据读取----//	
	lcd1602_line1[0] = num_to_char[ds1302_time[6] / 16];
	lcd1602_line1[1] = num_to_char[ds1302_time[6] % 16];		  //年
	lcd1602_line1[3] = num_to_char[ds1302_time[4] / 16];
	lcd1602_line1[4] = num_to_char[ds1302_time[4] % 16];		  //月
	lcd1602_line1[6] = num_to_char[ds1302_time[3] / 16];
	lcd1602_line1[7] = num_to_char[ds1302_time[3] % 16];		  //日
											   
	lcd1602_line1[10] = num_to_char[temperature / 1000];
	lcd1602_line1[11] = num_to_char[temperature / 100 % 10];
	lcd1602_line1[13] = num_to_char[temperature / 10 % 10];
	lcd1602_line1[14] = num_to_char[temperature % 10];	     //温度

	//-----第二行数据读取----//	
	lcd1602_line2[0] = num_to_char[ds1302_time[2] / 16];
	lcd1602_line2[1] = num_to_char[ds1302_time[2] % 16];		  //时
	lcd1602_line2[3] = num_to_char[ds1302_time[1] / 16];
	lcd1602_line2[4] = num_to_char[ds1302_time[1] % 16];		  //分
	lcd1602_line2[6] = num_to_char[ds1302_time[0] / 16];
	lcd1602_line2[7] = num_to_char[ds1302_time[0] % 16];		  //秒

	///----1602显示数据
	for(i=0; i<16; i++)
	{
		Write_Com_Lcd1602(0x80 + i);
		Write_Dat_Lcd1602(lcd1602_line1[i]);
	}
	for(i=0; i<16; i++)
	{
		Write_Com_Lcd1602(0x80 + 0x40 + i);
		Write_Dat_Lcd1602(lcd1602_line2[i]);
	}
} 

/*
**************************************************************************************************	
**						LCD1602终端修改时间函数
**
**		功能:输入命令 writetime ;进入修改时间参数操作
**		输入格式为 11(年)08(月)05(日)10(时)12(分)	   只输入数字(十位)
**
**************************************************************************************************
*/

void Write_Time(void)
{
	uchar temp,i;
	Send(">> Please input current time \r\n");
	Send(">> 输入格式:年月日时分秒(闹钟)时(闹钟)分 \r\n");
		//由于此前存储数组中已存放有数据,所以需要对存储数组进行清除
	Clear_Terminal(input_size);							   //清除缓存区

	//***判断输入数据是否有效
		do
		{
			while(!RI);
				RI = 0;
				temp = SBUF;
	
			if((temp == 0x08) && (input_size > 0))				    //退格指令
			{
				input_size = input_size - 1;
				Sendbyte(0x08);
				Sendbyte(' ');
			}

			SBUF = temp;
			while(!TI);
				TI = 0;
	
			if(temp != 0x08)						 //当输入退格键(0x08)时,数据不存入存储数组
			{
				rec[input_size] = temp;					 //存放输入的时间信息
				input_size ++;
			}

			if(input_size > 25)     //当接收数组存放的数目大于设定值时,跳出循环
					break;
		}
		while((temp != '\r') /*&& (temp >= '0') && (temp <= '9')*/);  //当操作回车键、输入非数字时,不进入循环

    //	Send("\r\n>> Error : It is a invalid number and break \r\n\r\n");

		Send("\r\n\r\n");
		//时间修改	 
		//格式:11 08 08 10 12 30 

				   //2位十进制转换为BCD码并存入数组
		ds1302_time[6] = ((rec[0] << 4) & 0xf0) + (rec[1] & 0x0f);   //年
		ds1302_time[4] = ((rec[2] << 4) & 0xf0) + (rec[3] & 0x0f);   //月
		ds1302_time[3] = ((rec[4] << 4) & 0xf0) + (rec[5] & 0x0f);   //日
		ds1302_time[2] = ((rec[6] << 4) & 0xf0) + (rec[7] & 0x0f);   //时
		ds1302_time[1] = ((rec[8] << 4) & 0xf0) + (rec[9] & 0x0f);   //分
		ds1302_time[0] = ((rec[10] << 4) & 0xf0) + (rec[11] & 0x0f); //秒

		time_buzzer[7] = ((rec[12] << 4) & 0xf0) + (rec[13] & 0x0f); //闹钟——时
		time_buzzer[8] = ((rec[14] << 4) & 0xf0) + (rec[15] & 0x0f); //闹钟——分

		Set1302(ds1302_time);

		lcd1602_line1[0] = rec[0];			   
		lcd1602_line1[1] = rec[1];		   //修改 年
		lcd1602_line1[3] = rec[2];
		lcd1602_line1[4] = rec[3];		   //月
		lcd1602_line1[6] = rec[4];
		lcd1602_line1[7] = rec[5];		   //日
		lcd1602_line2[0] = rec[6];		   
		lcd1602_line2[1] = rec[7];		   //时
		lcd1602_line2[3] = rec[8];
		lcd1602_line2[4] = rec[9];		   //分   
		lcd1602_line2[6] = rec[10];
		lcd1602_line2[7] = rec[11];		   //秒   

		lcd1602_line2[10] = rec[12];
		lcd1602_line2[11] = rec[13];
		lcd1602_line2[13] = rec[14];
		lcd1602_line2[14] = rec[15];	  //闹钟状态设置

		Get1302(ds1302_time);

	//***lcd1602显示数据读取***//
	//-----第一行数据读取----//	
	lcd1602_line1[0] = num_to_char[ds1302_time[6] / 16];
	lcd1602_line1[1] = num_to_char[ds1302_time[6] % 16];		  //年
	lcd1602_line1[3] = num_to_char[ds1302_time[4] / 16];
	lcd1602_line1[4] = num_to_char[ds1302_time[4] % 16];		  //月
	lcd1602_line1[6] = num_to_char[ds1302_time[3] / 16];
	lcd1602_line1[7] = num_to_char[ds1302_time[3] % 16];		  //日
											   

	//-----第二行数据读取----//	
	lcd1602_line2[0] = num_to_char[ds1302_time[2] / 16];
	lcd1602_line2[1] = num_to_char[ds1302_time[2] % 16];		  //时
	lcd1602_line2[3] = num_to_char[ds1302_time[1] / 16];
	lcd1602_line2[4] = num_to_char[ds1302_time[1] % 16];		  //分
	lcd1602_line2[6] = num_to_char[ds1302_time[0] / 16];
	lcd1602_line2[7] = num_to_char[ds1302_time[0] % 16];		  //秒

			///----1602显示修改后的数据
		for(i=0; i<16; i++)
		{
			Write_Com_Lcd1602(0x80+i);
			Write_Dat_Lcd1602(lcd1602_line1[i]);
		}
		for(i=0; i<16; i++)
		{
			Write_Com_Lcd1602(0x80 + 0x40 + i);
			Write_Dat_Lcd1602(lcd1602_line2[i]);
		}
}

/*
**************************************************************************************************	
**						蜂鸣器操作函数
**
**		功能:利用蜂鸣器实现不同的声音信号产生,并代表响应操作状态
**
**		包括蜂鸣器音乐播放器,蜂鸣器闹钟提醒和蜂鸣器整点报时
**
**		闹钟蜂鸣器提醒,按键 S5 停止
**
**************************************************************************************************
*/

//*****蜂鸣器闹钟,整点报时****//
void Buzzer_Timer(void)
{
	Taddr = 0x81; 
	for(i=0; i<7; i++)					     //读取DS1302实时时间
	{
		time_buzzer[i] = R1302(Taddr);
		Taddr += 2; 	
	}
	if((time_buzzer[1] == time_buzzer[8]) && (time_buzzer[2] == time_buzzer[7]))
	{
		Buzzer_Time();
	
		if(KEY == 0)				//按键停止闹钟
		{
			Delay_ms(5);		    //按键延时消抖
			if(KEY == 0)
			{
				time_buzzer[7] = '0';		   //这里保证在任何时候不响应闹钟
				time_buzzer[8] = '0';
				}
		} 
	}
	else if((time_buzzer[0] == 0x00) && (time_buzzer[1] == 0x00))	 //整点报时
	{
		FM = 0;
		Delay_ms(500);
		FM = 1;
	}
	else															//其余情况,蜂鸣器停止鸣叫
		FM = 1;
}

///***蜂鸣器闹钟提醒****////
void Buzzer_Time(void)
{
		FM = 0;
		Delay_ms(500);
		FM = 1;
		Delay_ms(500);		
}

///*****蜂鸣器播放音乐****///
void Buzzer_Music(void)
{
	Send(">> Please appreciate the music \r\n\r\n");
	Beep_Music();							 		//蜂鸣器播放音乐
}

/*void timer0() interrupt 1 using 1
{
	TH0 = 0xfe;
	TL0 = frq;
	FM = ~ FM;	
}

///****蜂鸣器报警求助信号****  /////
void Buzzer_Sos(void)
{	
	uint count = 5000;
	TR0 = 1;

	while(count--)
	{
		frq++;
		Delay_ms(1);
	}
	TR0 = 0; 
	FM = 1;
	Send(">> SOS ? you should call 911 \r\n\r\n");
} */

/*
**************************************************************************************************	
**						电压显示函数
**
**		功能:将ADC0804读取的电压值值转换为ASCII码存入vol数组,
**		通过超级终端显示出来
**
**		Terminal_Voltage():将DS18B20读取的环境温度值转换为ASCII码并存入temper数组中
**		Voltage_Display() :将temper数组中的温度值发送至超级终端
**
**************************************************************************************************
*/

void Terminal_Voltage(void)
{
	voltage = Adc0804();
	vol[0] = num_to_char[voltage /100];
	vol[2] = num_to_char[voltage /10 %10];
	vol[3] = num_to_char[voltage %10];
}

void Voltage_Display(void)
{
	uchar i = 0;
	Terminal_Voltage();
	Send(">> 当前测点电压值为:");

	while(temper[i] != '\0')
	{
		SBUF = vol[i++];        					//发送电压值          
		while(!TI);
		TI = 0;

		if(i == 4)
		Send("V");	
	}
	Send("\r\n\r\n");		
}
/*
**************************************************************************************************	
**						温度显示函数
**
**		功能:将传感器读取的温度值转换为ASCII码存入temper数组,
**		通过超级终端显示出来
**
**		Terminal_Temper():将DS18B20读取的环境温度值转换为ASCII码并存入temper数组中
**		Temper_Display() :将temper数组中的温度值发送至超级终端
**
**************************************************************************************************
*/

void Terminal_Temper(void)
{
	temperature = Ds18b20();
	temper[0] = num_to_char[temperature / 1000];
	temper[1] = num_to_char[temperature / 100 % 10];
	temper[3] = num_to_char[temperature / 10 % 10];
	temper[4] = num_to_char[temperature % 10];
}	  

void Temper_Display(void)
{
	uchar i = 0;
	Terminal_Temper();
	Send(">> 当前环境温度值为:");

	while(temper[i] != '\0')
	{
		SBUF = temper[i++];        					//发送温度值          
		while(!TI);
		TI = 0;
		if(i == 5)
		Send("℃");	
	}
	Send(" \r\n");	
}

/*
**************************************************************************************************	
**						数码管显示和关闭
**
**		功能:进入操作后,可以连续输入任意数字,然后终端上显示,
**		当输入非数字字符时,系统提示警告并退出当前环境,之后可操作数码管关闭。
**
**************************************************************************************************
*/

void Dataled_On(void)
{
	uchar temp, i = 0;
	Dataled_Display(10);
	Send(">> Lighton the dataled and you can make the dataled display the number you want\r\n");
	Send(">> Please input number \r\n>> ");

	while(!RI);
	RI = 0;
	temp = SBUF;

/****输入为数字才控制数码管显示,否则将退出当前服务程序****/
			
	while((temp >= '0') && (temp <= '9'))				   
	{	
		Send(" ");												   
		Sendbyte(temp);
		i++;

		Dataled_Display(temp - 0x30);							  //控制显示相应输入数字

		while(!RI);
		RI = 0;
		temp = SBUF;

		if(i == 10)
		{
			Send("\r\n>> ");
			i=0;
		}
	}  
	Send("\r\n>> ");
	Sendbyte(temp);
	Send("\r\n>> Error : It is a invalid number and break \r\n\r\n");	 //发送错误报告并退出当前服务
}

///****数码管关闭****////
void Dataled_Off(void)
{
	Send(">> Lightoff the DATALED \r\n\r\n");
	Dataled_Display(11);
} 

/*
**************************************************************************************************	
**						LED显示和关闭
**
**		   通过命令 ledon 和 ledoff 控制led的显示和关闭
**		   并附带操作成功提示功能
**
**************************************************************************************************
*/

void Led_On(void)
{
	Send(">> Lighton the LED \r\n\r\n");
	Led_Lighton();	
}

////*****关闭LED***///
void Led_Off(void)
{
	Send(">> Lightoff the LED \r\n\r\n");
	Led_Lightoff();	
}

/*
**************************************************************************************************	
**						实时计算函数
**
**		功能:输入操作命令 compute ,则进入相应操作内容
**      随即输入计算操作数据,该系统只可进行输入数据为10以内的计算。
**
**------备注:该函数一开始是在另一程序中进行测试,并成功获得预期结果。
**		但移植入本程序中没有得到预期结果,故为待检测函数。
**
**
**************************************************************************************************
*/

void Compute_Terminal(void)
{
	uint a,b,out,i;

	Clear_Terminal(input_size);						 //清除缓存区
	Rec_Terminal(20);	

	a = rec[0] - 0x30;
	b = rec[2] - 0x30;

	switch(rec[1])
	{
		case '+':	out = a + b;   break;
		case '-':	out = a - b;   break;
		case '*':	out = a * b;   break;
		case '/':	out = a / b;   break;
	}
	Send("\r\n>> ");

		result[0] = num_to_char[out / 10000];
		result[1] = num_to_char[out / 1000 % 10];
		result[2] = num_to_char[out / 100 % 10];
		result[3] = num_to_char[out / 10 % 10];
		result[4] = num_to_char[out % 10];

		while(result[i] != '\0')
		{
			SBUF = result[i++];        				       
			while(!TI);
			TI = 0;
		}
	Send(" \r\n\r\n");			
}

/*
**************************************************************************************************	
**						终端控制函数
**
**		功能:输入相应操作命令,则进入相应操作内容
**      当输入非正确操作命令时,系统提示警告并退出当前环境
**
**************************************************************************************************
*/

void Terminal(void)
{	
	Display_Lcd1602();
}

/*
**************************************************************************************************	
**						串行口中断函数
**
**		功能:超级终端输入数据时,响应中断,并执行相应指令操作       
**
**************************************************************************************************
*/

void Serialinterrupt(void) interrupt 4
{
	Rec_Terminal(20);	   						  
	Send("\r\n");

	if((Compare_Terminal(Operation_help,rec) == FALSE) && (input_size >= 20))
	{
		Send(">> Warnning : Your command string is too long! \r\n\r\n");		//输入命令串过长警告
	}

	else if(Compare_Terminal(Operation_F_color,rec) == TURE)
	{
		Send(F_BLUE);											//设置显示颜色,可选及扩展操作
	}

	else if(Compare_Terminal(Operation_help,rec) == TURE)
	{
		Help();													//命令帮助
	}

	else if(Compare_Terminal(Operation_reboot,rec) == TURE)
	{
		Reboot();												//重新启动MCU		
	}

	else if(Compare_Terminal(Operation_clear,rec) == TURE)
	{
		Clear();                                                //清屏
	}

	else if(Compare_Terminal(Operation_music,rec) == TURE)		 //蜂鸣器播放音乐
	{	
		Buzzer_Music();
	}	
			
/*	else if(Compare_Terminal(Operation_stop,rec) == TURE)		//闹钟停止
	{
		time_buzzer[7] = 0;
		time_buzzer[8] = 0;
	}	*/

	else if(Compare_Terminal(Operation_writetime,rec) == TURE)	//进入时间修改操作 
	{
		Write_Time();
	}

	else if(Compare_Terminal(Operation_voltage,rec) == TURE)	 //显示电压值
	{
		Voltage_Display();
	}

	else if(Compare_Terminal(Operation_temper,rec) == TURE)		//显示温度值
	{
		Temper_Display();
	}

	else if(Compare_Terminal(Operation_compute,rec) == TURE)	//启动简易计算器
	{
		Compute_Terminal();		
	}

	else if(Compare_Terminal(Operation_ledon,rec) == TURE)		//点亮led
	{	
		Led_On();
	}

	else if(Compare_Terminal(Operation_ledoff,rec) == TURE)		//关灭led
	{
		Led_Off();
	}

	else if(Compare_Terminal(Operation_dataledon,rec) == TURE)	    //数码管全显
	{
		Dataled_On();
	}

	else if(Compare_Terminal(Operation_dataledoff,rec) == TURE)		         //数码管全灭
	{
		Dataled_Off();
	}

	else												
		Send(">> Error : It is a invalid command \r\n>> If you want to konw available commands, type 'help' \r\n\r\n"); //发送错误报告

		Clear_Terminal(input_size);						 //清除缓存区		  
}	
		 
adc0804.c
#include"adc0804.h"
#include"delay.h"

sbit WELA = P2^7;
sbit AD_WR = P3^6;
sbit AD_RD = P3^7;

uchar adv;
uint value;

/*
**************************************************************************************************	
**						ADC0804转换函数
**
**		描述:ADC0804为8位并行芯片,可一次性读取AD转换后电压值,
**		adc0804()无参带返回整型电压值
**
**************************************************************************************************
*/

uint Adc0804(void)
{
	WELA = 1;
	P0 &= 0x7f;      //置ad_cs端为0.选通ad,且不影响P0口的其他作用
//	WELA = 0;	

	AD_WR = 0;
	_nop_();
	AD_WR = 1;
	P0 |= 0x80;		  //关闭ad_cs

	Delay_ms(5);
	P0 &= 0x7f; 
	AD_RD = 0;
	adv = P1;
	AD_RD = 1;
	P0 |= 0x80;		  //关闭ad_cs
	WELA = 0;

	value = (uint)(adv*100*5.0/255);						   //转换公式

	AD_WR = 0;		  //该引脚与LCD的读写选择端为同一引脚,此处将其置零,不影响LCD的读写显示
	return value;
} 
at24c02.c
#include"at24c02.h"
#include"delay.h"

sbit SDA = P2^0;    
sbit SCL = P2^1;	   //申明数据线和时钟线端口

 
//***初始化
void Init_IIc(void)
{
	SCL = 1;
	SDA = 1;
}

//***开始信号
void Start_IIc(void)
{
	SCL = 1;
	SDA = 1;
	delay5us;
	SDA = 0;	
}      

//***停止信号
void Stop_IIc(void)
{
	SCL = 1;
	SDA = 0;
	delay5us;
	SDA = 1;
}

//***应答信号
void Respons_IIc(void)
{
	uchar i = 0;
	SCL = 1;
	delay5us;
	while((SDA == 1) && (i < 255))
		i++;		
}

//***非应答信号
void Norespons_IIc(void)
{
	SCL = 1;
	SDA = 1;
	delay5us;
}

//***写一个字节函数
void Write_Byte_IIc(uchar dat)
{
	uchar i;
	SCL = 0;

	for(i=0; i<8; i++)
	{
		if(dat & 0x80)
			SDA = 1;
		else
			SDA = 0;

		dat = dat << 1;
		delay5us;
		SCL = 1;
		delay5us;
		SCL = 0;
	}
}

//***读一个字节函数
uchar Read_Byte_IIc(void)
{
	uchar temp,i;
	for(i=0; i<8; i++)
	{
		SCL = 1;
		temp = temp << 1;

		if(SDA)
			temp = temp | 0x01;
		else
			temp = temp | 0x00;

		delay5us;
		SCL = 0;
	}
	return temp;	
}

//***写操作函数
void Write_IIc(uchar add,uchar dat)
{
	Start_IIc();
	Write_Byte_IIc(0xa0);
	Respons_IIc();
	Write_Byte_IIc(add);
	Respons_IIc();
	Write_Byte_IIc(dat);
	Respons_IIc();
	Stop_IIc();	
}

//***读操作函数
uchar Read_IIc(uchar add)
{
	uchar value;
	Start_IIc();
	Write_Byte_IIc(0xa0);
	Respons_IIc();
	Write_Byte_IIc(add);
	Respons_IIc();
	Start_IIc();
	Write_Byte_IIc(0xa1);
	Respons_IIc();
	value = Read_Byte_IIc();
	Norespons_IIc();
	Stop_IIc();

	return value;
}
ds18b20.c
#include"delay.h"
#include"ds18b20.h"

sbit DQ = P2^2;

uint count;

/*
**************************************************************************************************	
**						DS18B20操作函数
**
**		功能:单总线操作命令格式,读取当前环境温度值
**
**		start_ds18b20()		:DS18B20单总线开始函数,
**		write_byte_ds18b20():DS18B20单总线写字节函数,低位写入
**		read_byte_ds18b20()	:DS18B20单总线读字节函数
**		ds18b20()			:DS18B20单总线温度读取,转换,返回值为 当前温度值 * 100
**
**************************************************************************************************
*/

void  Start_Ds18b20(void)
{
	DQ = 1;
	DQ = 0;
	delay480us;
	DQ = 1;
	delay60us;
	while(DQ == 1);
	delay240us;
	DQ = 1;
	delay240us;	
}

void Write_Byte_Ds18b20(uchar dat)
{
	uchar i;
	for(i=0; i<8; i++)
	{
		DQ=1;
		DQ=0;
		delay2us;

		if(dat & 0x01)
			DQ = 1;
		else
			DQ = 0;

		dat = dat >> 1;	
		delay60us;
		DQ = 1;
		delay2us;
	}
}

uchar Read_Byte_Ds18b20(void)
{
	uchar i,temp;
	for(i=0; i<8; i++)
	{
		DQ = 1;
		DQ = 0;
		delay2us;
		DQ = 1;					
		temp = temp >> 1;

		if(DQ == 1)
			temp = temp | 0x80;
		else
			temp = temp | 0x00;

		delay60us;
		DQ = 1;
		delay2us;
	}
	return  temp;
}

uint Ds18b20(void)
{
	uchar a,b;
	float temper;
	uint  temp;

	Start_Ds18b20();
	Write_Byte_Ds18b20(0xcc);
	Write_Byte_Ds18b20(0x44);

	Start_Ds18b20();
	Write_Byte_Ds18b20(0xcc);
	Write_Byte_Ds18b20(0xbe);

//***温度读取
	a = Read_Byte_Ds18b20();
	b = Read_Byte_Ds18b20();

//***温度转换
	temp = b;
	temp = (temp << 8) | a;
	temper = temp * 0.0625;
	count = temper * 100 + 0.5;

	return count;
}
ds1302.c
#include"ds1302.h"

/*sbit SCLK = P3^2;
sbit RST = P3^3;
sbit IO = P2^4;

/*
**************************************************************************************************	
**						DS1302写函数
**
**		描述:DS1302写操作,包含写入单个字节和写入操作
**
**		Write_Ds1302_Byte(uchar temp)    :写入单个字节;
**		Write_Ds1302(uchar add,uchar dat):写操作
**
**************************************************************************************************
*

void Write_Ds1302_Byte(uchar temp)
{
	uchar i;
	RST = 1;
	for(i=0; i<8; i++)
	{
		SCLK = 0;
		IO = temp & 0x01;
		temp >>= 1;
		SCLK = 1;						//上升沿写入
	}
}

void Write_Ds1302(uchar add,uchar dat)
{
	RST = 0;
	SCLK = 0;
	RST = 1;
	Write_Ds1302_Byte(add);
	Write_Ds1302_Byte(dat);
	SCLK = 1;
	RST = 0;
	IO = 0;
}

/*
**************************************************************************************************	
**						DS1302读函数
**
**		描述:DS1302读操作,包含读出单个字节和读出操作
**
**		Read_Ds1302_Byte(void)      :读出单个字节,带返回值;
**		uchar Read_Ds1302(uchar add):读操作,带返回值
**
**************************************************************************************************
*

uchar Read_Ds1302_Byte(void)
{
	uchar i,temp;
	RST = 1;
	for(i=0; i<8; i++)
	{
		SCLK = 1;
		temp >>= 1;
		if(IO)
		temp |= 0x80;
	
		SCLK = 0;              //下降沿数据读取 	
	}
	return temp;
}


uchar Read_Ds1302(uchar add)
{
	uchar temp;
	RST = 0;
	SCLK = 0;
	RST = 1;
	Write_Ds1302_Byte(add);
	temp = Read_Ds1302_Byte();
	SCLK = 1;
	RST = 0;
	IO = 0;
	return temp;
}

/*
**************************************************************************************************	
**						DS1302时间数据初始化和读取
**
**		描述:DS1302初始化时间以及读取时间数据
**
**		Ds1302_Set(uchar *clock):设置初始时间数据
**		Ds1302_Get(uchar time[]):读取芯片当前运转时间
**
**************************************************************************************************
*

void Ds1302_Set(uchar *clock)
{
	uchar i;
	uchar add = 0x80;

	for(i=0; i<7; i++)
	{
		Write_Ds1302(add,*clock);			/*格式为: 秒 分 时 日 月 星期 年 *
		clock++;
		add +=2; 
	}
}

void Ds1302_Get(uchar time[]) 
{
    uchar i;
    uchar add = 0x81;

    for (i=0; i<7; i++)
    {
        time[i] = Read_Ds1302(add);			/*格式为: 秒 分 时 日 月 星期 年 *
        add += 2;
    }
}	*/

/*sbit SCLK = P3^2;
sbit RST = P3^3;
sbit IO = P2^4;

/*
**************************************************************************************************	
**						DS1302写函数
**
**		描述:DS1302写操作,包含写入单个字节和写入操作
**
**		Write_Ds1302_Byte(uchar temp)    :写入单个字节;
**		Write_Ds1302(uchar add,uchar dat):写操作
**
**************************************************************************************************
*

void Write_Ds1302_Byte(uchar temp)
{
	uchar i;
	RST = 1;
	for(i=0; i<8; i++)
	{
		SCLK = 0;
		IO = temp & 0x01;
		temp >>= 1;
		SCLK = 1;						//上升沿写入
	}
}

void Write_Ds1302(uchar add,uchar dat)
{
	RST = 0;
	SCLK = 0;
	RST = 1;
	Write_Ds1302_Byte(add);
	Write_Ds1302_Byte(dat);
	SCLK = 1;
	RST = 0;
	IO = 0;
}

/*
**************************************************************************************************	
**						DS1302读函数
**
**		描述:DS1302读操作,包含读出单个字节和读出操作
**
**		Read_Ds1302_Byte(void)      :读出单个字节,带返回值;
**		uchar Read_Ds1302(uchar add):读操作,带返回值
**
**************************************************************************************************
*

uchar Read_Ds1302_Byte(void)
{
	uchar i,temp;
	RST = 1;
	for(i=0; i<8; i++)
	{
		SCLK = 1;
		temp >>= 1;
		if(IO)
		temp |= 0x80;
	
		SCLK = 0;              //下降沿数据读取 	
	}
	return temp;
}


uchar Read_Ds1302(uchar add)
{
	uchar temp;
	RST = 0;
	SCLK = 0;
	RST = 1;
	Write_Ds1302_Byte(add);
	temp = Read_Ds1302_Byte();
	SCLK = 1;
	RST = 0;
	IO = 0;
	return temp;
}

/*
**************************************************************************************************	
**						DS1302时间数据初始化和读取
**
**		描述:DS1302初始化时间以及读取时间数据
**
**		Ds1302_Set(uchar *clock):设置初始时间数据
**		Ds1302_Get(uchar time[]):读取芯片当前运转时间
**
**************************************************************************************************
*

void Ds1302_Set(uchar *clock)
{
	uchar i;
	uchar add = 0x80;

	for(i=0; i<7; i++)
	{
		Write_Ds1302(add,*clock);			/*格式为: 秒 分 时 日 月 星期 年 *
		clock++;
		add +=2; 
	}
}

void Ds1302_Get(uchar time[]) 
{
    uchar i;
    uchar add = 0x81;

    for (i=0; i<7; i++)
    {
        time[i] = Read_Ds1302(add);			/*格式为: 秒 分 时 日 月 星期 年 *
        add += 2;
    }
} 	*/

	  
sbit  T_CLK = P3^2;   /*实时时钟时钟线引脚 */
sbit  T_IO = P2^4;   /*实时时钟数据线引脚 */
sbit  T_RST = P3^3;   /*实时时钟复位线引脚 */
sbit  ACC0 = ACC^0;
sbit  ACC7 = ACC^7;

/******************************************************************** 

 函 数 名:RTInputByte()
 功    能:实时时钟写入一字节
 说    明:往DS1302写入1Byte数据 (内部函数)
 入口参数:d 写入的数据 
 返 回 值:无  
 
***********************************************************************/
void RTInputByte(uchar d) 
{ 
    uchar i;
    ACC = d;
    for(i=8; i>0; i--)
    {
        T_IO = ACC0;           /*相当于汇编中的 RRC */
        T_CLK = 1;
        T_CLK = 0;
        ACC = ACC >> 1; 
    } 
}
/******************************************************************** 

 函 数 名:RTOutputByte()
 功    能:实时时钟读取一字节
 说    明:从DS1302读取1Byte数据 (内部函数)
 入口参数:无  
 返 回 值:ACC
  
***********************************************************************/
uchar RTOutputByte(void) 
{ 
    uchar i;
    for(i=8; i>0; i--)
    {
        ACC = ACC >>1;         /*相当于汇编中的 RRC */
        ACC7 = T_IO;
        T_CLK = 1;
        T_CLK = 0;
    } 
    return(ACC); 
}
/******************************************************************** 

 函 数 名:W1302()
 功    能:往DS1302写入数据
 说    明:先写地址,后写命令/数据 (内部函数)
 调    用:RTInputByte() , RTOutputByte()
 入口参数:ucAddr: DS1302地址, ucData: 要写的数据
 返 回 值:无

***********************************************************************/
void W1302(uchar ucAddr, uchar ucDa)
{
    T_RST = 0;
    T_CLK = 0;
    T_RST = 1;
    RTInputByte(ucAddr);       /* 地址,命令 */
    RTInputByte(ucDa);       /* 写1Byte数据*/
    T_CLK = 1;
    T_RST = 0;
} 
/******************************************************************** 

 函 数 名:R1302()
 功    能:读取DS1302某地址的数据
 说    明:先写地址,后读命令/数据 (内部函数)
 调    用:RTInputByte() , RTOutputByte()
 入口参数:ucAddr: DS1302地址
 返 回 值:ucData :读取的数据
 设    计:wenqian          日    期:2002-03-19
 修    改:                     日    期: 
***********************************************************************/
uchar R1302(uchar ucAddr)
{
    uchar ucData;
    T_RST = 0;
    T_CLK = 0;
    T_RST = 1;
    RTInputByte(ucAddr);             /* 地址,命令 */
    ucData = RTOutputByte();         /* 读1Byte数据 */
    T_CLK = 1;
    T_RST = 0;
    return(ucData);
}


/******************************************************************** 

 函 数 名:Set1302()
 功    能:设置初始时间
 说    明:先写地址,后读命令/数据(寄存器多字节方式)
 调    用:W1302()
 入口参数:pClock: 设置时钟数据地址 格式为: 秒 分 时 日 月 星期 年
                               7Byte (BCD码)1B 1B 1B 1B 1B  1B  1B
 返 回 值:无
  
***********************************************************************/
void Set1302(uchar *pClock) 
{
    uchar i;
    uchar ucAddr = 0x80; 
	EA = 0;
    W1302(0x8e,0x00);           /* 控制命令,WP=0,写操作?*/
    for(i =7; i>0; i--)
    { 
        W1302(ucAddr,*pClock);  /* 秒 分 时 日 月 星期 年 */ 
        pClock++;
        ucAddr +=2;
    }
    W1302(0x8e,0x80);           /* 控制命令,WP=1,写保护?*/
	EA = 1;
}
/******************************************************************** 

 函 数 名:Get1302()
 功    能:读取DS1302当前时间
 说    明:
 调    用:R1302() 
 入口参数:ucCurtime: 保存当前时间地址。当前时间格式为: 秒 分 时 日 月 星期 年 
                                        7Byte (BCD码)   1B 1B 1B 1B 1B  1B  1B
 返 回 值:无
  
***********************************************************************/
void Get1302(uchar ucCurtime[]) 
{
    uchar i;
    uchar ucAddr = 0x81;
	EA = 0;
    for (i=0; i<7; i++)
    {
        ucCurtime[i] = R1302(ucAddr);/*格式为: 秒 分 时 日 月 星期 年 */
        ucAddr += 2;
    }
	EA = 1;
}
lcd1602.c
#include"lcd1602.h"

//***写指令函数
void Write_Com_Lcd1602(uchar com)
{
	lcdrs = 0;						//选择写命令模式
	P0 = com;							//将要写入的命令字送到数据总线上
	Delay_ms(5);						//延时,是数据稳定
	lcden = 1;						//使能端-高脉冲,发送数据
	Delay_ms(5);						
	lcden = 0; 
}

//***写数据函数
void Write_Dat_Lcd1602(uchar dat)
{
	lcdrs = 1;					   //选择写数据模式
	P0 = dat;						   //将要写入的数据送到数据总线上
	Delay_ms(5);
	lcden = 1;
	Delay_ms(5);
	lcden = 0;
}

//***初始化函数
void Init_Lcd1602(void)
{
	lcden = 0;					  //拉低使能端
	lcdrw = 0;					  //选择写模式
	Write_Com_Lcd1602(0x38);				  //设置16*2显示,5*7点阵,8位数据端口
	Write_Com_Lcd1602(0x0c);				  //设置开显示,不显示光标
	Write_Com_Lcd1602(0x06);				  //写一个字符后地址指针加1
	Write_Com_Lcd1602(0x01);				  //显示清零,数据指针清零
}
led.c
#include"led.h"

#define led  P1
#define on   0x00
#define off  0xff

sbit DIOLA = P2^5;				 //锁存端

/*
**************************************************************************************************	
**						LED显示函数
**
**		功能:LED的显示和关闭
**
**************************************************************************************************
*/

//***点亮led
void Led_Lighton(void)
{
	DIOLA = 1;
	led = on;
	DIOLA = 0;	
}

//***关灭led
void Led_Lightoff(void)
{
	DIOLA = 1;
	led = off;
	DIOLA = 0;
}
beep.c
#include"delay.h"
#include"beep.h"

uchar code SOUNDLONG[];				//声明音长表
uchar code SOUNDTONE[];				//声明音调表

/*
**************************************************************************************************	
**						蜂鸣器操作函数
**
**		功能:蜂鸣器两种不同的鸣叫方式
**
**		beep_music():蜂鸣器演奏《生日快乐》
**		Music()	    :通过改变蜂鸣器的占空比来实现音调和音量调节
**		beep_warn()	:蜂鸣器简单的连续5次鸣叫
**
**************************************************************************************************
*/
 
void Beep_Music(void)
{
  		Music();  							//演奏《生日快乐》
//  		delay_ms(2000);
/*  		delay_ms(2000);						//演奏完毕延时
  		Music(2);  							//演奏《三轮车》
		delay_ms(2000);
  		delay_ms(2000);						//演奏完毕延时	  */
}

void Music(void)
{
 	uint k,n;						//定义循环辅助变量
 	uint SoundLong,SoundTone;		//定义音长音调变量,音长指时间长度,音调指震荡频率
 	uint i,j,m;						//定义循环辅助变量

 	do
 	{
  		if(i >= 57)							//如果演奏超过定义部分则回到初始位置
			i = 0;
  		if(j >= 57)
			j = 0;
  		SoundLong = SOUNDLONG[i];				//从表中取得音长
  		SoundTone = SOUNDTONE[j];				//从表中取得音调
  		i++;								//指向下一个音长
  		j++;								//指向下一个音调
 
  		for(n=0; n<SoundLong; n++)			//音长指的是频率,这里决定蜂鸣器震动多少次
  		{
   			for(k=0; k<12; k++)				//这里是震动一次
   			{
    			FM = 0;						//打开
    			for(m=0; m<SoundTone/2; m++)	//延时
     				;
    			FM = 1;						//关闭
    			for(m=0; m<SoundTone/2; m++)
     				;						//延时
   			}
  		}
  		Delay50us(11);						//延时
 	}
	while((SOUNDLONG[i] != 0) || (SOUNDTONE[j] != 0));//当两个表没有到达结尾时循环执行以上部分
}

uchar code SOUNDLONG[]=
{
	9,3,12,12,12,24,
  	9,3,12,12,12,24,
  	9,3,12,12,12,12,12,
  	9,3,12,12,12,24,
  	0, //生日快乐end
  	9,3,12,12,12,24,
  	9,3,12,12,12,24,
  	9,3,12,12,12,12,12,
  	9,3,12,12,12,24,
  	0, //生日快乐end
};

uchar code SOUNDTONE[]=
{
	212,212,190,212,159,169,
	212,212,190,212,142,159,
	212,212,106,126,159,169,190,
	119,119,126,159,142,159,
	0, //生日快乐end
	212,212,190,212,159,169,
	212,212,190,212,142,159,
	212,212,106,126,159,169,190,
	119,119,126,159,142,159,
	0, //生日快乐end
};

dataled.c

#include"dataled.h"

#define dataled   P0

//uchar code table_dataled[] = {0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0x00,0xff};
						//***共阳极数码管  0~9	10全亮,11全灭
uchar code table_dataled[] = {0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0xff,0x00};
						//***共阴极数码管  0~9

/*
**************************************************************************************************	
**						数码管函数
**
**		功能:改变数码管的段选端数据(位选端不变)使6位数码管连体显示数字
**
**************************************************************************************************
*/

void Dataled_Display(uchar num)
{
	WELA = 1;							//锁存器端口
	dataled = table_dataled[num];
	WELA = 0;
	DULA = 1;						   //锁存器端口
	dataled |= 0xc0;
	DULA = 0;	
}	


delay.c
#include"common.h"
#include"delay.h"

/*
**************************************************************************************************	
**						延时函数
**
**		功能描述:fOSC = 11.0592MHZ	,分别延时 t ms 和 time us。
**
**************************************************************************************************
*/

void Delay_ms(uint t)
{
	uchar j;
	for(; t>0; t--)
		for(j=110; j>0; j--);	
}

void Delay50us(uchar time)
{
 	uchar a,b;
 	for(a=0; a<time; a++)
  		for(b=0; b<6; b++);
}
其中一部分 .h 头文件没有贴出来,里面是函数声明,以及一些芯片引脚的宏定义。

硬件开发算驱动开发吧,和芯片打交道的,需要阅读各个芯片资料(datasheet),必须根据芯片的时序图来编程,弄清楚芯片的最大延时是多少,抗电压值,以及时序图等,然后通过主控制器(MCU,CPU等)来驱动控制。





你可能感兴趣的:(控制系统,PL-51)