蓝桥杯第六届国赛试题--“智能物料传送系统”

题目要求

功能简述
智能物料传送系统能够实现货物类型判断、过载监测、紧急停止和系统参数存储记录等功能。系统硬件部分主要由按键电路、显示电路、数据存储电路、传感器检测电路及单片机系统组成,系统框图如图1所示:
蓝桥杯第六届国赛试题--“智能物料传送系统”_第1张图片
I2C总线驱动程序、CT107D单片机考试平台电路原理图以及本题所涉及到的芯片数据手册,可参考计算机上的电子文档。原理图文件、程序流程图及相关工程文件请以考生号命名,并保存在计算机上的考生文件夹中(文件夹名为考生准考证号,文件夹位于Windows桌面上)。
设计任务及要求
1. 过载监测与货物类型识别
1.1空载、过载监测
使用电位器RB2输出电压Vo模拟压力变送器输出,设备实时采集电位器输出电压,完成货物空载、过载监测功能。
1.1.1当0<Vo<1V时,判断为空载,L1点亮;
1.1.2当1≤Vo<4V时,判断为非空载,货物被填装到传送起始位置,L2点亮;
1.1.3当Vo≥4V时,判断为过载状态,L3以0.5秒为间隔闪烁提醒,蜂鸣器报警提示。
说明:空载状态下,所有数码管熄灭。
1.2货物类型判断
货物被填装到传送起始位置后,系统启动超声波测距功能,完成货物类型判断,数码管显示界面如图2所示:
1.2.1当超声探头与货物之间的距离小于等于30cm时判断为I类货物;
1.2.2当超声探头与货物之间的距离大于30cm时判断为II类货物。
蓝桥杯第六届国赛试题--“智能物料传送系统”_第2张图片
说明:
1.货物类型显示格式:I类货物-数字1、II类货物-数字2;
2. A3草稿纸短边接近30cm,可用于验证测距结果。
2. 货物传送
在非空载、非过载的前提下,通过按键控制继电器吸合,启动货物传送过程,并通过数码管实时显示剩余的传送时间,倒计时结束后,继电器自动断开,完成本次传送过程,数码管显示格式如图 3 所示:
蓝桥杯第六届国赛试题--“智能物料传送系统”_第3张图片
说明:继电器吸合时,指示灯 L10 点亮,断开时 L10 熄灭。
3. 按键功能描述
3.1 按键 S4 定义为“启动传送”按键,按键按下后,启动货物传送过程。
说明:按键 S4 在空载、过载、传送过程中无效。
3.2 按键 S5 定义为“紧急停止”按键,按键按下后,继电器立即断开,指示灯 L4以 0.5 秒为间隔闪烁,剩余传送时间计时停止。再次按下 S5,传送过程恢复,L4 熄灭,恢复倒计时功能,继电器吸合,直到本次传送完成。
说明:按键 S5 仅在传送过程中有效。
3.3 按键 S6 定义为“设置”按键,按下 S6 按键,调整 I 类货物传送时间,再次按下 S6 按键,调整 II 类货物传送时间,第三次按下 S6,保存调整后的传送时间到 E2PROM,并关闭数码管显示。设置过程中数码管显示界面如图 4 所示:
蓝桥杯第六届国赛试题--“智能物料传送系统”_第4张图片
说明
1.货物传送时间可设定范围为 1-10 秒,通过按键 S7 调整;
2. “设置”按键 S6、“调整”按键 S7 仅在空载状态下有效;
3. 通过按键 S6 切换选择到不同货物类型的传送时间时,显示该类货物传送
时间的数码管闪烁。
4. 数据存储
I、II 类型货物的传送时间在设置完成后需要保存到 E2PROM 中,设备重新上电后,能够恢复最近一次的传送时间配置信息。
5. 上电初始化状态与工作流程说明
5.1 I 类设备默认传送时间为 2 秒,II 类设备为 4 秒;
5.2 最终作品提交前,将 RB2 输出电压调整到最小值,确保设备处于空载状态;

程序代码

主函数

#include "stc15f2k60s2.h"
#include "iic.h"
#include "display.h"
#include "driver.h"
#include "sonic.h"


uchar key_value;	  //按键值
uchar S5_count;			//S5按键次数

extern uchar mode_display;		  //显示模式
extern uchar voltage;						//电压值
extern unsigned char countdown1;	//货物I倒计时
extern unsigned char countdown2;  //货物II倒计时
extern unsigned char goods_kind;	//货物类型
extern uchar S6_count;				//S6按键次数

bit flag500ms;
bit S4_enable;					//S4按键使能
bit led4_flag;					//led4闪烁标志

extern bit S5_enable;			//S5按键使能

extern bit unload_flag;				//空载标志
extern bit transmit_flag;				//传送标志
extern bit countdown_flag;			//倒计时标志
extern bit relay_flag;			//继电器标志

void goods_test();	  //空载、过载检测
void delayms(uint ms);

void main()
{
  Timer0Init();
  All_init();
	countdown1=Read_eeprom(0x00);
	delayms(10);
	countdown2=Read_eeprom(0x01);
	delayms(10);
	
  while(1)
  {
	  Display1();
	  goods_test();
		Display2();
		Display3();
		
		
		
	  key_value=key_init();
	  switch(key_value)
	  {  
	    case 4:
			if(S4_enable)
			{
				mode_display=1;
				relay_flag=1;
				countdown_flag=1;
				S5_enable=1;
				
				countdown1=Read_eeprom(0x00);
				delayms(10);
				countdown2=Read_eeprom(0x01);
				delayms(10);
			}
	    break;
			
			case 5:
				if(S5_enable)
				{
			    S5_count++;
					if(S5_count==2)
						S5_count=0;
					if(S5_count==1)
					{
						countdown_flag=0;				//停止计数
						relay_flag=0;						//关闭继电器
						led4_flag=1;						//led4闪烁
					}
					else
					{
						countdown_flag=1;
						relay_flag=1;
						led4_flag=0;
					}						
				}								
			break;
			
			case 6:
				if(unload_flag)
				{
					mode_display=2;
					if(mode_display==2)
					S6_count++;
					
					if(S6_count==3)
					{
						S6_count=0;
						mode_display=0;
						Write_eeprom(0x00,countdown1);
						delayms(10);
						Write_eeprom(0x01,countdown2);
						delayms(10);
					}
				}					
			break;
				
			case 7:
			if(unload_flag)
			{
				if(S6_count==1)
				{
					countdown1++;
					if(countdown1==11)
						countdown1=1;
				}
				
				if(S6_count==2)
				{
					countdown2++;
					if(countdown2==11)
						countdown2=1;
				}
			}
			break;
	  }
			
		if(mode_display==1)
		{
			if(relay_flag)
			{			
				Relay(1);
				Beep(0);
			}
			else
			{
				Relay(0);
				Beep(0);
			}
	  }
  }
}


void goods_test()
{ 
	voltage=Read_Pcf8591(0x03);
  delayms(10);
	
  if(led4_flag)
		{
			if(flag500ms)
			{		
				led_init(0xf7);		
			}
			else
			{
				led_init(0xff);
			}
		}
	else
	{
		if(voltage<51)		//小于1V,空载
		{
			led_init(0xfe);
			Beep(0);
			Relay(0);
			S4_enable=0;
			unload_flag=1;			//空载标志
		}
		if((voltage>=51)&&(voltage<204))		//非空载
		{
			led_init(0xfd);
			Beep(0);
			if(relay_flag==0)
				Relay(0);
			S4_enable=1;
			unload_flag=0;
			transmit_flag=1;
		}
		if(voltage>=204)														//过载
		{
			Beep(1);		//蜂鸣器报警
			Relay(0);
			S4_enable=0;
			unload_flag=0;
			if(flag500ms)
			{		
				led_init(0xfb);		
			}
			else
			{
				led_init(0xff);
			}
		}
  }
}

void delayms(unsigned int ms)		//@11.0592MHz
{
	unsigned char i, j;
	while(ms--)
	{
		i = 11;
		j = 190;
		do
		{
			while (--j);
		} while (--i);
	}
}

LED、蜂鸣器、继电器及按键驱动

#include "driver.h"

void All_init()
{
  P2=(P2&0X1F)|0X80;
  P0=0xff;
  P2=P2&0X1F;

  P2=(P2&0X1F)|0Xa0;
  P0=0x00;
  P2=P2&0X1F;
}

void led_init(unsigned char led)
{
  P0=0XFF;
  P2=(P2&0X1F)|0X80;
  P0=led;
  P2=P2&0X1F;
}

void Beep(bit on_off)		//蜂鸣器
{
	if(on_off)
		P06=1;
	else
		P06=0;
	P2=P2&0X1F|0XA0;
	P2=P2&0X1F;
}

void Relay(bit on_off)		//继电器
{
	if(on_off)
		P04=1;
	else
		P04=0;
	P2=P2&0X1F|0XA0;
	P2=P2&0X1F;
}


uchar key_init()
{
  static uchar key_state=0;
  uchar key_press, key_return=0;
  key_press=P3&0X0F;

  switch(key_state)
  {
    case key_state0:
	if(key_press!=0x0f)
	key_state=key_state1;
	break;

	case key_state1:
	if(key_press!=0x0f)
	{
	  if(key_press==0x0e)	key_return=7;
	  if(key_press==0x0d)	key_return=6;
	  if(key_press==0x0b)	key_return=5;
	  if(key_press==0x07)	key_return=4;
	  key_state=key_state2;
	}
	else
	key_state=key_state0;
	break;

	case key_state2:
	if(key_press==0x0f)
	key_state=key_state0;
	break;
  }
  return key_return;
}

超声波测距

#include "sonic.h"
#include "intrins.h"

void Delay13us();		//@11.0592MHz

unsigned int Get_distance()
{
	long distance=0;
	long i,temp=0;
	Echo=1;
	for(i=0;i<10;i++)
	{
		Trig=~Trig;
		Delay13us();
	}
	while(Echo)
	{
		temp++;
		if(temp>=1000)
			break;
	}
	distance=temp/7;
	return distance;
}

void Delay13us()		//@11.0592MHz
{
	unsigned char i;

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

显示函数

#include "display.h"
#include "sonic.h"
#include "driver.h"

unsigned char code SMG_TAB[]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F};
unsigned char SMG_WEI[]={0X01,0X02,0X04,0X08,0X10,0X20,0X40,0X80};

unsigned char goods_display[8];
unsigned char time_display[8];
unsigned char set_display[8];

unsigned char mode_display;
unsigned char goods_kind;			//货物类型

unsigned char countdown1=2;
unsigned char countdown2=4;
unsigned char countdown;

unsigned char voltage;
unsigned char S6_count;
long sonic_distance;

bit blink_flag;

extern bit flag500ms;
bit unload_flag;
bit transmit_flag;
bit flag200ms;
bit countdown_flag;
bit relay_flag;
bit S5_enable;

void Display1()
{
  if(transmit_flag)
	{
		if(flag200ms)			//200ms测一次
		{
			flag200ms=0;
		  sonic_distance=Get_distance();
		}
	}
	
	if(sonic_distance<=30)
	{
		goods_kind=1;					//货物类型1
	}
	if(sonic_distance>30)
	{
		goods_kind=2;				//货物类型2
	}
	
	if(unload_flag)					//空载状态下,数码管全部熄灭
	{
		goods_display[0]=0x00;
		goods_display[1]=0X00;
		goods_display[2]=0x00;
		goods_display[3]=0x00;
		goods_display[4]=0x00;
		goods_display[5]=0X00;
		goods_display[6]=0X00;
		goods_display[7]=0x00;
	}
	else
	{
		goods_display[0]=SMG_TAB[1];
		goods_display[1]=0X00;
		goods_display[2]=0x00;
		goods_display[3]=SMG_TAB[sonic_distance/10%10];
		goods_display[4]=SMG_TAB[sonic_distance%10];
		goods_display[5]=0X00;
		goods_display[6]=0X00;
		goods_display[7]=SMG_TAB[goods_kind];
	}
}

void Display2()
{
	if(goods_kind==1)
   countdown=countdown1;
  if(goods_kind==2)
   countdown=countdown2;	
	
	time_display[0]=SMG_TAB[2];
	time_display[1]=0X00;
	time_display[2]=0x00;
	time_display[3]=0x00;
	time_display[4]=0x00;
	time_display[5]=0X00;
	time_display[6]=SMG_TAB[countdown/10];
	time_display[7]=SMG_TAB[countdown%10];
}

void Display3()
{	
	set_display[0]=SMG_TAB[3];
	set_display[1]=0X00;
	set_display[2]=0x00;	
	set_display[5]=0X00;
	
	if(blink_flag)				//数码管闪烁
	{
		if(S6_count==1)
		{
			set_display[3]=SMG_TAB[countdown1/10];
	    set_display[4]=SMG_TAB[countdown1%10];
		}
		
		if(S6_count==2)
		{
			set_display[6]=SMG_TAB[countdown2/10];
	    set_display[7]=SMG_TAB[countdown2%10];
		}
	}
	
	else
	{
		if(S6_count==1)
		{
			set_display[3]=0x00;
	    set_display[4]=0x00;
		}
		else
		{
			set_display[3]=SMG_TAB[countdown1/10];
	    set_display[4]=SMG_TAB[countdown1%10];
		}
		
		if(S6_count==2)
		{
			set_display[6]=0x00;
	    set_display[7]=0x00;
		}
		else
		{
			set_display[6]=SMG_TAB[countdown2/10];
	    set_display[7]=SMG_TAB[countdown2%10];
		}
	}
}

void Timer0Init(void)		//1毫秒@11.0592MHz
{
	AUXR |= 0x80;		//定时器时钟1T模式
	TMOD &= 0xF0;		//设置定时器模式
	TL0 = 0xCD;		//设置定时初值
	TH0 = 0xD4;		//设置定时初值
	TF0 = 0;		//清除TF0标志
	TR0 = 1;		//定时器0开始计时
	EA=1;
	ET0=1;
}

void timer0() interrupt 1
{
  unsigned char smg_count,i;
	unsigned int led_count,sonic_count,daojishi,blink_count;
  smg_count++;
	led_count++;
	sonic_count++;
	daojishi++;
	blink_count++;
	
  if(smg_count==3)
  {
    smg_count=0;

	P2=(P2&0X1F)|0XC0;
	P0=SMG_WEI[i];
	P2=P2&0X1F;

	if(mode_display==0)
	{
		P2=(P2&0X1F)|0XE0;
		P0=~goods_display[i];
		P2=P2&0X1F;
	}
	
	if(mode_display==1)
	{
		P2=(P2&0X1F)|0XE0;
		P0=~time_display[i];
		P2=P2&0X1F;
	}
	
	if(mode_display==2)
	{
		P2=(P2&0X1F)|0XE0;
		P0=~set_display[i];
		P2=P2&0X1F;
	}
	
	i++;
	if(i==8)
	i=0;
  }
	
	if(led_count==500)
	{
		led_count=0;
		flag500ms=~flag500ms;
	}
	
	if(sonic_count==200)
	{
		sonic_count=0;
		flag200ms=1;
	}
	
	if(daojishi==1000)
	{
		daojishi=0;
		if(countdown_flag)
		{
			if(goods_kind==1)
			{
				countdown1--;
				if(countdown1==0)
				{
					countdown_flag=0;
					countdown1=0;
					relay_flag=0;
					S5_enable=0;
				}
			}
			
			if(goods_kind==2)
			{
				countdown2--;
				if(countdown2==0)
				{
					countdown_flag=0;
					countdown2=0;
					relay_flag=0;
					S5_enable=0;
				}
			}
		}
	}
	
	if(blink_count==400)
	{
		blink_count=0;
		blink_flag=~blink_flag;
	}
}

AD及EEPROM
说明:经过这一段时间的测试,发现读取RB2上的电压值时,先关闭定时器中断,读取数值比较稳定,同时官方给的iic驱动中,somenop中一共有25个_nop_()比较合适,具体见程序

/*
  程序说明: IIC总线驱动程序
  软件环境: Keil uVision 4.10 
  硬件环境: CT107单片机综合实训平台(12MHz)
  日    期: 2011-8-9
*/
#include "iic.h"

//总线启动条件
void IIC_Start(void)
{
	SDA = 1;
	SCL = 1;
	somenop;
	SDA = 0;
	somenop;
	SCL = 0;	
}

//总线停止条件
void IIC_Stop(void)
{
	SDA = 0;
	SCL = 1;
	somenop;
	SDA = 1;
}

//应答位控制
void IIC_Ack(unsigned char ackbit)
{
	if(ackbit) 
	{	
		SDA = 0;
	}
	else 
	{
		SDA = 1;
	}
	somenop;
	SCL = 1;
	somenop;
	SCL = 0;
	SDA = 1; 
	somenop;
}

//等待应答
bit IIC_WaitAck(void)
{
	SDA = 1;
	somenop;
	SCL = 1;
	somenop;
	if(SDA)    
	{   
		SCL = 0;
		IIC_Stop();
		return 0;
	}
	else  
	{ 
		SCL = 0;
		return 1;
	}
}

//通过I2C总线发送数据
void IIC_SendByte(unsigned char byt)
{
	unsigned char i;
	for(i=0;i<8;i++)
	{   
		if(byt&0x80) 
		{	
			SDA = 1;
		}
		else 
		{
			SDA = 0;
		}
		somenop;
		SCL = 1;
		byt <<= 1;
		somenop;
		SCL = 0;
	}
}

//从I2C总线上接收数据
unsigned char IIC_RecByte(void)
{
	unsigned char da;
	unsigned char i;
	
	for(i=0;i<8;i++)
	{   
		SCL = 1;
		somenop;
		da <<= 1;
		if(SDA) 
		da |= 0x01;
		SCL = 0;
		somenop;
	}
	return da;
}

unsigned char Read_Pcf8591(unsigned char addr)
{
  unsigned char temp;
  ET0=0;						//关闭定时器,防止程序被打乱
  IIC_Start();
  IIC_SendByte(0x90);
  IIC_WaitAck();
  IIC_SendByte(addr);
  IIC_WaitAck();

  IIC_Start();
  IIC_SendByte(0x91);
  IIC_WaitAck();
  temp=IIC_RecByte();
  IIC_Ack(0);
  IIC_Stop();
  ET0=1;
  return temp;
}

void Write_eeprom(unsigned char addr,unsigned char dat)
{
  ET0=0;						//关闭定时器,防止程序被打乱
  IIC_Start();
  IIC_SendByte(0xa0);
  IIC_WaitAck();
  IIC_SendByte(addr);
  IIC_WaitAck();
  IIC_SendByte(dat);
  IIC_WaitAck();  
  IIC_Stop();
  ET0=1;
}

unsigned char Read_eeprom(unsigned char addr)
{
  unsigned char temp;
  ET0=0;						//关闭定时器,防止程序被打乱
  IIC_Start();
  IIC_SendByte(0xa0);
  IIC_WaitAck();
  IIC_SendByte(addr);
  IIC_WaitAck();

  IIC_Start();
  IIC_SendByte(0xa1);
  IIC_WaitAck();
  temp=IIC_RecByte();
  IIC_Ack(0);
  IIC_Stop();
  ET0=1;
  return temp;
}

以上就是代码全部内容,欢迎交流,共同学习~
喜欢就关注一下吧~

你可能感兴趣的:(蓝桥杯)