Detailed explanation of the questions of the third provincial competition of Lanqiao Cup MCU (automatic water vending machine)

Lanqiao Cup Information Package
Source Code
It is strongly recommended to do it yourself first. This is the simplest question for Lanqiao Cup MCU.
First, start with the system block diagram of the test question
Insert image description here
As shown in the picture, there is AD conversion, so IIC must be used
There is a digital tube, so the digital tube should be written first
There are buttons, but make sure they are independent buttons or matrix buttons, scroll down
Insert image description here
S5, S7, so use independent buttons Just press the buttons
Therefore, we first create the project, then add the required digital tubes, IIC, and independent buttons and debug them.
main.c

#include <stc15f2k60s2.h>
#include "intrins.h"
#include "iic.h"

#define uchar unsigned char
#define uint unsigned int
	
void SMG_output(void);
void init(void);
void Delay1ms(void);
void delay5ms(void);
void Dkey_scan(void);

uchar tab[]={
    
    0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,\
0x40,0x79,0x24,0x30,0x19,0x12,0x02,0x78,0x00,0x10,0xff,0xbf};
uchar SMG[8]={
    
    20,20,20,20,20,20,20,20};//初始显示10,全息数码管

void main(void)
{
    
    
	init();
	while(1)
	{
    
    
		SMG_output();
		Dkey_scan();
	}
}

void Dkey_scan(void) //矩阵按键
{
    
    
	static uchar keybyte=0;
	static uchar key;
	if(((P3&0X0F)!=0X0F)&&(keybyte==0))
	{
    
    
		delay5ms();
		if((P3&0X0F)!=0X0F)
		{
    
    
			keybyte=1;key=P3&0x0f;
		}
	}
	if((keybyte==1)&&((P3&0X0F)==0X0F))
	{
    
    
		if((P3&0X0F)==0X0F)
		{
    
    
			switch(key)
			{
    
    
				case 0x0e:SMG[0]=1;
					break;
				case 0x0d:SMG[1]=1;
					break;
				case 0x0b:SMG[2]=1;
					break;
				case 0x07:SMG[3]=1;
					break;
			}
			keybyte=0;
		}
	}
}

void SMG_output(void) //数码管显示函数
{
    
    
	uchar i;
	for(i=0;i<8;i++)
	{
    
    
	P2=(P2&0X1F)|0Xc0;
	P0=(1<<i);
	P2=(P2&0X1F)|0Xe0;
	P0=tab[SMG[i]];
	Delay1ms();
	}
	P2=(P2&0X1F)|0Xc0;
	P0=0Xff;
	P2=(P2&0X1F)|0Xe0;
	P0=0Xff;	
}

void init(void) //初始化函数,关闭所有外设
{
    
    
	P2=(P2&0X1F)|0XA0;
	P0=0X00;
	P2=(P2&0X1F)|0X80;
	P0=0Xff;
	P2=(P2&0X1F)|0Xc0;
	P0=0Xff;
	P2=(P2&0X1F)|0Xe0;
	P0=0Xff;	
}

void Delay1ms(void)		//@11.0592MHz
{
    
    
	unsigned char i, j;

	_nop_();
	_nop_();
	_nop_();
	i = 11;
	j = 190;
	do
	{
    
    
		while (--j);
	} while (--i);
}

void delay5ms(void)		//@11.0592MHz
{
    
    
	unsigned char i, j;

	i = 54;
	j = 199;
	do
	{
    
    
		while (--j);
	} while (--i);
}

iic.c

#include "iic.h"

#define DELAY_TIME 40
//IIC的读函数,参数(硬件地址,寄存器地址,数据)
void IIC_write(uchar hw_address,uchar reg_address,uchar num)
{
    
     
	IIC_Start();
	IIC_SendByte(hw_address&0xfe);
	IIC_WaitAck();
	IIC_SendByte(reg_address);
	IIC_WaitAck();
	IIC_SendByte(num);
	IIC_WaitAck();	
	IIC_Stop();	
}	
//IIC读函数 参数:硬件地址,寄存器地址
uchar IIC_read(uchar hw_address,uchar reg_address)
{
    
    
	uchar num;
	IIC_Start();
	IIC_SendByte(hw_address&0xfe);
	IIC_WaitAck();
	IIC_SendByte(reg_address);	
	IIC_WaitAck();
	IIC_Stop();
	
	IIC_Start();
	IIC_SendByte(hw_address|0x01);
	IIC_WaitAck();
	num=IIC_RecByte();
	IIC_WaitAck();
	IIC_Stop();	
	
	return num;
}

//
void IIC_Delay(unsigned char i)
{
    
    
    do{
    
    _nop_();}
    while(i--);        
}

//
void IIC_Start(void)
{
    
    
    SDA = 1;
    SCL = 1;
    IIC_Delay(DELAY_TIME);
    SDA = 0;
    IIC_Delay(DELAY_TIME);
    SCL = 0;	
}

//
void IIC_Stop(void)
{
    
    
    SDA = 0;
    SCL = 1;
    IIC_Delay(DELAY_TIME);
    SDA = 1;
    IIC_Delay(DELAY_TIME);
}

//
void IIC_SendAck(bit ackbit)
{
    
    
    SCL = 0;
    SDA = ackbit;  					
    IIC_Delay(DELAY_TIME);
    SCL = 1;
    IIC_Delay(DELAY_TIME);
    SCL = 0; 
    SDA = 1;
    IIC_Delay(DELAY_TIME);
}

//
bit IIC_WaitAck(void)
{
    
    
    bit ackbit;
	
    SCL  = 1;
    IIC_Delay(DELAY_TIME);
    ackbit = SDA;
    SCL = 0;
    IIC_Delay(DELAY_TIME);
    return ackbit;
}

//
void IIC_SendByte(unsigned char byt)
{
    
    
    unsigned char i;

    for(i=0; i<8; i++)
    {
    
    
        SCL  = 0;
        IIC_Delay(DELAY_TIME);
        if(byt & 0x80) SDA  = 1;
        else SDA  = 0;
        IIC_Delay(DELAY_TIME);
        SCL = 1;
        byt <<= 1;
        IIC_Delay(DELAY_TIME);
    }
    SCL  = 0;  
}

//
unsigned char IIC_RecByte(void)
{
    
    
    unsigned char i, da;
    for(i=0; i<8; i++)
    {
    
       
    	SCL = 1;
		IIC_Delay(DELAY_TIME);
		da <<= 1;
		if(SDA) da |= 1;
		SCL = 0;
		IIC_Delay(DELAY_TIME);
    }
    return da;    
}

iic.h

#ifndef _IIC_H
#define _IIC_H

#include "stc15f2k60s2.h"
#include "intrins.h"

#define uchar unsigned char
#define uint unsigned int

sbit SDA = P2^1;
sbit SCL = P2^0;

void IIC_Start(void); 
void IIC_Stop(void);  
bit IIC_WaitAck(void);  
void IIC_SendAck(bit ackbit); 
void IIC_SendByte(unsigned char byt); 
unsigned char IIC_RecByte(void); 

uchar IIC_read(uchar hw_address,uchar reg_address);
void IIC_write(uchar hw_address,uchar reg_address,uchar num);

#endif

Then compile, and you will find several warnings, *** WARNING L16: UNCALLED SEGMENT, IGNORED FOR OVERLAY PROCESS. Warnings like these are usually caused by functions that are not called. Ignore them and download and debug directly. The effect should be that when the button is pressed, the digital tube lights up accordingly.
Then continue to read the questions below.
Insert image description here
The digital tube display has two states, so it is necessary to define a variable for switching states. After definition, first display it exactly as shown on the digital tube, define a price variable price=50,50方便显示; define a total price all_price=50, and then display it. The code after the change is as follows:

uchar SMG_mode=0; //数码管切换状态变量
uchar price=50; //价格变量
uint all_price=50,water_num=100; //总价变量 //出水量定义
void main(void)
{
    
    
	init();
	while(1)
	{
    
    
		if(SMG_mode==0) //数码管模式一 售水机出水状态数码管显示
		{
    
    //加上10都是为了显示小数点
			SMG[0]=20;SMG[1]=price/100+10;SMG[2]=price%100/10;
			SMG[3]=price%10;SMG[4]=water_num/1000;
			SMG[5]=water_num%1000/100+10;
			SMG[6]=water_num%100/10;SMG[7]=water_num%10;
		}
		else if(SMG_mode==1) //数码管模式二 售水机出停水态数码管显示
		{
    
    //加上10都是为了显示小数点
			SMG[0]=20;SMG[1]=price/100+10;SMG[2]=price%100/10;
			SMG[3]=price%10;SMG[4]=all_price/1000;
			SMG[5]=all_price%1000/100+10;
			SMG[6]=all_price%100/10;SMG[7]=all_price%10;
		}
		SMG_output();
		Dkey_scan();
	}
}

As the title
Insert image description here
Then the digital tube needs to be controlled by buttons, so the corresponding control program is added to the buttons (S7 displays digital tube mode one, and the relay is turned on, L10 lights up, and S6 displays Digital tube mode two, and the relay is disconnected and L10 goes out). Since only S7 and S6 are needed, the other two independent buttons are deleted.
The program corresponding to independent key modification is:

void Dkey_scan(void)
{
    
    
	static uchar keybyte=0;
	static uchar key;
	if(((P3&0X0F)!=0X0F)&&(keybyte==0))
	{
    
    
		delay5ms();
		if((P3&0X0F)!=0X0F)
		{
    
    
			keybyte=1;key=P3&0x0f;
		}
	}
	if((keybyte==1)&&((P3&0X0F)==0X0F))
	{
    
    
		if((P3&0X0F)==0X0F)
		{
    
    
			switch(key)
			{
    
    
				case 0x0e:
					if(SMG_mode==1)SMG_mode=0; //切换数码管模式
					P2=0XA0;P0=0X10;  //点亮L10,接通继电器
					break;
				case 0x0d:
					if(SMG_mode==0)SMG_mode=1;
					P2=0XA0;P0=0X00;  //熄灭L10,关闭继电器
					break;
			}
			keybyte=0;
		}
	}
}

Remember to download and debug!!!
Then read the test questions
Insert image description here
Since you need to use AD conversion, you have to use IIC. First of all, the requirement is PCF8591 Read the voltage of the photoresistor, so the hardware address read by IIC is 0x90, then the photoresistor address is 0x01, then the input voltage is less than 1.25V, L1 lights up, otherwise L1 is off, so first convert the read value into a voltage value, that is, convert 255 to 5V, and then make a judgment.
So ​​the main function becomes:

uchar light=0;
void main(void)
{
    
    
	init();
	while(1)
	{
    
    
		light=IIC_read(0x90,0x01); //读取光敏电阻阻值
		light=light*1.9607; //500/255 放大100倍
		if(light<125) //判断条件
		{
    
    
			P2=0X80;P0=0XFE; //打开L1;
		}
		else if(light>125)
		{
    
    
			P2=0X80;P0=0XFF; //关闭L1;
		}

Then download and debug, and find that the photoresistor L1 lights up when covered.
Then look at the last requirement:
Insert image description here
Calculate the price and give the water output limit. 100 ml/second is 0.1 liter/second, so you must first use timing. device to time the water discharge.
Change the code as follows:
Timer water output

void time0() interrupt 1
{
    
    
	t++;
	if(t==1000) //1ms计时1000次==1s
	{
    
    
		t=0;
		if(SMG_mode==0) //数码管模式0才加水 即出水模式才加水
				water_num+=10; //每一秒出水
	}
}

Press button to calculate price and reset

				case 0x0e:
					if(SMG_mode==1){
    
    SMG_mode=0;water_num=0;}//切换数码管模式,出水量清零
					P2=0XA0;P0=0X10;  //点亮L10,接通继电器
					break;
				case 0x0d:
					if(SMG_mode==0)SMG_mode=1;
					P2=0XA0;P0=0X00;  //熄灭L10,关闭继电器
					all_price=((water_num*price)/100); //计算价格
					break;

Water outlet restrictions

		if(water_num>9999)
		{
    
    
			SMG_mode=1;P2=0XA0;P0=0X00;  //熄灭L10,关闭继电器
			all_price=((water_num*price)/100); //计算价格
		}

Finally, don’t forget to change the initial water output and price, and delete useless functions.
Full code:

#include <stc15f2k60s2.h>
#include "intrins.h"
#include "iic.h"

#define uchar unsigned char
#define uint unsigned int
	
void SMG_output(void);
void init(void);
void Delay1ms(void);
void delay5ms(void);
void Dkey_scan(void);
void Timer0Init(void);
uchar tab[]={
    
    0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,\
0x40,0x79,0x24,0x30,0x19,0x12,0x02,0x78,0x00,0x10,0xff,0xbf};
uchar SMG[8]={
    
    20,20,20,20,20,20,20,20};//初始显示10,全息数码管

uchar SMG_mode=0; //数码管切换状态变量
uchar price=50; //价格变量
uint all_price=0,water_num=0; //总价变量 //出水量定义
uint light=0;
uint t=0;  //定时器变量
void main(void)
{
    
    
	init(); //初始开发板
	Timer0Init(); //初始化定时器
	while(1)
	{
    
    
		light=IIC_read(0x90,0x01); //读取光敏电阻阻值
		light=light*1.9607; //500/255 放大100倍
		if(light<125) //判断条件
		{
    
    
			P2=0X80;P0=0XFE; //打开L1;
		}
		else if(light>125)
		{
    
    
			P2=0X80;P0=0XFF; //关闭L1;
		}
		if(SMG_mode==0) //数码管模式一 售水机出水状态数码管显示
		{
    
    //加上10都是为了显示小数点
			SMG[0]=20;SMG[1]=price/100+10;SMG[2]=price%100/10;
			SMG[3]=price%10;SMG[4]=water_num/1000;
			SMG[5]=water_num%1000/100+10;
			SMG[6]=water_num%100/10;SMG[7]=water_num%10;
		}
		else if(SMG_mode==1) //数码管模式二 售水机出停水态数码管显示
		{
    
    //加上10都是为了显示小数点
			SMG[0]=20;SMG[1]=price/100+10;SMG[2]=price%100/10;
			SMG[3]=price%10;SMG[4]=all_price/1000;
			SMG[5]=all_price%1000/100+10;
			SMG[6]=all_price%100/10;SMG[7]=all_price%10;
		}
		if(water_num>9999)
		{
    
    
			SMG_mode=1;P2=0XA0;P0=0X00;  //熄灭L10,关闭继电器
			all_price=((water_num*price)/100); //计算价格
		}
		SMG_output();
		Dkey_scan();
	}
}

void Dkey_scan(void)
{
    
    
	static uchar keybyte=0;
	static uchar key;
	if(((P3&0X0F)!=0X0F)&&(keybyte==0))
	{
    
    
		delay5ms();
		if((P3&0X0F)!=0X0F)
		{
    
    
			keybyte=1;key=P3&0x0f;
		}
	}
	if((keybyte==1)&&((P3&0X0F)==0X0F))
	{
    
    
		if((P3&0X0F)==0X0F)
		{
    
    
			switch(key)
			{
    
    
				case 0x0e:
					if(SMG_mode==1){
    
    SMG_mode=0;water_num=0;}//切换数码管模式,出水量清零
					P2=0XA0;P0=0X10;  //点亮L10,接通继电器
					break;
				case 0x0d:
					if(SMG_mode==0)SMG_mode=1;
					P2=0XA0;P0=0X00;  //熄灭L10,关闭继电器
					all_price=((water_num*price)/100); //计算价格
					break;
			}
			keybyte=0;
		}
	}
}

void time0() interrupt 1
{
    
    
	t++;
	if(t==1000) //1ms计时1000次==1s
	{
    
    
		t=0;
		if(SMG_mode==0) //数码管模式0才加水 即出水模式才加水
				water_num+=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 SMG_output(void)
{
    
    
	uchar i;
	for(i=0;i<8;i++)
	{
    
    
	P2=(P2&0X1F)|0Xc0;
	P0=(1<<i);
	P2=(P2&0X1F)|0Xe0;
	P0=tab[SMG[i]];
	Delay1ms();
	}
	P2=(P2&0X1F)|0Xc0;
	P0=0Xff;
	P2=(P2&0X1F)|0Xe0;
	P0=0Xff;	
}

void init(void)
{
    
    
	P2=(P2&0X1F)|0XA0;
	P0=0X00;
	P2=(P2&0X1F)|0X80;
	P0=0Xff;
	P2=(P2&0X1F)|0Xc0;
	P0=0Xff;
	P2=(P2&0X1F)|0Xe0;
	P0=0Xff;	
}

void Delay1ms(void)		//@11.0592MHz
{
    
    
	unsigned char i, j;

	_nop_();
	_nop_();
	_nop_();
	i = 11;
	j = 190;
	do
	{
    
    
		while (--j);
	} while (--i);
}

void delay5ms(void)		//@11.0592MHz
{
    
    
	unsigned char i, j;

	i = 54;
	j = 199;
	do
	{
    
    
		while (--j);
	} while (--i);
}

Final demonstration video
Insert image description here
At the end, you can send private messages and comments if you have any questions.

Guess you like

Origin blog.csdn.net/darlingqx/article/details/127431854