本帖最后由 凌净清河 于 2018-7-24 08:38 编辑
本作品采用STC15F104W单片机和四位共阴极数码管设计
主要亮点:
1.数码管使用74HC595作为段选驱动,为初学者提供了新的思路
次要亮点:
1.使用小巧的STC15F104W单片机
DS18B20的通信要点在于时序的严格对应,相比之下DHT11这一类的单总线通信时序要求更加宽松。
因为DS18B20算是极为常用的学习器件,故不做过多讲解,本次作品不涉及搜索BOM、精度调节等操作,只是单器件读取温度值,数据处理将可以显示的温度值设置为-20℃~80℃。
(事实证明不同器件之间会有差异,读取的值也会不尽相同)
DS18B20数据处理参考普中科技相关例程

#include<STC15.H>
sbit DSPORT=P3^5;//DS18B20管脚定义
#include<intrins.h>
#include"DS18B20.c"
sbit S1=P3^4;
sbit S2=P3^3;//数码管位选管脚定义
sbit SER=P3^0;
sbit RCLK=P3^1;
sbit SRCLK=P3^2;//74HC595管脚定义
//全局变量表
unsigned char code smgduan[10]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};//给74HC595的段选值
unsigned char Display_Temperature[4]={0x40,0x40,0x40,0x40};
int Data_temperature=0;
unsigned char t0_cnt=0;
/*##############################################################################################
设计名称:基于DS18B20的数显温度计
设计者:清河
平台:STC15F104W
硬件部分
数码管显示:位选使用74HC138改为2-4线译码、段选使用74HC595减少IO口使用
使用4位共阴极数码管,显示无符号位
注意:由于STC15系列采用Y5内核,所以有关DS18B20精准延时部分在移植时应首先考虑更换
##############################################################################################*/
void delay(unsigned int cnt)//调用该函数进行一段时间的延时
{
while(cnt--);
}
void hc595send(unsigned char dat)//使用SPI向74HC595发送一个字节的数据
{
unsigned char a;
SRCLK=0;
RCLK=0;
for(a=0;a<8;a++)
{
SER=dat>>7;
dat<<=1;
SRCLK=1;
_nop_();
_nop_();
SRCLK=0;
}
RCLK=1;
_nop_();
_nop_();
RCLK=0;
}
void smgdisplay()//数码管显示函数,参数为需要显示的数组
{
unsigned char i;
for(i=0;i<4;i++)
{
switch(i)//位选,选择点亮的数码管
{
case(0):
S1=0;S2=1; break;
case(1):
S1=1;S2=0; break;
case(2):
S1=0;S2=0; break;
case(3):
S1=1;S2=1; break;
}
hc595send(Display_Temperature);
delay(10); //间隔一段时间扫描
hc595send(0x00);//消隐
}
}
void Data_processing()
{
float temperature=0.0;//【03c4】似乎只是一个用于更改值为float类型的中间变量,考虑删去
int temperature_middle;//为了不更改全局变量中读取出来的Data_temperature设置此中转值
if(Data_temperature>0xf000)//当温度值为负数
{
Display_Temperature[0]=0x40;//显示符号“-”的段码
//因为读取的温度是实际温度的补码,所以减1,再取反求出原码
temperature_middle=Data_temperature-1;
temperature_middle=~temperature_middle;
temperature=temperature_middle;
temperature_middle=temperature*0.0625*100+0.5;
//留两个小数点就*100,+0.5是四舍五入,因为C语言浮点数转换为整型的时候把小数点
//后面的数自动去掉,不管是否大于0.5,而+0.5之后大于0.5的就是进1了,小于0.5的就
//算加上0.5,还是在小数点后面。
if(temperature_middle<2000)
{
if(temperature_middle>=1000)
{
Display_Temperature[1]=smgduan[temperature_middle%10000/1000];
Display_Temperature[2]=smgduan[temperature_middle%1000/100]|0x80;
Display_Temperature[3]=smgduan[temperature_middle%100/10];
}
else
{
Display_Temperature[1]=smgduan[temperature_middle%1000/100]|0x80;
Display_Temperature[2]=smgduan[temperature_middle%100/10];
Display_Temperature[3]=smgduan[temperature_middle%10];
}
}
else
{
unsigned char i;
for(i=0;i<4;i++)
{
Display_Temperature=0x40;
}
}
}
else
{
temperature=Data_temperature;//因为数据处理有小数点所以将温度赋给一个浮点型变量
//如果温度是正的那么,那么正数的原码就是补码它本身
temperature_middle=(int)(temperature*0.0625*100+0.5);
//留两个小数点就*100,+0.5是四舍五入,因为C语言浮点数转换为整型的时候把小数点
//后面的数自动去掉,不管是否大于0.5,而+0.5之后大于0.5的就是进1了,小于0.5的就
//算加上0.5,还是在小数点后面。
if(temperature_middle<8000)
{
if(temperature_middle>=1000)
{
Display_Temperature[0]=smgduan[temperature_middle%10000/1000];
Display_Temperature[1]=smgduan[temperature_middle%1000/100]|0x80;
Display_Temperature[2]=smgduan[temperature_middle%100/10];
Display_Temperature[3]=smgduan[temperature_middle%10];
}
else
{
Display_Temperature[0]=0x00;
Display_Temperature[1]=smgduan[temperature_middle/100]|0x80;
Display_Temperature[2]=smgduan[temperature_middle%100/10];
Display_Temperature[3]=smgduan[temperature_middle%10];
}
}
else
{
unsigned char i;
for(i=0;i<4;i++)
{
Display_Temperature=0x40;
}
}
}
}
void sys_init()
{
TH0=0;
TL0=0;
ET0=1;
TR0=1;
EA=1;
}
void main()
{
sys_init();
while(1)
{
smgdisplay();
}
}
void Temperature_Refresh() interrupt 1
{
TL0 = 0x00;
TH0 = 0x28;//5ms初值
if(t0_cnt==10)
{
hc595send(0x00);
Data_temperature=DS18B20_GetTemperature();
Data_processing();
t0_cnt=0;
}
else
{
t0_cnt++;
}
}
由于中断时的数据读取和处理会占用一部分时间,导致数码管有轻微闪烁感,使用者可以考虑将转换精度调为最低并修改转换等待时间以减少数码管的闪烁感,同时别忘记调一下数据处理函数中对应的精度值。
上述程序仍然臃肿,但由于是普通器件的使用,没有难点,所以也没有进行优化,以完成功能为目的。
新矿城学习基地 凌净清河
|