蓝桥杯单片机第11届省赛第一次疑惑点

佬们,第11届省赛第一次的题,请问我的eeprom和代码逻辑正确吗,4t上测评结果是错的,这是结果

led的评分处,我前面的一个错了,后面的结果也都错了

这部分是eeprom的代码

这是我key的代码 按下S12,实现界面切换,在S12中实现存储

voltage_set 是 参数界面的参数,是Vp

switch(key_down)
	{
		case 12:
			if(seg_mode == 1)//在退出参数界面前,存储voltage_set
			{
				eeprom_write(&voltage_set,0,1);
				eeprom_write(&eeprom_clock,8,1);
           //eeprom_clock是eeprom的加锁数据,确保voltage_set的读取正确,没有被污染
				voltage_set_dis = voltage_set;
           //voltage_set_dis是voltage_set的保存值,保存每次设置好的voltage_set
			}
				
			if(seg_mode == 0)
					voltage_set = voltage_set_dis;
			
			seg_mode++;//seg_mode 是数码管界面的参数 0 为数据界面  1 为参数界面  2 为                 计数界面
		    seg_mode = seg_mode % 3;
		break;
    }

在main函数中实现读取

void main()
{
	system_init();
	
	eeprom_read(&eeprom_check,8,1);//eeprom_check是eeprom的加锁数据,确保voltage_set的读取正确,没有被污染
	if(eeprom_check == eeprom_clock)
	{
		eeprom_read(&voltage_set,0,1);//读取到voltage_set
		voltage_set_dis = voltage_set;
	}
	
	Timer1_Init();
	while(1)
	{
		key_proc();
		seg_proc();
		led_proc();
		ad_da();
	}
}

在板子上设置好voltage_set,断电重新上电后,voltage_set可以读取出来,但4t测评没有通过

这部分是voltage_count(计数值)的代码

void ad_da()
{
	
	if(ad_slow < 90)
		return;
	ad_slow = 0;
	
	ad_3_100x = ad_read(0x43) / 51.0 * 100; //ad_3_100x  是目前采集到的电压 范围是0~500
	if(ad_3_100x < ad_old)//采集到的电压这时是递减状态
	{
	if(((voltage_set * 10) >= ad_3_100x) && ((voltage_set * 10) <= ad_old))
    //voltage_set 大于现在的电压,小于上一刻的电压
		voltage_count++;
    }
	
	ad_old = ad_3_100x;//ad_old 为上一刻的电压
}

voltage_count 在板子上测试没有问题,在4t上测试,采集到的电压第一,二次递减时,voltage_count 数据正确,第三次时错误,我不知道4t的结果为什么第三次电压递减时voltage_count 没有加一

这是完整的代码

main文件的代码

#include <STC15F2K60S2.H>
#include <key.h>
#include <seg.h>
#include <led.h>
#include <init.h>
#include <iic.h>

idata unsigned char key_slow;
idata unsigned char key_val,key_up,key_down,key_old;

idata unsigned char seg_slow;
idata unsigned char seg_pos;
pdata unsigned char seg_buf[8] = {10,10,10,10,10,10,10,10};

pdata unsigned char uled[8] = {0,0,0,0,0,0,0,0};

idata unsigned int ad_3_100x ;//目前的电压
idata unsigned char ad_slow;



idata unsigned char seg_mode = 0; // 0 数据界面     1 参数   2 计数
idata unsigned char voltage_set = 30;// 修改值
idata unsigned char voltage_set_dis = 30;// 显示值
idata unsigned char voltage_count = 0;//计数值
idata unsigned int ad_old = 0;//上一次的电压
idata unsigned char eeprom_clock = 2;//eeprom的加锁数据
idata unsigned char eeprom_check;//eeprom的加锁数据
idata bit uled1_enable;//led的变量
idata unsigned int time_5s;//led的变量
idata bit uled1_enable_2;//led的变量
idata unsigned char key_erro;//led的变量
void key_proc()
{
	if(key_slow < 25)
		return;
	key_slow = 0;
	
	key_val = key_read();
	key_down = key_val & (key_val ^ key_old);
	key_up = ~key_val & (key_val ^ key_old);
	key_old = key_val;
	
	
	
	switch(key_down)
	{
		case 12:
			if(seg_mode == 1)
			{
				eeprom_write(&voltage_set,0,1);
				eeprom_write(&eeprom_clock,8,1);
				voltage_set_dis = voltage_set;
			}
				
			if(seg_mode == 0)
					voltage_set = voltage_set_dis;
			
			seg_mode++;
		seg_mode = seg_mode % 3;
		break;
		
		case 13:
			if(seg_mode == 2)
			{
			voltage_count = 0;
				key_erro = 0;
			}
			else
				key_erro++;
		break;
			
		case 16:
			if(seg_mode == 1)
			{
			voltage_set = voltage_set +5;
		if(voltage_set == 55)
			voltage_set = 0;
		key_erro = 0;
	    }
			else
				key_erro++;
		break;
		
		case 17:
			if(seg_mode == 1)
			{
			voltage_set = voltage_set -5;
		if(voltage_set > 50)
			voltage_set = 50;
		key_erro = 0;
	    }
			else
				key_erro++;
		break;
	}
}

void seg_proc()
{
	if(seg_slow < 90)
		return;
	seg_slow = 0;
	
	switch(seg_mode)
	{
		case 0:
			seg_buf[0] = 11;
		seg_buf[1] = 10;
		seg_buf[2] = 10;
		seg_buf[3] = 10;
		seg_buf[4] = 10;
		seg_buf[5] = ad_3_100x / 100 % 10 + ',';
		seg_buf[6] = ad_3_100x / 10 % 10;
		seg_buf[7] = ad_3_100x / 1 % 10;
		
		
		
		break;
		
		case 1:
			seg_buf[0] = 12;
		seg_buf[1] = 10;
		seg_buf[2] = 10;
		seg_buf[3] = 10;
		seg_buf[4] = 10;
		seg_buf[5] = voltage_set / 10 % 10 +',';
		seg_buf[6] = voltage_set / 1 % 10;
		seg_buf[7] = 0;
		break;
		
		case 2:
			seg_buf[0] = 13;
		seg_buf[1] = 10;
		seg_buf[2] = 10;
		seg_buf[3] = 10;
		seg_buf[4] = 10;
		seg_buf[5] = (voltage_count >= 100) ? (voltage_count / 100 % 10) : 10;
		seg_buf[6] = (voltage_count >= 10) ? (voltage_count / 10 % 10) : 10;
		seg_buf[7] = (voltage_count / 1 % 10) ;
		break;
	}
}

void led_proc()
{
	uled[0] = uled1_enable_2;
	uled[1] = voltage_count % 2;
	if(key_erro >= 3)
		uled[2] = 1;
	else
		uled[2] = 0;
	led_dis(uled);
}

void ad_da()
{
	
	if(ad_slow < 90)
		return;
	ad_slow = 0;
	
	ad_3_100x = ad_read(0x43) / 51.0 * 100;
	if(ad_3_100x < ad_old)
	{
	if(((voltage_set * 10) >= ad_3_100x) && ((voltage_set * 10) <= ad_old))
		voltage_count++;
}
	
	if( (voltage_set * 10) > ad_3_100x)
		uled1_enable = 1;
	else
		uled1_enable = 0;

	
	ad_old = ad_3_100x;
}

void Timer1_Init(void)		//1毫秒@12.000MHz
{
	AUXR &= 0xBF;			//定时器时钟12T模式
	TMOD &= 0x0F;			//设置定时器模式
	TL1 = 0x18;				//设置定时初始值
	TH1 = 0xFC;				//设置定时初始值
	TF1 = 0;				//清除TF1标志
	TR1 = 1;				//定时器1开始计时
	ET1 = 1;				//使能定时器1中断
	EA = 1;
}

void Timer1_Isr(void) interrupt 3
{
	key_slow++;
	seg_slow++;
	ad_slow++;
	
	seg_pos++;
	seg_pos = seg_pos % 8;
	if(seg_buf[seg_pos] > 20)
		seg_dis(seg_pos,seg_buf[seg_pos] - ',',1);
	else
		seg_dis(seg_pos,seg_buf[seg_pos],0);
	
	if(uled1_enable)
	{
		time_5s++;
		if(time_5s >= 5000)
		{
			time_5s = 5001;
			uled1_enable_2 = 1;
		}
		else
			uled1_enable_2 = 0;
	}
	else
	{
		uled1_enable_2 = 0;
		time_5s = 0;
	}
}

void main()
{
	system_init();
	
	eeprom_read(&eeprom_check,8,1);
	if(eeprom_check == eeprom_clock)
	{
		eeprom_read(&voltage_set,0,1);
		voltage_set_dis = voltage_set;
	}
	
	Timer1_Init();
	while(1)
	{
		key_proc();
		seg_proc();
		led_proc();
		ad_da();
	}
}

iic文件的代码

void eeprom_write(unsigned char *str,unsigned char addr,unsigned char num)
{
	I2CStart();
	I2CSendByte(0xa0);
	I2CWaitAck();
	
	I2CSendByte(addr);
	I2CWaitAck();
	
	while(num--)
	{
		I2CSendByte(*str ++);
		I2C_Delay(200);
		I2CWaitAck();
	}
	I2CStop();
	I2C_Delay(255);
	I2C_Delay(255);
	I2C_Delay(255);
	I2C_Delay(255);
	I2C_Delay(255);
	I2C_Delay(255);
	I2C_Delay(255);
	I2C_Delay(255);
	I2C_Delay(255);
	I2C_Delay(255);
}

void eeprom_read(unsigned char *str,unsigned char addr,unsigned char num)
{
	I2CStart();
	I2CSendByte(0xa0);
	I2CWaitAck();
	
	I2CSendByte(addr);
	I2CWaitAck();
	
	I2CStart();
	I2CSendByte(0xa1);
	I2CWaitAck();
	
	while(num--)
	{
		*str ++ = I2CReceiveByte();
		if(num)
			I2CSendAck(0);
		else
			I2CSendAck(1);
	}
	I2CStop();
}
1 个赞

同问。。。。。。

这个加锁好像是会出错,但是直接读取4t就能直结果(不过这种我感觉毫无逻辑可言)

4T测评时,平台会预先往地址0写入测试值(比如写入10,代表1.0V)

但4T不知道你有校验机制,它不会往地址8写入你的锁值,所以直接读取就行
例如

  eeprom_read(&V_eeprom, 0, 1);    // 直接读地址0
  V_val = (V_eeprom / 10.0);       // 直接用

你的"防垃圾数据"校验机制,反而让4T预设的正确数据读不出来

2 个赞

直接读取就可以,加锁会有错误

1 个赞

voltage_count的逻辑代码是对的,4t测评错误是因为eeprom上锁代码,导致voltage_count的代码错误,我在改正eeprom的上锁代码后,voltage_count的代码没有扣分。
eeprom的解决方法有两个,第一个就是大家说的去掉上锁代码,直接读取,4t的测评机制好恶心,不按照咱们的正常逻辑来。

第二个方法是进入参数界面前 ,从eeprom读取一次参数,代码在按键函数key_proc()中实现

void key_proc()
{

key_val = key_read();
key_down = key_val & (key_val ^ key_old);
key_up = ~key_val & (key_val ^ key_old);
key_old = key_val;

switch(key_down)
{
case 12:
if(seg_mode == 1)
{
voltage_set_right = voltage_set;
eeprom_write(&voltage_set_right,0,1);
eeprom_write(&eeprom_clock,8,1);

  	// 退出参数界面前,把参数写入eeprom
  	
  }
  	
  if(seg_mode == 0)
  {
  	eeprom_read(&voltage_set_right,0,1);
  	// 进入参数界面前  从eeprom读取一次参数

voltage_set = voltage_set_right;

  }
  
  seg_mode++;

seg_mode = seg_mode % 3;
break;

case 13:
if(seg_mode == 2)
{
voltage_count = 0;
key_erro = 0;
}
else
key_erro++;
break;

case 16:
if(seg_mode == 1)
{
voltage_set = voltage_set +5;
if(voltage_set == 55)
voltage_set = 0;
key_erro = 0;
}
else
key_erro++;
break;

case 17:
if(seg_mode == 1)
{
voltage_set = voltage_set -5;
if(voltage_set == 251)
voltage_set = 50;
key_erro = 0;
}
else
key_erro++;
break;
}

}

是在按键12切换界面时实现

case 12:
if(seg_mode == 1)
{
voltage_set_right = voltage_set;
eeprom_write(&voltage_set_right,0,1);
eeprom_write(&eeprom_clock,8,1);

// 退出参数界面前,把参数写入eeprom
}

if(seg_mode == 0)
{
eeprom_read(&voltage_set_right,0,1);

//进入参数界面前 ,从eeprom读取一次参数

voltage_set = voltage_set_right;
}

seg_mode++;

seg_mode = seg_mode % 3;

break;