整理电脑里面资料的时候,发现以前大二结束的时候写的一个小项目,贴出来吧,回味下曾经倒腾硬件方面的日子,那些年和几个小伙伴一起逛电子商城,边吐槽玩硬件就是烧钱,还时不时的往那跑,用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 */ #endifterminal.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; }
#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等)来驱动控制。