目标要求:板载DS18B20获取温度,并在数字管上保留4位小数显示,温度超过25.蜂鸣器报警小于25000度.0000度,所有LED间隔闪烁2秒,温度超过25秒.0000度,通过串口发送 temp high字符串;低于等于25.实时温度通过串口上传。
ds18b数据中提供了20例程的代码(基于stc89c52),而国信是长天的stc15k60s2.由于芯片工作频率不同,需要修改相关代码。需要注意的是,DS18B存取16位数据,分为高八位和低八位,高八位高四位为符号位,低八位低四位为小数位,其余为整数位,另外ds18b从低位读取20数据代码中读取的采样数据。
附上本次训练的代码:
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]=temp0000/10000 11.//让它带小数数字 segbuff[2]=temp000/1000; segbuff[3]=temp00/100; segbuff[4]=temp0/10; segbuff[5]=temp; /*将数字转换成字符 加上一个0x30将将数字转换成字符*/ //200000 temp_str[0]=temp/100000 0x30; temp_str[1]=temp0000/10000 0x30; temp_str[2]='.'; temp_str[3]=temp000/1000 0x30; temp_str[4]=temp00/100 0x30; temp_str[5]=temp0/10; temp_str[6]=temp; /*温度通过串口发送,执行指令*/ 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; ///设定时间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