第三届蓝桥杯单片机类温度监控器
题目要求
要实现温度监控可以将功能模块化,
前期准备
头文件、管脚定义、全局变量定义、函数声明
#include<STC15F2K60S2.H>
#include"Delay.h"
#include"SelectHC573.h"
#include"Disp_SMG.h"
#include"onewire.h"
#include "iic.h"
sbit S7=P3^0;//按键
sbit S6=P3^1;
sbit S5=P3^2;
sbit S4=P3^3;
sbit L1=P0^0;//LED
sbit L2=P0^2;
sbit J=P0^4;//继电器
unsigned char SMG_DM[18]={
0xc0,0xf9,0xa4,0xb0,0x99,0x92,
0x82,0xf8,0x80,0x90,0x88,0x80,
0xc6,0xc0,0x86,0x8e,0xbf,0x7f
};
unsigned int temp=0;//温度
unsigned char max=30;//上限
unsigned char min=20;//下限
char a=1;//存储数据控制位
void Dsip();
void All_Init();
锁存器选择函数
//=================================
//函 数 名:锁存器选择函数
//功 能:将选择的锁存器打开
//输入参数:所选择的锁存器
//输出参数:无
void SelectHC573(unsigned char n)
{
switch(n)
{
case 0:P2=P2&0x1f;break; //将打开的锁存器关闭
case 4:P2=P2&0x1f|0x80;break; //打开LED相关的锁存器
case 5:P2=P2&0x1f|0xa0;break; //蜂鸣器、继电器相关的锁存器
case 6:P2=P2&0x1f|0xc0;break; //数码管位选
case 7:P2=P2&0x1f|0xe0;break; //数码管段选
}
}
外设关闭函数
//========================
//函数名:外设初始化函数
//功能:关闭外设
//输入参数:无
//输出参数:无
//========================
void All_Init()
{
SelectHC573(4);
P0=0xff;//熄灭LED数据
SelectHC573(0);
SelectHC573(5);
P0=0x00;//熄灭蜂鸣器、继电器数据
SelectHC573(0);
}
延时函数
//======================
//函数名:延时函数
//功能:延时
//输入参数:延时大小
//输出参数:无
void Delay(unsigned char t)
{
while(t--);
}
功能实现
功能一数码管显示
//======================
//函数名:数码管显示函数
//功能:传入参数,让数码管显示
//输入参数:要显示的数据,和要显示的位置
//输出参数:无
//========================
void Disp_SMG(unsigned char dat,unsigned char pos)
{
SelectHC573(6);
P0=0x01<<pos;//要显示的位置
SelectHC573(7);
P0=dat;//要显示的数据
}
下面这段代码实现了题目中的要求
//========================
//函数名:显示
//功能:将要显示的数据放在一个函数中
//输入参数:无
//输出参数:无
//========================
void Dsip()
{
Disp_SMG(SMG_DM[max/10],0);
Delay(100);
Disp_SMG(SMG_DM[max%10],1);
Delay(100);
Disp_SMG(SMG_DM[min/10],2);
Delay(100);
Disp_SMG(SMG_DM[min%10],3);
Delay(100);
Disp_SMG(0xff,4);
Delay(100);
Disp_SMG(0xff,5);
Delay(100);
Disp_SMG(SMG_DM[temp/10],6);
Delay(100);
Disp_SMG(SMG_DM[temp%10],7);
Delay(100);
}
效果是这样的
功能二温度获取
要实现此功能需要ds18b20数字芯片获取,
#include "onewire.h"
//单总线延时函数
void Delay_OneWire(unsigned int t)
{
while(t--);
}
//DS18B20初始化
bit Init_DS18B20(void)
{
bit initflag = 0;
DQ = 1;
Delay_OneWire(144);
DQ = 0;
Delay_OneWire(960);
DQ = 1;
Delay_OneWire(120);
initflag = DQ;
Delay_OneWire(60);
return initflag;
}
//通过单总线写一个字节
void Write_DS18B20(unsigned char dat)
{
unsigned char i;
for(i=0;i<8;i++)
{
DQ = 0;
DQ = dat&0x01;
Delay_OneWire(60);
DQ = 1;
dat >>= 1;
}
Delay_OneWire(60);
}
//读一个字节
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(60);
}
return dat;
}
上述代码考试当天会提供,我们只需要自己进行修改即可,(上面的代码是修改过的)比赛所提供的文件中onewire.h中没有声明函数,需要自己进行声明
比赛当天提供的代码是1Hz的,将onewire.c中所有延时函数扩大12倍即可成为12Hz的
温度获取
void Delay_wd(unsigned int t)
{
while(t--)
{
Dsip();
}
}
//========================
//函数名:温度获取函数
//功能:获取温度给全局变量temp
//输入参数:无
//输出参数:无
//========================
void Ds18B20_temp()
{
unsigned int LSB,MSB;//温度数据
Init_DS18B20();//初始化
Write_DS18B20(0xcc);//跳过ROM指令
Write_DS18B20(0x44);//开始温度转换
Delay_wd(1000);//稍微延时一下
Init_DS18B20();//初始化
Write_DS18B20(0xcc);//跳过ROM指令
Write_DS18B20(0xbe);//读取高速缓存
LSB=Read_DS18B20();//读取低8位
MSB=Read_DS18B20();//读取高8位
Init_DS18B20();//初始化
temp=MSB;
temp=(temp<<8)|LSB;//高8位左移,低四位赋给temp
temp>>=4;//去掉小数位
}
注意:不要将高位和低位弄反了,不然读出来的数据是错误的
功能三按键实现
这个功能很好实现,定义两个全局变量max\min为上下限温度,当按键按下时数值改变,并且将数值保存在AT24C02中。
void Key()
{
if(S7==0)
{
Delay(10);
if(S7==0)
{
min--;
a=0;//全局变量,为实现功能四而设定
}
}
if(S6==0)
{
Delay(10);
if(S6==0)
{
max--;
a=0;
}
}
if(S5==0)
{
Delay(10);
if(S5==0)
{
min++;
a=0;
}
}
if(S4==0)
{
Delay(10);
if(S4==0)
{
max++;
a=0;
}
}
if(a==0)//功能四的部分实现
{
Write_24c02(0x00,max);//向e2prom写入温度上限
Delay(2000);
Write_24c02(0x01,min);//写入温度下限
a=2;
}
}
功能四将数据保存在AT24C02中
#include "iic.h"
void IIC_Start(void)
{
SDA = 1;
SCL = 1;
somenop;
SDA = 0;
somenop;
SCL = 0;
}
void IIC_Stop(void)
{
SDA = 0;
SCL = 1;
somenop;
SDA = 1;
}
void IIC_Ack(unsigned char ackbit)
{
if(ackbit)
{
SDA = 0;
}
else
{
SDA = 1;
}
somenop;
SCL = 1;
somenop;
SCL = 0;
SDA = 1;
somenop;
}
bit IIC_WaitAck(void)
{
SDA = 1;
somenop;
SCL = 1;
somenop;
if(SDA)
{
SCL = 0;
IIC_Stop();
return 0;
}
else
{
SCL = 0;
return 1;
}
}
void IIC_SendByte(unsigned char byt)
{
unsigned char i;
for(i=0;i<8;i++)
{
if(byt&0x80)
{
SDA = 1;
}
else
{
SDA = 0;
}
somenop;
SCL = 1;
byt <<= 1;
somenop;
SCL = 0;
}
}
unsigned char IIC_RecByte(void)
{
unsigned char da;
unsigned char i;
for(i=0;i<8;i++)
{
SCL = 1;
somenop;
da <<= 1;
if(SDA)
da |= 0x01;
SCL = 0;
somenop;
}
return da;
}
这些代码比赛当天都会提供,需要自己看手册来实现功能就行,我们要写的代码是下面的部分
void Write_24c02(unsigned char seat,unsigned char dat)
{
IIC_Start();
IIC_SendByte(0xa0);
IIC_WaitAck();
IIC_SendByte(seat);
IIC_WaitAck();
IIC_SendByte(dat);
IIC_WaitAck();
IIC_Stop();
}
//========================
//========================
void EEPROM_Read(unsigned char* pucBuf,unsigned char addr,
unsigned char num)
{
IIC_Start();
IIC_SendByte(0xa0);
IIC_WaitAck();
IIC_SendByte(addr);
IIC_WaitAck();
IIC_Start();
IIC_SendByte(0xa1);
IIC_WaitAck();
while(num--)
{
*pucBuf++ = IIC_RecByte();
if(num)
IIC_Ack(0);
else IIC_Ack(0);
}
IIC_Stop();
}
其实本质就是时序图,大概总结了一下,写入数据的如下
启动总线-----发送设备地址+写-----等待应答-----发送数据的储存地址(0x00-0xFF,256个字节)-----等待应答-----发送数据-----等待应答-----停止总线
读入数据如下
启动总线-----发送设备地址+写-----等待应答-----发送数据存储地址-----等待应答-----发送设备地址+读-----等待应答-----读取数据-----主机发送是否应答……
功能五、六
自己现在没有一个直流电机,就用L1、L2d代替超过上限时工作和不工作
void Elect()
{
if(temp<min)
{
All_Init();
SelectHC573(5);
J=1;
}
else
{
All_Init();
SelectHC573(5);
J=0;
}
if(temp>max)
{
SelectHC573(4);
P0=0xfd;
}
else
{
SelectHC573(4);
P0=0xfe;
}
}
主函数
void main()
{
All_Init();
EEPROM_Read(&max,0x00,1);//读取温度上下限
EEPROM_Read(&min,0x01,1);
while(1)
{
Elect();
Key();
Dsip();
Ds18B20_temp();
}
}
具体文件
链接:https://pan.baidu.com/s/1pRPqaDrWomakjsXBSTjPgA
提取码:qwer