蓝桥杯单片机第十二届国赛题

前言:比赛一天天接近,十分紧张,有没有大佬可以分享一下数模电的速成资源,有偿求

题目

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

个人理解与感受

第十二届国赛的题目难度也中规中矩,毕竟分值没有14届的高,况且还少考了单总线温度传感器的使用,依旧没有考串口。这道题目写起来没有什么太大的阻碍,连续采样功能我有印象有省赛考过,连续采样六次的,好像是第十四届的省赛,光敏传感器触发第十四届也“回光返照”过,也不是什么新鲜的考点了。本次一个稍微新颖但是没有难度的一个地方就是是根据DS1302中的秒值来进行读取,这实质上也是考察BCD码与十进制码的转换,与第十一届的题目类似。
关于多次采样计算平均值,我是直接用一个long来计算之前所有的总和,这样需要的空间就比较固定,也不会有溢出的风险,代码量也相当少:

disall = disall + distance;
	if(trigger > 0){
		disavr = disall * 10 / trigger;
	}

其中disall就是long类型的用于承载之前所有距离的变量,trigger是测试的次数,将disall先×10是为了搞到小数点,也不用浮点型的变量,非常非常方便好用。
当然用数组的方法也是可以,但是代码量会比较多,排序也比较麻烦,而且占用空间比较大。
LED模块我依旧使用先给状态量赋值再给P0赋值的方法来点亮LED灯,效果很稳定。
关于DAC的变量,我的建议是用斜率-截距式的表达式进行赋值,两点式和点斜式很好写,但是用整形来写容易失真。
截距式更不用说了,纯纯自虐。
在这里插入图片描述

底层驱动代码

IIC

unsigned char guangmin(){
	unsigned char ret;
	I2CStart();
	I2CSendByte(0x90);
	I2CWaitAck();
	I2CSendByte(0x41);
	I2CWaitAck();
	
	I2CStart();
	I2CSendByte(0x91);
	I2CWaitAck();
	ret = I2CReceiveByte();
	I2CSendAck(1);
	I2CStop();
	
	return ret;
}

void DAC(unsigned char dat){
	I2CStart();
	I2CSendByte(0x90);
	I2CWaitAck();
	I2CSendByte(0x41);
	I2CWaitAck();
	I2CSendByte(dat);
	I2CWaitAck();
	I2CStop();
}

DS1302

调用部分写在了主函数

void ds1302config(){
	unsigned char i;
	Write_Ds1302_Byte(0x8e,0x00);
	for(i = 0;i < 3;i++){
		Write_Ds1302_Byte(ds1302writeaddr[i],time[i]);
	}
	Write_Ds1302_Byte(0x8e,0x80);
}

void ds1302read(){
	unsigned char i;
	for(i = 0;i < 3;i++){
		time[i] = Read_Ds1302_Byte(ds1302readaddr[i]);
	}
	secondtmp = (time[0] / 16 * 10) + (time[0] % 16);
}

主程序代码

#include <STC15F2K60S2.H>
#include "inithc138.h"
#include "delay.h"
#include "ds1302.h"
#include "intrins.h"
#include "iic.h"

#define de 5
code unsigned char Seg_Table[17] = 
{
0xc0, //0
0xf9, //1
0xa4, //2
0xb0, //3
0x99, //4
0x92, //5
0x82, //6
0xf8, //7
0x80, //8
0x90, //9
0x88, //A
0x83, //b
0xc6, //C
0xa1, //d
0x86, //E
0x8e, //F
0xbf
};
unsigned char ds1302readaddr[3] = {0x81,0x83,0x85};
unsigned char ds1302writeaddr[3] = {0x80,0x82,0x84};
unsigned char time[3] = {0x01,0x20,0x20};
unsigned char mode1 = 0;
unsigned char mode2 = 0;
bit moshi = 0;//模式标识符
unsigned char jilu = 0;//记录模式选择
unsigned int ustime = 0;//超声波时间
unsigned int distance = 0;//超声波距离
unsigned int dismax = 0;//最大距离
unsigned long disall = 0;//距离总和
unsigned long disavr = 0;//平均距离
unsigned int dismin = 0;//最小距离
unsigned char trigger = 0;//采集次数
unsigned char caijishijian = 2;//采集时间
unsigned char julicanshu = 20;//距离参数
bit show = 0;//显示模式选择
unsigned char voltage = 0;//光敏电阻电压数据
bit light = 0;//亮暗状态
unsigned char secondtmp = 0;
unsigned char ledstat = 0xff;//LED状态
unsigned char dacload = 0;//DAC输出量
bit flag = 0;//保证每次进入测距状态只测一次
unsigned char canshufujin = 0;//记录距离在定时模式下位于参数附近的次数
//***********************************DS1302
void ds1302config(){
	unsigned char i;
	Write_Ds1302_Byte(0x8e,0x00);
	for(i = 0;i < 3;i++){
		Write_Ds1302_Byte(ds1302writeaddr[i],time[i]);
	}
	Write_Ds1302_Byte(0x8e,0x80);
}

void ds1302read(){
	unsigned char i;
	for(i = 0;i < 3;i++){
		time[i] = Read_Ds1302_Byte(ds1302readaddr[i]);
	}
	secondtmp = (time[0] / 16 * 10) + (time[0] % 16);
}
//***********************************
//***********************************超声波
sbit TX = P1^0;
sbit RX = P1^1;
void Delay12us(void)	//@12.000MHz
{
	unsigned char data i;

	_nop_();
	_nop_();
	i = 33;
	while (--i);
}

void fangbo(){
	unsigned char i;
	for(i = 0;i < 8;i++){
		TX = 1;
		Delay12us();
		TX = 0;
		Delay12us();
	}
}

void ceju(){
	flag = 1;//测了
	CMOD = 0x00;			//设置定时器模式
	CL = 0x00;				//设置定时初始值
	CH = 0x00;				//设置定时初始值
	CF = 0;				//清除TF0标志
	CR = 0;	
	
	fangbo();
	CR = 1;
	while((RX == 1) && (CH < 0x17));
	CR = 0;
	
	if(RX == 0){
		RX = 1;
		ustime = (CH << 8) | CL;
		distance = ustime * 0.017;
	}
}
//***********************************
//***********************************数据显示界面
void shijianshuju(){//时间数据显示界面
	showsmg(1,Seg_Table[time[2] / 16]);
	showsmg(2,Seg_Table[time[2] % 16]);
	showsmg(3,Seg_Table[16]);
	showsmg(4,Seg_Table[time[1] / 16]);
	showsmg(5,Seg_Table[time[1] % 16]);
	showsmg(6,Seg_Table[16]);
	showsmg(7,Seg_Table[time[0] / 16]);
	showsmg(8,Seg_Table[time[0] % 16]);
}

void julishuju(){//距离记录
	showsmg(1,0xc7);
	if(moshi == 0){
		showsmg(2,Seg_Table[12]);//触发模式
	}else{
		showsmg(2,Seg_Table[15]);//定时模式
	}
	
	showsmg(8,Seg_Table[distance % 10]);
	if(distance > 9){
		showsmg(7,Seg_Table[distance / 10 % 10]);
	}
	if(distance > 99){
		showsmg(6,Seg_Table[distance / 100]);
	}
}

void shujujilu(){
	if(jilu == 0){
		showsmg(1,0x89);
		showsmg(2,0xfe);
		showsmg(7,Seg_Table[dismax / 10]);
		showsmg(8,Seg_Table[dismax % 10]);
	}
	if(jilu == 1){
		showsmg(1,0x89);
		showsmg(2,0xbf);
		showsmg(6,Seg_Table[disavr / 100]);
		showsmg(7,Seg_Table[disavr / 10 % 10] & 0x7f);
		showsmg(8,Seg_Table[disavr % 10]);
	}
	if(jilu == 2){
		showsmg(1,0x89);
		showsmg(2,0xf7);
		showsmg(7,Seg_Table[dismin / 10]);
		showsmg(8,Seg_Table[dismin % 10]);
	}
}

void xianshi(){
	switch(mode1){
		case 0:shijianshuju();break;
		case 1:julishuju();break;
		case 2:shujujilu();break;
	}
}
//***********************************
//***********************************参数设置界面
void caijishijianshezhi(){//采集时间设置界面
	showsmg(1,0x8c);
	showsmg(2,Seg_Table[1]);
	showsmg(7,Seg_Table[caijishijian / 10]);
	showsmg(8,Seg_Table[caijishijian % 10]);
}

void julicanshushezhi(){//距离参数设置界面
	showsmg(1,0x8c);
	showsmg(2,Seg_Table[2]);
	showsmg(7,Seg_Table[julicanshu / 10]);
	showsmg(8,Seg_Table[julicanshu % 10]);
}

void canshujiemian(){
	switch(mode2){
		case 0:caijishijianshezhi();break;
		case 1:julicanshushezhi();break;
	}
}
//***********************************
//***********************************
void showselect(){
	if(show == 0){
		xianshi();//数据显示界面
	}else{
		canshujiemian();//参数设置界面
	}
}
//***********************************
//***********************************按键扫描
void scankey(){
	P33 = 0;P32 = 1;P44 = 1;P35 = 1;
	if(P44 == 0){Delay(de);while(P44 == 0){showselect();}//S4
		show = ~show;
		mode1 = 0;mode2 = 0;jilu = 0;
	}
	if((show == 0) && (mode1 == 1)){//S13在测距数据显示界面下
		if(P35 == 0){Delay(de);while(P35 == 0){showselect();}
			moshi = ~moshi;
		}
	}
	if((show == 0) && (mode1 == 2)){//S13在数据记录显示界面下
		if(P35 == 0){Delay(de);while(P35 == 0){showselect();}
			jilu++;
			jilu %= 3;
		}
	}
	
	P33 = 1;P32 = 0;P44 = 1;P35 = 1;
	if(show == 0){//S5在数据显示界面下
		if(P44 == 0){Delay(de);while(P44 == 0){showselect();}
			mode1++;
			mode1 %= 3;
		}
	}
	if(show == 1){//S5在参数设置界面下
		if(P44 == 0){Delay(de);while(P44 == 0){showselect();}
			mode2++;
			mode2 %= 2;
		}
	}
	if(P35 == 0){Delay(de);while(P35 == 0){showselect();}//S4}
		if(show == 1){//S13为参数调整按键
			if(mode2 == 0){//调整采集时间参数
				caijishijian++;
				if(caijishijian > 9){caijishijian = 2;}
			}
			if(mode2 == 1){//调整距离参数
				julicanshu += 10;
				if(julicanshu > 80){julicanshu = 10;}
			}
		}
	}
}
//***********************************
//***********************************测距模式
void jilumoshi(){//记录数据判断
	if(trigger == 1){//最小值的初始化
		dismin = distance;
	}
	if(dismax < distance){//记录最大值
		dismax = distance;
	}
	if(dismin > distance){
		dismin = distance;
	}
	disall = disall + distance;
	if(trigger > 0){
		disavr = disall * 10 / trigger;
	}
	
	if(moshi == 1){
		if((distance >= (julicanshu - 5)) && (distance <= julicanshu + 5)){
			canshufujin++;
		}else{
			canshufujin = 0;
		}
	}else{
		canshufujin = 0;
	}
}

void lianganpanduan(){
	voltage = guangmin();
	Delay(1);
	if(voltage < 20){
		light = 1;//暗下来
	}else{
		light = 0;//亮
	}
}

void dingshimoshi(){//定时模式
	if(secondtmp % caijishijian == 0){
		if(flag == 0){
			ceju();
			trigger++;
			jilumoshi();
		}
	}else{
		flag = 0;
	}
}

void chufamoshi(){//触发模式
	if(light == 1){
		if(flag == 0){
			ceju();
			trigger++;
			jilumoshi();
		}
	}else{
		flag = 0;
	}
}

void cejumoshi(){
	if(moshi == 0){
		chufamoshi();
	}
	if(moshi == 1){
		dingshimoshi();
	}
}
//***********************************
//***********************************LED
void led(){
	if((show == 0) && (mode1 == 0)){
		ledstat = ledstat & ~0x01;
	}else{
		ledstat = ledstat | 0x01;
	}
	
	if((show == 0) && (mode1 == 1)){
		ledstat = ledstat & ~0x02;
	}else{
		ledstat = ledstat | 0x02;
	}
	
	if((show == 0) && (mode1 == 2)){
		ledstat = ledstat & ~0x04;
	}else{
		ledstat = ledstat | 0x04;
	}
	
	if(moshi == 0){//触发模式
		ledstat = ledstat & ~0x08;
	}else{
		ledstat = ledstat | 0x08;
	}
	
	if(canshufujin >= 3){//定时模式下附近次数超过三次
		ledstat = ledstat & ~0x10;
	}else{
		ledstat = ledstat | 0x10;
	}
	
	if(light){
		ledstat = ledstat | 0x20;
	}else{
		ledstat = ledstat & ~0x20;
	}
	
	outputp0(4,ledstat);
}
//***********************************
//***********************************
void DACshuchu(){
	if(distance <= 10){
		dacload = 51;
	}else if(distance >= 80){
		dacload = 255;
	}else{
		dacload = 2.91 * distance + 21.86;
	}
	DAC(dacload);
	Delay(1);
}
//***********************************
//***********************************
void main(){
	initsys();
	ds1302config();
	ds1302read();
	lianganpanduan();
	Delay(5);
	initsys();
	while(1){
		lianganpanduan();
		cejumoshi();
		ds1302read();
		showselect();
		scankey();
		led();
		DACshuchu();
	}
}

展示视频

注:一个人拍视频旁边没支架,DAC就没法展示了,但是是可以实现的。
我的板子s8不行,我就把功能换成了s12和s13。

g012

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值