蓝桥杯单片机组第十四届省赛,字节跳动算法工程师面试总结

105 阅读8分钟
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


![](https://p3-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/a46938c6801c4b4f909f962245158239~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg5py65Zmo5a2m5Lmg5LmL5b-DQUk=:q75.awebp?rk3s=f64ab15b&x-expires=1771863698&x-signature=I5tCNF86WXGvgSWRVwDbSwDtMHA%3D)




> 

> 题目中只要求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烧录工具生成代码

> 

> 

> 





> 

> ![](https://p3-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/3588e438bec0477d88bc5a236637bbd0~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg5py65Zmo5a2m5Lmg5LmL5b-DQUk=:q75.awebp?rk3s=f64ab15b&x-expires=1771863698&x-signature=qRMvem7Z4kApqSyekutJQznMasg%3D)加上一句**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生成

> 

> 

> 



![](https://p3-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/e189f42603c042f390d274a6f092fc94~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg5py65Zmo5a2m5Lmg5LmL5b-DQUk=:q75.awebp?rk3s=f64ab15b&x-expires=1771863698&x-signature=XlLTyTlXjdFAbePJoXN6nQ9sp9U%3D)




> 

> 对应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();

img img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上物联网嵌入式知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、电子书籍、讲解视频,并且后续会持续更新

如果你需要这些资料,可以戳这里获取