题目
读取ds18b20温度数据需要较长时间,逻辑分析仪观察读取一次温度(两字节)大概需要13毫秒,因此温度读取不能放在定时器中断,这会严重影响定时精度,导致数码管剧烈闪烁、计时错误等。另外,将温度读取放在主函数会发现温度指示灯L2在显示温度时,数码管和L2每隔一段时间会同时闪一下。这是因为主函数读取温度数据(16位)可能会被定时器中断,就比如读到第5位温度数据时产生中断,这时将执行中断函数,而执行完中断函数需要一定时间,后面几位温度数据据继续输出,MCU会错过读取这段数据,导致数据读取丢失,因此即使温度不变,读取的温度数据也会变化。
解决的办法有两个,一是判断读取的温度数据是否在正常范围内,一般在0-40度之间(乘了10,方便显示小数,因此40度为400),再改变主函数中温度值代码如下:
temp = TemperGet( );
if(temp > 0 && temp < 400) //降低 因中断导致的数据接收错误 的概率
tempr = temp; //tempr为要显示处理的温度值,是个全局变量。
这一方法可以明显降低L2和数码管闪烁概率,但是仍然可能出现闪烁现象;二是换一个高速温度传感器,比如LM75A这样的IIC接口温度传感器,这样就可以将温度读取的函数放在中断函数里,避免读取数据时被打断。
main.c
#include<stc15f2k60s2.h>
#include "intrins.h"
#define uchar unsigned char
#define uint unsigned int
#define s0 0
#define s1 1
#define s2 2
char * get_ds1302();
void ds1302_init(char *time);
int TemperGet( );
int read_vol( );
uchar semg[15] = {0xc0, 0xf9, 0xa4, 0xb0, 0x99, 0x92, 0x82, 0xf8, 0x80, 0x90,
0x86, 0xc6, 0x8c, 0xff, 0xbf};
uchar semg_bit[8] = {0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80};
uchar semg_temp[8] = {13, 13, 13, 13, 13, 13, 13, 13};
uchar state = s0;
uchar state_data = s0;
uchar state_para = s0;
char time[3] = {16, 59, 50};
int tempr = 201;
uchar bri;
int vol = 100;
char hour_para =17;
char tempr_para = 25;
char led_para = 4;
void Delay5ms() //@11.0592MHz
{
unsigned char i, j;
i = 54;
j = 199;
do
{
while (--j);
} while (--i);
}
void Timer0Init(void) //2毫秒@12.000MHz
{
AUXR |= 0x80; //定时器时钟12T模式
TMOD &= 0xF0; //设置定时器模式
TL0 = 0x40; //设置定时初值
TH0 = 0xA2; //设置定时初值
TF0 = 0; //清除TF0标志
TR0 = 1; //定时器0开始计时
EA = 1;
ET0 = 1;
}
void display()
{
static uchar i = 0;
P2 = 0x00; P0 = 0xff;
if( (state == 0) && (state_data == s1) && (i == 6) )
{
P2 = 0xe0; P0 = semg[semg_temp[i]] & 0x7f; P2 = 0x00; P0 = 0xff;
P2 = 0xc0; P0 = semg_bit[i];
}
else if( (state == 0) && (state_data == s2) && (i == 2) )
{
P2 = 0xe0; P0 = semg[semg_temp[i]] & 0x7f; P2 = 0x00; P0 = 0xff;
P2 = 0xc0; P0 = semg_bit[i];
}
else
{
P2 = 0xe0; P0 = semg[semg_temp[i]]; P2 = 0x00; P0 = 0xff;
P2 = 0xc0; P0 = semg_bit[i];
}
P2 = 0x00; P0 = 0xff;
i++;
if(i == 8)
i = 0;
}
void led()
{
static uchar state_led = s0;
static int count_time = 0;
P2 = 0x00; P0 = 0xff;
switch(state_led)
{
case s0:
{
P02 = 1;
if(bri)
{
count_time++;
if(count_time == 1480)
state_led = s1;
}
else
count_time = 0;
} break;
case s1:
{
P02 = 0;
count_time = 0;
if(!bri)
{
P02 = 1;
count_time = 0;
state_led = s0;
}
else
state_led = s1;
} break;
default: state_led = s0; break;
}
if(hour_para > 8)
{
if( (time[0] >= hour_para) || (time[0] < 8) )
P00 =0;
else
P00 =1;
}
else if(hour_para < 8)
{
if( (time[0] >= hour_para) && (time[0] < 8) )
P00 =0;
else
P00 =1;
}
else
P00 = 1;
if(tempr < tempr_para * 10)
P01 = 0;
else
P01 = 1;
P0 = P0 | 0xf8;
if(bri)
P0 = P0 & (~(0x01 << (led_para - 1)));
else
P0 = P0 | 0xf8;
P2 = 0x80;
P2 = 0x00; P0 = 0xff;
}
void fun() interrupt 1
{
static uchar i = 0, k = 0;
uchar *temp_time, j;
display();
led();
k++;
if(k >= 100)
{
k = 0;
temp_time = get_ds1302( );
for(j= 0; j < 3; j++)
time[j] = temp_time[j];
}
if(state == s0)
{
i++;
if(i >= 100)
{
i= 0;
vol = read_vol( );
if(vol < 200)
bri = 1;
else
bri = 0;
}
}
}
void disfun() interrupt 3
{
display();
led();
}
char keyscan()
{
uchar keyrow, keycolumn, keycode, i ,j;
static uchar keystate = s0;
char keyvalue;
P44 = 0; P42 = 0; P3 = 0x0f;
keyrow = P3 & 0x0f;
P44 = 1; P42 = 1; P3 = 0xf0;
if(P44 == 0) keycolumn = 0x70;
else if(P42 == 0) keycolumn = 0xb0;
else keycolumn = P3 & 0xf0;
keycode = ~(keyrow | keycolumn);
switch(keystate)
{
case s0:
if(keycode)
keystate = s1;
else
keyvalue = -1;
break;
case s1:
if(keycode)
{
for(i = 0; i < 4; i++)
for(j = 0; j < 4; j++)
if( keycode == ((0x80>>i) |(0x08>>j)) )
{
keyvalue = i*4 +j + 4;
break;
}
keystate = s2;
}
else
keystate = s0;
break;
case s2:
{
keyvalue = -1;
if(!keycode)
keystate = s0;
else ;
} break;
default: keystate = s0; break;
}
return keyvalue;
}
void menu(char keyvalue)
{
static char temp_hour = 17, temp_tempr = 25, temp_led = 4;
switch(state)
{
case s0:
{
if(keyvalue == 4)
{
state_para = s0;
state = s1;
}
switch(state_data)
{
case s0:
{
semg_temp[0] = time[0] / 10;
semg_temp[1] = time[0] % 10;
semg_temp[2] = 14;
semg_temp[3] = time[1] / 10;
semg_temp[4] = time[1] % 10;
semg_temp[5] = 14;
semg_temp[6] = time[2] / 10;
semg_temp[7] = time[2] % 10;
if(keyvalue == 5)
state_data = s1;
} break;
case s1:
{
semg_temp[0] = 11;
semg_temp[1] = 13;
semg_temp[2] = 13;
semg_temp[3] = 13;
semg_temp[4] = 13;
semg_temp[5] = tempr / 100;
semg_temp[6] = (tempr - semg_temp[5] * 100) / 10;
semg_temp[7] = tempr % 10;
if(keyvalue == 5)
state_data = s2;
} break;
case s2:
{
semg_temp[0] = 10;
semg_temp[1] = 13;
semg_temp[2] = vol / 100;;
semg_temp[3] = (vol - semg_temp[2] * 100) / 10;
semg_temp[4] = vol % 10;
semg_temp[5] = 13;
semg_temp[6] = 13;
semg_temp[7] = bri;
if(keyvalue == 5)
state_data = s0;
} break;
default: state_data = s0; break;
}
} break;
case s1:
{
semg_temp[2] = 13;
semg_temp[3] = 13;
semg_temp[4] = 13;
semg_temp[5] = 13;
if(keyvalue == 4)
{
state = s0;
state_data = s0;
hour_para = temp_hour;
tempr_para = temp_tempr;
led_para = temp_led;
}
switch(state_para)
{
case s0:
{
semg_temp[0] = 12;
semg_temp[1] = 1;
semg_temp[6] = temp_hour / 10;
semg_temp[7] = temp_hour % 10;
if(keyvalue == 5)
state_para = s1;
else if(keyvalue == 8)
{
temp_hour++;
if(temp_hour > 23)
temp_hour = 0;
}
else if(keyvalue == 9)
{
temp_hour--;
if(temp_hour < 0)
temp_hour = 23;
}
} break;
case s1:
{
semg_temp[0] = 12;
semg_temp[1] = 2;
semg_temp[6] = temp_tempr / 10;
semg_temp[7] = temp_tempr % 10;
if(keyvalue == 5)
state_para = s2;
else if(keyvalue == 8)
{
temp_tempr++;
if(temp_tempr > 99)
temp_tempr = 0;
}
else if(keyvalue == 9)
{
temp_tempr--;
if(temp_tempr < 0)
temp_tempr = 99;
}
} break;
case s2:
{
semg_temp[0] = 12;
semg_temp[1] = 3;
semg_temp[6] = 13;
semg_temp[7] = temp_led;
if(keyvalue == 5)
state_para = s0;
else if(keyvalue == 8)
{
temp_led++;
if(temp_led > 8)
temp_led = 4;
}
else if(keyvalue == 9)
{
temp_led--;
if(temp_led < 4)
temp_led = 8;
}
} break;
default: state_para = s0; break;
}
} break;
default: state = s0; break;
}
}
void allinit()
{
P2 = 0x80; P0 = 0xff;
P2 = 0xe0; P0 = 0xff;
P2 = 0xc0; P0 = 0xff;
P2 = 0xa0; P0 = 0x00;
}
void main()
{
char keyvalue;
int temp = 0;
ds1302_init(&time);
allinit();
Timer0Init();
while(1)
{
keyvalue = keyscan();
menu(keyvalue);
temp = TemperGet( );
if(temp > 0 && temp < 400) //降低 因中断导致的数据接收错误 的概率
tempr = temp;
Delay5ms();
}
}
ds1302.c
/*
程序说明: DS1302驱动程序
软件环境: Keil uVision 4.10
硬件环境: CT107单片机综合实训平台 8051,12MHz
日 期: 2011-8-9
*/
#include <reg52.h>
#include <intrins.h>
#define uchar unsigned char
sbit SCK=P1^7;
sbit SDA=P2^3;
sbit RST = P1^3; // DS1302复位
void Write_Ds1302(unsigned char temp)
{
unsigned char i;
for (i=0;i<8;i++)
{
SCK=0;
SDA=temp&0x01;
temp>>=1;
SCK=1;
}
}
void Write_Ds1302_Byte( unsigned char address,unsigned char dat )
{
RST=0; _nop_();
SCK=0; _nop_();
RST=1; _nop_();
Write_Ds1302(address);
Write_Ds1302(dat);
RST=0;
}
unsigned char Read_Ds1302_Byte ( unsigned char address )
{
unsigned char i,temp=0x00;
RST=0; _nop_();
SCK=0; _nop_();
RST=1; _nop_();
Write_Ds1302(address);
for (i=0;i<8;i++)
{
SCK=0;
temp>>=1;
if(SDA)
temp|=0x80;
SCK=1;
}
RST=0; _nop_();
SCK=0; _nop_();
SCK=1; _nop_();
SDA=0; _nop_();
SDA=1; _nop_();
return temp;
}
void ds1302_init(char *time)
{
uchar addr, i;
addr = 0x84;
Write_Ds1302_Byte(0x8e, 0x00);
for(i = 0; i < 3; i++)
{
Write_Ds1302_Byte(addr, ((time[i] / 10) << 4) + (time[i] % 10) );
addr -= 2;
}
Write_Ds1302_Byte(0x8e, 0x80);
}
char * get_ds1302()
{
char time[3];
uchar addr, i;
addr = 0x85;
Write_Ds1302_Byte(0x8e, 0x00);
for(i = 0; i < 3; i++)
{
time[i] = Read_Ds1302_Byte(addr);
time[i] = ((time[i] / 16) * 10) + (time[i] % 16);//BCD码转换为10进制数
addr -= 2;
}
Write_Ds1302_Byte(0x8e, 0x80);
return time;
}
ds18b20.c
/*
程序说明: 单总线驱动程序
软件环境: Keil uVision 4.10
硬件环境: CT107单片机综合实训平台(外部晶振12MHz) STC89C52RC单片机
日 期: 2011-8-9
*/
#include<stc15f2k60s2.h>
#include<intrins.h>
#define uchar unsigned char
#define uint unsigned int
sbit DQ = P1^4; //单总线接口
//单总线延时函数
void Delay_OneWire(unsigned int t) //STC89C52RC
{
while(t--);
}
//通过单总线向DS18B20写一个字节
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);
}
//从DS18B20读取一个字节
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;
}
//DS18B20设备初始化
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;
}
int TemperGet()
{
uchar low,high,temp;
int tempr;
init_ds18b20();
Write_DS18B20(0xcc);
Write_DS18B20(0x44);
Delay_OneWire(100);
init_ds18b20();
Write_DS18B20(0xcc);
Write_DS18B20(0xbe);
low=Read_DS18B20();
high=Read_DS18B20();
temp = (low & 0x0f) * 0.625;
low=low>>4;
high=high<<4;
tempr = (high | low) *10 + temp;
return tempr;
}
iic.c
/*
程序说明: IIC总线驱动程序
软件环境: Keil uVision 4.10
硬件环境: CT107单片机综合实训平台 8051,12MHz
日 期: 2011-8-9
*/
#include<stc15f2k60s2.h>
#include "intrins.h"
#define somenop {_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();}
#define SlaveAddrW 0xA0
#define SlaveAddrR 0xA1
//总线引脚定义
sbit SDA = P2^1; /* 数据线 */
sbit SCL = P2^0; /* 时钟线 */
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;
}
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;
}
int read_vol( )
{
int dat;
IIC_Start();
IIC_SendByte(0x90);
IIC_WaitAck();
IIC_SendByte(0x01);
IIC_WaitAck();
IIC_Start();
IIC_SendByte(0x91);
IIC_WaitAck();
dat=IIC_RecByte();
IIC_Stop();
dat=dat*1.96078;
return dat;
}