一:LED显示模块
void Led_Disp(unsigned char addr,unsigned char enable)
{
unsigned char temp = 0x00;
unsigned char temp_old = 0xff;
if(enable) //逻辑上点亮第addr位
temp |= 0x01 << addr;
else //逻辑上熄灭第addr位
temp &= ~(0x01 << addr);
if(temp != temp_old)
{
P0 = ~temp; //亮起来吧!
P2 = P2 & 0X1f | 0x80;
P2 &= 0x1f;
temp_old = temp;
}
}
二:数码管显示模块
unsigned char Seg_Duan[] = {0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,
0xf8,0x80,0x90,0xff,0xbf};//0-9 10为全灭 11为- 数码管段选
unsigned char Seg_Wei[] = {0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80}; //数码管位选
void Seg_Disp(unsigned Wei,Duan,point)
{
P0 = 0x00; //消隐
P2 = P2 & 0x1f | 0xe0; //打开Y4通道
P2 &= 0x1f; //关闭通道
P0 = Seg_Wei[Wei]; //位选
P2 = P2 & 0X1f | 0xc0; //打开Y6通道
P2 &= 0x1f; //关闭通道
if(point) //段选
P0 = Seg_Duan[Duan] & 0x7f; //添加小数点
else
P0 = Seg_Duan[Duan];
P2 = P2 & 0X1f | 0xe0; //打开Y7通道
P2 &= 0x1f //关闭通道
}
三:键盘读取模块
unsigned char Key_Read()
{
unsigned char temp = 0; //注意被激活时位低电平状态!0才是激活
P44 = 0; P42 = 1; P35 = 1; P34 = 1;
if(P33 == 0) temp = 4;
if(P32 == 0) temp = 5;
if(P31 == 0) temp = 6;
if(P30 == 0) temp = 7;
P44 = 1; P42 = 0; P35 = 1; P34 = 1;
if(P33 == 0) temp = 8;
if(P32 == 0) temp = 9;
if(P31 == 0) temp = 10;
if(P30 == 0) temp = 11;
P44 = 1; P42 = 1; P35 = 0; P34 = 1;
if(P33 == 0) temp = 12;
if(P32 == 0) temp = 13;
if(P31 == 0) temp = 14;
if(P30 == 0) temp = 15;
P44 = 1; P42 = 1; P35 = 1; P34 = 0;
if(P33 == 0) temp = 16;
if(P32 == 0) temp = 17;
if(P31 == 0) temp = 18;
if(P30 == 0) temp = 19;
return temp;
}
四:外设初始化模块
void Sys_Init()
{
P0 = 0x00; //LED初始化,全灭
P2 = P2 & 0x1f | 0x80; //打开Y4通道
P2 &= 0x1f;
P0 = 0xff; //蜂鸣器,继电器初始化,关闭
P2 = P2 & 0x1f | 0xa0; //打开Y5通道
P2 &= 0x1f
}
五:DS1302模块时钟(写在提供的ds1302底层中)
/* # DS1302代码片段说明
1. 本文件夹中提供的驱动代码供参赛选手完成程序设计参考。
2. 参赛选手可以自行编写相关代码或以该代码为基础,根据所选单片机类型、运行速度和试题
中对单片机时钟频率的要求,进行代码调试和修改。
*/
//
#include <ds1302.h>
#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);
}
/* 需要自己写的DS1302读写! */
void RTC_Set(unsigned char* ucRTC) //读
{
Write_Ds1302_Byte(0X8e,0x00); //打开写保护
Write_Ds1302_Byte(0x84,ucRTC[0]); //时
Write_Ds1302_Byte(0x82,ucRTC[1]); //分
Write_Ds1302_Byte(0x80,ucRTC[2]); //秒
Write_Ds1302_Byte(0x8e,0x80); //关闭写保护
}
void RTC_Read(unsigned char* ucRTC) //写
{
ucRTC[0] = Read_Ds1302_Byte(0X85) //时
ucRTC[1] = Read_Ds1302_Byte(0X83) //分
ucRTC[2] = Read_Ds1302_Byte(0X81) //秒
}
六:DS18B20温度模块(写在提供的OneWire底层中)
/* # 单总线代码片段说明
1. 本文件夹中提供的驱动代码供参赛选手完成程序设计参考。
2. 参赛选手可以自行编写相关代码或以该代码为基础,根据所选单片机类型、运行速度和试题
中对单片机时钟频率的要求,进行代码调试和修改。
*/
#include <onewire.h>
//
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 Temperature_Read()
{
unsigned char low,high;
unsigned float temperature;
init_ds18b20();
Write_DS18B20(0xcc);
Write_DS18B20(0x44);
init_ds18b20();
Write_DS18B20(0xcc);
Write_DS18B20(0xbe);
low = Read_DS18B20();
high = Read_DS18B20();
temperature = (( high << 8 ) | low) / 16.0;
return temperature;
}
七:PCF8591 AD/DA转换模块(写在提供的I2C底层中)
/* # I2C代码片段说明
1. 本文件夹中提供的驱动代码供参赛选手完成程序设计参考。
2. 参赛选手可以自行编写相关代码或以该代码为基础,根据所选单片机类型、运行速度和试题
中对单片机时钟频率的要求,进行代码调试和修改。
*/
#define DELAY_TIME 5
#include <iic.h>
//
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);
}
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();
// temp = temp * (5.0 / 255); //处理
return temp;
}
void DA_Write(unsigned char dat)
{
I2CStart();
I2CSendByte(0x91);
I2CWaitAck();
I2CSendByte(0X41) //保证D6 = 1;
I2CWaitAck();
I2CStop();
//处理!
}
五:主函数,定时器0动态扫描及对应的处理函数
unsigned char Seg_Buf[8] = {10,10,10,10,10,10,10,10}; //数码管扫描专用变量 默认全灭
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}; //Led数据扫描变量 默认全灭
unsigned char Key_Slow_Down; //键盘减速专用变量
unsigned char Seg_Slow_Down; //数码管减速专用变量
unsigned char Key_Val,Key_Down,Key_Up,Key_Old; //键盘处理专用变量
unsigned char Seg_Pos; //数码管扫描变量
unsigned char ucRTC[2] = {0x23,0x55,0x40} //DS1302时钟专属变量 默认23-55-40
float Temperature; //DS18B20温度专属变量
unsigned char AD_Dat;
/* 按键处理函数 */
void Key_Proc() //负责键盘逻辑
{
if(Key_Slow_Down) return;
Key_Slow_Down = 1; //防止短时间多次触发该函数
Key_Val = Key_Read();
Key_Down = Key_Val & (Key_Val ^ Key_Old) //没太懂,先记住了
Key_Up = ~Key_Down;
Key_Old = Key_Val;
switch(Key_Down)
{
case 4:
break; //...接下来就可以写逻辑了
}
}
/* 信息处理函数 */
void Seg_Proc()
{
if(Seg_Slow_Down) return;
Seg_Slow_Down = 1;
/* 信息读取区域 */ //ds1302时钟 DS18B20温度 PCF8591 AD/DA都可以在这里读取
/* DS1302 */
RTC_Read(ucRTC);
/* DS18B20 */
Temperature = Temperature_Read();
/* PCF8591 */
AD_Dat = AD_Read(0x41); //或者43
/* 信息处理区域 */ //可以在这里把上边读取到的数据处理后赋值给Seg_Buf[]
/* DS1302 */
Seg_Buf[0] = ucRTC[0] / 16; //时第一位
Seg_Buf[1] = ucRTC[0] % 16; //时第二位
Seg_Buf[2] = ucRTC[1] / 16; //分第一位
Seg_Buf[3] = ucRTC[1] % 16; //分第二位
Seg_Buf[4] = ucRTC[2] / 16; //秒第一位
Seg_Buf[5] = ucRTC[2] % 16; //秒第二位
/* DS18B20 */
Seg_Buf[0] = (unsigned char)Temperature / 10 % 1; //整数第一位
Seg_Buf[1] = (unsigned char)Temperature % 10; //整数第二位
Seg_Buf[2] = (unsigned char)(Temperature * 100) % 10; //小数第一位
Seg_Buf[3] = (unsigned char)(Temperature * 10) % 10; //小数第二位
/* 其他处理函数 */
void LED_Proc()
{
//可以在这里操作LED 蜂鸣器等其他外设
}
void Timer0Init(void) //1毫秒@12.000MHz
{
AUXR &= 0x7F; //定时器时钟12T模式
TMOD &= 0xF0; //设置定时器模式
TL0 = 0x18; //设置定时初值
TH0 = 0xFC; //设置定时初值
TF0 = 0; //清除TF0标志
TR0 = 1; //定时器0开始计时
ET0 = 1;
EA = 1;
}
void Timer0Server() interrupt 1 //动 态 扫 描 !
{
if(++Key_Slow_Down == 10) Key_Slow_Down = 0;
if(++Seg_Slow_Down == 100) 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]);
}
void main()
{
Sys_Init();
RTC_Set();
While(1)
{
Key_Proc();
Seg_Proc();
LED_Proc();
}
}