Detailed explanation of the 9th Provincial Competition Questions of Lanqiao Cup Microcontroller (Lighting Controller)

I highly recommend you do it yourself before watching it! ! !

Demo video

Question explanation

First of all, start with the preparation of the program block diagram of the topic.
Insert image description here
Debug the PCF8591 (analog input), buttons, digital tube, and EEPROM of the program block diagram first.
Insert image description here
Insert image description here
Then take a look at the basic functionality to give yourself an idea of ​​the entire process. Then prepare the four modes of LED controlled by the colored lights. My suggestion here is to use an array to save the state

uchar LED1[8]={
    
    0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f}; //模式1
uchar LED2[8]={
    
    0x7f,0xbf,0xdf,0xef,0xf7,0xfb,0xfd,0xfe}; //模式2
uchar LED3[4]={
    
    0x7e,0xbd,0xdb,0xe7}; //模式3
uchar LED4[4]={
    
    0xe7,0xdb,0xbd,0x7e}; //模式4

Then continue to read the question. The brightness adjustment here requires adjusting the pwm duty cycle, so let’s put it down first and convert the Rb2 voltage into 4 levels.
Insert image description here

uchar SMG_mode=0,move; //数码管模式定义,滑动变阻器Rb2定义
uchar shine_mode=0; //定义光强
void main(void)
{
    
    
	move=IIC_read(PCF8591_address,Move_address); //读取Rb2电阻阻值
	move=move*1.9608; //500/255 将255转换到500		
	if(move<125) shine_mode=1;
	else if(move<250) shine_mode=2;
	else if(move<375) shine_mode=3;
	else shine_mode=4;
}

Then continue to read the questions below. First set up
Insert image description here
S7: control the LED flow, so just set a variable to control it.
S6: It is a button for switching the status of the digital tube, and also controls a variable to switch. Since the set unit needs to flash, a timer needs to be used. Note that the data must also be stored in eeprom. Note that the size of eeprom is 255, so the time can only be reduced to save it

uchar SMG_mode=0,move; //数码管模式定义,滑动变阻器Rb2定义
uchar shine_mode=0; //定义光强
char led_mode=1; //led模式
int gap=400; //设置流转间隔
void main(void)
{
    
    
	init(); //初始开发板
	Timer0Init(); //定时器初始化
//	threshold=IIC_read(0xA0,0x00); //上电读取EEPROM
	while(1)
	{
    
    
		if(SMG_mode==0)//数码管全息,模式一
		{
    
    
			SMG[0]=SMG[1]=SMG[2]=SMG[3]=SMG[4]=SMG[5]=20;
			SMG[6]=SMG[7]=20;
		}
		else if(SMG_mode==1) //模式控制,将模式赋值放定时器闪烁
		{
    
    
			SMG[0]=SMG[2]=21;
			SMG[3]=20;
			if(gap<1000){
    
    SMG[4]=20;
			SMG[5]=gap/100;SMG[6]=gap%100/10;SMG[7]=gap%10;} //1000以下显示
			else
			{
    
    SMG[4]=gap/1000;SMG[5]=gap%1000/100; //1000以上显示
			SMG[6]=gap%100/10;SMG[7]=gap%10;}
		}
		else if(SMG_mode==2)//间隔控制,将间隔赋值放定时器闪烁
		{
    
    
			SMG[0]=SMG[2]=21;SMG[1]=led_mode;
			SMG[3]=20;		
		}
		move=IIC_read(PCF8591_address,Move_address); //读取Rb2电阻阻值
		move=move*1.9608; //500/255 将255转换到500		
		if(move<125) shine_mode=1;
		else if(move<250) shine_mode=2;
		else if(move<375) shine_mode=3;
		else shine_mode=4;
		
		SMG_output();
		Dkey_scan();
	}
}
//定时器中断服务函数
uchar t=0; //定时器内计数变量
bit state=0; //闪控制变量
void time0() interrupt 1
{
    
    
	if((SMG_mode==1)||(SMG_mode==2))
	{
    
    
		t++;
		if(t>=160) //800ms/5ms=160次
		{
    
    
			t=0;
			if(state==0)
			{
    
    
				state=1;
				switch(SMG_mode)
				{
    
    
					case 1:SMG[1]=led_mode;break;
					case 2:
							if(gap<1000){
    
    SMG[4]=20;
							SMG[5]=gap/100;SMG[6]=gap%100/10;SMG[7]=gap%10;} //1000以下显示
							else
							{
    
    SMG[4]=gap/1000;SMG[5]=gap%1000/100; //1000以上显示
							SMG[6]=gap%100/10;SMG[7]=gap%10;}
						break;
				}
			}
			else
			{
    
    
				state=0;
				switch(SMG_mode)
				{
    
    
					case 1:SMG[1]=20;break;
					case 2:SMG[4]=SMG[5]=SMG[6]=SMG[7]=20;break;
				}
			}
		}
	}
}
bit ledenable=0; //led工作使能
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: //S7
					if(ledenable==0)ledenable=1;
				else ledenable=0;
					break;
				case 0x0d: //S6
				if(SMG_mode==0){
    
    SMG_mode=1;P2=0X80;P0=0xff;}//进入设置关灯
				else if(SMG_mode==1)SMG_mode=2;
				else if(SMG_mode==2)
				{
    
    SMG_mode=0;IIC_write(AT24C02_address,0x00,led_mode);
				IIC_write(AT24C02_address,0x00,(gap/100));} //保存模式和间隔
					break;
				case 0x0b: //S5
				
					break;
				case 0x07: //S4
				
					break;
			}
			keybyte=0;
		}
	}
}

Then set the S5 and S4 buttons.
Insert image description here

bit ledenable=0; //led工作使能
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: //S7
					if(ledenable==0)ledenable=1;
				else ledenable=0;
					break;
				case 0x0d: //S6
				if(SMG_mode==0)SMG_mode=1;
				else if(SMG_mode==1)SMG_mode=2;
				else if(SMG_mode==2)
				{
    
    SMG_mode=0;IIC_write(AT24C02_address,0x00,led_mode);
				IIC_write(AT24C02_address,0x00,gap);} //保存模式和间隔
					break;
				case 0x0b: //S5
				switch(SMG_mode)
				{
    
    
					case 1:led_mode++;break;
					case 2:gap+=100;break;
				}
				if(gap>=1200)gap=1200;  //限幅
				if(led_mode>=4)led_mode=4;  //限幅
					break;
				case 0x07: //S4
				switch(SMG_mode)
				{
    
    
					case 1:led_mode--;break;
					case 2:gap-=100;break;
				}
				if(gap<=400)gap=400;  //限幅
				if(led_mode<=1)led_mode=1;  //限幅
					break;
			}
			keybyte=0;
		}
	}
}

After doing this, the next step is to adjust the LED mode and brightness. Of course, these must be adjusted in the timer.
Interval adjustment is to turn on and off according to the prescribed interval. Brightness adjustment is to subdivide the light state in the interval. That is to say, when you light it, you can't keep it on, you have to make it shine. The interval determines the brightness.
Here I take the PWM with a period of 20ms, divided into four duty cycles, 11ms/20ms, 14ms/20ms, 17/20ms, 20ms/20ms, so that the brightness can be controlled. a>

else //led模式
	{
    
    
		if(ledenable==1) //led使能有效才进行
		{
    
    
			tt++;
			if(tt>=gap)//gap到达间隔时间控制led间隔
			{
    
    
				tt=0;
				if(state==1){
    
    state=0;}
				else {
    
    state=1;num+=1;}
			}
			
			if(state==1)//亮
			{
    
    
				if(ttt<((shine_mode*3)+8))
				{
    
    
					switch(led_mode)
					{
    
    
						case 1:if(num>=8)num=0;led=LED1[num];break;//led1
						case 2:if(num>=8)num=0;led=LED2[num];break;//led2
						case 3:if(num>=4)num=0;led=LED3[num];break;//led3
						case 4:if(num>=4)num=0;led=LED4[num];break;//led4
					}
				}
				else
				{
    
    
					led=0xff;//模式0熄灭
				}
				ttt++;
				if(ttt>=20)ttt=0;
			}
			else//灭
			{
    
    
				led=0xff;//模式0控制间隔设置熄灭
			}
		}
	}

Then there is the brightness level display.
Insert image description here

	while((key==0x07)&&(SMG_mode==0))
	{
    
    
		keybyte=0;key=P3&0x0f;
		SMG[6]=21;SMG[7]=shine_mode;
		SMG[0]=SMG[1]=SMG[2]=SMG[3]=SMG[4]=SMG[5]=20;		
		SMG_output();P2=0X80;P0=led;
	}

complete program

main.c

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

#define uchar unsigned char
#define uint unsigned int

#define AT24C02_address 0xA0 //EEPROM地址
#define PCF8591_address 0x90 //PCF地址
#define Move_address 0x03 //滑动变阻器地址

void init(void);
void Delay1ms(void);
void delay5ms(void);
void Dkey_scan(void);
void SMG_output(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 LED1[8]={
    
    0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f}; //模式1
uchar LED2[8]={
    
    0x7f,0xbf,0xdf,0xef,0xf7,0xfb,0xfd,0xfe}; //模式2
uchar LED3[4]={
    
    0x7e,0xbd,0xdb,0xe7}; //模式3
uchar LED4[4]={
    
    0xe7,0xdb,0xbd,0x7e}; //模式4

uchar SMG_mode=0; //数码管模式定义
uint move=0; //滑动变阻器Rb2定义
uchar shine_mode=0; //定义光强
char led_mode=1; //led模式
uint gap=400; //设置流转间隔
uchar led=0xff; //led显示变量
bit ledenable=0; //led工作使能
void main(void)
{
    
    
	init(); //初始开发板
	led_mode=IIC_read(AT24C02_address,0x00); //上电读取EEPROM
	delay5ms();
	gap=IIC_read(AT24C02_address,0x01);
	gap *=100;
	Timer0Init(); //定时器初始化
	while(1)
	{
    
    
		move=IIC_read(PCF8591_address,Move_address); //读取Rb2电阻阻值
		move=move*1.9608; //500/255 将255转换到500		
		if(move<125) shine_mode=1;
		else if(move<250) shine_mode=2;
		else if(move<375) shine_mode=3;
		else shine_mode=4;
		if(SMG_mode==0)//数码管全息,模式一
		{
    
    
			SMG[0]=SMG[1]=SMG[2]=SMG[3]=SMG[4]=SMG[5]=20;
			SMG[6]=SMG[7]=20;
		}
		else if(SMG_mode==1) //模式控制,将模式赋值放定时器闪烁
		{
    
    
			SMG[0]=SMG[2]=21;
			SMG[3]=20;
			if(gap<1000){
    
    SMG[4]=20;
			SMG[5]=gap/100;SMG[6]=gap%100/10;SMG[7]=gap%10;} //1000以下显示
			else
			{
    
    SMG[4]=gap/1000;SMG[5]=gap%1000/100; //1000以上显示
			SMG[6]=gap%100/10;SMG[7]=gap%10;}
		}
		else if(SMG_mode==2)//间隔控制,将间隔赋值放定时器闪烁
		{
    
    
			SMG[0]=SMG[2]=21;SMG[1]=led_mode;
			SMG[3]=20;		
		}
		
		P2=0X80;P0=led;
		SMG_output();
		Dkey_scan();
	}
}

uint t=0; //定时器内计数变量
uint tt=0;//控制led间隔变量
uint ttt=0; //控制led光强
bit state=0; //闪控制变量
uchar num=0; //led数组选择变量
void time0() interrupt 1
{
    
    
	if((SMG_mode==1)||(SMG_mode==2))
	{
    
    
		t++;
		if(t>=800) //800ms
		{
    
    
			t=0;
			if(state==0)
			{
    
    
				state=1;
				switch(SMG_mode)
				{
    
    
					case 1:SMG[1]=led_mode;break; //模式一控制模式设置闪烁
					case 2://模式二控制间隔设置闪烁
							if(gap<1000){
    
    SMG[4]=20;
							SMG[5]=gap/100;SMG[6]=gap%100/10;SMG[7]=gap%10;} //1000以下显示
							else
							{
    
    SMG[4]=gap/1000;SMG[5]=gap%1000/100; //1000以上显示
							SMG[6]=gap%100/10;SMG[7]=gap%10;}
					break;
				}
			}
			else
			{
    
    
				state=0;
				switch(SMG_mode)
				{
    
    
					case 1:SMG[1]=20;break;//模式一控制模式设置熄灭
					case 2:SMG[4]=SMG[5]=SMG[6]=SMG[7]=20;break;//模式二控制间隔设置熄灭
				}
			}
		}
	}
	else //led模式
	{
    
    
		if(ledenable==1) //led使能有效才进行
		{
    
    
			tt++;
			if(tt>=gap)//gap到达间隔时间控制led间隔
			{
    
    
				tt=0;
				if(state==1){
    
    state=0;}
				else {
    
    state=1;num+=1;}
			}
			
			if(state==1)//亮
			{
    
    
				if(ttt<((shine_mode*3)+8))
				{
    
    
					switch(led_mode)
					{
    
    
						case 1:if(num>=8)num=0;led=LED1[num];break;//led1
						case 2:if(num>=8)num=0;led=LED2[num];break;//led2
						case 3:if(num>=4)num=0;led=LED3[num];break;//led3
						case 4:if(num>=4)num=0;led=LED4[num];break;//led4
					}
				}
				else
				{
    
    
					led=0xff;//模式0熄灭
				}
				ttt++;
				if(ttt>=20)ttt=0;
			}
			else//灭
			{
    
    
				led=0xff;//模式0控制间隔设置熄灭
			}
		}
	}
}

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;
		}
	}
	while((key==0x07)&&(SMG_mode==0))
	{
    
    
		keybyte=0;key=P3&0x0f;
		SMG[6]=21;SMG[7]=shine_mode;
		SMG[0]=SMG[1]=SMG[2]=SMG[3]=SMG[4]=SMG[5]=20;		
		SMG_output();P2=0X80;P0=led;
	}
	if((keybyte==1)&&((P3&0X0F)==0X0F))
	{
    
    
		if((P3&0X0F)==0X0F)
		{
    
    
			switch(key)
			{
    
    
				case 0x0e: //S7
					if(ledenable==0)ledenable=1;
				else ledenable=0;
					break;
				case 0x0d: //S6
				if(SMG_mode==0){
    
    SMG_mode=1;P2=0X80;P0=0xff;}//进入设置关灯
				else if(SMG_mode==1)SMG_mode=2;
				else if(SMG_mode==2)
				{
    
    SMG_mode=0;IIC_write(AT24C02_address,0x00,led_mode);delay5ms();
				IIC_write(AT24C02_address,0x01,(gap/100));} //保存模式和间隔
					break;
				case 0x0b: //S5
				if(SMG_mode==1)led_mode++;
				else if(SMG_mode==2)gap+=100;
				if(gap>=1200)gap=1200;  //限幅
				if(led_mode>=4)led_mode=4;  //限幅
					break;
				case 0x07: //S4
				if(SMG_mode==1)led_mode--;
				else if(SMG_mode==2)gap-=100;
				if(gap<=400)gap=400;  //限幅
				if(led_mode<=1)led_mode=1;  //限幅
					break;
			}
			keybyte=0;
		}
	}
}

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);
}

iic.c

#include "iic.h"

#define DELAY_TIME 40

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();	
}	

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); 
void IIC_write(uchar hw_address,uchar reg_address,uchar num);
uchar IIC_read(uchar hw_address,uchar reg_address);


#endif

Project Files

Project files have comments

Guess you like

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