第六届省赛-温度记录器
用了两个定时器,DS1302,DS18B20。学小蜜蜂的教程,代码相似。
/* 数码管末位过亮,用定时器解决。经测试,1ms较好,末位过亮不明显,
温度采集好像又出了点问题
*/
#include <REG52.H>
#include "ds1302.h"
#include <onewire.h>
typedef unsigned char u8;
typedef unsigned int u16;
u8 SMGtab[10] = {0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90};
u8 Read_RTC_addr[8] = {0x81,0x83,0x85,0x87,0x89,0x8b,0x8d,0x8f};
u8 Write_RTC_addr[8] = {0x80,0x82,0x84,0x86,0x88,0x8a,0x8c,0x8e};
u8 RTC_TimeData[7] = {0x50,0x59,0x23,0x00,0x00,0x00,0x00};
//秒, 分, 时, 日, 月, 周, 年
u16 temperature_Tab[10] = {0};
sfr AUXR=0x8e; //定义特殊功能寄存器
sbit S4 = P3^3;
sbit S5 = P3^2;
sbit S6 = P3^1;
sbit S7 = P3^0;
sbit L1 = P0^0;
void Delay(u16 t)
{
while(t--);
}
void SelectChannel(u8 Channel)
{
switch (Channel)
{
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; //选通数码管段选
default:P2 &= 0x1f;break; //都不选通
}
}
void SystemInit() //初始化
{
SelectChannel(5);P0 &= 0xBF; //关闭蜂鸣器,开启为P0 |= 0x40;
SelectChannel(5);P0 &= 0xEF; //关闭继电器,开启为P0 |= 0x10;
SelectChannel(4);P0 = 0xFF; //关闭LED
}
void Timer0Init(void) //10毫秒@11.0592MHz
{
AUXR &= 0x7F; //定时器时钟12T模式
TMOD &= 0xF0; //设置定时器模式
TMOD |= 0x01; //设置定时器模式
TL0 = 0x00; //设置定时初始值
TH0 = 0xDC; //设置定时初始值
TF0 = 0; //清除TF0标志
TR0 = 0; //定时器0不计时
EA = 1;
ET0 = 1;
}
void Timer1Init(void) //1毫秒@11.0592MHz
{
// AUXR &= 0x7F; //定时器时钟12T模式
TMOD &= 0x0F; //设置定时器模式
TMOD |= 0x10; //设置定时器模式
TL1 = 0x66; //设置定时初始值
TH1 = 0xFC; //设置定时初始值
TF1 = 0; //清除TF1标志
TR1 = 1; //定时器1计时
// EA = 1;
ET1 = 1;
}
/*********************独立按键开始*********************/
u8 flag_time=0; //时间切换标志位 0,1,2,3,4
u8 flag_interface=0;//界面切换标志位 0:计时时间 1:RTC时钟 2:读取温度
u16 sec=0; //采集间隔 0,1,5,30,60
u8 temperature_bit=0;
void BTN() //独立按键
{
if(S4==0 && flag_interface==0) //切换计时时间
{
Delay(100); //延时消抖
if(S4==0)
{
flag_interface = 0;
flag_time++;
if(flag_time>4)
flag_time=1;
switch (flag_time)
{
case 1:sec=1;break;
case 2:sec=5;break;
case 3:sec=30;break;
case 4:sec=60;break;
default:sec=0;break;
}
while(S4==0); //按下时停在这里,防止按一次键多次触发该函数
}
}
if(S5==0 && flag_interface==0) //确认并显示RTC,开始采集温度
{
Delay(100);
if(S5==0)
{
flag_interface = 1;
TR0 = 1; //定时器0开始计时
while(S5==0);
}
}
if(S6==0 && flag_interface!=0) //L1熄灭
{
Delay(100);
if(S6==0)
{
temperature_bit++;
if(temperature_bit > 9)
{
temperature_bit = 0;
}
flag_interface = 2;
TR0 = 0; //定时器0停止计时
P0=0xff;
SelectChannel(4);
while(S6==0);
}
}
if(S7==0 && flag_interface==2) //返回采集间隔界面,用于下一次采集
{
Delay(100);
if(S7==0)
{
flag_interface = 0;
while(S5==0);
}
}
}
/*********************独立按键结束*********************/
/*********************DS1302开始*********************/
u8 i;
void DS1302_Init()
{
Write_Ds1302_Byte(Write_RTC_addr[7],0x00 ); //(0x8e,0x00)关闭写保护
for(i=0;i<6;i++)
{
Write_Ds1302_Byte(Write_RTC_addr[i],RTC_TimeData[i] );
}
Write_Ds1302_Byte(Write_RTC_addr[7],0x80 ); //(0x8e,0x80)开启写保护
}
void DS1302_Read()
{
for(i=0;i<6;i++)
{
RTC_TimeData[i] = Read_Ds1302_Byte (Read_RTC_addr[i]);
}
}
/*********************DS1302结束*********************/
/*********************DS18B20开始*********************/
u16 temperature;
void Read_DS18B20_temperature()
{
u8 LSB,MSB;
init_ds18b20();
Write_DS18B20(0xcc);
Write_DS18B20(0x44);
Delay(1000);
init_ds18b20();
Write_DS18B20(0xcc);
Write_DS18B20(0xBE);
LSB = Read_DS18B20();
MSB = Read_DS18B20();
init_ds18b20();
temperature = MSB;
temperature = (temperature << 8) | LSB;
if((temperature & 0xf800) == 0x0000)
{
temperature >>= 4;
temperature = temperature*10;
temperature = temperature + (LSB & 0x0f) * 0.625; //小数部分转化为浮点数,右移四位,*10,再转换为整型加到温度上
}
}
/*********************DS18B20结束*********************/
/*********************数码管开始*********************/
bit flag_BlinkBar=1; //数码管“-”闪烁标志位
void SMGbit(u8 n,u8 value)
{
SelectChannel(6);P0 = 0x01<<n; //位选
SelectChannel(7);P0 = value; //段选
Delay(500); //消影
}
void SMG_Time()
{
if(flag_interface == 0) //采集间隔时间显示
{
SMGbit(5,0xBF); //-
SMGbit(6,SMGtab[sec/10]); //sec十位
SMGbit(7,SMGtab[sec%10]); //sec个位
}
if(flag_interface == 1) //RTC时钟
{
SMGbit(0,SMGtab[RTC_TimeData[2] >> 4]); //hour十位
SMGbit(1,SMGtab[RTC_TimeData[2] & 0x0f]); //hour个位
if(flag_BlinkBar == 1)
{
SMGbit(2,0xBF); //“-”
}
else
{
SMGbit(2,0xFF); //灭
}
SMGbit(3,SMGtab[RTC_TimeData[1] >> 4]); //min十位
SMGbit(4,SMGtab[RTC_TimeData[1] & 0x0f]); //min个位
if(flag_BlinkBar == 1)
{
SMGbit(5,0xBF); //“-”
}
else
{
SMGbit(5,0xFF); //灭
}
SMGbit(6,SMGtab[RTC_TimeData[0] >> 4]); //sec十位
SMGbit(7,SMGtab[RTC_TimeData[0] & 0x0f]); //sec个位
}
if(flag_interface == 2)
{
SMGbit(0,0xBF); //“-”
SMGbit(1,SMGtab[temperature_bit/10]);
SMGbit(2,SMGtab[temperature_bit%10]);
SMGbit(5,0xBF); //“-”
SMGbit(6,SMGtab[(temperature_Tab[temperature_bit]/100)%10]); //温度十位
SMGbit(7,SMGtab[(temperature_Tab[temperature_bit]/10)%10]); //温度个位
}
}
/*********************数码管结束*********************/
void main()
{
SystemInit();
Timer0Init();
Timer1Init();
DS1302_Init();
while(1)
{
BTN();
DS1302_Read();
Read_DS18B20_temperature();
}
}
u16 count; //定时器计数,每10ms加一,以达到预定时间
bit flagLED=1; //LED亮灭标志位。这样更严谨,因为L1=~L1;有时候会有问题。
void Timer0Int() interrupt 1 //定时器0中断每10ms执行一次该函数
{
count++;
if(count%50 == 0) //if(count == 50)这种写法不是每0.5s执行一次,应该写成if(count%50 == 0)
{
flag_BlinkBar = ~flag_BlinkBar;
}
if(count == 100 && sec > 0)
{
count=0;
sec--;
for(i=0;i<10;i++)
{
temperature_Tab[i] = temperature;
}
}
if(count == 50 && sec == 0)
{
count=0;
P0=0xff;
SelectChannel(4);
flagLED=~flagLED;
L1=flagLED;
}
TL0 = 0x00; //设置定时初始值
TH0 = 0xDC; //设置定时初始值
}
void Timer1Int() interrupt 3 //定时器1中断每1ms执行一次该函数
{
SMG_Time();
TL1 = 0x66; //设置定时初始值 //经测试,1ms较好
TH1 = 0xFC; //设置定时初始值
}