51单片机实训周-智能秒表程序

51单片机实训周-智能秒表程序

单片机实训周做的项目,选题是智能秒表,用开发板实现。
本次实验开发语言以C51语言为主,运用《单片机原理及应用》中已学习的相关知识,综合运用单片机I/O口、定时器、中断、串行口及输入(如按键)、输出(如LED小灯、数码管)设备,实现项目的基本功能。

题目要求:

智能秒表程序:

  1. 按键功能:通过按键控制秒表的启停、复位;
  2. 数码管显示:显示计时时间,注意误差修正;
  3. 串口通信:使用串口控制秒表的启停、复位。

设计思路

配置并启动T0,使用T0中段来进行数码管,按键、按键扫描和秒表的计时。使用第四行作为独立按键来使用,进行秒表的启停和复位,Esc键代表复位调用复位函数,回车键代表启停调用启停函数。按键驱动函数来检测按键动作,调度相应动作函数。动作函数为启停和复位。按键扫描函数,需在定时中断中调用,并且进行按键消抖,将按键动作赋值给数组使驱动函数调用动作函数。数码管动态扫描刷新函数需在定时中断中调用。秒表计数函数是每隔10ms调用一次进行秒表计数累加,能保留小数点后两位,当处于运行状态时才会递增计数值即此时的启停函数的秒表运行标志变量为1。秒表计数显示函数将小数部分转换到低2位,整数部分转换到高4位,并且高位的0显示为空字符同时显示小数点。数码管动态扫描函数,在中断时调用,将缓冲区数据送到P0口,显示消隐。使用串口控制秒表的启停、复位,需要增加串口配置函数,设置通信波特率为9600,使用T1定时计数器。UART 中断服务函数在电脑通过串口调试助手发送指令时调用动作函数。P为暂停,E为启动调用启停函数,R为复位调用复位函数。在这里插入图片描述

#include 
sbit ADDR3 = P1^3;
sbit ENLED = P1^4;
sbit KEY1 = P2^4;
sbit KEY2 = P2^5;
sbit KEY3 = P2^6;
sbit KEY4 = P2^7;
unsigned char sbufMessage[] = {0x53, 0x54, 0x41, 0x52, 0x54,0x50, 0x41, 0x55, 0x53, 0x45, 0x52, 0x45, 0x53, 0x45, 0x54
};
unsigned char sbufMessageN[] = {0x0D, 0x0A};
unsigned char code LedChar[] = {  //数码管显示字符转换表0xC0, 0xF9, 0xA4, 0xB0, 0x99, 0x92, 0x82, 0xF8,0x80, 0x90, 0x88, 0x83, 0xC6, 0xA1, 0x86, 0x8E
};
unsigned char LedBuff[6] = {  //数码管显示缓冲区0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
};
unsigned char KeySta[4] = {  //按键当前状态1, 1, 1, 1
};
bit StopwatchRunning = 0;  //秒表运行标志
bit StopwatchRefresh = 1;  //秒表计数刷新标志
unsigned char DecimalPart = 0;  //秒表的小数部分
unsigned int  IntegerPart = 0;  //秒表的整数部分
unsigned char T0RH = 0;  //T0重载值的高字节
unsigned char T0RL = 0;  //T0重载值的低字节
void ConfigTimer0(unsigned int ms);
void StopwatchDisplay();
void KeyDriver();
void ConfigUART(unsigned int baud);
void main(){EA = 1;      //开总中断ENLED = 0;   //使能选择数码管ADDR3 = 1;P2 = 0xFE;   //P2.0置0,选择第4行按键作为独立按键ConfigTimer0(2);  //配置T0定时2msConfigUART(9600);while (1){if (StopwatchRefresh)  /*需要刷新秒表示数时调用显示函数*/{StopwatchRefresh = 0;StopwatchDisplay();}KeyDriver();  //调用按键驱动函数}
}
/* 配置并启动T0,ms-T0定时时间 */
void ConfigTimer0(unsigned int ms){unsigned long tmp;  //临时变量tmp = 11059200 / 12;      //定时器计数频率tmp = (tmp * ms) / 1000;  //计算所需的计数值tmp = 65536 - tmp;        //计算定时器重载值tmp = tmp + 18;           //补偿中断响应延时造成的误差T0RH = (unsigned char)(tmp>>8);  //定时器重载值拆分为高低字节T0RL = (unsigned char)tmp;TMOD &= 0xF0;   //清零T0的控制位TMOD |= 0x01;   //配置T0为模式1TH0 = T0RH;     //加载T0重载值TL0 = T0RL;ET0 = 1;        //使能T0中断TR0 = 1;        //启动T0
}
/* 秒表计数显示函数 */
void StopwatchDisplay(){signed char i;unsigned char buf[4];  //数据转换的缓冲区//小数部分转换到低2位LedBuff[0] = LedChar[DecimalPart%10];LedBuff[1] = LedChar[DecimalPart/10];//整数部分转换到高4位buf[0] = IntegerPart%10;buf[1] = (IntegerPart/10)%10;buf[2] = (IntegerPart/100)%10;
buf[3] = (IntegerPart/1000)%10;
//整数部分高位的0转换为空字符for (i=3; i>=1; i--){if (buf[i] == 0)LedBuff[i+2] = 0xFF;elsebreak;
}
//有效数字位转换为显示字符for ( ; i>=0; i--){LedBuff[i+2] = LedChar[buf[i]];}LedBuff[2] &= 0x7F;  //点亮小数点
}
/* 秒表启停函数 */
void StopwatchAction(){if (StopwatchRunning)    //已启动则停止StopwatchRunning = 0;else                     //未启动则启动StopwatchRunning = 1;
}
/* 秒表复位函数 */
void StopwatchReset(){StopwatchRunning = 0;  //停止秒表DecimalPart = 0;       //清零计数值IntegerPart = 0;StopwatchRefresh = 1;  //置刷新标志
}
/* 按键驱动函数,检测按键动作,调度相应动作函数,需在主循环中调用 */
void KeyDriver(){unsigned char i;static unsigned char backup[4] = {1,1,1,1};for (i=0; i<4; i++){  //循环检测4个按键if (backup[i] != KeySta[i]){  //检测按键动作if (backup[i] != 0){      //按键按下时执行动作if (i == 1)          //Esc键复位秒表StopwatchReset();else if (i == 2)     //回车键启停秒表StopwatchAction();}backup[i] = KeySta[i];   //刷新前一次的备份值}}
}
/* 按键扫描函数,需在定时中断中调用 */
void KeyScan(){unsigned char i;static unsigned char keybuf[4] = {  //按键扫描缓冲区0xFF, 0xFF, 0xFF, 0xFF};//按键值移入缓冲区keybuf[0] = (keybuf[0] << 1) | KEY1;keybuf[1] = (keybuf[1] << 1) | KEY2;keybuf[2] = (keybuf[2] << 1) | KEY3;keybuf[3] = (keybuf[3] << 1) | KEY4;for (i=0; i<4; i++){//消抖后更新按键状态if (keybuf[i] == 0x00){   //连续8次扫描值为0,即16ms内都是按下状态时,可认为按键已稳定的按下KeySta[i] = 0;}else if (keybuf[i] == 0xFF){   //连续8次扫描值为1,即16ms内都是弹起状态时,可认为按键已稳定的弹起KeySta[i] = 1;}}
}
/* 数码管动态扫描刷新函数,需在定时中断中调用 */
void LedScan(){static unsigned char i = 0;  //动态扫描索引P0 = 0xFF;             //关闭所有段选位,显示消隐P1 = (P1 & 0xF8) | i;  //位选索引值赋值到P1口低3位P0 = LedBuff[i];       //缓冲区中索引位置的数据送到P0口if (i < 5)             //索引递增循环,遍历整个缓冲区i++;elsei = 0;
}
/* 秒表计数函数,每隔10ms调用一次进行秒表计数累加 */
void StopwatchCount(){if (StopwatchRunning){  //当处于运行状态时递增计数值DecimalPart++;           //小数部分+1if (DecimalPart >= 100){  //小数部分计到100时进位到整数部分DecimalPart = 0;IntegerPart++;       //整数部分+1if (IntegerPart >= 9){  //整数部分计到9时归零IntegerPart = 0;}}StopwatchRefresh = 1;    //设置秒表计数刷新标志}
}
/* T0中断服务函数,完成数码管、按键扫描与秒表计数 */
void InterruptTimer0() interrupt 1{static unsigned char tmr10ms = 0;TH0 = T0RH;  //重新加载重载值TL0 = T0RL;LedScan();   //数码管扫描显示KeyScan();   //按键扫描tmr10ms++; //定时10ms进行一次秒表计数if (tmr10ms >= 5){tmr10ms = 0;StopwatchCount();  //调用秒表计数函数}
}void ConfigUART(unsigned int baud){SCON = 0x50;                             //配置串口为模式 1TMOD &= 0x0F;                            //清零 T1 的控制位TMOD |= 0x20;                            //配置 T1 为模式 2TH1 = 256 - (11059200 / 12 / 32) / baud; //计算 T1 重载值TL1 = TH1;                               //初值等于重载值ET1 = 0;                                 //禁止 T1 中断ES = 1;                                  //使能串口中断TR1 = 1;                                 //启动 T1
}

需要完整代码评论区联系我


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部