当前位置: 首页 > news >正文

蓝桥杯单片机STC15F2K60S2第十四届省赛代码详细讲解(附完整代码)

        本文是写第十四届的蓝桥杯省赛代码,新手教程作者也写了一篇,欢迎去观看作者专门为新手写的一篇。也欢迎收录该专栏。

蓝桥杯单片机STC15F2K60S2第十三届省赛代码详细讲解(附完整代码)

专栏: 

        蓝桥杯单片机

        然后接下来是正文:

试题:

 

 

 

 

 iic.c

/*	#   I2C代码片段说明1. 	本文件夹中提供的驱动代码供参赛选手完成程序设计参考。2. 	参赛选手可以自行编写相关代码或以该代码为基础,根据所选单片机类型、运行速度和试题中对单片机时钟频率的要求,进行代码调试和修改。
*/
#include "iic.h"
#include "intrins.h"
#define DELAY_TIME	5//
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);
}//输出ADC的值,用来计算PCF8591的分压结果,实现亮暗检测
unsigned char ADC_Output(char channel)
{unsigned char adc_val;	//输出的ADC的值I2CStart();I2CSendByte(0x90);		//开启ADC通道,0x90是ADC的设备地址,指定为写操作I2CWaitAck();I2CSendByte(channel);	//指定要读的ADC通道 0x41是光敏电阻I2CWaitAck();I2CStart();I2CSendByte(0x91);		//指定为读操作I2CWaitAck();adc_val=I2CReceiveByte();I2CSendAck(1);I2CStop();return adc_val;
}

iic.h

#ifndef  __IIC_H__
#define  __IIC_H__#include <stc15.h>#define sda  P21
#define scl  P20unsigned char ADC_Output(char channel);
#endif

display.c

#include <STC15F2K60S2.H>code unsigned char Show_Number[]={
0xc0, 0xf9, 0xa4, 0xb0, 0x99, 0x92, 0x82, 0xf8, 0x80, 0x90, //9
0x88, //A
0x83, //b
0xc6, //C  12
0xa1, //d
0x86, //E
0x8e, //F 15
0xbf,  // - 16
0x89,  // H 17
0x8C,  // P 18
0x88  // R  19
};//0到9的浮点小数
code unsigned char Show_FNumber[]={0x40, 0x79, 0x24, 0x30, 0x19, 0x12, 0x02, 0x78, 0x00, 0x10};//延时函数
void Delayms(int ms)	//@12.000MHz
{unsigned char data i, j;int k=0;for(k=0;k<ms;k++){i = 12;j = 169;do{while (--j);} while (--i);}
}void Select_Hc573(unsigned char Number)
{switch(Number){case 4:P2=(P2 & 0x1f) | 0x80;break;	//LED驱动case 5:P2=(P2 & 0x1f) | 0xA0;break; //蜂鸣器和继电器case 6:P2=(P2 & 0x1f) | 0xC0;break; //数码管位选case 7:P2=(P2 & 0x1f) | 0xE0;break; //数码管段选} //将P2位清零,不然数码管会闪烁P2 =(P2 & 0x1f) | 0x00;
}//系统初始化,将蜂鸣器和数码管关闭
void System_Init(void)
{P0=0x00;Select_Hc573(5);Select_Hc573(6);P0=0xff;Select_Hc573(4);
}void Display_Number(unsigned char Pos,unsigned char Data)
{P0 = 0x01 << Pos-1;Select_Hc573(6);P0 = Show_Number[Data];Select_Hc573(7);Delayms(1);P0 =0x01 << Pos -1;Select_Hc573(6);P0 =0xff;Select_Hc573(7);
}//显示小数
void Display_FNumber(unsigned char Pos,unsigned char Data)
{P0 = 0x01 << Pos -1;Select_Hc573(6);P0=Show_FNumber[Data];Select_Hc573(7);Delayms(1);P0 = 0x01 << Pos -1;Select_Hc573(6);P0=0xff;Select_Hc573(7);Delayms(1);
}//显示LED,ON_OFF 1为开启,0为关闭
void Display_LED(unsigned char Pos,unsigned ON_OFF)
{static unsigned char Temp=0xff;if(ON_OFF){switch(Pos){case 1: Temp =Temp&0xfe;break;case 2: Temp =Temp&0xfd;break;case 3: Temp =Temp&0xfb;break;case 4: Temp =Temp&0xf7;break;case 5: Temp =Temp&0xef;break;case 6: Temp =Temp&0xde;break;}}else {switch(Pos){case 1:Temp=Temp | 0x01;break;case 2:Temp=Temp | 0x02;break;case 3:Temp=Temp | 0x04;break;case 4:Temp=Temp | 0x08;break;case 5:Temp=Temp | 0x10;break;case 6:Temp=Temp | 0x20;break;}}P0=Temp;Select_Hc573(4);
}

display.h 

#ifndef		__DISPLAY_H__
#define		__DISPLAY_H__void SelectHc573(unsigned char Number);
void System_Init(void);
void Display_Number(unsigned char Pos,unsigned char Data);
void Display_FNumber(unsigned char Pos,unsigned char Data);
void Display_LED(unsigned char Pos,unsigned ON_OFF);
void Delayms(int ms);#endif

ds1302.c

/*	# 	DS1302代码片段说明1. 	本文件夹中提供的驱动代码供参赛选手完成程序设计参考。2. 	参赛选手可以自行编写相关代码或以该代码为基础,根据所选单片机类型、运行速度和试题中对单片机时钟频率的要求,进行代码调试和修改。
*/								
#include "ds1302.h"
#include <STC15F2K60S2.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);			
}//写保护
#define WP 		0x8e
#define W_Sec 	0x80
#define R_Sec	0x81
#define W_Min	0x82
#define R_Min	0x83
#define W_Hour	0x84
#define R_Hour	0x85//写初始化时间到ds1302
void WriteDate(ds1302 *date)
{unsigned hour, min, sec;hour =date->Hour/10*16 + date->Hour%10;	//十进制转化为十六进制min=date->Min/10*16 + date->Min%10;sec=date->Sec/10*16 + date->Sec%10;//取消写保护Write_Ds1302_Byte(WP,0x00);Write_Ds1302_Byte(W_Hour,hour);Write_Ds1302_Byte(W_Min,min);Write_Ds1302_Byte(W_Sec,sec);//开启写保护Write_Ds1302_Byte(WP,0x00);
}//读取当前时间
ds1302 ReadTime()
{unsigned char hour,min,sec;ds1302 date;hour = Read_Ds1302_Byte(R_Hour);min = Read_Ds1302_Byte(R_Min);sec = Read_Ds1302_Byte(R_Sec);date.Hour = hour/16*10 + hour%16;	//十六进制转化为十进制date.Min = min/16*10 + min%16;date.Sec =sec/16*10 + sec%16;return date;
}

ds1302.h

#ifndef  __DS1302_H__
#define  __DS1302_H__#include "intrins.h"
#include <STC15F2K60S2.H>//#define SCK		P17
//#define SDA		P23
//#define RST		P13//定义ds1302的数据类型
typedef struct{unsigned char Hour;unsigned char Min;unsigned char Sec;
}ds1302;void WriteDate(ds1302 *date);
ds1302 ReadTime();#endif

onrwire.c

/*	# 	单总线代码片段说明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;Delay_OneWire(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;
}unsigned char Read_Temperature(void)
{unsigned temp,th,tl;init_ds18b20();Write_DS18B20(0xcc);Write_DS18B20(0x44);init_ds18b20();			//开启温度转换Write_DS18B20(0xcc);Write_DS18B20(0xbe);	//开启温度读取tl = Read_DS18B20();th = Read_DS18B20();temp = (th *256 + tl) * 0.0625;return temp;
}

onewire.h

#ifndef  __ONEWIRE_H__
#define  __ONEWIRE_H__#include <STC15F2K60S2.H>#define DQ  P14
unsigned char Read_Temperature(void);
#endif

main.c

#include <STC15F2K60S2.H>
#include "display.h"
#include "ds1302.h"
#include "onewire.h"
#include "iic.h"
#include "string.h"ds1302 Date={23,59,50};unsigned int Freq;		//NE555的频率
unsigned char Wet_Val;	//湿度的数据
unsigned char Adc_Val;	//ADC的值
unsigned char Collect_Flag=1;	//暗亮环境的标志,1表示处于亮环境
unsigned char i;	//数组的索引
//unsigned char temp=0;	//温度
unsigned char count2,sec;	//暗环境时的计时,3秒后退出
unsigned char show;		//0为温湿度界面的显示,1显示Show_Switch对应的界面
unsigned char t[3],w[3]; //用于保存采集的温度、湿度,只保留3组
unsigned char L5_Flag,L6_Flag,L4_Flag;	//LED的标志为 1为开启LED
unsigned char count_trigger=0; //用来记录触发的次数
unsigned char last_hour,last_min;	//最近一次触发的时间
unsigned char Temp_Para=30;	//温度参数
unsigned char Key_Val;		//用来记录按键
unsigned char Switching=1;	//界面切换 1.时间显示界面 2.回显界面 3.参数显示
unsigned char S5_Flag=1;	//回显界面下,切换温度、湿度、时间回显
unsigned char Count3,Count_Sec;	//用于S9长按两秒的计时
unsigned char Temping=0;		//温度
unsigned char Flag_100ms;		//0.1s的标志位,L4以0.1秒为间隔进行闪烁
unsigned char Flag_1s;			//用来表示1s时间到,统计NE555的频率
unsigned char Count;			//用于定时器的中断定时void Key_Board(void);
void Show_Switch(void);
void Timer0_Init(void);		//@12.000MHz;
void Timer1_Init(void);		//10毫秒@12.000MHz
void Timer2_Init(void);	//20毫秒@12.000MHzvoid main()
{System_Init();WriteDate(&Date);Timer0_Init();Timer1_Init();Timer2_Init();while(1){		if(Freq<2000 && Freq>200)Wet_Val=2/45*Freq + 1.11;else if(Freq == 2000)Wet_Val = 90;else if(Freq == 200)Wet_Val = 10;else Wet_Val =0;		//无效数据Adc_Val = ADC_Output(0x01);		//读取ADC的值if(Adc_Val > 100)	Collect_Flag=1;		//ADC值大于100表示处于亮环境if(Adc_Val <=100 && Collect_Flag ==1)	//触发数据测量条件{Collect_Flag=0; AUXR |= 0x10;	//启动定时器2show =1;t[i]=Temping;if(Wet_Val != 0){ w[i] = Wet_Val; L5_Flag=0; }else {L5_Flag=1;}	//采集到无效数据,无效数据不保存,点亮LED5count_trigger++;if(i==0 && count_trigger>=2)	//本次采集大小与上次比较{if(Temping > t[2] && Wet_Val > w[2])	L6_Flag=1;	//采集到的温度湿度均升高,LED6点亮else L6_Flag=0;}else L6_Flag=1;if(i !=0 && count_trigger>=2){if(Temping >t[i-1]&&Wet_Val>w[i-1])	L6_Flag=1;	//温湿度都大于上次else L6_Flag=0;}else L6_Flag=0;i++;if(i>3) i=0;last_hour = Date.Hour;last_min = Date.Min;if(Temping > Temp_Para)	L4_Flag=1;	//采集温度大于温度参数,LED4点亮else L4_Flag=0;}Key_Board();	//按键检测函数Show_Switch();	//所有显示函数放在此函数内,为了使按键按下,不影响显示内容}
}//按键检测函数
void Key_Board(void)
{unsigned char Key;//P44为第一列按键,P3低四位为每一行,第一行为0x01P44 =0; P42=1;P3 |=0x0f;	//将每一行置1Key= P3; Key = Key & 0x0c;if(Key != 0x0c){Delayms(5);		//消抖if(Key != 0x0c){switch(Key){case 0x04: Key_Val = 4; Switching++;if(Switching > 3){Switching =1;S5_Flag=1;}								break;	case 0x08: Key_Val=5;if(Switching == 2)	//回显界面{S5_Flag++;}if(S5_Flag > 3)S5_Flag=1;break;}}	while(Key != 0x0c){Key = P3; Key = Key & 0x0c;Show_Switch();}}P44=1;P42=0;P3 |= 0x0f;Key = P3; Key &=0x0c;if(Key !=0x0c){Delayms(5);if(Key != 0x0c){switch(Key)		//S8++ S9--{case 0x04: Key_Val=8;if(Switching == 3) Temp_Para++;if(Temp_Para > 99) Temp_Para=0;break;case 0x08: Key_Val=9;if(Switching == 3) Temp_Para--;if(Temp_Para == 255) Temp_Para =99;break;}if(S5_Flag == 3) { Count3 = 0; Count_Sec = 0;}	//时间回显下,S9按下两秒计时开始}while(Key != 0x0c){Key = P3; Key = Key & 0x0c;Show_Switch();if(Count_Sec >= 2 && S5_Flag == 3) //时间回显界面,长按S9两秒,数据清零{memset(t,0,sizeof(t)); memset(w,0,sizeof(w));	//将数组里的全部元素清零count_trigger=0;	//触发次数清零}}}
}unsigned char max(unsigned char p[])
{unsigned char i;unsigned char Max=p[0];for(i=1;i<3;i++){if(p[i] > Max)Max=p[i];}return Max;
}void Show_Switch(void)
{//最大温度和湿度unsigned char t_max,w_max;int t_avr,w_avr;	//温湿度平均值Date= ReadTime();Temping = Read_Temperature();t_max=max(t); w_max=max(w);t_avr = (t[0] + t[1]+t[2])/3.0*10;w_avr=(w[0]+w[1]+w[2])/3.0*10;if(show !=1){if(Switching ==1)	//时间显示界面{Display_Number(1,Date.Hour/10);Display_Number(2,Date.Hour%10);Display_Number(3,16);Display_Number(4,Date.Min/10);Display_Number(5,Date.Min%10);Display_Number(6,16);Display_Number(7,Date.Sec/10);Display_Number(8,Date.Sec%10);}if(Switching == 2)	//回显界面,默认温度回显C{switch(S5_Flag)	//温度回显C,湿度回显H,时间回显F{//温度回显case 1: Display_Number(1,12);if(count_trigger !=0 )	//触发次数不为0{Display_Number(3,t_max/10);Display_Number(4,t_max%10);	//最大温度Display_Number(5,16);Display_Number(6,t_avr/100);Display_FNumber(7,t_avr%100/10);Display_Number(8,t_avr%10);}break;case 2: Display_Number(1,17);	//Hif(count_trigger != 0){Display_Number(3,w_max/10);Display_Number(4,w_max%10);Display_Number(5,16);Display_Number(6,w_avr/100);Display_FNumber(7,w_avr%100/10);Display_Number(8,w_avr%10);}break;case 3:Display_Number(1,15);Display_Number(2,count_trigger/10);Display_Number(3,count_trigger%10);	//触发次数显示if(count_trigger != 0){Display_Number(4,last_hour/10);Display_Number(5,last_hour%10);Display_Number(6,16);Display_Number(7,last_min/10);Display_Number(8,last_min%10);}break;}}if(Switching == 3)	//参数设置界面{Display_Number(1,18);Display_Number(7,Temp_Para/10);Display_Number(8,Temp_Para%10);}}else 	//温湿度显示界面,每次显示3秒后自动退出{Display_Number(1,14);Display_Number(4,Temping/10);Display_Number(5,Temping%10);Display_Number(6,16);//温度if(Wet_Val != 0){Display_Number(7,Wet_Val/10);Display_Number(8,Wet_Val%10);}else {Display_Number(7,19);Display_Number(8,19);}}//LED显示switch(Switching){case 1: Display_LED(1,1);Display_LED(2,0);Display_LED(3,0);break;case 2: Display_LED(2,1);Display_LED(1,0);Display_LED(3,0);break;case 3: Display_LED(3,1);Display_LED(1,0);Display_LED(2,0);break;}if(L4_Flag ==1){if(Flag_100ms) Display_LED(4,1);else Display_LED(4,0);}else Display_LED(4,0);if(L5_Flag == 1){Display_LED(5,1);} else Display_LED(5,0);if(L6_Flag == 1){Display_LED(6,1);} else Display_LED(6,0);
}void Timer0_Init(void)		//@12.000MHz
{AUXR &= 0x7F;			//定时器时钟12T模式TMOD &= 0xF0;			//设置定时器模式TMOD |=0x04;TL0 = 0;				//设置定时初始值TH0 = 0;				//设置定时初始值TF0 = 0;				//清除TF0标志ET0 = 1;				//使能定时器0中断TR0 = 1;				//定时器0开始计时
}void Timer1_Init(void)		//10毫秒@12.000MHz
{AUXR &= 0xBF;			//定时器时钟12T模式TMOD &= 0x0F;			//设置定时器模式TL1 = 0xF0;				//设置定时初始值TH1 = 0xD8;				//设置定时初始值TF1 = 0;				//清除TF1标志TR1 = 1;				//定时器1开始计时ET1 = 1;				//使能定时器1中断EA =1;					//使能全局中断,确保定时器1能正常中断
}void Timer1(void) interrupt 3
{Count++;Count3++;if(Count == 100){Count =0;Flag_1s=1;}if(Count % 10 == 0){Flag_100ms=~Flag_100ms;}if(Flag_1s == 1){Flag_1s=0; TR0 =0;Freq = TH0*256 + TL0;	//定时器0是用P34来读取NE555的频率TH0=0;TL0=0;TR0=1;}if(Count3 == 100){Count3=0;Count_Sec++;}
}void Timer2_Init(void)		//20毫秒@12.000MHz
{AUXR &= 0xFB;			//定时器时钟12T模式T2L = 0xE0;				//设置定时初始值T2H = 0xB1;				//设置定时初始值
//	AUXR |= 0x10;			//定时器2开始计时AUXR &= 0xef;IE2 |= 0x04;			//使能定时器2中断
}void Timer2(void) interrupt 12
{count2++;if(count2 == 50)	//1000毫秒{count2=0;sec++;if(sec == 3){sec=0;show =0;		//显示Show_Switch对应的界面AUXR &= 0xef;	//关闭定时器2}	}
}

http://www.mrgr.cn/news/60425.html

相关文章:

  • Ribbon解说
  • 51单片机完全学习——LCD1602液晶显示屏
  • 新增新质生产力论文复刻(SSCI)10份新质生产力数据合集-最新出炉 附下载链接
  • 排序算法(冒泡,插入),希尔排序(插入升级),希尔排序和插入排序时间比较!
  • Spring Boot与Flyway实现自动化数据库版本控制
  • UML之用例视图
  • Ubuntu18.04安装velodyne驱动
  • AI-基本概念-CNN/RNN/注意力机制
  • Qt6切换音轨
  • 枫清科技仲光庆:AI+行业新范式,双轮驱动助力数智化升级
  • 【建造&机械】木材运输车辆检测系统源码&数据集全套:改进yolo11-GhostHGNetV2
  • SegNet DeconvNet——论文阅读
  • 院士领衔,瑞德磁电誓将中国红染遍磁电产业
  • 前端分页:非当前页进行表单验证
  • 802.1AS-2011_Gptp协议栈
  • 【动手学强化学习】part2-动态规划算法
  • Pytorch学习--DataLoader的使用
  • mabtisx突然不起作用:mapper跳转不到xml
  • 采用WinSW将jar包做成window本地服务
  • 扣子(Coze)
  • 【vue 全家桶】1、vue 基础(更新中)
  • CRD臻珈设计 | 北外滩虹口源·717:摩登印象,艺术永恒
  • Unity 编辑器扩展精髓 之 窗口创建与绘制基础组件
  • 二十一、行为型(中介者模式)
  • JAVA运算符详解
  • 【山西】《信息化项目软件运维费用测算指南》(DB 14/T 2163-2020)-省市费用标准解读系列01