2012-2013学年第一学期论文题目:单片机系统设计开发应用—智能仪器学院:计算机科学与信息工程专业:软件工程学号:姓名:高红斌日期:2013年12月1日单片机系统设计开发应用—智能仪器一、设计要求及目的本实验通过一个单通道通用型智能仪器的软硬件系统设计,将这学期学过的单片机原理加以综合运用,以此掌握单片机应用系统的设计要领,本次试验设计的总体目标是一路电压信号输入和两路报警开关量输出控制功能,其中信号电压范围0—5VDC,AD采样分辨率8bit,数码管显示信息为:以为参数字符和三位十进制采样值,控制参数有两个,即下限报警值L和上线报警值H,当采样值大于H时,高位报警继电器接通(用LED 状态灯D1亮表示);当采样值小于L时,下位报警继电器接通(用D2表示);当采样值介于L和H之间时,两路报警器功能均被解除(D1和D2均熄灭表示)二、实验环境微型计算机一台,proteus软件,keilC编译器。
三、元器件列表,图表 1四、实验原理本实验选用了一只六联共阴极数码管显示器,按照动态显示原理接线,其中段码通过锁存器74LS245驱动后接于P0口,位码则有反相器74LS04驱动后接于。
A/D转换器采用逐次逼近方式的芯片ADC0809,其并行数据输出端直接连接于P2口,4个控制端CLOCK,START,EOC,和OE分别接于,采用查询法等待转换结束,转换时钟利用定时器中断产生。
四个面板按键通过8位串行输入并行输出移位寄存器74LS164与单片机接口,其移位时终端与单片机的TXD引脚相连,串行数据端(1和2脚)与单片机的RXD引脚相连,串口输出功能采用汇编语言与C51语言混合编程实现。
软件系统采用一个有多个功能模块构成的程序,模块之间相互依赖,他们之间的关系如图,程序有主要的两个功能模块组成——控制模块和菜单模块。
这两个模块能够同时运行。
这里,“同时”的意思是指用户进行菜单操作的时候,程序还能采集数据并进行控制。
图表 2软件系统结构组成“控制”和“菜单”这两个主要的模块都是建立在其他小模块的基础上的,比如控制模块建立在A/D转换和LED 显示的基础上,菜单建立在按键检测和LED显示的基础上,而按键检测又建立在串口输出的基础上。
下表列出了各个模块的主要函数。
图表 3各个模块的主要函数和功能五、程序源代码//void ad_init();void control_thread();void menu_thread();void main(){ad_init();while (1){menu_thread();control_thread();}}//#define MENU_ON 0#define MENU_OFF 1#define MENU_NUM 2#define MENU_MAX 999#define MENU_MIN 0unsigned char param_value[] = {100, 150}; unsigned char menu_status = MENU_OFF;char _menu_name[] = {'L','H'}; //参数名的符号unsigned char _menu_value[] = {0,0}; //供显示用的参数数组unsigned char _menu_idx = 0; //参数序号char get_key();void print(char name, unsigned int value);void menu_thread(void){char i = 0;char key = get_key();if (menu_status == MENU_OFF){//当前菜单为关闭状态时if (key == 0){ //若按键0已被按下menu_status = MENU_ON; //置当前菜单为打开状态_menu_idx = 0; //设置参数序号0//将所有参数当前值取出,送入供显示的参数数组中for (i = 0 ; i < MENU_NUM ; i++){_menu_value[i] = param_value[i];}}} else{//如果当前菜单为打开状态,则进行以下操作:if (key == 0){//若按键0按下,则不保存键值,仅切换到下一个参数if (++_menu_idx == MENU_NUM){ //判断是否所有参数都循环到了menu_status = MENU_OFF; //若已循环完成,设置菜单关闭状态}} else if (key == 1){//若按键1按下,则保存键值,并切换到下一个参数param_value[_menu_idx] = _menu_value[_menu_idx];if (++_menu_idx == MENU_NUM){menu_status = MENU_OFF;}} else if (key == 2) {//若按键2按下,则参数值加10_menu_value[_menu_idx] += 10;if (_menu_value[_menu_idx] > MENU_MAX) {_menu_value[_menu_idx] = MENU_MAX;}} else if (key == 3) {//若按键3按下,则参数值减10_menu_value[_menu_idx] -= 10;if (_menu_value[_menu_idx] < MENU_MIN) {_menu_value[_menu_idx] = MENU_MIN;}}}if (menu_status == MENU_ON) {//菜单状态为开时,显示参数值print(_menu_name[_menu_idx], _menu_value[_menu_idx]);}}//#include <>sbit P32 = P3^2;sbit P33 = P3^3;sbit P34 = P3^4;sbit P35 = P3^5;sbit P37 = P3^7; unsigned char ad() { P33 = 0;P33 = 1;P33 = 0;while(!P34);P35 = 1;return P2;}void ad_init() {TMOD = 0x02;TH0 = 0;TL0 = 0;ET0 = 1;TR0 = 1;EA = 1;}void _ad_clock(void) interrupt 1 {P32 = ~P32;}//#include<>sbit P16=P1^6;sbit P17=P1^7;unsigned char ad();void print(char name, unsigned int value); extern unsigned char param_value[2];extern char menu_status;void control_thread() {//第1步:A/D转换unsigned char value = ad();//第2步:根据采样值控制LED灯if (value > param_value[1]) {P16 = 0;P17 = 1;} else if (value <= param_value[1] && value >= param_value[0]) {P16 = 0;P17 = 0;} else {P16 = 1;P17 = 0;}//第3步:如果菜单是关闭的,显示采集到的数值if (menu_status == 1) {print(' ', value);}}//#include <>#define CHECK_KEY_DOWN 0 //处在检测按键压下阶段标志#define CHECK_KEY_UP 1 //处在检测按键抬起阶段标志#define KEY_UP 0 //按键抬起标志#define KEY_DOWN 1 //按键压下标志sbit _p33 = P3^3;sbit _p34 = P3^4;sbit _p35 = P3^5;sbit _p36 = P3^6;char _key_status = CHECK_KEY_DOWN; //按键检测状态(初值为检测压下阶段)char _key_idx = 0; //按键序号void serial(char byte);char _check_key(unsigned char _key_idx) { //检查按键状态serial(~(0x01<<_key_idx)); //将待查按键键码转换成扫描码后输出if (_p36 == 0) { //根据P36状态决定返回值return KEY_DOWN;} else {return KEY_UP;}}char get_key(void) {char result = -1; //无键按下时键值为-1if (_key_status == CHECK_KEY_DOWN) { //如果当前处于检查压下阶段,进行以下操作if (_check_key(_key_idx) == KEY_DOWN) { //判断当前扫描键的状态,若为压下标志则_key_status = CHECK_KEY_UP; //将检查阶段标志设置为抬起} else { //否则,将检查阶段标志设置为压下if (++_key_idx == 4) { //判断是否4个按键已经轮流扫描一遍_key_idx = 0; //是,则将待扫描按键号设为0 }}} else if (_key_status == CHECK_KEY_UP) { //如果当前处于检查抬起阶段,进行以下操作if (_check_key(_key_idx) == KEY_UP) { //判断当前扫描键的状态,若为抬起标志则result = _key_idx; //键值输出_key_status = CHECK_KEY_DOWN; //按键检查阶段标志改为压下if (++_key_idx == 4) { //判断是否4个按键已经轮流扫描一遍_key_idx = 0; //是,则将待扫描按键号设为0 }}}return result;}//#include<>char code map1[]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F}; char code map2[]={0x00,0x76,0x38};char _convert(char c){ if(c==' ')return map2[0];else if(c=='H')return map2[1];else if(c=='L')return map2[2];else if(c>='0'&&c<='9') return map1[c-'0']; return 0;}void _delay(){int i=0,j=0;for(i=0;i<10;i++){for(j=0;j<10;j++){}}}void print(char name, unsigned int value) { char buf[6];char i = 5;for (i = 5 ; i > 1 ; i--) {buf[i] = '0' + value % 10;value /= 10;if (value == 0) {break;}}i--;for ( ; i >= 1 ; i--) {buf[i] = ' ';}buf[0] = name;for (i = 0 ;i < 6 ;i++) {P1 &= 0xC0;P1 |= (1 << i);P0 = _convert(buf[i]);delay();}}//PUBLIC _SERIALDE SEGMENT CODERSEG DE_SERIAL:MOV SCON, #0MOV SBUF, R7JNB TI, $CLR TIRETEND六、实验结果图表 4程序通过编译,并且没有错误系统运行效果如图所示,参数设置状态效果如图所示。