蓝桥杯电子类单片机组省赛——第九届“彩灯控制器”

本文详细介绍了使用STM32进行嵌入式系统编程的经验,包括初始化定时器、IIC通信、按键扫描、ADC值读取以及LED显示。代码中实现了1毫秒定时器中断、独立按键扫描、数码管显示及亮度控制等功能,同时展示了如何通过EEPROM读取和存储参数。示例代码涉及状态机、中断服务函数等编程技巧,适用于STM32初学者及实践经验积累。
摘要由CSDN通过智能技术生成

这是我第二次写第九届的题目了,总体感觉还行,没有什么难点。第二次写第九届省赛赛题给我的感觉是:写代码的时候一定要保持头脑清晰,这样才能更高效地写代码(毕竟这比赛重逻辑)。好了,废话不多说,我直接贴代码了(全程使用状态机,减少脑髓流失)!

#include "STC15F2K60S2.H"
#include "iic.h"

#define u8 unsigned char 
#define KEY_STATE_0 0
#define KEY_STATE_1 1
#define KEY_STATE_2 2

#define LED_0 0X00
#define LED_1 ((0x01)<<(1-1))
#define LED_2 ((0x01)<<(2-1))
#define LED_3 ((0x01)<<(3-1))
#define LED_4 ((0x01)<<(4-1))
#define LED_5 ((0x01)<<(5-1))
#define LED_6 ((0x01)<<(6-1))
#define LED_7 ((0x01)<<(7-1))
#define LED_8 ((0x01)<<(8-1))

u8 code t_display[]={                       //标准字库
//   0    1    2    3    4    5    6    7    8    9    A    B    C    D    E    F
    0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F,0x77,0x7C,0x39,0x5E,0x79,0x71,
//black  -     H    J    K    L    N    o   P    U     t    G    Q    r   M    y
    0x00,0x40,0x76,0x1E,0x70,0x38,0x37,0x5C,0x73,0x3E,0x78,0x3d,0x67,0x50,0x37,0x6e,
    0xBF,0x86,0xDB,0xCF,0xE6,0xED,0xFD,0x87,0xFF,0xEF,0x46};    //0. 1. 2. 3. 4. 5. 6. 7. 8. 9. -1

u8 code T_COM[]={0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80};      //位码
u8 code LED_COM[]={LED_0,LED_1,LED_2,LED_3,LED_4,LED_5,LED_6,LED_7,LED_8};//led显示操作码

static u8 key_state=KEY_STATE_0;//后面会用到独立按键,这个是按键的状态标志位
void Timer0Init(void)		//1毫秒定时器中断
{
	AUXR |= 0x80;		//定时器时钟1T模式
	TMOD &= 0xF0;		//设置定时器模式
	TL0 = 0xCD;		//设置定时初值
	TH0 = 0xD4;		//设置定时初值
	TF0 = 0;		//清除TF0标志
	TR0 = 1;		//定时器0开始计时
	ET0=1;
	EA=1;
}

unsigned char KEY_SCAN()//按键扫描函数
{
		u8 KEY=0;
		u8 key_val=0;
	
		P30=1;P31=1;P32=1;P33=1;
		if(P30==0)   KEY=7;
		if(P31==0)   KEY=6;
		if(P32==0)   KEY=5;
		if(P33==0)   KEY=4;
		if((P30==1)&&(P31==1)&&(P32==1)&&(P33==1))  KEY=0;

		switch(key_state)
	{
		case KEY_STATE_0: 
		if(KEY!=0)
		{
			key_state=KEY_STATE_1;
		}
		break;
		
		case KEY_STATE_1: 
		switch(KEY)
		{
				case 4: key_val=4; break;
				case 5: key_val=5; break;
				case 6: key_val=6; break;
				case 7: key_val=7; break;

		}
			key_state=KEY_STATE_2;
		break;
		
		case KEY_STATE_2:  
		if(KEY==0)
		{
			key_state=KEY_STATE_0;
		}
		
		break;
		
		
		
	}
	
	return key_val;
	

}



/**********************************用到了17个外部变量*************************************/

bit key_flag=0;//按键读取标志位
u8 key_val=0;//按键的键值
u8 adc_val;//adc读取的值
u8 led_choose1=0;//选择的第一个led灯
u8 led_choose2=0;//选择的第二个led灯
u8 led_mode=1;//led模式
u8 led_mode_time[5];//每个led流转模式的间隔时间
u8 led_mode_smgdisplay=1;//运行模式编号 1、2、3、4
u8 smg_display_index=0;//0、数码管全部熄灭  1、模式编号  2、流转间隔    (123循环)
bit smg_diaplay_flag=0;//0: 数码管熄灭表示  1: 数码管打开表示
bit led_flag=0;//led显示标志位
static int led_count=0;//led计数器
u8 led_level=1;//led亮度等级  (1-4)
u8 smg_display[8];//数码管显示数组
u8 smg_display_mode_index=1;//1、正常显示模式   2、S4按下模式
bit smg_blink_flag=0;//数码管闪烁标志位置

/***********************************************************************************/

void main()
{
	led_mode_time[1]=read_24c02(1);
	led_mode_time[2]=read_24c02(2);
	led_mode_time[3]=read_24c02(3);
	led_mode_time[4]=read_24c02(4);   //EEPROM读取键值
	
	P2=0XA0;P0=0X00;P2=0X00;     //关闭蜂鸣器
	Timer0Init();       //定时器0中断
	

	while(1)//下面是需要执行的函数
	{
		adc_val=read_adc(0x03); //读取adc的值
		
		if(adc_val<=64)
		{
			led_level=1;
		}
		
		else if(adc_val<=128)
		{
			led_level=2;
		}
		else if(adc_val<=192)
		{
			led_level=3;
		}
		else if(adc_val<=255)
		{
			led_level=4;
		}
		//不同的adc的值对应不同的led亮度等级
		

			    	if(key_flag)  //定时器扫描按键进入
					 {
							key_flag=0;
							key_val=KEY_SCAN();
						 						if((smg_display_index==0)&&(key_state==KEY_STATE_2))
								{
												if(key_val==4)
												smg_display_mode_index=2;						
								}
								
								else
								{
												smg_display_mode_index=1;						
								}

							switch(key_val)
							{
								case 4:  
									
									
								
								
								if((smg_display_index==1)&&(led_mode_smgdisplay!=1))  //模式编号
								{
										led_mode_smgdisplay--;
								}
								if((smg_display_index==2)&&(led_mode_time[led_mode_smgdisplay]!=4))
								{
										led_mode_time[led_mode_smgdisplay]--;
										write_24c02(led_mode_smgdisplay,led_mode_time[led_mode_smgdisplay]);
									
									
								}
								break;
								
								case 5: 
								if((smg_display_index==1)&&(led_mode_smgdisplay!=4))  //模式编号
								{
										led_mode_smgdisplay++;
								}
								if((smg_display_index==2)&&(led_mode_time[led_mode_smgdisplay]!=12))
								{
										led_mode_time[led_mode_smgdisplay]++;
										write_24c02(led_mode_smgdisplay,led_mode_time[led_mode_smgdisplay]);
								}
								break;
								
								case 6:  
								smg_display_index++;
								
								
								break;
								
								case 7:  led_flag=~led_flag; break;

							}
					 }
					 
					 

								
								
					 if(smg_display_index==0)
					 {
							smg_diaplay_flag=0;
						}
					 
					 if(smg_display_index==1)
					 {
							smg_diaplay_flag=1;
					}	
					
					if(smg_display_index==2)
					{
							smg_diaplay_flag=1;
					}
					if(smg_display_index==3)//数码管模式越界
					{
							smg_display_index=0;
					}
					
					if(smg_display_mode_index==1)//非特殊显示模式
					{
								if(smg_diaplay_flag)//数码管打开
								{
									smg_display[0]=t_display[17];
									
									if(smg_display_index==1)//标号模式
									{
											if(smg_blink_flag)
											{
													smg_display[1]=t_display[led_mode_smgdisplay];
											}
											else
											{
													smg_display[1]=t_display[16];
											}
									}
									else
									{
											smg_display[1]=t_display[led_mode_smgdisplay];
									}
									smg_display[2]=t_display[17];
									smg_display[3]=t_display[16];
									
									if(smg_display_index==2)//间隔时间显示模式
									{
											if(smg_blink_flag)
											{
														if(led_mode_time[led_mode_smgdisplay]>=10)
														{
														smg_display[4]=t_display[1];
														}
														else
														{
														smg_display[4]=t_display[16];
														}
														smg_display[5]=t_display[led_mode_time[led_mode_smgdisplay]%10];
														smg_display[6]=t_display[0];
														smg_display[7]=t_display[0];

											}
											else
											{
														smg_display[4]=t_display[16];
														smg_display[5]=t_display[16];
														smg_display[6]=t_display[16];
														smg_display[7]=t_display[16];
											}
									}
									
									else
									{
														if(led_mode_time[led_mode_smgdisplay]>=10)
														{
														smg_display[4]=t_display[1];
														}
														else
														{
														smg_display[4]=t_display[16];
														}
														smg_display[5]=t_display[led_mode_time[led_mode_smgdisplay]%10];
														smg_display[6]=t_display[0];
														smg_display[7]=t_display[0];
									}

									
								}
								
								else//数码管关闭
								{
									smg_display[0]=t_display[16];
									smg_display[1]=t_display[16];
									smg_display[2]=t_display[16];
									
									smg_display[3]=t_display[16];
									smg_display[4]=t_display[16];
									
									smg_display[5]=t_display[16];
									smg_display[6]=t_display[16];
									smg_display[7]=t_display[16];
								}				 
					}
					
					else
					{
									smg_display[0]=t_display[16];
									smg_display[1]=t_display[16];
									smg_display[2]=t_display[16];
									smg_display[3]=t_display[16];
									smg_display[4]=t_display[16];
									smg_display[5]=t_display[16];
									smg_display[6]=t_display[17];
									smg_display[7]=t_display[led_level];
					}
					
					 
					 
					
	}
	


}

void Timer0(void)  interrupt 1		//1毫秒@11.0592MHz
{
		static int key_count=0,P2_count=0,i=0,led_light_level=1,smg_blink=0;
		key_count++;P2_count++;smg_blink++;
	
		if(smg_blink==800)
		{
			smg_blink=0;
			smg_blink_flag=~smg_blink_flag;
		}
		if(key_count==10)
		{	
			key_count=0;
			key_flag=1;
		}
		
		if(P2_count==1)
		{
			if(led_flag)
			{
				led_count++;
				led_light_level++;
				if(led_light_level==5)
				{
					led_light_level=1;
				}
			}
			else
			{
			led_count=0;
			led_choose1=0;
			led_choose2=0;
			led_mode=1;
			}
		}
		
		if(led_light_level<=led_level)
		{
			P0=~(LED_COM[led_choose1]|LED_COM[led_choose2]);P2=0X80;P2=0X00;
		}
		else
		{
			P0=~0;P2=0X80;P2=0X00;
		}
		
		if(P2_count==2)
		{
			P2_count=0;
			P2=0XC0;P0=0X00;P2=0X00;
			P2=0XE0;P0=~smg_display[i];P2=0X00;
			P2=0XC0;P0=T_COM[i];P2=0X00;
			i++;
			if(i==8)   {i=0;}

		}
		
		
			if ((led_count==led_mode_time[1]*50)&&(led_mode==1))
		{
			led_count=0;
			led_choose1=0;
			led_choose2++;
			if(led_choose2==8)
			{led_mode=2;}
			
		}
		
		if ((led_count==led_mode_time[2]*50)&&(led_mode==2))
		{
			led_count=0;
			led_choose1=0;
			led_choose2--;
			if(led_choose2==1)
			{
				led_mode=3;
			}

		}
		
		if ((led_count==led_mode_time[3]*50)&&(led_mode==3))
		{
	 					led_count=0;
						led_choose1++;
						led_choose2=(9-led_choose1);
						if(led_choose1==4)
						{
							led_mode=4;
						}



		}
		
		if ((led_count==led_mode_time[4]*50)&&(led_mode==4))
		{
	 					led_count=0;
						led_choose1--;
						led_choose2=(9-led_choose1);
						if(led_choose1==0)
						{
							led_choose2=1;
							led_mode=1;
						}
		}
		
		

}

代码就是这么多,也就400多行代码。实测完成度100%。
这里没有贴“iic.c“和”iic.h“的代码,有需要的同学点击下面的链接:

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Elec Liu

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值