第十二届2 蓝桥杯 单片机设计与开发项目 省赛

 

 

 

 

 

 下面是我自己写的题解,在我的板子上实现了所有功能,如果有问题可以留言,我会尽力帮忙。如果有错误或者更好的写法,恳请大佬指点。

#include <stc15f2k60s2.h>
#include <intrins.h>
sbit DQ = P1^4;
code unsigned char number[28] = 
{
0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0x88,0x83,0xc6,0xa1,0x86,0x8e,
0xbf,0x40,0x79,0x24,0x30,0x19,0x12,0x02,0x78,0x00,0x10,	// - 0.
0x8c
};//+17后为带.字
unsigned char ms10,uc_mod1,uc_recordtep = 25,uc_led = 0xff;
unsigned int ui_tep;
float f_v;
unsigned char uc_v;
void ds18b20();
sbit S4 = P4^4;
sbit S8 = P3^3;
sbit S9 = P3^2;
sbit S5 = P3^2;
sbit sda = P2^1;
sbit scl = P2^0;
void smg_led();
bit flag_tep,flag_mod2;
#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 I2CWaitAck(void)
{
	unsigned char ackbit;
	
    scl = 1;
	I2C_Delay(DELAY_TIME);
    ackbit = sda; 
    scl = 0;
	I2C_Delay(DELAY_TIME);
	
	return ackbit;
}
void PCF8591()		
{
	if(flag_mod2 == 0)		//判断模式1标志
	{
		if(ui_tep / 100 < uc_recordtep)
		{
			flag_tep = 1;			//条件判断标志
		}
		else
		{
			flag_tep = 0;
		}
		I2CStart();
		I2CSendByte(0x90);
		I2CWaitAck();
		I2CSendByte(0x40);
		I2CWaitAck();
		I2CSendByte(255 * flag_tep);	//直接输出0V或者5V (8591范围在0 - 255 即255时输出5v 0时输出0v)
		I2CWaitAck();
		I2CStop();
	}
	else		//进入模式2
	{
		if(ui_tep / 100 <= 20)		//简单的计算 有很多种算法 不唯一
		{
			f_v = 1 / 5.0 * 255;
			uc_v = f_v;
		}
		else if(ui_tep / 100 >= 40)
		{
			f_v = 4 / 5.0 * 255;
			uc_v = f_v;
		}
		else
		{
			f_v = ui_tep;
			f_v = (((f_v / 100.0) * 3) / 20.0 - 2) / 5.0 * 255;
			uc_v = f_v;			//取整后用于输出
		}
		I2CStart();
		I2CSendByte(0x90);
		I2CWaitAck();
		I2CSendByte(0x40);
		I2CWaitAck();
		I2CSendByte(uc_v);
		I2CWaitAck();
		I2CStop();
	}
}
void Delay30ms()		//@11.0592MHz
{
	unsigned char i, j, k;

	_nop_();
	_nop_();
	i = 2;
	j = 67;
	k = 183;
	do
	{
		do
		{
			while (--k);
		} while (--j);
	} while (--i);
}
void scan_key()
{
	P30 = 1;		//注意,因为题目要求矩阵按键和独立按键混用,所以得排除干扰项
	P31 = 1;		//这边的赋值都是用于排除干扰项,具体可以看原理图思考下为什么这么写
	P32 = 1;		
	P33 = 0;
	S4 = 1;
	if(S4 == 0)
	{
		while(S4 == 0)
		{
			smg_led();
		}
		Delay30ms();
		uc_mod1++;				//显示界面的切换
		uc_mod1 %=3;
	}
	if(uc_mod1 == 1)			//判断是否在参数设置界面
	{
		P44 = 1;			//这里也是用于干扰项排除
		S8 = 1;
		S9 = 1;
		P42 = 0;
		if(S8 == 0)
		{
			while(S8 == 0)
			{
				smg_led();
			}
			Delay30ms();
			uc_recordtep--;
		}
		if(S9 == 0)
		{
			while(S9 == 0)
			{
				smg_led();
			}
			Delay30ms();
			uc_recordtep++;
		}
	}
	if(uc_mod1 == 2)		//判断是否在DAC界面
	{
		P42 = 1;			//干扰项排除
		P44 = 0;
		S5 = 1;
		if(S5 == 0)
		{
			while(S5 == 0)
			{
				smg_led();
			}
			Delay30ms();
			flag_mod2 = ~flag_mod2;
		}
	}
}
void Delay600us()		//@11.0592MHz
{
	unsigned char i, j;

	i = 7;
	j = 113;
	do
	{
		while (--j);
	} while (--i);
}
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;
}
void HC138_choose(unsigned char m)
{
	switch(m)
	{
		case 0 :
		{
			P2 = (P2 & 0x1f) | 0x00;
			break;
		}
		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;
		}
	}
}
void smg_show(unsigned char wei,duan)
{
	HC138_choose(6);
	P0 = 0x01 << (wei - 1);
	HC138_choose(7);
	P0 = number[duan];
	Delay600us();
	P0 = 0xff;
}
void smg_led()
{
	unsigned int v;
	if(flag_mod2 == 0)
	{
		HC138_choose(4);
		P0 = uc_led & 0xfe;
		uc_led = P0;
	}
	else
	{
		HC138_choose(4);
		P0 = (uc_led & 0xff) | 0x01;
		uc_led = P0;
	}
	
	if(uc_mod1 == 0)
	{
		HC138_choose(4);
		uc_led = (uc_led & 0xff) | 0x08;		//关闭上一次点亮的灯(即关闭L4)
		P0 = uc_led & 0xfd;
		uc_led = P0;
	}
	else if(uc_mod1 == 1)
	{
		HC138_choose(4);
		uc_led = (uc_led & 0xff) | 0x02;		//同理关闭上个模式的灯
		P0 = uc_led & 0xfb;
		uc_led = P0;
	}
	else
	{
		HC138_choose(4);
		uc_led = (uc_led & 0xff) | 0x04;
		P0 = uc_led & 0xf7;
		uc_led = P0;
	}
	if(uc_mod1 == 0)			//温度显示界面
	{
		smg_show(1,12);
		smg_show(5,ui_tep / 1000);
		smg_show(6,ui_tep / 100 % 10 + 17);
		smg_show(7,ui_tep / 10 % 10);
		smg_show(8,ui_tep % 10);
	}
	else if(uc_mod1 == 1)			//参数设置界面
	{
		smg_show(1,27);
		smg_show(7,uc_recordtep / 10);
		smg_show(8,uc_recordtep % 10);
	}
	else						//DAC输出界面
	{
		if(flag_mod2 == 0)		//模式判断
		{
			smg_show(1,10);
			smg_show(6,5 * flag_tep + 17);		// +17用于带. 例如5+17 = 22,在我的数组里为5.的段码位置
			smg_show(7,0);
			smg_show(8,0);
		}
		else
		{
			f_v = uc_v / 255.0 * 5;			//这里f_v 只是借用上面的定义进行计算,不用考虑上下文联系
			v = f_v * 100;					//乘以100后进行小数运算,方便取整
			smg_show(1,10);
			smg_show(6,v / 100 + 17);
			smg_show(7,v / 10 % 10);
			smg_show(8,v % 10);
		}
	}
}
void ds18b20()
{
	unsigned char low,high;
	float f_tep;
	smg_led();
	init_ds18b20();
	Write_DS18B20(0xcc);
	Write_DS18B20(0x44);
	smg_led();
	f1:;
	smg_led();
	init_ds18b20();
	Write_DS18B20(0xcc);
	Write_DS18B20(0xbe);
	low = Read_DS18B20();
	high = Read_DS18B20();
	ui_tep = (high << 8) |	low;
	if(ui_tep < 0xf800)			
	{
		f_tep = ui_tep * 0.0625;
		ui_tep = f_tep * 100;
	}
	else
	{
		ui_tep = ~ui_tep;
		ui_tep += 1;
		f_tep = ui_tep * 0.0625;
		ui_tep = f_tep * 100;
	}
	smg_led();
	if(ui_tep == 8500)
	{
		goto f1;			//排除初始值干扰 可以不加
	}
}
void init()
{
	HC138_choose(4);
	P0 = 0xff;
	HC138_choose(5);
	P0 = 0x00;
	HC138_choose(6);
	P0 = 0x00;
	HC138_choose(7);
	P0 = 0xff;
}
void main()
{
	init();
	while(1)
	{
		ds18b20();
		PCF8591();
		scan_key();
		smg_led();
	}
}

以上,感谢大家的阅读

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值