1.首先看到所需的模块,写出对应的子程序
1.1 数码管模块(不改变的数组可以放在code里面减少内部内存的占用)
/*.h文件*/
#ifndef _SEG_H
#define _SEG_H
#include <stc15f2k60s2.h>
void Seg_Disp(unsigned char wela,dula,point);
#endif
/*.c文件*/
#include <seg.h>
code unsigned char Seg_Wela[] = {0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80};
code unsigned char Seg_Dula[] = {0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0xff,0xbf};//0-9 10-熄灭 11 -
void Seg_Disp(unsigned char wela,dula,point)
{
P0 =0xff;
P2 = P2 & 0x1f | 0xe0;
P2 &= 0x1f;
P0 = Seg_Wela[wela];
P2 = P2 & 0x1f | 0xc0;
P2 &= 0x1f;
P0 = Seg_Dula[dula];
if(point)
P0 &= 0x7f;
P2 = P2 & 0x1f | 0xe0;
P2 &= 0x1f;
}
1.2 Led函数
/*.h文件*/
#ifndef _LED_H
#define _LED_H
#include <stc15f2k60s2.h>
void Led_Disp(unsigned char addr,enable);
#endif
/*.c文件*/
#include <led.h>
void Led_Disp(unsigned char addr,enable)//LED显示函数
{
static unsigned char temp = 0x00;
static unsigned char temp_old = 0xff;
if(enable)
temp |= (0x01 << addr);
else
temp &= ~(0x01 << addr);
if(temp != temp_old)
{
P0 = ~temp;
P2 = P2 & 0x1f | 0x80;
P2 &= 0x1f;
temp_old = temp;
}
}
1.3 Key函数(这里使用四个按键,使用的是独立按键)
/*.h文件*/
#ifndef _KEY_H
#define _KEY_H
#include <stc15f2k60s2.h>
unsigned char Key_Read();
#endif
/*.c文件*/
#include <key.h>
unsigned char Key_Read()
{
unsigned char temp = 0;
if(P33 == 0) temp = 4;
if(P32 == 0) temp = 5;
if(P31 == 0) temp = 6;
if(P30 == 0) temp = 7;
return temp;
}
1.4 DS18B20(onewire)
/*.h文件*/
#ifndef _ONEWIRE_H
#define _ONEWIRE_H
void Delay_OneWire(unsigned int t);
void Write_DS18B20(unsigned char dat);
unsigned char Read_DS18B20(void);
bit init_ds18b20(void);
float rd_temperature();
#endif
/*.c文件*/
#include <reg52.h>
#include <onewire.h>
sbit DQ = P1^4;
//
void Delay_OneWire(unsigned int t)
{
unsigned char i;
while(t--){
for(i=0;i<12;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()
{
unsigned char low,high;
init_ds18b20();
Write_DS18B20(0xcc);//跳过rom
Write_DS18B20(0x44);//温度转化
init_ds18b20();
Write_DS18B20(0xcc);//跳过rom
Write_DS18B20(0xbe);//读取温度
low = Read_DS18B20();
high = Read_DS18B20();
return((high << 8) | low) / 16.0;
}
1.5 RTC(DS1302)
/*.h文件*/
#ifndef _DS1302_H
#define _DS1302_H
void Write_Ds1302(unsigned char temp);
void Write_Ds1302_Byte( unsigned char address,unsigned char dat );
unsigned char Read_Ds1302_Byte ( unsigned char address );
void Ds1302_Set(unsigned char *ucRct);
void Ds1302_Read(unsigned char *ucRct);
#endif
/*.c文件*/
#include <ds1302.h>
#include <reg52.h>
#include <intrins.h>
sbit SCK = P1^7;
sbit SDA = P2^3;
sbit RST = P1^3;
//
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_Set(unsigned char *ucRct)
{
unsigned char i;
Write_Ds1302_Byte(0x8e,0x00);
for(i = 0;i < 3;i++)
Write_Ds1302_Byte(0x84 - 2*i,ucRct[i]);
Write_Ds1302_Byte(0x8e,0x80);
}
void Ds1302_Read(unsigned char *ucRct)
{
unsigned char i;
for(i = 0;i < 3;i++)
ucRct[i] = Read_Ds1302_Byte(0x85 - 2*i);
}
2.主程序部分
/*头文件*/
#include <STC15F2K60S2.H>
#include <Init.h>
#include <Seg.h>
#include <Key.h>
#include <Led.h>
#include <ds1302.h>
#include <onewire.h>
/*变量定义区*/
unsigned char Key_Slow_Down;
unsigned int Seg_Slow_Down;
unsigned char Key_Val,Key_Old,Key_Up,Key_Down;
unsigned char Seg_Buf[8] = {10,10,10,10,10,10,10,10};
unsigned char Seg_Pos;
unsigned char Seg_Point[8] = {0,0,0,0,0,0,0,0};
unsigned char ucLed[8] = {0,0,0,0,0,0,0,0};
unsigned char ucRct[3] = {0x23,0x59,0x50};
unsigned char Seg_Mode;//0-参数设置界面 1-时钟显示界面 2-温度采集界面
code unsigned char Acquisition_interval[4] = {1,5,30,60};//温度采集间隔
unsigned char Acquisition_interval_disp_index;//温度采集间隔显示指针
unsigned char Acquisition_interval_ctrl_index;//温度采集间隔控制指针
bit Seg_Star_Flag;//0-灭 1-亮
unsigned char tempature_Buf[10];//采集的十个温度
unsigned char tempature_Buf_Index;//温度采集指针
bit Over_Flag;//判断是否采集完毕
unsigned char Sec_Num;
unsigned int Timer_1000Ms;
unsigned char Timer_100Ms;
/*处理函数*/
void Key_Proc()
{
if(Key_Slow_Down) return;
Key_Slow_Down = 1;
Key_Val = Key_Read();
Key_Down = Key_Val & (Key_Old ^ Key_Val);
Key_Up = ~ Key_Val & (Key_Old ^ Key_Val);
Key_Old = Key_Val;
switch(Key_Down)
{
case 4:
if(Seg_Mode == 0)
{
if(++Acquisition_interval_disp_index == 4)
Acquisition_interval_disp_index = 0;
}
break;
case 5:
if(Seg_Mode == 0)
{
Acquisition_interval_ctrl_index = Acquisition_interval_disp_index;//确认采集间隔
Seg_Mode = 1;
}
break;
case 6:
if(Seg_Mode == 2)
{
Over_Flag = 0;//不再进行闪烁
if(++tempature_Buf_Index == 10)
tempature_Buf_Index = 0;
}
break;
case 7:
if(Seg_Mode == 2)
{
Over_Flag = Seg_Mode = tempature_Buf_Index = 0;
Acquisition_interval_disp_index = Acquisition_interval_ctrl_index;
}
break;
}
if(tempature_Buf_Index <= 10)
{
if(Sec_Num == Acquisition_interval[Acquisition_interval_ctrl_index])
{
Sec_Num = 0;
tempature_Buf[tempature_Buf_Index] = rd_temperature();
tempature_Buf_Index++;
}
}
else
{
Sec_Num = tempature_Buf_Index = 0;//停止采集并将采集指针归0
Seg_Mode = 2;
Over_Flag = 1;
}
}
void Seg_Proc()
{
unsigned char i;
if(Seg_Slow_Down) return;
Seg_Slow_Down = 1;
Ds1302_Read(ucRct);
Seg_Star_Flag = ucRct[2] %16%2;
switch(Seg_Mode)
{
case 0:
for(i=0;i<5;i++)
Seg_Buf[i] = 10;
Seg_Buf[5] = 11;
Seg_Buf[6] = Acquisition_interval[Acquisition_interval_disp_index] /10 %10;
Seg_Buf[7] = Acquisition_interval[Acquisition_interval_disp_index] %10;
break;
case 1:
for(i=0;i<3;i++)
{
Seg_Buf[i*3] = ucRct[i]/16%16;
Seg_Buf[i*3+1] = ucRct[i]%16;
}
Seg_Buf[2] = Seg_Buf[5] = Seg_Star_Flag?11:10;
break;
case 2:
Seg_Buf[0] = 11;
Seg_Buf[1] = tempature_Buf_Index /10 %10;
Seg_Buf[2] = tempature_Buf_Index %10;
Seg_Buf[3] = Seg_Buf[4] = 10;
Seg_Buf[5] = 11;
Seg_Buf[6] = tempature_Buf[tempature_Buf_Index]/10%10;
Seg_Buf[7] = tempature_Buf[tempature_Buf_Index]%10;
break;
}
}
/*显示函数*/
void Led_Proc()
{
ucLed[0] = Over_Flag&Seg_Star_Flag;
}
/*定时器0初始化函数*/
void Timer0Init(void) //1ms@12.000MHz
{
AUXR &= 0x7F;
TMOD &= 0xF0;
TL0 = 0x18;
TH0 = 0xFC;
TF0 = 0;
TR0 = 1;
ET0 = 1;
EA = 1;
}
/*中断服务函数*/
void Timer0Sever() interrupt 1
{
if(++Key_Slow_Down == 10) Key_Slow_Down = 0;
if(++Seg_Slow_Down == 500) Seg_Slow_Down = 0;
if(++Seg_Pos == 8) Seg_Pos = 0;
Seg_Disp(Seg_Pos,Seg_Buf[Seg_Pos],Seg_Point[Seg_Pos]);
Led_Disp(Seg_Pos,ucLed[Seg_Pos]);
if(Seg_Mode == 1)
{
if(++Timer_1000Ms == 1000)
{
Timer_1000Ms = 0;
Sec_Num++;
}
}
else
Timer_1000Ms = 0;
if(Over_Flag == 1)//采集完毕
{
if(++Timer_100Ms == 100)
{
Timer_100Ms = 0;
Seg_Star_Flag ^= 1;
}
}
else
Timer_100Ms = 0;
}
/*主函数*/
void main()
{
System_Init();
Timer0Init();
Ds1302_Set(ucRct);
rd_temperature();
while(1)
{
Key_Proc();
Seg_Proc();
Led_Proc();
}
}
3.易错点分析
3.1
以1s为间隔闪烁,周期应该是2s,需要定义一个Timer_1000Ms来进行闪烁变量改变,但是在这里同时出现1s间隔和时钟,所以可以用时钟来进行闪烁间隔判断,不一定必须使用定时器
Seg_Star_Flag = ucRct[2] %16%2;
3.2
在一个数组在代码运行时不发生改变的时候,可以把它放在code里面防止内存爆满溢出,显示设置可以使用两个指针(显示指针和设置指针)或者使用一个显示变量和一个设置变量,本质上都是从时间间隔这个不变的数组里面取数据
code unsigned char Acquisition_interval[4] = {1,5,30,60};//温度采集间隔
unsigned char Acquisition_interval_disp_index;//温度采集间隔显示指针
unsigned char Acquisition_interval_ctrl_index;//温度采集间隔控制指针
3.3 当在一个模式中只有一个操作时,可以用模式作为条件进行判断,不需要增加判断的变量,可以节省内存,简化代码
if(Seg_Mode == 1)
{
if(++Timer_1000Ms == 1000)
{
Timer_1000Ms = 0;
Sec_Num++;
}
}
else
Timer_1000Ms = 0;
例如这里,在Seg_Mode = 0时只有一个间隔选择,Seg_Mode = 1时只有一个采集和显示,这些操作只有在这个界面进行,所以可以用Seg_Mode作为判断条件