一、大模板
本模板基于以下两篇文章和西风老师讲解归纳而成,仅为比赛学习而用。如有侵权立删。
#include "reg52.h"
#include "ds1302.h"
#include "onewire.h"
#include "iic.h"
sfr P4 = 0xC0;
sbit A0 = P3^4;
sbit A1 = P3^5;
sbit A2 = P4^2;
sbit A3 = P4^4;
/*===================初始化函数======================*/
void System_Init()
{
P0 = 0xff;//关闭数码管
P2 = P2 & 0x1f | 0x80;
P2 &= 0x1f;
P0 = 0x00;//关闭蜂鸣器,继电器
P2 = P2 & 0x1f | 0xa0;
P2 &= 0x1f;
}
/*===================数码管======================*/
unsigned char Seg_Dula[] = {0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0xff};//段选 0~9+熄灭
unsigned char Seg_Wela[] = {0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80};//位选
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=Seg_Dula[dula] & 0x7f;
}
else
{
P0=Seg_Dula[dula];
}
P2=P2&0x1f|0xe0;
P2&=0x1f;
}
/*===================按键======================*/
unsigned char Key4_Read(void) //独立按键读取函数
{
unsigned char Key_temp;
unsigned char Key_Value;
P3 |= 0x0f; //将P3低四位即独立按键接口拉高置为1
Key_temp = P3&0x0f;//读取P3低四位I/O口的电平
switch(Key_temp)//
{
case 0x0e : Key_Value = 7; break; //S7
case 0x0d : Key_Value = 6; break; //S6
case 0x0b : Key_Value = 5; break; //S5
case 0x07 : Key_Value = 4; break; //S4
default: Key_Value = 0;
}
return Key_Value;
}
unsigned char Key16_Read(void)
{
unsigned int Key_temp;
unsigned char Key_Value;
A3=0;
A2=1;
A1=1;
A0=1;
P3|=0X0F;
Key_temp = P3;
A3=1;
A2=0;
A1=1;
A0=1;
P3|=0X0F;
Key_temp = (Key_temp<<4) | (P3&0X0F);
A3=1;
A2=1;
A1=0;
A0=1;
P3|=0X0F;
Key_temp = (Key_temp<<4) | (P3&0X0F);
A3=1;
A2=1;
A1=1;
A0=0;
P3|=0X0F;
Key_temp = (Key_temp<<4) | (P3&0X0F);
switch(~Key_temp)
{
//第一列
case 0X8000: Key_Value = 4; break; //S4
case 0X4000: Key_Value = 5; break; //S5
case 0X2000: Key_Value = 6; break; //S6
case 0X1000: Key_Value = 7; break; //S7
//第二列
case 0X0800: Key_Value = 8; break; //S8
case 0X0400: Key_Value = 9; break; //S9
case 0X0200: Key_Value = 10; break; //S10
case 0X0100: Key_Value = 11; break; //S11
//第三列
case 0X0080: Key_Value = 12; break; //S12
case 0X0040: Key_Value = 13; break; //S13
case 0X0020: Key_Value = 14; break; //S14
case 0X0010: Key_Value = 15; break; //S15
//第四列
case 0X0008: Key_Value = 16; break; //S16
case 0X0004: Key_Value = 17; break; //S17
case 0X0002: Key_Value = 18; break; //S18
case 0X0001: Key_Value = 19; break; //S19
default: Key_Value = 0;
}
return Key_Value;
}
/*===================LED亮灭======================*/
unsigned char ucLed[8]={0,0,0,0,0,0,0,0};
void Led_Disp(unsigned char addr,enable)
{
static unsigned char temp;
static unsigned char temp_old;
if(enable)
temp |= 0x01 << addr;
else
temp &= ~(0x01 << addr);
if(temp != temp_old)
{
P0 = ~temp;
P2 = P2 & 0x1f | 0x80;
P2 &= 0x1f;
temp_old = temp;
}
}
void Beep(unsigned char enable)//蜂鸣器
{
static unsigned char temp;
static unsigned char temp_old;
if(enable)
{
temp |= 0x40;
}
else
{
temp &= ~0x40;
}
if(temp != temp_old)
{
P0 = temp;
P2 = (P2 & 0x1f) | 0xa0;
P2 = P2 & 0x1f;
temp_old = temp;
}
}
void Relay(unsigned char enable)//继电器
{
static unsigned char temp;
static unsigned char temp_old;
if(enable)
{
temp |= 0x10;
}
else
{
temp &= ~0x10;
}
if(temp != temp_old)
{
P0 = temp;
P2 = (P2 & 0x1f) | 0xa0;
P2 = P2 & 0x1f;
temp_old = temp;
}
}
/*===================DS18B20温度======================*/
float Temp_Read()//读取温度
{
unsigned char low,high;
init_ds18b20();
Write_DS18B20(0xcc);
Write_DS18B20(0x44);
init_ds18b20();
Write_DS18B20(0xcc);
Write_DS18B20(0xbe);
low=Read_DS18B20();
high=Read_DS18B20();
return (high<<8|low)/16.0;
}
/*===================DS1302时钟======================*/
//控制时分秒
unsigned char ucRtc[3] = {0x23,0x59,0x55};//时钟显示数组,时分秒
unsigned char unDat[3] = {0x22,0x12,0x31};//年月日
void Set_Rtc(unsigned char* ucRtc)//设置闹钟数据,将时钟显示数组中的数据写入
{
unsigned char i;
Write_Ds1302_Byte(0x8e,0x00);
for(i=0;i<3;i++)
Write_Ds1302_Byte(0x84-2*i,ucRtc[i]);
Write_Ds1302_Byte(0x8e,0x80);
}
void Get_Rtc(unsigned char* ucRtc)//读取闹钟数据,存放在时钟显示数组中
{
unsigned char i;
for(i=0;i<3;i++)
ucRtc[i]=Read_Ds1302_Byte(0x85-2*i);
}
void Set_Dat(unsigned char* ucDat)//设置日期,年月日
{
Write_Ds1302_Byte(0x8e,0);
Write_Ds1302_Byte(0x8c,ucDat[0]);
Write_Ds1302_Byte(0x88,ucDat[1]);
Write_Ds1302_Byte(0x86,ucDat[2]);
Write_Ds1302_Byte(0x8e,1);
}
void Read_Date(unsigned char* ucDat)//读取日期,年月日
{
ucDate[0] = Read_Ds1302_Byte(0x8d);
ucDate[1] = Read_Ds1302_Byte(0x89);
ucDate[2] = Read_Ds1302_Byte(0x87);
}
/*===================PCF8591======================*/
void Da_Wirte(unsigned char dat)
{
I2CStart();
I2CSendByte(0x90);
I2CWaitAck();
I2CSendByte(0x41);
I2CWaitAck();
I2CSendByte(dat);
I2CWaitAck();
I2CStop();
}
unsigned char Ad_Read(unsigned char addr)
{
unsigned char temp;
I2CStart();
I2CSendByte(0x90);
I2CWaitAck();
I2CSendByte(addr);
I2CWaitAck();
I2CStart();
I2CSendByte(0x91);
I2CWaitAck();
temp=I2CReceiveByte();
I2CSendAck(1);
I2CStop();
return temp;
}
/*===================EEPROM======================*/
void EEPROM_Write(unsigned char* EEPROM_String,unsigned char addr,num)//页写入
{
I2CStart();
I2CSendByte(0xa0);
I2CWaitAck();
I2CSendByte(addr);
I2CWaitAck();
while(num--)
{
I2CSendByte(*EEPROM_String++);
I2CWaitAck();
I2C_Delay(200);
}
I2CStop();
}
void EEPROM_Read(unsigned char* EEPROM_String,unsigned char addr,num)//读取
{
I2CStart();
I2CSendByte(0xa0);
I2CWaitAck();
I2CSendByte(addr);
I2CWaitAck();
I2CStart();
I2CSendByte(0xa1);
I2CWaitAck();
while(num--)
{
*EEPROM_String++=I2CReceiveByte();
if(num) I2CSendAck(0);
I2CSendAck(1);
}
I2CStop();
}
/*===================预备变量======================*/
unsigned char Key_Val,Key_Down,Key_Old,Key_Up;//按键专用变量
unsigned char Key_Slow_Down;//按键减速专用变量
unsigned char Seg_Buf[8] = {10,10,10,10,10,10,10,10};//数码管显示数组
unsigned char PointShow[8] = {0,0,0,0,0,0,0,0};//小数点显示数组
unsigned char Seg_Pos;//数码管扫描专用变量
unsigned int Seg_Slow_Down;//数码管减速专用变量
/*===================功能函数======================*/
void Key_Proc()//按键处理函数
{
if(Key_Slow_Down) return;
Key_Slow_Down = 1;
Key_Val = Key16_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:
//当写入数据为数组时,中间变量务必是8的倍数,最后变量为写入数据长度
EEPROM_Write(dat,0,2);
//当写入数据为变量时
EEPROM_Write(&a,8,1);
break;
}
}
void Seg_Proc()//数码管显示函数
{
if(Seg_Slow_Down) return;
Seg_Slow_Down = 1;//数码管显示减速
/*
Da_Write(51*0.4);//0.4V写入
*/
/*
//读取温度显示
temp=Temp_Read();
Seg_Buf[4]=(unsigned char)temp/10%10;//十位
Seg_Buf[5]=(unsigned char)temp%10;//个位
Seg_Buf[6]=(unsigned int)(temp*100)/10%10;//小数位第一位
Seg_Buf[7]=(unsigned int)(temp*100)%10;//小数位第二位
Seg_Point[5]=1;//个位小数点
*/
/*
//读取电压
//d_val为float类型
d_val=Ad_Read(0x43)/51.0; //0x43为光敏,0x41为电阻,/51.0为数据转换
Seg_Point[5]=1;
Seg_Buf[5]=(unsigned char)d_val%10;//个位
Seg_Buf[6]=(unsigned int)(d_val*100)/10%10;//小数位第一位
Seg_Buf[7]=(unsigned int)(d_val*100)%10;//小数位第二位
*/
}
void Led_Proc()//LED处理函数
{
}
/*===================定时器0计数器======================*/
void Timer0_Init(void)
{
TMOD &= 0xF0;
TMOD |= 0x05;
TL0 = 0;
TH0 = 0;
TF0 = 0;
TR0 = 1;
}
/*===================定时器1中断======================*/
void Timer1_Init(void)
{
TMOD &= 0x0F;
TL1 = (65535 - 1000)%256;
TH1 = (65535 - 1000)/256;
TF1 = 0;
TR1 = 1;
ET1 = 1;
EA = 1;
}
unsigned int freq;
unsigned int time_1s;
void Timer1Server() interrupt 3//定时器0终端服务函数
{
if(++Key_Slow_Down == 10) Key_Slow_Down = 0;//10ms按键减速
if(++Seg_Slow_Down == 500) Seg_Slow_Down = 0;//500ms数码管减速
if(++Seg_Pos == 8) Seg_Pos = 0;//数码管扫描
Seg_Disp(Seg_Pos,Seg_Buf[Seg_Pos],PointShow[Seg_Pos]);//数码管扫描
Led_Disp(Seg_Pos,ucLed[Seg_Pos]);//LED扫描
if (++time_1s == 1000)//频率读取
{
TR0 = 0;
time_1s = 0;
freq = TH0 << 8 | TL0;
TH0 = 0;
TL0 = 0;
TR0 = 1;
}
}
void Delay750ms(void) //@12.000MHz
{
unsigned char data i, j, k;
i = 35;
j = 51;
k = 182;
do
{
do
{
while (--k);
} while (--j);
} while (--i);
}
/*===================主函数======================*/
void main()
{
Temp_Read();
Delay750ms();//消除温度默认85显示
System_Init();
Timer0Init();
Set_Rtc(ucRtc);
while (1)
{
Key_Proc();
Seg_Proc();
Led_Proc();
}
}
二、头文件
DS1302
#ifndef __DS1302_H
#define __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);
void Write_Ds1302_Byte( unsigned char address,unsigned char dat );
unsigned char Read_Ds1302_Byte( unsigned char address );
#endif
IIC
#ifndef __IIC_H
#define __IIC_H
#include "reg52.h"
#include "intrins.h"
sbit sda = P2^1;
sbit scl = P2^0;
static void I2C_Delay(unsigned char n);
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
ONEWIRE
#ifndef __ONEWIRE_H
#define __ONEWIRE_H
#include "reg52.h"
sbit DQ = P1^4;
void Delay_OneWire(unsigned int t);
void Write_DS18B20(unsigned char dat);
unsigned char Read_DS18B20(void);
bit init_ds18b20(void);
#endif
三、重点操作
1、温度读取
//temp为float类型
temp=Temp_Read();
Seg_Buf[4]=(unsigned char)temp/10%10;//十位
Seg_Buf[5]=(unsigned char)temp%10;//个位
Seg_Buf[6]=(unsigned int)(temp*100)/10%10;//十分位
Seg_Buf[7]=(unsigned int)(temp*100)%10;//百分位
Seg_Point[5]=1;//小数点
//整数读取
temp=(unsigned char)Temp_Read();
2、电压读取
//d_val为float类型
d_val=Ad_Read(0x43)/51.0; //0x43为光敏,0x41为电阻,/51.0为数据转换
Seg_Point[5]=1;
Seg_Buf[5]=(unsigned char)d_val%10;
Seg_Buf[6]=(unsigned int)(d_val*100)/10%10;
Seg_Buf[7]=(unsigned int)(d_val*100)%10;
3、写入电压
//写入0.4V,需要*51进行数据转换
Da_Write(51*0.4);
4、写入EEPROM
//当写入数据为数组时,中间变量务必是8的倍数,最后变量为写入数据长度
EEPROM_Write(dat,0,2);
//当写入数据为变量时
EEPROM_Write(&a,8,1);
5、读取EEPROM
//当写入数据为数组时,中间变量务必是8的倍数,最后变量为写入数据长度
EEPROM_Write(dat,0,2);
//当写入数据为变量时
EEPROM_Write(&a,8,1);
6、参数设置
unsigned char Seg_Disp[] = {20,30,50};
unsigned char Seg_Ctrol[] = {20,30,50};
unsigned char Seg_Mode;//0-显示 1-参数设置 2-其他界面
void Key_Proc()
{
if(Key_Slow_Down)return;
Key_Slow_Down = 1;
switch(Key_Down)
{
case 4://界面切换按键
if(++Seg_Mode == 3)Seg_Mode = 0;
if(Seg_Mode == 1)//处于参数设置界面
{
Seg_Disp[0] = Seg_Ctrol[0];
Seg_Disp[1] = Seg_Ctrol[1];
Seg_Disp[2] = Seg_Ctrol[2];
}
if(Seg_Mode == 2)//参数设置界面切出后
{
Seg_Ctrol[0] = Seg_Disp[0];
Seg_Ctrol[1] = Seg_Disp[1];
Seg_Ctrol[2] = Seg_Disp[2];
}
break;
}
}
7、加减按键
unsigned char temp[] = {0,0,0}
unsigned char temp_index;
void Key_Proc()
{
if(Key_Slow_Down)return;
Key_Slow_Down = 1;
switch(Key_Down)
{
case 6://加
if(++temp[temp_index] == 100)
temp[index] = 99;
break;
case 7://减
if(--temp[temp_index] == 255)
temp[index] = 0;
break;
}
}
8、LED互斥点亮
unsigned char ucLed[] = {0,0,0,0,0,0,0,0};
unsigned char Seg_Disp_Mode;//0,1,2
for(i=0;i<3;i++)
{
ucLed[i] = (i == Seg_Disp_Mode);
}
9、数码管高位熄灭
unsigned char i = 3;//从第四位开始检测
while(Seg_Buf[i] == 0)
{
Seg_Buf[i] = 10;
if(++i == 7)break;//保留最后一位零显示
}
10、数码管定时闪烁
bit Seg_Flag;
unsigned int time_1s;
void Seg_Proc()
{
if(Seg_Slow_Down)return;
Seg_Slow_Down = 1;
switch(Seg_Disp_Mode)
{
case 0:
Seg_Buf[0] = temp/100%10;
Seg_Buf[1] = temp/10%10;
Seg_Buf[2] = temp%10;
if(Seg_Index == 0)
Seg_Buf[0] = Seg_Flag?temp/100%10:10;
Seg_Buf[1] = Seg_Flag?temp/10%10:10;
Seg_Buf[2] = Seg_Flag?temp%10:10;
}
break;
}
}
void Timer1_Init(void) //100微秒@12.000MHz
{
TMOD &= 0x0F; //设置定时器模式
TL1 = 0x20; //设置定时初始值
TH1 = 0xD1;
TF1 = 0; //清除TF1标志
TR1 = 1; //定时器1开始计时
ET1 = 1;
EA = 1;
}
void Timer1Server()interrupt 3
{
if(++Seg_Slow_Down == 500)Seg_Slow_Down = 0;
if(++time_1s == 1000)
{
time_1s = 0;
Seg_Flag = ~Seg_Flag;
}
}
11、彩灯闪烁(第九届省赛)
void Led_Proc()
{
unsigned char i;
if(System_Flag == 1)
{
if(Ms_Tick == Led_Time_Ctrol[Led_Mode])
{
Ms_Tick = 0;
switch(Led_Mode)
{
case 0:
if(++Led_Pos == 8)
{
Led_Pos = 7;
Led_Mode = 1;
}
break;
case 1:
if(--Led_Pos == 255)
{
Led_Pos = 7;
Led_Mode = 2;
}
break;
case 2:
Led_Pos += 9;
if(Led_Pos > 34)
{
Led_Pos = 34;
Led_Mode = 3;
}
break;
case 3:
Led_Pos -= 9;
if(Led_Pos > 200)
{
Led_Pos = 0;
Led_Mode = 0;
}
break;
}
}
}
if(Led_Mode < 2)
{
for(i=0;i<8;i++)
ucLed[i] = (i == Led_Pos);
}
else
{
for(i=0;i<8;i++)
ucLed[i] = (i == (Led_Pos / 10) || i == (Led_Pos % 10));
}
}
12、按键长短按
void Key_Proc()
{
if(Key_Slow_Down)return;
Key_Slow_Down = 1;
Key_Val = Key16_Read();
Key_Down = Key_Val & (Key_Val ^ Key_Old);
Key_Old = Key_Val;
if(Key_Down == 12 || Key_Down == 13) //假设按键12、13
Key_Flag = 1;
if(Timer_1000Ms < 1000 && Key_Flag == 1) //短按
{
switch(Key_Up)
{
case 12: //短按12
Timer_1000Ms = Key_Flag = 0;
break;
case 13: //短按13
Timer_1000Ms = Key_Flag = 0;
break;
}
}
else //长按
{
switch(Key_Old)
{
case 12:
Timer_1000Ms = Key_Flag = 0;
break;
case 13:
Timer_1000Ms = Key_Flag = 0;
break;
}
}
}
//中断函数写
if(Key_Flag)Timer_1000Ms++;
13、AD电压分等级
unsigned char Level;
Level = Ad_Read(0x43)/64;//64 = 256/4 电压读取分为四个等级
14、PWM控制LED亮度
void Timer1Server()interrupt 3
{
if(++Led_Count == 12)Led_Count = 0;
if(Led_Count <= (Led_Level+1)*3 )
Led_Disp(Seg_Pos,ucLed[Seg_Pos]);
else
Led_Disp(Seg_Pos,0);
}