大家好,今天给大家分享2022年第十三届的蓝桥杯省赛程序题。先上题目:

今年的省赛程序题难度不算大,使用到的模块有矩阵按键,蜂鸣器、继电器、LED、DS18B20、时钟模块、数码管;这些都是往年经常考到的模块,需要要注意的就是矩阵按键是简化版的,只打开了S12、S13、S15、S16,还有就是LED和继电器蜂鸣器模块的配合,因为本次的题目把他们三个全都用到了,他们三个又共用P0端口,LED是共阳极的接法,继电器和蜂鸣器是共阴极的接法,所以在写代码的时候,我建议把LED和继电器蜂鸣器分开,把其中的一个放到定时器里去控制,这样程序会稳定一些。
拿到题目后,我们先把温度传感器和时钟的相关函数进行完善。
时钟模块:
#include "ds1302.h"
//---DS1302写入和读取时分秒的地址命令---//
//---秒分时日月周年 最低位读写位;-------//
unsigned char code READ_RTC_ADDR[7] = {0x81, 0x83, 0x85, 0x87, 0x89, 0x8b, 0x8d};
unsigned char code WRITE_RTC_ADDR[7] = {0x80, 0x82, 0x84, 0x86, 0x88, 0x8a, 0x8c};
//---DS1302时钟初始化2016年5月7日星期六23点59分50秒。---//
//---存储顺序是秒分时日月周年,存储格式是用BCD码---//
unsigned char TIME[7] = {50, 59, 23, 0x07, 0x05, 0x06, 0x16};
unsigned char read(unsigned char add)
{
unsigned char i,temp;
unsigned char dat1,dat2;
CE=0;
SCLK=0;
CE=1;
writebyte(add);
for(i=0;i<8;i++)
{
SCLK=0;
temp>>=1;
if(IO)
{
temp|=0x80;
}
SCLK=1;
}
IO=0;
dat1=temp/16;//0XFF 1111 1111
dat2=temp%16;
temp=dat1*10+dat2;
return temp;
}
void writebyte(unsigned char dat)
{
unsigned char i;
for(i=0;i<8;i++)
{
SCLK=0;
IO=dat&0x01;
SCLK=1;
dat>>=1;
}
}
void write(unsigned char add,unsigned char dat)
{
unsigned char num;
CE=0;
SCLK=0;
CE=1;
writebyte(add);
num=(dat/10<<4)|(dat%10);// 55
writebyte(num);
CE=0;
}
void Init_DS1302()
{
unsigned char i;
write(0x8e,0x00);
for(i=0;i<7;i++)
{
write(WRITE_RTC_ADDR[i],TIME[i]);
}
write(0x8e,0x80);
}
void readtime()
{
unsigned char i;
write(0x8e,0x00);
for(i=0;i<7;i++)
{
TIME[i]=read(READ_RTC_ADDR[i]);
}
write(0x8e,0x80);
}时钟模块头文件:
#ifndef __DS1302_H_ #define __DS1302_H_ //---包含头文件---// #include <reg52.h> #include <intrins.h> //---定义ds1302使用的IO口---// sbit CE=P1^3; sbit IO=P2^3; sbit SCLK=P1^7; //---定义全局函数---// void readtime(); unsigned char read(unsigned char add); void writebyte(unsigned char dat); void write(unsigned char add,unsigned char dat); void Init_DS1302(); //---加入全局变量--// extern unsigned char TIME[7]; //加入全局变量 #endif
温度传感器模块:
#include "onewire.h"
/****************************单总线延时函数****************************/
void Delay_OneWire(unsigned int t)
{
unsigned char aa;
while(t--)
{
for(aa=0;aa<10;aa++);
}
}
/****************************DS18B20芯片初始化****************************/
bit Init_DS18B20(void)
{
bit initflag = 0;
DQ = 1;
Delay_OneWire(12);
DQ = 0;
Delay_OneWire(80);
DQ = 1;
Delay_OneWire(10);
initflag = DQ;
Delay_OneWire(5);
return initflag;
}
/****************************通过单总线向DS18B20写一个字节****************************/
void Write_DS18B20(unsigned char dat)
{
unsigned char i;
for(i=0;i<8;i++)
{
DQ = 0;
DQ = dat&0x01;
Delay_OneWire(5);
DQ = 1;
dat >>= 1;
}
Delay_OneWire(5);
}
/****************************从DS18B20读取一个字节****************************/
unsigned char Read_DS18B20(void)
{
unsigned char i;
unsigned char dat;
for(i=0;i<8;i++)
{
DQ = 0;
dat >>= 1;
DQ = 1;
if(DQ)
{
dat |= 0x80;
}
Delay_OneWire(5);
}
return dat;
}
/****************************温度读取处理函********************/
unsigned char Tempget()
{
unsigned int low,high,temp;
Init_DS18B20();
Write_DS18B20(0xcc);
Write_DS18B20(0x44);
Delay_OneWire(20);
Init_DS18B20();
Write_DS18B20(0xcc);
Write_DS18B20(0xbe);
low=Read_DS18B20();
high=Read_DS18B20();
temp=high<<4;
temp|=(low>>4);
return temp;
}温度传感器模块头文件:
#ifndef _ONEWIRE_H #define _ONEWIRE_H #include <reg52.h> #define OW_SKIP_ROM 0xcc #define DS18B20_CONVERT 0x44 #define DS18B20_READ 0xbe //IC引脚定义 sbit DQ = P1^4; //函数声明 void Delay_OneWire(unsigned int t); void Write_DS18B20(unsigned char dat); bit Init_DS18B20(void); unsigned char Read_DS18B20(void); unsigned char Tempget(); #endif
写完这些之后,我们要新建一个工程,把准备工作做好,比如关闭蜂鸣器继电器LED、初始化数码管、延迟函数、LED、矩阵键盘的位定义等:
#include <reg52.h>
#include <ds1302.h>
#include <onewire.h>
typedef unsigned int u16;
typedef unsigned char u8;
sfr P4=0XC0;
sbit R3=P3^2;
sbit R4=P3^3;
sbit C3=P3^5;
sbit C4=P3^4;
sbit L1=P0^0;
sbit L2=P0^1;
sbit L3=P0^2;
u8 code smgduan[10]={0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90};
u8 code smgduan_dp[10]={0x40,0x79,0x24,0x30,0x19,0x12,0x02,0x78,0x00,0x10};
u8 temp_setup=23,temp_get;
void display_sec();
/***************延迟函数函数,单位1ms******************/
void delayms(u16 i)
{
u16 aa;
while(i--)
{
for(aa=0;aa<845;aa++);
}
}
/***************通道选择函数******************/
void InitHC138(u8 add)
{
switch(add)
{
case(4):
P2=(P2&0X1F)|0X80;break;
case(5):
P2=(P2&0X1F)|0Xa0;break;
case(6):
P2=(P2&0X1F)|0Xc0;break;
case(7):
P2=(P2&0X1F)|0Xe0;break;
}
}
/***************蜂鸣器继电器LED初始化函数******************/
void InitHC573()
{
InitHC138(4);
P0=0XFF;
InitHC138(5);
P0=0X00;
}
/***************数码管段选位选函数******************/
void DigDisplay(u8 add,u8 dat)
{
InitHC138(6);
P0=0X01<<add;
InitHC138(7);
P0=dat;
}
/***************消隐函数******************/
void DisplayOFF()
{
InitHC138(7);
P0=0XFF;
}
/***************温度获取函数******************/
void TempGet1()
{
temp_get=Tempget();
}做好这些准备工作之后,我们就可以开始审题了:

显示功能这一块要求三个界面,我们可以写三个显示函数并将它们单独封装,方便后面调用:
/***************温度数据显示函数******************/
void DispalyTempDat()
{
DigDisplay(0,0xc1);
delayms(1);
DigDisplay(1,smgduan[1]);
delayms(1);
DigDisplay(5,smgduan[temp_get/10]);
delayms(1);
DigDisplay(6,smgduan_dp[temp_get%10]);
delayms(1);
DigDisplay(7,smgduan[temp_get*10%10]);
delayms(1);
DisplayOFF();
}
/***************时间显示函数******************/
void DisplayTime()
{
DigDisplay(0,0xc1);
delayms(1);
DigDisplay(1,smgduan[2]);
delayms(1);
DigDisplay(3,smgduan[TIME[2]/10]);
delayms(1);
DigDisplay(4,smgduan[TIME[2]%10]);
delayms(1);
DigDisplay(5,0xBF);
delayms(1);
DigDisplay(6,smgduan[TIME[1]/10]);
delayms(1);
DigDisplay(7,smgduan[TIME[1]%10]);
delayms(1);
DisplayOFF();
}
/***************温度参数显示函数******************/
void DisplayTempSetup()
{
DigDisplay(0,0xc1);
delayms(1);
DigDisplay(1,smgduan[3]);
delayms(1);
DigDisplay(6,smgduan[temp_setup/10]);
delayms(1);
DigDisplay(7,smgduan[temp_setup%10]);
delayms(1);
DisplayOFF();
}然后看按键功能要求:

对于按键扫描函数也是尽量只做数据处理,不调用其他函数,设置了几个变量,在按键按下时,只对变量进行处理,之后再写一个函数,根据变量的值进行显示函数的调用,S16只在参数设置界面下有效,S17在时间显示界面、参数设置界面有效,所以我们需要在判断按键按下之后还要再判断一个条件,这样子函数在执行的时候更加稳定。要注意的是在S17按键按下的时候,要进行分和秒的显示,最简单的办法就是在松手检测的时候调用一下显示函数,这也是按键扫描函数里唯一调用显示函数的一个地方,注意参数变量的范围。
u8 display_add=1;
bit relay_setup=1;
/***************数码管显示_按下S17时显示秒******************/
void display_sec()
{
DigDisplay(0,0xc1);
delayms(1);
DigDisplay(1,smgduan[2]);
delayms(1);
DigDisplay(3,smgduan[TIME[1]/10]);
delayms(1);
DigDisplay(4,smgduan[TIME[1]%10]);
delayms(1);
DigDisplay(5,0xBF);
delayms(1);
DigDisplay(6,smgduan[TIME[0]/10]);
delayms(1);
DigDisplay(7,smgduan[TIME[0]%10]);
delayms(1);
DisplayOFF();
}
/***************按键扫描******************/
void KeyScan()
{
R3=0;
R4=1;
C3=1;C4=1;
if(C3==0) //S13
{
delayms(10);
if(C3==0)
{
relay_setup=~relay_setup;
while(!C3);
}
}
else if(C4==0) //S17
{
delayms(10);
if(C4==0)
{
if(display_add==3)
{
temp_setup--;
while(!C4);
}
else if(display_add==2)
{
while(!C4)
{
display_sec();
}
}
}
}
R3=1;
R4=0;
C3=1;C4=1;
if(C3==0) //S12
{
delayms(10);
if(C3==0)
{
display_add++;
while(!C3);
}
}
else if(C4==0) //S16
{
delayms(10);
if(C4==0)
{
if(display_add==3)
{
temp_setup++;
while(!C4);
}
}
}
}
/***************按键处理******************/
void KeyPro()
{
if(display_add>3) display_add=1;
if(temp_setup>99) temp_setup=10;
if(temp_setup<10) temp_setup=99;
}
/***************数码管显示******************/
void DisplayDat()
{
if(display_add==1)
{
DispalyTempDat();
}
if(display_add==2)
{
DisplayTime();
}
if(display_add==3)
{
DisplayTempSetup();
}
}当按键函数和扫描函数都写完之后,整体的逻辑也就结束了,接下来就是继电器蜂鸣器和LED的控制了:

打开定时器,对温度以及时间进行判断,并选择要打开的模块,对函数进行封装;注意,L3在达到要求后需要以0.1秒为间隔进行闪烁,对于LED再定义几个标志变量,当达到要求后,标志变量置1,在定时器里对LED进行开关处理。
bit relay;
bit flag_L3;
bit flag_L1;
bit flag_L2;
/***************继电器处理******************/
void RelayPro()
{
if(relay_setup==1) //温度控制
{
if(temp_get>(temp_setup))
{
InitHC138(5);
P0=0X10;
relay=1;
}
else
{
InitHC138(5);
P0=0X00;
relay=0;
}
}
else if(relay_setup==0) //时间控制
{
InitHC138(5);
P0=0X00;
relay=0;
if(TIME[1]==0)
{
InitHC138(5);
P0=0X10;
relay=1;
}
if((TIME[1]==0)&&(TIME[0]>5))
{
InitHC138(5);
P0=0X00;
relay=0;
}
}
}
/***************led处理******************/
void LedPro()
{
if((TIME[1]==0)&&(TIME[0]<5))
{
flag_L1 = 1;
}
else if((TIME[1]==0)&&(TIME[0]>5))
{
flag_L1 = 0;
}
if(relay_setup==1)
{
InitHC138(4);
P0=0XFF;
L2=0;
}
else if(relay_setup==0)
{
InitHC138(4);
P0=0XFF;
L2=1;
}
if(relay==1)
{
flag_L3=1;
}
else if(relay==0)
{
flag_L3=0;
}
}
/***************定时器中断******************/
void Time0Init()
{
TMOD|=0X01;
TL0 = 0x18; //设置定时初值1ms
TH0 = 0xFC;
ET0=1;
TR0=1;
EA=1;
}
void Time0() interrupt 1
{
u16 count_ms;
TL0 = 0x18; //设置定时初值1ms
TH0 = 0xFC;
if(flag_L3==1)
{
count_ms++;
if(count_ms==100)
{
InitHC138(4);
P0=0XFF;
L3=~L3;
count_ms=0;
}
}
if(flag_L1 == 1)
{
L1=0;
}
}所有的代码完成之后,我们把需要用到的函数放进主函数里就可以了,要记得上电演示一遍哦:
void main()
{
InitHC573();
Time0Init();
Init_DS1302();
while(1)
{
readtime();
TempGet1();
KeyScan();
KeyPro();
DisplayDat();
RelayPro();
LedPro();
}
}好了,今天的分享到这里就结束了,感谢大家o(* ̄▽ ̄*)ブ。
我要赚赏金
