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=12;
//if(P32==0) temp=13;
//if(P31==0) temp=14;
//if(P30==0) temp=15;
ET0 = 1;
P3=0xff;
return temp;
}
#### 2.1.2 数码管
Seg.c #include <Seg.h>
code unsigned char Dulu[18]={ 0xc0, //0 0xf9, //1 0xa4, //2 0xb0, //3 0x99, //4 0x92, //5 0x82, //6 0xf8, //7 0x80, //8 0x90, //9 0xff, //熄灭 0xbf, //- 0xc6, //C 0x89, //H 0x8e, //F 0x8c, //P 0x86, //E 0x88 //A };
code unsigned char Wulu[8]={0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80};
void Seg_Disp(unsigned char addr,dat,point) { //用段选消隐 P0=0xff; P2=P2&0x1f|0xe0; P2&=0x1f;
//位选
P0=Wulu[addr];
P2=P2&0x1f|0xc0;
P2&=0x1f;
//段选
P0=Dulu[dat];
if(point)
P0&=0x7f;
P2=P2&0x1f|0xe0;
P2&=0x1f;
}
#### 2.1.3 Led
>
> 我使用的是Led灯1亮,0灭的逻辑,所有P0取了一下反
>
>
>
Led.c #include <Led.h>
void Led_Disp(unsigned char addr,unsigned char flag) { static unsigned char temp=0x00; static unsigned char temp_old=0xff;
if(flag)
temp|=0x01<<addr;
else
temp&=~(0x01<<addr);
if(temp!=temp_old)
{
P0=~temp;
P2=P2&0x1f|0x80;
P2&=0x1f;
temp_old=temp;
}
}
#### 2.1.4 初始化
>
> 关闭了Led和数码管,防止在烧录过程在乱叫
>
>
>
Init.c #include <Init.h>
void System_Init(void) { P0=0xff; P2=P2&0x1f|0x80; P2&=0x1f;
P0=0x00;
P2=P2&0x1f|0xa0;
P2&=0x1f;
}
>
> 准备工作做好了,接下来我们开始写题目要求的底层代码
>
>
>
---
### 2.2 题目要求底层
>
> 由于第十四届只提供了.c文件,所有我们需要自己写.h文件
>
>
>
#### 2.2.1 PCF88591

>
> 题目中只要求ADC转换,所以我只写了这个部分。
>
>
>
iic.c /* # I2C代码片段说明 1. 本文件夹中提供的驱动代码供参赛选手完成程序设计参考。 2. 参赛选手可以自行编写相关代码或以该代码为基础,根据所选单片机类型、运行速度和试题 中对单片机时钟频率的要求,进行代码调试和修改。 */
#include <iic.h> #include <intrins.h> #define DELAY_TIME 5
sbit scl=P2^0; sbit sda=P2^1;
// 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();
return temp;
}
iic.h #include <STC15F2K60S2.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); unsigned char AD_Read(unsigned char addr); //void DA_Read(unsigned char dat);
#### 2.2.2 DS18B20
>
> 该模块一次只能读取8位,所以要读两次,采用float型数据
>
>
>
onewire.c /* # 单总线代码片段说明 1. 本文件夹中提供的驱动代码供参赛选手完成程序设计参考。 2. 参赛选手可以自行编写相关代码或以该代码为基础,根据所选单片机类型、运行速度和试题 中对单片机时钟频率的要求,进行代码调试和修改。 */
#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 Read_Temperature(void) { unsigned char high,low;
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;
}
onewire.h #include <STC15F2K60S2.H>
void Delay_OneWire(unsigned int t) ; void Write_DS18B20(unsigned char dat); unsigned char Read_DS18B20(void); bit init_ds18b20(void); float Read_Temperature(void);
#### 2.2.3 DS1302
>
> 该模块读取数据是16进制,不要忘记数码管表示时除或者取余16
>
>
>
ds1302.c /* # DS1302代码片段说明 1. 本文件夹中提供的驱动代码供参赛选手完成程序设计参考。 2. 参赛选手可以自行编写相关代码或以该代码为基础,根据所选单片机类型、运行速度和试题 中对单片机时钟频率的要求,进行代码调试和修改。 */ #include <ds1302.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 Set_Rtc(unsigned char ucRtc) { unsigned char i; Write_Ds1302_Byte(0x8e,0);//关闭写保护 for(i=0;i<3;i++) Write_Ds1302_Byte(0x84-i2,ucRtc[i]); Write_Ds1302_Byte(0x8e,1);//打开写保护 }
void Read_Rtc(unsigned char ucRtc) { unsigned char i; for(i=0;i<3;i++) ucRtc[i]=Read_Ds1302_Byte(0x85-i2); }
ds1302.h #include <STC15F2K60S2.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 Set_Rtc(unsigned char *ucRtc); void Read_Rtc(unsigned char *ucRtc);
#### 2.2.4 NE555
>
> NE555模块我放在main.c里面写的,采用定时器0,可以用STC烧录工具生成代码
>
>
>
>
> 加上一句**TMOD|=0x05;**就ok了
>
>
>
//NE555必须使用定时器0 且要加入(TMOD|=0x05;)这段代码 //定时器0初始化 void Timer0Init(void) //0毫秒@12.000MHz { AUXR &= 0x7F; //定时器时钟12T模式 TMOD &= 0xF0; //设置定时器模式 TMOD |= 0x05; //设置计时方式 TL0 = 0x00; //设置定时初始值 TH0 = 0x00; //设置定时初始值 TF0 = 0; //清除TF0标志 TR0 = 1; //定时器0开始计时 }
---
## 3.main.c文件
### 3.1 定时器
>
> 因为NE555采用定时器0,所以我采用定时器1来计时
>
>
>
/利用STC工具生成后要加入(ET1=1,EA=1)两段代码 //定时器1初始化 void Timer1Init(void) //1毫秒@12.000MHz { AUXR &= 0xBF; //定时器时钟12T模式 TMOD &= 0x0F; //设置定时器模式 TL1 = 0x18; //设置定时初始值 TH1 = 0xFC; //设置定时初始值 TF1 = 0; //清除TF1标志 TR1 = 1; //定时器1开始计时
ET1=1;
EA=1;
}
//定时器1 void Timer1Sever(void) interrupt 3 { if(++Key_Slow==10) Key_Slow=0; if(++Seg_Slow==500) Seg_Slow=0; if(++Seg_Pos==8) Seg_Pos=0;
if(++Timer_1000ms==1000)
{
TR0=0;//停止计时
Timer_1000ms=0;
Freq=(TH0<<8)|TL0;
TH0=TL0=0;
TR0=1;//开始计时
}
if(Find_Flag==1)
{
if(++Timer_3000ms==3000)
{
Timer_3000ms=3001;
}
}
if(S9_Flag==1)
{
if(++Timer_2000ms==2000)
Timer_2000ms=2001;
}
else
Timer_2000ms=0;
if(++Timer_1000ms==1000)
{
Timer_1000ms=0;
Led_Star_Flag=!Led_Star_Flag;
}
Seg_Disp(Seg_Pos,Seg_Buf[Seg_Pos],Seg_Point[Seg_Pos]);
Led_Disp(Seg_Pos,ucLed[Seg_Pos]);
}
### 3.2 void main()
>
> DS18B20上电后会先显示85,所以要延时750ms,STC生成
>
>
>

>
> 对应DS1302模块,要先设置时间
>
>
>
//main()函数 void main() { //读取DS18B20要在main()函数里面先读取延时750ms。 Read_Temperature(); Delay750ms(); //读书DS1302的时间要先在main()函数里面先设置。 Set_Rtc(ucRtc); //用定时器要先初始化 Timer0Init(); Timer1Init(); //板子要先初始化 System_Init(); while(1) { Key_Proc(); Seg_Proc(); Led_Proc(); } }
### 3.3 完整代码
main.c #include <STC15F2K60S2.H> #include <intrins.h> #include <iic.h> #include <onewire.h> #include <ds1302.h> #include <Seg.h> #include <Key.h> #include <Led.h> #include <Init.h>
//变量定义区 /按键/ unsigned char Key_Slow;//10 unsigned char Key_Val,Key_Down,Key_Up,Key_Old; /数码管/ unsigned int Seg_Slow;//500 unsigned Seg_Pos; unsigned Seg_Buf[8]={10,10,10,10,10,10,10,10}; unsigned Seg_Point[8]={0,0,0,0,0,0,0,0}; /Led/ unsigned ucLed[8]={0,0,0,0,0,0,0,0}; /自定义变量/
unsigned char Seg_Disp_Mode;//界面:0-时间,1-回显,2-参数 /时间界面/ unsigned char ucRtc[3]={0x13,0x03,0x05};//时-分-秒,写出0x的形式 /回显界面/ unsigned char Re_Disp_Mode;//回显:0-温度,1-湿度,2-时间 //温度回显· unsigned char Max_Temperature;//最大温度 float Aver_Temperature;//平均温度 //湿度回显 unsigned char Max_Humidity;//最大湿度 float Aver_Humidity;//平均湿度 //时间回显 unsigned char trigger_Inedx;//触发次数 unsigned char trigger_Time[3];//触发时间 /参数界面/ unsigned char Temperature_Set=30;
/温湿度界面/ unsigned int Freq;//实时频率 unsigned int Timer_1000ms; /S9长短按/ unsigned int Timer_2000ms;//用于S9长按 bit S9_Flag;//记录是否按下S9; /温湿度界面/ bit Tem_And_Hum_Flag;//温湿度界面和其他界面的区分标志 unsigned char Temperature_Disp;//温湿度界面的温度 unsigned char Humidity_Disp;//温湿度界面的湿度 unsigned char Temperature_Disp_Old;//上一次温湿度界面的温度 unsigned char Humidity_Disp_Old;//上一次温湿度界面的湿度 bit Error_Humidity;//湿度是否有效 bit Led6_Flag;//判断本次采集的温湿度是否均升高 /判断是否进入采集/ bit flag;//判断湿度数据是否有效,有效为0,无效为1; unsigned char Voltage; unsigned char Voltage_Old; unsigned int Timer_3000ms;//3s bit Find_Flag; /报警指示灯/ bit Led_Star_Flag;//控制亮灭 bit Led_Flag;//表明采集温度大于温度参数的状态 unsigned int Timer_1000ms;//1000ms
//清空数据函数 void Clear_Data(void) { unsigned char i=0; Max_Temperature=0; Aver_Temperature=0; Max_Humidity=0; Aver_Humidity=0; trigger_Inedx=0; for(i=0;i<3;i++) trigger_Time[i]=0; }
//按键处理函数 void Key_Proc() { if(Key_Slow) return; Key_Slow=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;
//时间回显界面
if(Re_Disp_Mode==2&&Seg_Disp_Mode==1)
{
if(Key_Down==9)
S9_Flag=1;//开始计时
if(Key_Up==9)//S9抬起
{
if(Timer_2000ms>=2000&&S9_Flag==1)
{
Clear_Data();
S9_Flag=0;//停止计时
}
else
S9_Flag=0;//停止计时
}
}
switch(Key_Down)
{
case 4:
if(++Seg_Disp_Mode==3)
Seg_Disp_Mode=0;
Re_Disp_Mode=0;
break;
case 5:
if(Seg_Disp_Mode==1)
{
if(++Re_Disp_Mode==3)
Re_Disp_Mode=0;
}
break;
case 8:
if(Seg_Disp_Mode==2)
{
if(++Temperature_Set==100)
Temperature_Set=99;
}
break;
case 9:
//参数界面
if(Seg_Disp_Mode==2)
{
if(--Temperature_Set==255)
Temperature_Set=0;
}
break;
}
}
//湿度处理函数 bit Read_Humidity(void) { if(Freq<200||Freq>2000) Error_Humidity=0;//无效数据 else { Error_Humidity=1; Humidity_Disp=(unsigned char)(2/45*(Freq-200)+10); } return Error_Humidity; }
//清除数码管 void Clear_Seg(void) { unsigned char i; for(i=0;i<8;i++) { Seg_Buf[i]=10; Seg_Point[i]=0; } } //信息处理函数 void Seg_Proc() { unsigned char i; if(Seg_Slow) return; Seg_Slow=1;
Read_Rtc(ucRtc);
Temperature_Disp=(unsigned char)Read_Temperature();
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上物联网嵌入式知识点,真正体系化!
由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、电子书籍、讲解视频,并且后续会持续更新