前言:省赛之前第一次把全部模块学完后以后第一次挑战的真题就是第十四届的省赛题,当时我的代码习惯和风格并不好,就把我的程序整出了很多bug(在资源里有我之前写的两版,均多多少少有些bug,第一次做全崩了,第二次有bug,那个14省是最新的)。现在我做过的题多了,代码风格有所改善。我选择再做一次第十四届的省赛题,因为我感觉这种糅合了许多模块和别样触发方式的题目很值得一刷再刷,可以练练自己的编程速度和改进自己的代码风格。
题目
个人理解与感受
首先这道题目把三个底层驱动文件都用上了,这在之前的省赛以及第十五届省赛都是没有的,乃至之前的国赛将全部底层驱动文件都用上的也少见。但从这一点可见其难度,这就能打退很多在省赛之前没把所有模块学会的选手。还有光敏触发跳转页面,以及数据有无效的判断,这些如果没有经过一定的练习并形成比较好的代码风格都是容易出问题。
在获取数据方面,我是选择实时获取数据,然后在触发之后用一个新数据(比如后面将会出现的tempcurrent)来获取触发时刻的温度、时间、湿度(频率)。在我的前两次编写中是使用触发后再获取数据。
温度方面,我尝试了只在初始化的时候进行延时读取,后续把不用延时,发现这样的温度读取也更稳定,也不容易对其他数据的读取造成大的影响。
频率转湿度方面,我将湿度直接的值放大了100倍,这样更加精确。
这是我在4T官网进行的测评(我的板子用的是S12 S13,上传用的就是题目要求的S8 S9)它对实时时钟的上电没有明确说明,导致我丢掉这一分。
还有我明明都再回显界面有显示啊,什么垃圾测评啊啊啊啊啊啊啊
还好最后分数还是比较可观,毕竟也是走过一轮省赛的人了。
垃圾4T测评
底层驱动代码
全部都用了,但每个都是浅尝辄止
IIC
unsigned char guangmin(){
unsigned char ret;
I2CStart();
I2CSendByte(0x90);
I2CWaitAck();
I2CSendByte(0x41);
I2CWaitAck();
I2CStart();
I2CSendByte(0x91);
I2CWaitAck();
ret = I2CReceiveByte();
I2CSendAck(1);
I2CStop();
return ret;
}
DS18B20
void cewen(){
unsigned char LSB,MSB;
init_ds18b20();
Write_DS18B20(0xcc);
Write_DS18B20(0x44);
if(ce){//这里的意思是测完第一次后就不再延时了
delaysmg(100);
ce = 0;
}
init_ds18b20();
Write_DS18B20(0xcc);
Write_DS18B20(0xbe);
LSB = Read_DS18B20();
MSB = Read_DS18B20();
init_ds18b20();
temp = (MSB << 8) | LSB;
temp = temp * 0.0625;
}
DS1302实时时钟
void ds1302config(){
unsigned char i;
Write_Ds1302_Byte(0x8e,0x00);
for(i = 0;i < 3;i++){
Write_Ds1302_Byte(ds1302writeaddr[i],rtctime[i]);
}
Write_Ds1302_Byte(0x8e,0x80);
}
void ds1302read(){
unsigned char i;
for(i = 0;i < 3;i++){
rtctime[i] = Read_Ds1302_Byte(ds1302readaddr[i]);
}
}
主程序代码
#include <STC15F2K60S2.H>
#include "delay.h"
#include "inithc138.h"
#include "ds1302.h"
#include "onewire.h"
#include "iic.h"
#define de 5
code unsigned char Seg_Table[17] =
{
0xc0, //0
0xf9, //1
0xa4, //2
0xb0, //3
0x99, //4
0x92, //5
0x82, //6
0xf8, //7
0x80, //8
0x90, //9
0x88, //A
0x83, //b
0xc6, //C
0xa1, //d
0x86, //E
0x8e, //F
0xbf
};
unsigned char ds1302writeaddr[3] = {0x80,0x82,0x84};
unsigned char ds1302readaddr[3] = {0x81,0x83,0x85};
unsigned char rtctime[3] = {0x30,0x50,0x10};
unsigned char show = 0;//显示功能切换
unsigned char showlast = 0;//记录跳转前的显示界面
unsigned char huixian = 0;//回显模式切换
unsigned int tempmax = 0;//最大温度
unsigned long tempall = 0;//全部温度加起来
unsigned int tempavr = 0;//平均温度
unsigned int wetmax = 0;//最大湿度
unsigned long wetall = 0;//全部湿度加起来
unsigned int wetavr = 0;//平均湿度
unsigned char trigger = 0;//触发次数
unsigned char trigtime[2] = {0x00,0x00};
unsigned int temp = 0;//温度
unsigned int wet;
char tempcanshu = 30;//温度参数
bit ce = 1;//测温标志位
unsigned int hz_count = 0;
unsigned char count = 0;
unsigned int tmp = 0;//频率
bit youxiao = 0;//有效为1,无效为0
bit youxiao2 = 1;
bit keystat = 0;//长短按检测
unsigned char key_count = 0;//长按数秒
unsigned char light = 0;//光照强度
bit caiji = 0;//采集触发
unsigned char xianshishuju = 0;//显示数据三秒
unsigned char ledstat = 0xff;//LED状态
unsigned int tempcurrent,wetcurrent,tmpcurrent;
bit flag = 0;//闪烁标志位
bit tempda = 0;//温度是不是比之前的大
bit wetda = 0;//湿度是不是比之前的大
//************************************DS1302读写
void ds1302config(){
unsigned char i;
Write_Ds1302_Byte(0x8e,0x00);
for(i = 0;i < 3;i++){
Write_Ds1302_Byte(ds1302writeaddr[i],rtctime[i]);
}
Write_Ds1302_Byte(0x8e,0x80);
}
void ds1302read(){
unsigned char i;
for(i = 0;i < 3;i++){
rtctime[i] = Read_Ds1302_Byte(ds1302readaddr[i]);
}
}
//************************************
//************************************温度测量
void showselect();
void delaysmg(unsigned int xms){
while(xms--){
Delay(1);
showselect();
//scankey();
}
}
void cewen(){
unsigned char LSB,MSB;
init_ds18b20();
Write_DS18B20(0xcc);
Write_DS18B20(0x44);
if(ce){
delaysmg(100);
ce = 0;
}
init_ds18b20();
Write_DS18B20(0xcc);
Write_DS18B20(0xbe);
LSB = Read_DS18B20();
MSB = Read_DS18B20();
init_ds18b20();
temp = (MSB << 8) | LSB;
temp = temp * 0.0625;
}
//************************************
//************************************湿度测量
void Timer0_Isr(void) interrupt 1
{
hz_count++;
}
void Timer1_Isr(void) interrupt 3
{
count++;
if(count == 20){
tmp = hz_count;
hz_count = 0;
count = 0;
}
if(keystat){
key_count++;
}
if(caiji){
xianshishuju++;
}
if(xianshishuju == 60){
show = showlast;
caiji = 0;
xianshishuju = 0;
}
if((count % 2) == 0){
flag = ~flag;
}
}
void Timer_Init(void) //50毫秒@12.000MHz
{
AUXR &= 0xBF; //定时器时钟12T模式
TMOD = 0x07; //设置定时器模式
//数数
TL0 = 0xFF; //设置定时初始值
TH0 = 0xFF; //设置定时初始值
TF0 = 0; //清除TF1标志
TR0 = 1; //定时器1开始计时
ET0 = 1; //使能定时器1中断
//读秒
TL1 = 0xB0; //设置定时初始值
TH1 = 0x3C; //设置定时初始值
TF1 = 0; //清除TF1标志
TR1 = 1; //定时器1开始计时
ET1 = 1; //使能定时器1中断
EA = 1;
}
void pinlvzhuanhuashidu(){//频率转换成湿度
if((tmp < 200) || (tmp > 2000)){
youxiao = 0;
}else{
youxiao = 1;
wet = 4.4444 * tmp + 111.112;
}
}
//************************************
//************************************显示功能
void shijianjiemian(){//时间界面
showsmg(1,Seg_Table[rtctime[2] / 16]);
showsmg(2,Seg_Table[rtctime[2] % 16]);
showsmg(3,Seg_Table[16]);
showsmg(4,Seg_Table[rtctime[1] / 16]);
showsmg(5,Seg_Table[rtctime[1] % 16]);
showsmg(6,Seg_Table[16]);
showsmg(7,Seg_Table[rtctime[0] / 16]);
showsmg(8,Seg_Table[rtctime[0] % 16]);
}
void wenduhuixian(){//温度回显
showsmg(1,Seg_Table[12]);
if(trigger){
showsmg(3,Seg_Table[tempmax / 10]);
showsmg(4,Seg_Table[tempmax % 10]);
showsmg(5,Seg_Table[16]);
showsmg(6,Seg_Table[tempavr / 100]);
showsmg(7,Seg_Table[tempavr / 10 % 10] & 0x7f);
showsmg(8,Seg_Table[tempavr % 10]);
}
}
void shiduhuixian(){//湿度回显
showsmg(1,0x89);
if(trigger){
showsmg(3,Seg_Table[wetmax / 1000]);
showsmg(4,Seg_Table[wetmax / 100 % 10]);
showsmg(5,Seg_Table[16]);
showsmg(6,Seg_Table[wetavr / 100]);
showsmg(7,Seg_Table[wetavr / 10 % 10] & 0x7f);
showsmg(8,Seg_Table[wetavr % 10]);
}
}
void shijianhuixian(){//时间回显
showsmg(1,Seg_Table[15]);
showsmg(2,Seg_Table[trigger / 10]);
showsmg(3,Seg_Table[trigger % 10]);
if(trigger){
showsmg(4,Seg_Table[trigtime[1] / 16]);
showsmg(5,Seg_Table[trigtime[1] % 16]);
showsmg(6,Seg_Table[16]);
showsmg(7,Seg_Table[trigtime[0] / 16]);
showsmg(8,Seg_Table[trigtime[0] % 16]);
}
}
void huixianjiemian(){//回显界面选择
switch(huixian){
case 0:wenduhuixian();break;
case 1:shiduhuixian();break;
case 2:shijianhuixian();break;
}
}
void wenducanshujiemian(){//温度参数界面
showsmg(1,0x8c);
showsmg(7,Seg_Table[tempcanshu / 10]);
showsmg(8,Seg_Table[tempcanshu % 10]);
}
void wenshidujiemian(){//温湿度界面
showsmg(1,Seg_Table[14]);
showsmg(4,Seg_Table[temp / 10]);
showsmg(5,Seg_Table[temp % 10]);
showsmg(6,Seg_Table[16]);
if(youxiao){
showsmg(7,Seg_Table[wet / 1000 % 10]);
showsmg(8,Seg_Table[wet / 100 % 10]);
}else{
showsmg(7,Seg_Table[10]);
showsmg(8,Seg_Table[10]);
}
}
//************************************
void showselect(){
switch(show){
case 0:shijianjiemian();break;
case 1:huixianjiemian();break;
case 2:wenducanshujiemian();break;
case 3:wenshidujiemian();break;
}
}
//************************************
//************************************采集触发
void caijishuju(){//采集数据
trigtime[0] = rtctime[1];
trigtime[1] = rtctime[2];//记录时间
tempcurrent = temp;wetcurrent = wet;
tmpcurrent = tmp;
if((tmpcurrent < 200) || (tmpcurrent > 2000)){
youxiao2 = 0;
}else{
youxiao2 = 1;
}
if(youxiao2){
trigger++;
if(trigger){
wetall = (wetcurrent / 100 *10) + wetall;//求和
wetavr = wetall / trigger;//计算湿度平均值
tempall = (tempcurrent * 10) + tempall;//求和
tempavr = tempall / trigger;//计算温度平均值
}
if(temp > tempmax){//看看这次数据有没有比之前大
if(trigger >= 2){
tempda = 1;
}
tempmax = temp;
}else{
tempda = 0;
}
if(wet > wetmax){//看看这次数据有没有比之前大
if(trigger >= 2){
wetda = 1;
}
wetmax = wet;
}else{
wetda = 0;
}
}
}
void caijichufa(){//光敏判断
light = guangmin();
Delay(1);
if(light < 10){
if(caiji == 0){
//触发次数增加一次
caijishuju();
}
caiji = 1;
}
}
void tiaozhuan(){//跳转
if(caiji){
show = 3;
}
}
//************************************
//************************************
void scankey(){//我的S8虚焊,S8换成S12 S9换成S13
P33 = 0;P32 = 1;P44 = 1;P35 = 1;
if(P44 == 0){Delay(de);while(P44 == 0){showselect();}
show++;//S4
show %= 3;
showlast = show;
huixian = 0;
}
if(show == 2){//S13
if(P35 == 0){Delay(de);while(P35 == 0){showselect();}
tempcanshu++;
if(tempcanshu > 99){
tempcanshu = 0;
}
}
}
P33 = 1;P32 = 0;P44 = 1;P35 = 1;
if(show == 1){
if(P44 == 0){Delay(de);while(P44 == 0){showselect();}
huixian++;
huixian %= 3;
}
}
if(P35 == 0){Delay(de);//S13
while(P35 == 0){
keystat = 1;showselect();
}
keystat = 0;
if((show == 1) && (huixian == 2)){
if(key_count >= 40){
trigger = 0;
trigtime[0] = 0;trigtime[1] = 0;
tempall = 0;tempavr = 0;
wetall = 0;wetavr = 0;
}
}
if(show == 2){
tempcanshu--;
if(tempcanshu < 0){
tempcanshu = 99;
}
}
key_count = 0;
}
}
//************************************
//************************************LED
void LED(){
if(show == 0){
ledstat = ledstat & ~0x01;
}else{
ledstat = ledstat | 0x01;
}
if(show == 1){
ledstat = ledstat & ~0x02;
}else{
ledstat = ledstat | 0x02;
}
if(show == 3){
ledstat = ledstat & ~0x04;
}else{
ledstat = ledstat | 0x04;
}
if((tempcurrent > tempcanshu) && (flag == 1)){
ledstat = ledstat & ~0x08;
}else{
ledstat = ledstat | 0x08;
}
if(youxiao2 == 0){
ledstat = ledstat & ~0x10;
}else{
ledstat = ledstat | 0x10;
}
if((tempda == 1) && (wetda == 1)){
ledstat = ledstat & ~0x20;
}else{
ledstat = ledstat | 0x20;
}
outputp0(4,ledstat);
}
//************************************
void main(){
cewen();
ds1302config();
Timer_Init();
initsys();
while(1){
cewen();
ds1302read();
pinlvzhuanhuashidu();
showselect();
LED();
if(caiji == 0){//采集过程中键盘锁定
scankey();
}
caijichufa();
tiaozhuan();
}
}
展示视频
注:我的板子S8有问题,换成了S12,对应地,S9换成S13
S014