14届内容居多,采用模块化思想对代码进行书写,数码管,LED采用定时器扫描,按键使用矩阵键盘并进行3行消抖,主循环采用分时降速对不同外设进行数据采集,提高单片机运行速度。
文末附上完整代码连接。
官方代码
iic.c 注意头文件,sda,scl的定义需要自己写
#include <STC15F2K60S2.H>
#include "intrins.h"
sbit scl=P2^0;
sbit sda=P2^1;
完整 iic.h
#ifndef __IIC_H_
#define __IIC_H_
void I2CStart(void);
void I2CStop(void);
void I2CSendByte(unsigned char byt);
unsigned char I2CReceiveByte(void);
unsigned char I2CWaitAck(void);
void I2CSendAck(unsigned char ackbit);
#endif
完整 iic.c
#include <STC15F2K60S2.H>
#include "intrins.h"
sbit scl=P2^0;
sbit sda=P2^1;
#define DELAY_TIME 5
//
static void I2C_Delay(unsigned char n)
{
do
{
_nop_();_nop_();_nop_();_nop_();_nop_();
_nop_();_nop_();_nop_();_nop_();_nop_();
_nop_();_nop_();_nop_();_nop_();_nop_();
}
while(n--);
}
//
void I2CStart(void)
{
sda = 1;
scl = 1;
I2C_Delay(DELAY_TIME);
sda = 0;
I2C_Delay(DELAY_TIME);
scl = 0;
}
//
void I2CStop(void)
{
sda = 0;
scl = 1;
I2C_Delay(DELAY_TIME);
sda = 1;
I2C_Delay(DELAY_TIME);
}
//
void I2CSendByte(unsigned char byt)
{
unsigned char i;
for(i=0; i<8; i++){
scl = 0;
I2C_Delay(DELAY_TIME);
if(byt & 0x80){
sda = 1;
}
else{
sda = 0;
}
I2C_Delay(DELAY_TIME);
scl = 1;
byt <<= 1;
I2C_Delay(DELAY_TIME);
}
scl = 0;
}
//
unsigned char I2CReceiveByte(void)
{
unsigned char da;
unsigned char i;
for(i=0;i<8;i++){
scl = 1;
I2C_Delay(DELAY_TIME);
da <<= 1;
if(sda)
da |= 0x01;
scl = 0;
I2C_Delay(DELAY_TIME);
}
return da;
}
//
unsigned char I2CWaitAck(void)
{
unsigned char ackbit;
scl = 1;
I2C_Delay(DELAY_TIME);
ackbit = sda;
scl = 0;
I2C_Delay(DELAY_TIME);
return ackbit;
}
//
//void I2CSendAck(unsigned char ackbit)
//{
// scl = 0;
// sda = ackbit;
// I2C_Delay(DELAY_TIME);
// scl = 1;
// I2C_Delay(DELAY_TIME);
// scl = 0;
// sda = 1;
// I2C_Delay(DELAY_TIME);
//}
onewire.c 注意头文件,DQ的定义需要自己写
#include <STC15F2K60S2.H>
#include "intrins.h"
#include "onewire.h"
sbit DQ=P1^4;
完整onewire.h
#ifndef __ONEWIRE_H_
#define __ONEWIRE_H_
void Write_DS18B20(unsigned char dat);
unsigned char Read_DS18B20(void);
bit init_ds18b20(void);
#endif
完整onewire.c
#include <STC15F2K60S2.H>
#include "intrins.h"
#include "onewire.h"
sbit DQ=P1^4;
//
void Delay_OneWire(unsigned int t)
{
t=12*t;
while(t--);
}
//
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;
}
ds1302.c 注意头文件,SCK,SDA,RST的定义需要自己写
#include <STC15F2K60S2.H>
#include "intrins.h"
sbit SCK=P1^7;
sbit SDA=P2^3;
sbit RST=P1^3;
完整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 );
#endif
完整ds1302.c
#include <STC15F2K60S2.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 Display_menu(unsigned char menu)//显示函数
void read_adc1()//ADC光敏电阻采集
void DS1302_init()//时间初始化
void Read_ds1302()//读取时间
void Read_temp()//读取温度
void Hz_to_shidu()//频率转湿度
void canji_foucation()//触发功能
void Display()//显示切换功能
void led_foucation()//LED功能
unsigned char key()//按键扫描
void key_press()//按键功能
完整函数foucation.c
#include "foucation.h"
unsigned char time[]={0x05,0x03,0x13,0x00,0x00,0x00,0x00};
unsigned char c_time1,c_time2;
unsigned int max_temp;//最大温度
unsigned int sum_temp;//平均温度
unsigned int temp_m,temp_c,temp_old;//温度累加,触发温度,上一次触发温度
unsigned int bijiao_temp=0;//温度比较
unsigned int bijiao_shidu=0;//湿度比较
unsigned int max_shidu;//最大湿度
unsigned int sum_shidu;//平均湿度
unsigned int shidu_m,shidu_c,shidu_old;//湿度累加,触发湿度,上一次触发湿度
unsigned char i,chufa;//触发次数
unsigned char canshu_temp=30;//温度参数
unsigned int temp;//实时温度
unsigned int shidu;//实时湿度
unsigned char shidu_flag;//湿度变量与L5有关
unsigned int old_time_huixian;//长按2s计时标志
unsigned char light,old_light,menu_light;//光强存储,上一次光强存储,触发回显界面切换标志
unsigned int light_time,light_old_time; //触发3s计时相关
unsigned char key_s4=1,key_s5=1;//按键S4,S5变量
unsigned char key_value,key_old=0,key_up,key_down,key_long;//按键扫描,三行代码相关
unsigned char key_l=0;//按键扫描切换变量
code unsigned char Seg_Table[] =
{
0xc0, //0
0xf9, //1
0xa4, //2
0xb0, //3
0x99, //4
0x92, //5
0x82, //6
0xf8, //7
0x80, //8
0x90, //9
0x88, //A
0x83, //b
0xc6, //C
0xa1, //d
0x86, //E
0x8e //F
};
void Display_menu(unsigned char menu)//显示函数
{
switch(menu)
{
case 1:
dat[0]=Seg_Table[time[2]/16];
dat[1]=Seg_Table[time[2]%16];
dat[2]=0xbf;
dat[3]=Seg_Table[time[1]/16];
dat[4]=Seg_Table[time[1]%16];
dat[5]=0xbf;//-
dat[6]=Seg_Table[time[0]/16];
dat[7]=Seg_Table[time[0]%16];
break;//时间界面time
case 2:
dat[0]=Seg_Table[12];
dat[1]=0xff;
if(chufa==0)
{
dat[2]=0xff;
dat[3]=0xff;
dat[4]=0xff;
dat[5]=0xff;
dat[6]=0xff;
dat[7]=0xff;
}
else
{
dat[2]=Seg_Table[bijiao_temp/10];
dat[3]=Seg_Table[bijiao_temp%10];
dat[4]=0xbf;
dat[5]=Seg_Table[sum_temp/100];
dat[6]=Seg_Table[sum_temp/10%10]&0x7f;
dat[7]=Seg_Table[sum_temp%10];
}
break;//温度回显界面
case 3:
dat[0]=0x89;//H
dat[1]=0xff;
if(chufa==0)
{
dat[2]=0xff;
dat[3]=0xff;
dat[4]=0xff;
dat[5]=0xff;
dat[6]=0xff;
dat[7]=0xff;
}
else
{
dat[2]=Seg_Table[bijiao_shidu/10];
dat[3]=Seg_Table[bijiao_shidu%10];
dat[4]=0xbf;
dat[5]=Seg_Table[sum_shidu/100];
dat[6]=Seg_Table[sum_shidu/10%10]&0x7f;
dat[7]=Seg_Table[sum_shidu%10];
}
break;//湿度回显界面
case 4:
dat[0]=Seg_Table[15];//F
dat[1]=Seg_Table[chufa/10];
dat[2]=Seg_Table[chufa%10];//触发次数
if(chufa==0)
{
dat[3]=0xff;
dat[4]=0xff;
dat[5]=0xff;
dat[6]=0xff;
dat[7]=0xff;
}
else
{
dat[3]=Seg_Table[c_time2/16];
dat[4]=Seg_Table[c_time2%16];//时
dat[5]=0xbf;
dat[6]=Seg_Table[c_time1/16];//分
dat[7]=Seg_Table[c_time1%16];
}
break;//时间回显界面
case 5:
dat[0]=0x8c;//P
dat[1]=0xff;
dat[2]=0xff;
dat[3]=0xff;
dat[4]=0xff;
dat[5]=0xff;
dat[6]=Seg_Table[canshu_temp/10];
dat[7]=Seg_Table[canshu_temp%10];
break;//参数界面
case 6:
dat[0]=0x86;//E
dat[1]=0xff;
dat[2]=0xff;
dat[3]=Seg_Table[temp/10];
dat[4]=Seg_Table[temp%10];//温度
dat[5]=0xbf;
if(Hz_flag==0)
{
dat[6]=0x88;//
dat[7]=0x88;//湿度
}
else if(Hz_flag==1)
{
dat[6]=Seg_Table[shidu/10];//
dat[7]=Seg_Table[shidu%10];//湿度
}
break;//温湿度界面
case 7:
dat[0]=0xff;
dat[1]=0xff;
dat[2]=0xff;
dat[3]=Seg_Table[light/10000];
dat[4]=Seg_Table[light/1000%10];
dat[5]=Seg_Table[light/100%10];
dat[6]=Seg_Table[light/10%10];
dat[7]=Seg_Table[light%10];
break;//测试
}
}
void read_adc1()//ADC光敏电阻采集
{
I2CStart();
I2CSendByte(0x90);//写
I2CWaitAck();
I2CSendByte(0x01);//通道1
I2CWaitAck();
I2CStop();
I2CStart();
I2CSendByte(0x91);//读
I2CWaitAck();
light=I2CReceiveByte();//存储光强值0-255;
I2CWaitAck();
I2CStop();
// I2CStart();
// I2CSendByte(0x90);
// I2CWaitAck();
// I2CSendByte(0x03);//通道3
// I2CWaitAck();
// I2CStop();
//
// I2CStart();
// I2CSendByte(0x91);
// I2CWaitAck();
// light=I2CReceiveByte();
// I2CWaitAck();
// I2CStop();
//DAC
// I2CStart();
// I2CSendByte(0x90);
// I2CWaitAck();
// I2CSendByte(0x40);
// I2CWaitAck();
// I2CSendByte(dat);
// I2CWaitAck();
// I2CStop();
//EEPROM
写
// I2CStart();
// I2CSendByte(0xA0);
// I2CWaitAck();
// I2CSendByte(adress);//写入地址
// I2CWaitAck();
// I2CSendByte(date);//写入数据
// I2CWaitAck();
// I2CStop();
读
// I2CStart();
// I2CSendByte(0xA0);
// I2CWaitAck();
// I2CSendByte(adress);//写入地址
// I2CWaitAck();
//
// I2CStart();
// I2CSendByte(0xA1);
// I2CWaitAck();
// date=I2CReceiveByte();
// I2CWaitAck();
// I2CStop();
}
void DS1302_init()//时间初始化
{
unsigned char i,j=0x80;//写
Write_Ds1302_Byte(0x8e,0x00);//0x00 开启写入
for(i=0;i<7;i++)
{
Write_Ds1302_Byte(j,time[i]);//写入时间初始化数组
j+=2;
}
Write_Ds1302_Byte(0x8e,0x80);//0x80 关闭写入
}
void Read_ds1302()//读取时间
{
unsigned char i,j=0x81;//读
for(i=0;i<7;i++)//循环读
{
time[i]=Read_Ds1302_Byte(j);
j+=2;
}
}
void Read_temp()//读取温度
{
unsigned char LSB,MSB;//定义高低位变量
init_ds18b20();
Write_DS18B20(0xcc);
Write_DS18B20(0x44);
init_ds18b20();
Write_DS18B20(0xcc);
Write_DS18B20(0xbe);
LSB=Read_DS18B20();//低八位
MSB=Read_DS18B20();//高八位
temp=(MSB<<8)|LSB;
temp=temp>>4;//读取整数
// if((temp&0xf800)==0x0000)//小数点后一位
// {
// temp=temp>>4;//读取整数
temp=temp*10;
temp=temp+(LSB&0x0f)*0.625;
// }
}
void Hz_to_shidu()//频率转湿度
{
if((Hz_count>2000)|(Hz_count<200))//无效频率,湿度不转换
{
Hz_flag=0;//无效数据标志
}
else if(199<Hz_count<1999)//有效频率,湿度转换
{
Hz_flag=1;//数据有效
// if(Hz_count==200){shidu=10;}
// if(Hz_count==2000){shidu=90;}
shidu=Hz_count/23+2;//粗略湿度转换
}
}
void canji_foucation()//触发功能
{
if(bijiao_temp<temp_c)bijiao_temp=temp_c;//比较温度用于采集最大值
if(bijiao_temp>temp_c)bijiao_temp=bijiao_temp;//比较温度用于采集最大值
if(bijiao_shidu<shidu_c)bijiao_shidu=shidu_c;//比较湿度用于采集最大值
if(bijiao_shidu>shidu_c)bijiao_shidu=bijiao_shidu;//比较湿度用于采集最大值
if(m!=6)//位于温度,湿度界面下不触发
{
jlu_m=m;//存储触发前界面变量,方便回到触发之前的界面
if(light<50 && old_light>50&&menu_light==0)//触发条件,亮到暗
{
if(Hz_flag==1)//湿度有效的情况下触发次数加1,统计
{
chufa+=1;//触发次数+1;
temp_m=temp+temp_m;//累加计算平均值
shidu_m=shidu+shidu_m;//累加计算湿度
temp_old=temp_c;//存储上一次触发存储温度值
shidu_old=shidu_c;//存储上一次触发湿度值
temp_c=temp;//存储此次触发温度
shidu_c=shidu;//存储此次触发湿度
sum_temp=(temp_m*10)/chufa;//计算平均值
sum_shidu=(shidu_m*10)/chufa;//计算平均值
c_time1=time[1];//存储最近一次触发时间
c_time2=time[2];
shidu_flag=0;//定义有效触发与L5灯相关
menu_light=1;//界面切换标志
light_old_time=light_time;//切换计时3s,与定时器有关
}
else
{
shidu_flag=1;//定义无效触发与L5灯相关
menu_light=1;//界面切换标志
light_old_time=light_time;//切换计时3s,与定时器有关
}
}
}
if(m==6)//位于触发界面下
{
if(menu_light==1)//满足触发界面切换标志
{
if((light_time-light_old_time)==1500)//3s计时
{
menu_light=0;//清零界面触发标志
light_time=0;//清零计时值
m=jlu_m;//界面回显,用于回到触发前的界面
}
}
}
}
void Display()//显示切换功能
{
if(menu_light==0)//非触发界面,S4正常切换
{
switch(key_s4)
{
case 1:m=1;break;
case 2:m=2;break;
case 3:m=5;break;
}
if(m==2 |m==3 |m==4 )//S5正常切换回显界面
{
switch(key_s5)
{
case 1:m=2;break;
case 2:m=3;break;
case 3:m=4;break;
}
}
}
else if(menu_light==1)//触发界面仅显示温度湿度界面
{
m=6;
}
}
void led_foucation()//LED功能
{
if(m==1){LED|=0X01;}else{LED&=~0X01;}//时间界面L1亮
if(m==2|m==3|m==4){LED|=0X02;}else{LED&=~0X02;}//回显界面L2亮
if(m==6){LED|=0X04;}else{LED&=~0X04;}//触发温度湿度界面L3亮
if(temp_c>canshu_temp)//采集温度大于温度参数L4,0.1s间隔闪烁
{
if(led_delay<50){LED|=0X08;}//亮
else LED&=~0X08;//灭
if(led_delay>100)led_delay=0;
}
else LED&=~0X08;
if(shidu_flag==0) LED &=~0X10;//湿度有效触发,L5熄灭
if(shidu_flag==1) LED|=0X10;//湿度无效触发,L5亮
if(chufa>=2)//触发次数大于等于2
{
if((temp_c>temp_old)&&(shidu_c>shidu_old))//此次采集到的温度大于上一次的温度
{
LED|=0X20;//L6点亮
}
else LED &=~0X20;//L6熄灭
}
}
unsigned char key()//按键扫描
{
unsigned char key_v;//定义存储建值
if(key_l==0)//轮流执行
{
P32=0;P33=1;P44=1;P42=1;//扫描第一行
if(P44==0){key_v=5;}
else if(P42==0){key_v=9;}
else key_l=1;//无触发执行下一个程序
}
if(key_l==1)//轮流执行
{
P32=1;P33=0;P44=1;P42=1;//扫描第二行
if(P44==0){key_v=4;}
else if(P42==0){key_v=8;}
else key_v=0;//无任何触发赋值0
key_l=0;//归零回去轮流执行
}
return key_v;//返回触发值
}
void key_press()//按键功能
{
key_value=key();//赋值
key_down=key_value&(key_value^key_old);//下降沿
key_up=~key_value&(key_value^key_old);//上升沿
key_old=key_value;//三行消抖
if(key_down)
{
switch(key_down)//按键按下操作
{
case 4:if(m!=6){key_s4++;key_s5=1;if(key_s4==4)key_s4=1;} break;//第6个界面无效,界面切换,保证时间到回显为温度回显
case 5:if(m==2|m==3|m==4){key_s5++;if(key_s5==4)key_s5=1;} break;//回显界面切换按键,回显界面有效
case 8:if(m==5){canshu_temp++;if(canshu_temp>99)canshu_temp=99;}break;//温度参数加按键仅在温度参数设置界面有效
case 9:if(m==4){key_long=1;old_time_huixian=time_huixian;}//长按标志,计时赋值,仅在时间回显界面有效
if(m==5){canshu_temp--;if(canshu_temp<0)canshu_temp=0;}break;//温度参数减按键仅在温度参数设置界面有效
}
}
if(time_huixian-old_time_huixian<1000)//2s计时
{
if(key_up==9)//短按抬起无响应
{
}
}
else
{
if(key_up==9 && key_long==1)//长按2s抬起触发
{
key_long=0;//长按标志清零
chufa=0;//触发次数清零
sum_shidu=0;//湿度求和清零
sum_temp=0;//温度求和清零
temp_m=0;//温度求和清零
shidu_m=0;//湿度求和清零
bijiao_temp=0;//温度最大值清零
bijiao_shidu=0;//湿度最大值清零
old_time_huixian=0;//长按2s时间清零
}
}
}
foucation.h
#include <STC15F2K60S2.H>
#include "iic.h"
#include "ds1302.h"
#include "onewire.h"
extern unsigned char adc_delay,delay_time,time_delay,temp_delay,light_delay,led_delay;
extern unsigned char pos[8],dat[8];
extern unsigned int Hz_time,Hz,Hz_count,Hz_flag;
extern unsigned char light,old_light,menu_light;
extern unsigned char LED;
extern unsigned int light_time,light_old_time;
extern unsigned char key_s4,key_s5;
extern unsigned char jlu_m,m;
extern unsigned int time_huixian;
void read_adc1();
void Display_menu(unsigned char menu);
void DS1302_init();
void Read_ds1302();
void Read_temp();
void Hz_to_shidu();
void Display();
void canji_foucation();
void led_foucation();
void key_press();
#endif
主函数main.c
#include "foucation.h"
unsigned char pos[8]={0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80},dat[8];
unsigned char key_delay,adc_delay,delay_time,time_delay,temp_delay,light_delay,led_delay;//定时器器计时变量
unsigned char jlu_m,m=1;//界面显示变量
unsigned int Hz_time,Hz,Hz_count,Hz_flag;//频率相关变量
unsigned char LED;//led显示变量
unsigned int time_huixian;//S9长按计时2s;
void Delay750ms() //初始化延时函数
{
unsigned char i, j, k;
_nop_();
_nop_();
i = 32;
j = 133;
k = 87;
do
{
do
{
while (--k);
} while (--j);
} while (--i);
}
void sys_init()//系统初始化
{
P2=0X80;P0=0XFF;P2|=0X1F;
P2=0XA0;P0=0X00;P2|=0X1F;
Read_temp();
Delay750ms();
Read_temp();//先读取温度防止出现85
DS1302_init();//时间初始化
}
void Timer1Init(void) //2毫秒计时
{
AUXR |= 0x40; //定时器时钟1T模式
TMOD &= 0x0F; //设置定时器模式
TL1 = 0x9A; //设置定时初值
TH1 = 0xA9; //设置定时初值
TF1 = 0; //清除TF1标志
TR1 = 1; //定时器1开始计时
ET1=1;
EA=1;
}
void Timer0Init(void) //计数
{
TMOD |=0x06; //设置定时器模式
TL0 = 0xFF; //设置定时初值
TH0 = 0xFF; //设置定时初值
TF0 = 0;
TR0 = 1;
ET0=1;
EA=1;
}
void main()
{
sys_init();//初始化
Timer0Init();//计数器0初始化
Timer1Init();//定时器1初始化
while(1)
{
led_foucation(); //LED相关
Display(); //切换相关
Display_menu(m); //显示相关
Hz_to_shidu(); //hz转换湿度
canji_foucation(); //触发相关
if(led_delay>100) { led_delay=0; }//中断计时清零
if(adc_delay>100) { adc_delay=0;read_adc1(); }//ADC减速
if(time_delay>50) { time_delay=0;Read_ds1302(); }//时间减速读取
if(temp_delay>200) { temp_delay=0;Read_temp(); }//温度减速扫描
if(light_delay>200){ light_delay=0;old_light=light;}//触发变量赋值
if(key_delay>20) { key_delay=0;key_press(); }//按键降速消抖
}
}
void T1_sever() interrupt 3
{
unsigned char i;
P2=0xc0;P0=0xff; P2 |=0x1f;
P2=0xe0;P0=dat[i]; P2 |=0x1f;
P2=0xc0;P0=pos[i]; P2 |=0x1f;
i+=1;if(i==8)i=0; //数码管扫描显示
P2=0x80;P0=~LED; P2 |=0X1F;//LED扫描显示
delay_time++;
adc_delay++;
time_delay++;
temp_delay++;
Hz_time++;
light_time++;
light_delay++;
led_delay++;
key_delay++;
time_huixian++;//计时变量
if(Hz_time>=500)//1s统计一次频率
{
Hz_count=Hz;
Hz=0;
Hz_time=0;
}
}
void T0_sever() interrupt 1//对ne55脉冲进行计数
{
Hz++;
}
源代码工程连接:链接:https://pan.baidu.com/s/1IxR3717vZ6ckbUy2p2UHcQ?pwd=1234
提取码:1234