国信长天单片机竞赛训练之DS18B20温度报警实验(三)

        目标要求:通过板载的DS18B20获取温度,并在数码管上保留4位小数显示,温度超过25.0000度,蜂鸣器报警;低于等于25.0000度,所有LED间隔2秒闪烁;温度超过25.0000度,通过串口发送“ temp high”字符串;低于等于25.0000,通过串口上传实时温度。

ds18b20例程的代码在资料中有提供(基于stc89c52的),而国信长天的则是stc15k60s2,由于芯片工作频率不同需要在相关代码上做些修改,需要注意的是DS18B20是存取16位数据,分为高八位和低八位,高八位的高四位为符号位,低八位的低四位是小数位,其余为为整数位,另外ds18b20的资料代码中读取采样的数据是从低位开始读取。

附上本次训练的代码:

main.c文件

#include <STC15F2K60S2.h>
#include "onewire.h"
#include "uart.h"
#include "time.h"
#include "seg.h"

static bit flag=1;
static bit flag2=1;//灯是否翻转的标志
unsigned int count=0;//计数
void Init_all(void);
#define ON  1
#define OFF 0

 
sbit relay =P0^4;
sbit buzzer=P0^6;
void buff(bit sw ){//蜂鸣器控制
	if(sw){
		
		P2=(P2&0x1f)|0xa0;//开蜂鸣器  1010 
		buzzer=1;relay=1;
		P2&=0x1f;
	}
	else {
		P2=(P2&0x1f)|0xa0;//关蜂鸣器  
		buzzer=0;relay=0;
		P2&=0x1f;
	}	
}
void led(bit sw){//led toggle
	if(sw){
	if(flag){
		 
		P2=(P2&0x1f)|0x80;
		P0=0x00;
		P2=(P2&0x1f); 
		flag=0;
	}
	else {
		 flag=1;
		P2=(P2&0x1f)|0x80;
		P0=0xff;
		P2=(P2&0x1f);
	}
}

else{
	P2=(P2&0x1f)|0x80;
		P0=0xff;
		P2=(P2&0x1f);//关led灯
}
}

void alarm(float temp,char *temp_str){//温度报警函数
	
	if(temp>25.0000){
		buff(ON);//开蜂鸣器
		led(OFF);//关灯
		flag2=1;
		send_string("temp high!\r\n");//串口发送高温 high temp
	 
	}
	else if(temp<25.0000){
		flag2=0;
		buff(OFF);//关蜂鸣器
		
		send_string(temp_str);//上传实时温度
		send_string("\r\n");
	}
	
}
void main(void)
{
	float temperature=0.0;
	unsigned  long temp=0;
	unsigned char temp_str[8]="\0";
	Init_all();
	Timer0Init();
	UartInit();//初始化串口的发送函数
	while (1)
	{
		/*显示温度保留2位小数通过数码管显示*/
		temperature=rd_temperature();
		temp=temperature*10000;//123456
		segbuff[0]=temp/100000;
		segbuff[1]=temp%100000/10000 + 11;//使其带上小数
		segbuff[2]=temp%10000/1000;
		segbuff[3]=temp%1000/100;
		segbuff[4]=temp%100/10;
		segbuff[5]=temp%10;
		
		/*数字转换成字符   加上一个0x30将数字转换成字符*/
																							//200000
		temp_str[0]=temp/100000+0x30;
		temp_str[1]=temp%100000/10000+0x30;
		temp_str[2]='.';
		temp_str[3]=temp%10000/1000+0x30;
		temp_str[4]=temp%1000/100+0x30;
		temp_str[5]=temp%100/10;
		temp_str[6]=temp%10;
		/*通过串口发送温度,执行指令*/
		 
		
		alarm(temperature,temp_str);
		
	}
	
}

void time0() interrupt 1 /*根据初始设置,1毫秒执行一次*/
{
	segplay();
	  
 if(!flag2){
		count++;	 
		if(count==2000){
		 led(ON);
			count=0; 
		}
	 
}
}

 
void Init_all(void)
{
	P2=0xa0;//关闭蜂鸣器继电器
	P0=0x00;
	
	P2=0x80;//关闭LED
	P0=0xff;
}


time.c

#include "time.h"

 
void Timer0Init(void) //1毫秒@11.0592MHz
{
	AUXR |= 0x80; //定时器时钟1T模式
	TMOD &= 0xF0; //设置定时器模式 16位自动重载
	TL0 = 0xCD;	  //设置定时初值
	TH0 = 0xD4;	  //设置定时初值
	TF0 = 0;	  //清除TF0标志
	TR0 = 1;	  //定时器0开始计时
	ET0 = 1;
	EA = 1; //这两个启动一定要加,否则不生效
}

onewire.c

#include "onewire.h"

 
void Delay_OneWire(unsigned int t)
{
	/*传统8051单片机是12T,而15单片机是1T,理论上应该扩大延时为12倍,实际上8-12倍都可以*/
	unsigned char i;
	while (t--)
	{
		for (i = 0; i < 8; i++)
			;
	}
}

 
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);
}

 
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;
}

 
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;
}

 
float rd_temperature(void)
{
	unsigned char low,high;/*用来存暂存器的值*/
	unsigned int temp;/*取整数*/
	float result;
	init_ds18b20();
	Write_DS18B20(0xcc);/*跳过rom搜索*/
	Write_DS18B20(0x44);/*开启温度转换*/
	
init_ds18b20();
Write_DS18B20(0xcc);/*跳过rom搜索*/
Write_DS18B20(0xbe);/*告诉总线准备读取暂存器*/
	
		//DS18B20 16位 高八位的低四位和低八位的高四位为整数
	low=Read_DS18B20();//低八位
		high=Read_DS18B20();//高八位
	temp =(high&0x0f);
	temp<<=8;
	temp|=low;
	result =temp*0.0625;	
	return result;
	
	
	
	
	
	
}

uart.c

#include "uart.h"

unsigned char xdata com0_buf[32];
unsigned char com0cnt = 0;

 
void UartInit(void) //9600bps@11.0592MHz
{
	SCON = 0x50;		//8位数据,可变波特率
	AUXR |= 0x40;		//定时器1时钟为Fosc,即1T
	AUXR &= 0xFE;		//串口1选择定时器1为波特率发生器
	TMOD &= 0x0F;		//设定定时器1为16位自动重装方式
	TL1 = 0xE0;		//设定定时初值
	TH1 = 0xFE;		//设定定时初值
	ET1 = 0;		//禁止定时器1中断
	TR1 = 1;		//启动定时器1
	
	
}

 
void send_char(unsigned char chr)
{

	
		SBUF=chr;/*没有完成TI=0 完成以后TI=1 单片机自动置1*/
		while(!TI);
		TI=0;
	
}

 
void send_string(unsigned char *str)//发送字符串
{
while(*str)
{
	send_char(*str);
	str++;
}
	
}

time.c

#include "time.h"

 
void Timer0Init(void) //1毫秒@11.0592MHz
{
	AUXR |= 0x80; //定时器时钟1T模式
	TMOD &= 0xF0; //设置定时器模式 16位自动重载
	TL0 = 0xCD;	  //设置定时初值
	TH0 = 0xD4;	  //设置定时初值
	TF0 = 0;	  //清除TF0标志
	TR0 = 1;	  //定时器0开始计时
	ET0 = 1;
	EA = 1; //这两个启动一定要加,否则不生效
}

seg.c

#include "seg.h"

unsigned char code segtab[] = {0xc0, 0xf9, 0xa4, 0xb0, 0x99, 0x92, 0x82, 0xf8, 0x80, 0x90, 0xff, 0xc0 & 0x7f, 0xf9 & 0x7f, 0xa4 & 0x7f, 0xb0 & 0x7f, 0x99 & 0x7f, 0x92 & 0x7f, 0x82 & 0x7f, 0xf8 & 0x7f, 0x80 & 0x7f, 0x90 & 0x7f,0x7f}; //共阳极7段数码管数据编码,自己可以加一些特殊符号,注意每个符号在数组中的位置
unsigned char segbuff[] = {10, 10, 10, 10, 10, 10, 10, 10};																																											//显示的数据,加一级缓存的好处是更新数据时只要改此缓存,定时刷新会自动将数据输出
unsigned char segaddr = 0;

 
void segplay(void)
{
	P2 = (P2 & 0x1f) | 0xe0; //消影
	P0 = 0xff;
	P2 &= 0x1f;

	P2 = (P2 & 0x1f) | 0xc0; //选管
	P0 = 1 << segaddr;
	P2 &= 0x1f;

	P2 = (P2 & 0x1f) | 0xe0; //送选中管子数据
	P0 = segtab[segbuff[segaddr]];
	P2 &= 0x1f;

	if (++segaddr == 8)
		segaddr = 0;
}

       最后附上工程的下载链接:

链接:https://pan.baidu.com/s/1_JT0biT4lbQoT9SE0M_Kig 
提取码:yzh1

posted @   昊月光华  阅读(21)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?
点击右上角即可分享
微信分享提示