一、分模块
1.led和smg检测
单片机上电后,8个LED灯 从左到右依次点亮,然后再从左到右依次熄灭,进行LED的 检测;8个数码管 从左到右,逐个数码管全部段码点亮,然后再从左到右,这个数据管全部 段码熄灭,进行数码管的检测。关闭蜂鸣器和继电器等无关设备。
void Displaysmg()
{
unsigned char i;
Select_Hc138(7,0x00);
for(i=0;i<8;i++)
{
Select_Hc138(6,~(0xfe<<i));
Delay(1000);
}//smg从左到右依次点亮
for(i=0;i<8;i++)
{
Select_Hc138(6,0xfe<<i);
Delay(1000);
}//smg从左到右依次熄灭
}
void running()
{
unsigned char j;
for(j=0;j<8;j++)
{
Select_Hc138(4,0xff<<j);//从左到右依次点亮
Delay(1000);
}
for(j=7;j>0;j--)
{
Select_Hc138(4,0xff>>j);//从左到右依次熄灭
Delay(1000);
}
Select_Hc138(4,0xff);
Displaysmg();
Select_Hc138(5,0x00);
Select_Hc138(7,0xff);
}
2.ds1302时钟读写及显示
初始化DS1302 实时时钟参数为:21年4月17日,星期六,23点58分32秒 ,并以此 时间为基准启动DS1302,计算系统运行的时间。这部分的初始化实时时钟我放到了最后系统初始化的部分了。
//===============ds1302时钟读写及显示=======================
void DS1302_Config()//配置时钟
{
unsigned char i;
Write_Ds1302_Byte(0x8e,0x00); //打开写寄存器
for(i=0;i<7;i++)
{
Write_Ds1302_Byte( Write_DS1302_adrr[i],Time[i]); //将Time里存储的数字分配到相应的地址中
}
Write_Ds1302_Byte(0x8e,0x80); //关闭写寄存器
}
void Read_DS1302_Timer()//读时间
{
unsigned char i;
for(i=0;i<7;i++)
{
Time[i]=Read_Ds1302_Byte( Read_DS1302_adrr[i] );//系统运行的时间
}
}
void Display_time()
{
Read_DS1302_Timer();
Display(smgduanma[Time[2]/16],0);//显示小时的十位
Display(smgduanma[Time[2]%16],1);//小时个位
Display(smgduanma[16],2);//显示-
Display(smgduanma[Time[1]/16],3);//显示分钟十位
Display(smgduanma[Time[1]%16],4);
Display(smgduanma[16],5);
Display(smgduanma[Time[0]/16],6);
Display(smgduanma[Time[0]%16],7);
DisplayAll();//消除不显示和重叠
}
3.温度读取与显示
采样DS18B20 的温度数据,换算后,显示在数码管的最右边三位 ,保留1位小数 。
需要注意的是温度显示时,只需要显示数码管最右边三位,其余地方不用做处理,因为数码管前三位需要显示光敏电阻电压,如果将其设置为0xff会影响最后结果显示。
//===============温度读取与显示=========================
void Read_ds18b20_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();
init_ds18b20();
temp=MSB;
temp=(temp<<8)|LSB;//合并为一个十六位的值
if((temp & 0xf800)==0x0000)//判断温度是否为正数
{
temp>>=4;//温度值右移四位,temp是16位的有符号整数,最高四位位小数部分,剩下12位是整数部分
temp=temp*10;//将12位整数部分转换为实际温度值
temp=temp+(LSB & 0x0f)*0.625;//将LSB的低四位乘以0.625是为了得到小数部分的实际值
}
}
void Display_temp()
{
Display(SMGNoDot_CA[(temp%10)%10],7);
Display(SMGDot_CA[((temp/10)%10)%10],6);
Display(SMGNoDot_CA[((temp/100)%10)%10],5);
DisplayAll();//消除显示重叠或显示不完整情况
}
4.读取显示通道1光敏电阻电压
采样PCF8591 通道1的电压,换算后,显示在数据管的最左边三位 ,保留2位小数 ;并 以该采样值为参数,控制PCF8591的DAC输出电压,使DAC的输出电压与光敏电阻的输出电压保持一致。PCF8591 通道1连接的是光敏电阻的输出电压,当光敏电阻的输出电压小于2V时,自动 点亮LED灯L1,反之,L1自动熄灭,记录LED灯的状态。
//================读取显示通道1光敏电阻电压===========
//通过I2C总线读取PCF8591模数转换器采集的数据,包括选择通道和读取数据。
unsigned char Read_PCF8591_ADC(void )
{
unsigned char tmp;
I2CStart(); //启动i2c通信
I2CSendByte(0x90); //PCF8591的写设备地址,告诉pcf8591要进行写操作
I2CWaitAck(); //等待设备的应答信号
I2CSendByte(0x01); //通道1,光敏电阻电压
I2CWaitAck();
I2CStop();
DisplaySMG_ADC(); //等待电压转换完成
I2CStart();
I2CSendByte(0x91); //PCF8591的读设备地址
I2CWaitAck();
tmp = I2CReceiveByte(); //读出AD采样数据
I2CSendAck(1); //产生非应答信号,告诉pcf8591不需要再发送数据
I2CStop();
return tmp;
}
void Read_AIN1()
{
adc1_value = Read_PCF8591_ADC();//读取通道1的adc值
adc1_volt = adc1_value * (5.0 / 255);//adc转换成电压值
smg1_volt = adc1_volt * 100;//转换成整数显示
if(adc1_volt < 2)
{
Select_Hc138(4,0xfe);
}
else
{
Select_Hc138(4,0xff);
}
}
void DisplaySMG_ADC()
{
//数码管左起第0位
Display(SMGNoDot_CA[smg1_volt % 10],2);
//数码管左起第1位
Display(SMGNoDot_CA[(smg1_volt / 10) % 10],1);
//数码管左起第2位
Display(SMGDot_CA[smg1_volt / 100],0);
DisplayAll();
}
5.s4s5按键
1.按键S4 控制显示界面切换,按下S4不动,显示DS1302的实时时间,格式为“时-分 秒”,如23点05分17秒的格式为“23-05-17”。松开S4后,恢复电压和温度数据显示。
2. 按键S5 为模拟火警触发,第1次按下S5,触发火警,LED灯L8点亮;再次按下S5,取 消火警,LED灯L8熄灭,记录火警的状态。
3. 累计S5按键的触发次数,当触发次数大于99时清零;这个部分还没有完全完成,后面会补充完整的。
//================按键================
void KeyaloneS4()
{
if(S4==0)
{
smg_Delay(100);
if(S4==0)
{
Display_time();
}
while(S4==0)
{
Display_time();
}
Display_temp();
DisplaySMG_ADC();
}
}
void KeyaloneS5()
{
state++;
if(state > 99)
{
state = 0;
}
if(S5 == 0)
{
smg_Delay(100);
if(std == 0xff)
{
std = 0x7f;
}
else
{
std = 0xff;
}
if(S5==0)
{
Select_Hc138(4,std);
while(S5 == 0)
{
Select_Hc138(4,std);
Display_temp();
DisplaySMG_ADC();
}
}
}
}
6.系统初始化
//================系统初始化================================
void Init_Temp() //初次温度读取,避免读取默认值85
{
unsigned char LSB,MSB;
init_ds18b20(); //复位
Write_DS18B20(0xcc); //跳过ROM
Write_DS18B20(0x44); //转换温度
do{
init_ds18b20(); //复位
Write_DS18B20(0xcc); //跳过ROM
Write_DS18B20(0xbe); //读暂存器
LSB = Read_DS18B20(); //先读取低8位
MSB = Read_DS18B20(); //后读取高8位
MSB = (MSB << 4) | (LSB >> 4);
}while(MSB == 85); //直到首次温度转换完成
//避免上电后读取温度默认值85
}
void initSystem()
{
Select_Hc138(4,0xff);
Select_Hc138(5,0x00);
Select_Hc138(7,0xff);
Init_Temp();
}
7.iic.c
/* # I2C代码片段说明
1. 本文件夹中提供的驱动代码供参赛选手完成程序设计参考。
2. 参赛选手可以自行编写相关代码或以该代码为基础,根据所选单片机类型、运行速度和试题
中对单片机时钟频率的要求,进行代码调试和修改。
*/
#include <STC15F2K60S2.H>
#include "intrins.h"
#define DELAY_TIME 5
sbit sda = P2^1;
sbit scl = P2^0;
//
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);
}
8.iic.h
#ifndef _IIC_H
#define _IIC_H
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
9.ds1302.c
/* # DS1302代码片段说明
1. 本文件夹中提供的驱动代码供参赛选手完成程序设计参考。
2. 参赛选手可以自行编写相关代码或以该代码为基础,根据所选单片机类型、运行速度和试题
中对单片机时钟频率的要求,进行代码调试和修改。
*/
//
#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);
}
10.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
11.onewire.c
/* # 单总线代码片段说明
1. 本文件夹中提供的驱动代码供参赛选手完成程序设计参考。
2. 参赛选手可以自行编写相关代码或以该代码为基础,根据所选单片机类型、运行速度和试题
中对单片机时钟频率的要求,进行代码调试和修改。
*/
//
#include <STC15F2K60S2.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;
}
12.onewire.h
#ifndef _ONEWIRE_H_
#define _ONEWIRE_H_
bit init_ds18b20(void);
unsigned char Read_DS18B20(void);
void Write_DS18B20(unsigned char dat);
#endif
二、完整代码
#include <STC15F2K60S2.H>
#include "ds1302.h"
#include "onewire.h"
#include "iic.h"
#define TSMG 500
sbit S4 = P3^3;
sbit S5 = P3^2;
unsigned char state=0;
unsigned char Write_DS1302_adrr[7]={0x80,0x82,0x84,0x86,0x88,0x8a,0x8c};
unsigned char Read_DS1302_adrr[7]={0x81,0x83,0x85,0x87,0x89,0x8b,0x8d};
unsigned char SMGNoDot_CA[10]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90};
unsigned char SMGDot_CA[10]={0x40,0x79,0x24,0x30,0x19,0x12,0x02,0x78,0x00,0x10};
unsigned int temp=0;
unsigned char adc1_value = 0; //AIN1的采样数据
float adc1_volt = 0; //AIN1的换算电压
unsigned int smg1_volt = 0; //AIN1的显示电压
unsigned char std = 0xff;
unsigned char code smgduanma[18]={
0xC0,0xF9,0xA4,0xB0,0x99,0x92,
0x82,0xF8,0x80,0x90,0x88,0x80,
0xc6,0xc0,0x86,0x8e,0xbf,0x7f
};
//2021.4.17 周六 23:58:32
//秒——分——时——日——月——周——年
unsigned char Time[7]={0x32,0x58,0x23,0x17,0x04,0x06,0x21};//采用BCD编码
//=============================================
void Display_temp();
void Display_time();
void DisplaySMG_ADC();
void Select_Hc138(unsigned char n,unsigned char dat)
{
P2=(P2&0x1f)|0x00;
P0=dat;
switch(n)
{
case(4):P2=(P2&0x1f)|0x80;
break;
case(5):P2=(P2&0x1f)|0xa0;
break;
case(6):P2=(P2&0x1f)|0xc0;
break;
case(7):P2=(P2&0x1f)|0xe0;
break;
}
P2=(P2&0x1f)|0x00;
}
void Delay(unsigned int t)
{
while(t--);
while(t--);
while(t--);
}
void smg_Delay(unsigned int t)
{
while(t--);
}
void Display(unsigned char value,unsigned char pos)//====显示
{
Select_Hc138(7,0xff);
Select_Hc138(6,0x01<<pos);
Select_Hc138(7,value);
smg_Delay(100);
}
void DisplayAll()//======消影
{
Select_Hc138(6,0xff);
Select_Hc138(7,0xff);
}
//==============led和smg检测=========================
void Displaysmg()
{
unsigned char i;
Select_Hc138(7,0x00);
for(i=0;i<8;i++)
{
Select_Hc138(6,~(0xfe<<i));
Delay(1000);
}//smg从左到右依次点亮
for(i=0;i<8;i++)
{
Select_Hc138(6,0xfe<<i);
Delay(1000);
}//smg从左到右依次熄灭
}
void running()
{
unsigned char j;
for(j=0;j<8;j++)
{
Select_Hc138(4,0xff<<j);//从左到右依次点亮
Delay(1000);
}
for(j=7;j>0;j--)
{
Select_Hc138(4,0xff>>j);//从左到右依次熄灭
Delay(1000);
}
Select_Hc138(4,0xff);
Displaysmg();
Select_Hc138(5,0x00);
Select_Hc138(7,0xff);
}
//===============ds1302时钟读写及显示=======================
void DS1302_Config()//配置时钟
{
unsigned char i;
Write_Ds1302_Byte(0x8e,0x00); //打开写寄存器
for(i=0;i<7;i++)
{
Write_Ds1302_Byte( Write_DS1302_adrr[i],Time[i]); //将Time里存储的数字分配到相应的地址中
}
Write_Ds1302_Byte(0x8e,0x80); //关闭写寄存器
}
void Read_DS1302_Timer()//读时间
{
unsigned char i;
for(i=0;i<7;i++)
{
Time[i]=Read_Ds1302_Byte( Read_DS1302_adrr[i] );//系统运行的时间
}
}
void Display_time()
{
Read_DS1302_Timer();
Display(smgduanma[Time[2]/16],0);//显示小时的十位
Display(smgduanma[Time[2]%16],1);//小时个位
Display(smgduanma[16],2);//显示-
Display(smgduanma[Time[1]/16],3);//显示分钟十位
Display(smgduanma[Time[1]%16],4);
Display(smgduanma[16],5);
Display(smgduanma[Time[0]/16],6);
Display(smgduanma[Time[0]%16],7);
DisplayAll();//消除不显示和重叠
}
//===============温度读取与显示=========================
void Read_ds18b20_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();
init_ds18b20();
temp=MSB;
temp=(temp<<8)|LSB;//合并为一个十六位的值
if((temp & 0xf800)==0x0000)//判断温度是否为正数
{
temp>>=4;//温度值右移四位,temp是16位的有符号整数,最高四位位小数部分,剩下12位是整数部分
temp=temp*10;//将12位整数部分转换为实际温度值
temp=temp+(LSB & 0x0f)*0.625;//将LSB的低四位乘以0.625是为了得到小数部分的实际值
}
}
void Display_temp()
{
Display(SMGNoDot_CA[(temp%10)%10],7);
Display(SMGDot_CA[((temp/10)%10)%10],6);
Display(SMGNoDot_CA[((temp/100)%10)%10],5);
DisplayAll();//消除显示重叠或显示不完整情况
}
//================读取显示通道1光敏电阻电压===========
//通过I2C总线读取PCF8591模数转换器采集的数据,包括选择通道和读取数据。
unsigned char Read_PCF8591_ADC(void )
{
unsigned char tmp;
I2CStart(); //启动i2c通信
I2CSendByte(0x90); //PCF8591的写设备地址,告诉pcf8591要进行写操作
I2CWaitAck(); //等待设备的应答信号
I2CSendByte(0x01); //通道1,光敏电阻电压
I2CWaitAck();
I2CStop();
DisplaySMG_ADC(); //等待电压转换完成
I2CStart();
I2CSendByte(0x91); //PCF8591的读设备地址
I2CWaitAck();
tmp = I2CReceiveByte(); //读出AD采样数据
I2CSendAck(1); //产生非应答信号,告诉pcf8591不需要再发送数据
I2CStop();
return tmp;
}
void Read_AIN1()
{
adc1_value = Read_PCF8591_ADC();//读取通道1的adc值
adc1_volt = adc1_value * (5.0 / 255);//adc转换成电压值
smg1_volt = adc1_volt * 100;//转换成整数显示
if(adc1_volt < 2)
{
Select_Hc138(4,0xfe);
}
else
{
Select_Hc138(4,0xff);
}
}
void DisplaySMG_ADC()
{
//数码管左起第0位
Display(SMGNoDot_CA[smg1_volt % 10],2);
//数码管左起第1位
Display(SMGNoDot_CA[(smg1_volt / 10) % 10],1);
//数码管左起第2位
Display(SMGDot_CA[smg1_volt / 100],0);
DisplayAll();
}
//================按键================
void KeyaloneS4()
{
if(S4==0)
{
smg_Delay(100);
if(S4==0)
{
Display_time();
}
while(S4==0)
{
Display_time();
}
Display_temp();
DisplaySMG_ADC();
}
}
void KeyaloneS5()
{
state++;
if(state > 99)
{
state = 0;
}
if(S5 == 0)
{
smg_Delay(100);
if(std == 0xff)
{
std = 0x7f;
}
else
{
std = 0xff;
}
if(S5==0)
{
Select_Hc138(4,std);
while(S5 == 0)
{
Select_Hc138(4,std);
Display_temp();
DisplaySMG_ADC();
}
}
}
}
//================系统初始化================================
void Init_Temp() //初次温度读取,避免读取默认值85
{
unsigned char LSB,MSB;
init_ds18b20(); //复位
Write_DS18B20(0xcc); //跳过ROM
Write_DS18B20(0x44); //转换温度
do{
init_ds18b20(); //复位
Write_DS18B20(0xcc); //跳过ROM
Write_DS18B20(0xbe); //读暂存器
LSB = Read_DS18B20(); //先读取低8位
MSB = Read_DS18B20(); //后读取高8位
MSB = (MSB << 4) | (LSB >> 4);
}while(MSB == 85); //直到首次温度转换完成
//避免上电后读取温度默认值85
}
void initSystem()
{
Select_Hc138(4,0xff);
Select_Hc138(5,0x00);
Select_Hc138(7,0xff);
Init_Temp();
}
void main()
{
initSystem();
running();
DS1302_Config();
while(1)
{
Read_AIN1();
DisplaySMG_ADC();
Display_temp();
Read_ds18b20_temp();
KeyaloneS4();
KeyaloneS5();
Select_Hc138(4,std);
}
}
标签:03,char,Hc138,进阶,temp,void,unsigned,蓝桥,Select
From: https://blog.csdn.net/weixin_67613273/article/details/136858505