功能
本设计将要实现一个以单片机为核心的屏显菜单系统设计。以单片机STM32单片机作为主控芯片,通过按键选择不同的选项,显示不同的界面功能。在界面部分主要显示菜单栏、时间、图片、音乐等功能。
掌握与研究的内容有以下几个方面:
(1)研究屏幕SPI通信方式。
(2)研究单总线通信协议。
(3)研究菜单步进系统设计。
(4)研究使用Keil编程环境编写单片机代码。

硬件
屏显菜单系统硬件如图1所示。硬件部分主要包括单片机最小系统、电源、按键模块、时钟模块、显示模块、语音模块。单片机检测不同按键按下,进行屏幕菜单选项选择,按下确定键后实现选项功能,可以选择时间显示,图片显示等功能。

在这里插入图片描述

在这里插入图片描述

演示视频

基于STM32的屏显菜单系统

核心代码

#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "led.h"
#include "timer.h"
#include "ADC.h"
#include "usart3.h"
#include "key.h"
#include "rtc.h"
#include "oled.h"
#include "stmflash.h"
#include "math.h"
#include "dht11.h"
#include "bmp280.h"
#include "exti.h"
#include "DS1302.h"
#include "lcd_init.h"
#include "lcd.h"
#include "pic.h"


u8 count;
u8 Play = 1;

u8 display_contrl=0;
u8 curtain_flag=0;
u8 last_curtain_flag=0;

u8 PageIndex = 1;//页面步进值
u8 Page1OptionIndex = 1;//选项步进值 1:时间   2:图片  3:音乐
u8 Page2OptionIndex = 1;

void SendData11( u8 addr )//发送函数。
{
    u8 i;
    
    SPEEKSDA = 1;/*开始拉高 */
    delay_us ( 1000 );
    
    SPEEKSDA = 0;/*开始引导码*/
    delay_us ( 2000 );/*此处延时最少要大于 2ms,此参数延时为 310ms */
    for ( i = 0; i < 8; i++ ) /*总共 8 位数据 */
    {
        SPEEKSDA = 1;
        if ( addr & 0x01 ) /*3:1 表示数据位 1,每个位用两个脉冲表示 */
        {
            delay_us ( 1200 );
            SPEEKSDA = 0;
            delay_us ( 400 );
         }
         else /*1:3 表示数据位 0 ,每个位用两个脉冲表示 */
        {
            delay_us ( 400 );
            SPEEKSDA = 0;
            delay_us ( 1200 );
        }
        addr >>= 1;
    }

}

//设置音量:vol(0-30)
void ONE_LINE_VOL(u8 vol)
{
    if(vol>30)vol=30;
    SendData11(vol/10);
    SendData11(vol%10);
    SendData11(0x0C);
}

void ONE_LINE_PLAY_SONG(u8 song)
{
    u8 i;
    u8 tmp[3];
    
    tmp[0]=song/100;song%=100;
    tmp[1]=song/10;
    tmp[2]=song%10;
    
    SendData11(0x0a);
    for(i=0;i<3;i++)
    {
       if(tmp[i]!=0)
       {
          SendData11(tmp[i]);
       }   
    }
    SendData11(0x0b);
}
//单线串口:播放
void ONE_LINE_PLAY()
{
    SendData11(0x11);  
}
//时间显示
void Time_Display()
{
	u8 x=40;
	u8 y=50;
	LCD_ShowChinese(64,16,"时间",BLACK,LGRAY,16,0);
	LCD_ShowIntNum(x,y,TIME[1]/16,1,RED,LGRAY,16);//年
	LCD_ShowIntNum(x+8,y,DS1302_Time[3],1,RED,LGRAY,16);
	LCD_ShowString(x+16,y,"-",RED,LGRAY,16,0);
	LCD_ShowIntNum(x+24,y,DS1302_Time[4],1,RED,LGRAY,16);//月
	LCD_ShowIntNum(x+32,y,DS1302_Time[5],1,RED,LGRAY,16);
	LCD_ShowString(x+40,y,"-",RED,LGRAY,16,0);
	LCD_ShowIntNum(x+48,y,DS1302_Time[6],1,RED,LGRAY,16);//日
	LCD_ShowIntNum(x+56,y,DS1302_Time[7],1,RED,LGRAY,16);

	LCD_ShowIntNum(x,y+16,DS1302_Time[8],1,RED,LGRAY,16);//时
	LCD_ShowIntNum(x+8,y+16,DS1302_Time[9],1,RED,LGRAY,16);
	LCD_ShowString(x+16,y+16,":",RED,LGRAY,16,0);
	LCD_ShowIntNum(x+24,y+16,DS1302_Time[10],1,RED,LGRAY,16);//分
	LCD_ShowIntNum(x+32,y+16,DS1302_Time[11],1,RED,LGRAY,16);
	LCD_ShowString(x+40,y+16,":",RED,LGRAY,16,0);
	LCD_ShowIntNum(x+48,y+16,DS1302_Time[12],1,RED,LGRAY,16);//秒
	LCD_ShowIntNum(x+56,y+16,DS1302_Time[13],1,RED,LGRAY,16);
}
//图片选项显示
void PictureDisplay()
{
	if((Page1OptionIndex==2)&&(PageIndex==2))
	{
		LCD_ShowChinese(64,16,"图片",BLACK,LGRAY,16,0);
		if(Page2OptionIndex==1)
		{
			LCD_ShowString(40+16,40,"1)",RED,LGRAY,16,0);
			LCD_ShowChinese(56+16,40,"图片",RED,YELLOW,16,0);
			LCD_ShowString(88+16,40,"1",RED,YELLOW,16,0);
		}
		else
		{
			LCD_ShowString(40+16,40,"1)",RED,LGRAY,16,0);
			LCD_ShowChinese(56+16,40,"图片",RED,LGRAY,16,0);
			LCD_ShowString(88+16,40,"1",RED,LGRAY,16,0);
		}
		if(Page2OptionIndex==2)
		{
			LCD_ShowString(40+16,56,"2)",RED,LGRAY,16,0);
			LCD_ShowChinese(56+16,56,"图片",RED,YELLOW,16,0);
			LCD_ShowString(88+16,56,"2",RED,YELLOW,16,0);
		}
		else
		{
			LCD_ShowString(40+16,56,"2)",RED,LGRAY,16,0);
			LCD_ShowChinese(56+16,56,"图片",RED,LGRAY,16,0);
			LCD_ShowString(88+16,56,"2",RED,LGRAY,16,0);
		}
	}
	
	
	if(PageIndex==3)
	{
		if(Page2OptionIndex==1)
		{
			LCD_ShowPicture(30,0,100,99,Image_xaau);
		}
		if(Page2OptionIndex==2)
		{
			LCD_ShowPicture(65,80,40,40,gImage_1);
		}
	}
}
//音乐选项显示
void MusicDisplay()
{
	if((Page1OptionIndex==3)&&(PageIndex==2))
	{
		LCD_ShowChinese(64,16,"音乐",BLACK,LGRAY,16,0);
		
		if(Page2OptionIndex==1)
		{
			LCD_ShowString(40+16,40,"1)",RED,LGRAY,16,0);
			LCD_ShowChinese(56+16,40,"音乐",RED,YELLOW,16,0);
			LCD_ShowString(88+16,40,"1",RED,YELLOW,16,0);
		}
		else
		{
			LCD_ShowString(40+16,40,"1)",RED,LGRAY,16,0);
			LCD_ShowChinese(56+16,40,"音乐",RED,LGRAY,16,0);
			LCD_ShowString(88+16,40,"1",RED,LGRAY,16,0);
		}
		
			
		if(Page2OptionIndex==2)
		{
			LCD_ShowString(40+16,56,"2)",RED,LGRAY,16,0);
			LCD_ShowChinese(56+16,56,"音乐",RED,YELLOW,16,0);
			LCD_ShowString(88+16,56,"2",RED,YELLOW,16,0);
		}
		else
		{
			LCD_ShowString(40+16,56,"2)",RED,LGRAY,16,0);
			LCD_ShowChinese(56+16,56,"音乐",RED,LGRAY,16,0);
			LCD_ShowString(88+16,56,"2",RED,LGRAY,16,0);
		}
		
		if(Page2OptionIndex==3)
		{
			LCD_ShowString(40+16,72,"3)",RED,LGRAY,16,0);
			LCD_ShowChinese(56+16,72,"音乐",RED,YELLOW,16,0);
			LCD_ShowString(88+16,72,"3",RED,YELLOW,16,0);}
		else
		{
			LCD_ShowString(40+16,72,"3)",RED,LGRAY,16,0);
			LCD_ShowChinese(56+16,72,"音乐",RED,LGRAY,16,0);
			LCD_ShowString(88+16,72,"3",RED,LGRAY,16,0);
		}
	}
	
	
	if(PageIndex==3)
	{
		if(Page2OptionIndex==1)
		{
			LCD_ShowChinese(50,66,"播放音乐",RED,LGRAY,16,0);
			LCD_ShowString(114,66,"1",RED,LGRAY,16,0);
			if(Play==1)
			{
				Play=0;
				MUSIC1=0;delay_ms(1000);MUSIC1=1;
			}
		}
		if(Page2OptionIndex==2)
		{
			LCD_ShowChinese(50,66,"播放音乐",RED,LGRAY,16,0);
			LCD_ShowString(114,66,"2",RED,LGRAY,16,0);
			if(Play==1)
			{
				Play=0;
				MUSIC3=0;delay_ms(1000);MUSIC3=1;
				
			}
		}
		if(Page2OptionIndex==3)
		{
			LCD_ShowChinese(50,66,"播放音乐",RED,LGRAY,16,0);
			LCD_ShowString(114,66,"3",RED,LGRAY,16,0);
			if(Play==1)
			{
				Play=0;
				MUSIC2=0;delay_ms(1000);MUSIC2=1;
			}
		}
	}
}

//按键扫描
void Key_Scan()
{
	if(KEY0==0)//选项步进加
	{
		delay_ms(20);
		if(KEY0==0)
		{
			if(PageIndex==1)//界面一
			{
				if(++Page1OptionIndex>=4) Page1OptionIndex=1;
			}
			if(PageIndex==2)//界面二
			{
				if(Page1OptionIndex==2)//由图片选项进入
				{
					if(++Page2OptionIndex>=3) Page2OptionIndex=1;//图片只有2张
				}
				if(Page1OptionIndex==3)//由音乐选项进入
				{
					if(++Page2OptionIndex>=4) Page2OptionIndex=1;//音乐只有3首
				}
			}
		}
		while(KEY0==0);
	}
	if(KEY1==0)//选项步进减
	{
		delay_ms(20);
		if(KEY1==0)
		{
			if(PageIndex==1)//界面一
			{
				if((Page1OptionIndex--)<=1) Page1OptionIndex=3;
			}
			if(PageIndex==2)//界面二
			{
				if(Page1OptionIndex==2)//由图片选项进入
				{
					if((Page2OptionIndex--)<=1) Page2OptionIndex=2;
				}
				if(Page1OptionIndex==3)//由音乐选项进入
				{
					if((Page2OptionIndex--)<=1) Page2OptionIndex=3;
				}
			}
		}
		while(KEY1==0);
	}
	if(KEY2==0)//确定
	{
		delay_ms(20);
		if(KEY2==0)
		{
			LCD_Fill(0,0,LCD_W,LCD_H,LGRAY);
			if(++PageIndex>=3) PageIndex=3;
			if((PageIndex==3)&&(Page1OptionIndex==3))
			{
				Play=1;
			}
		}
		while(KEY2==0);
	}
	if(KEY3==0)//返回
	{
		delay_ms(20);
		if(KEY3==0)
		{
			LCD_Fill(0,0,LCD_W,LCD_H,LGRAY);
			if((PageIndex--)<=1) PageIndex=1;
		}
		while(KEY3==0);
	}
}

//  界面显示
void DisplayScreen()
{
	if(PageIndex==1)//界面一
	{
		LCD_ShowChinese(64,16,"菜单",BLACK,LGRAY,16,0);
		// 选项1
		if(Page1OptionIndex==1)
		{
			LCD_ShowString(56,40,"1:",RED,YELLOW,16,0);
			LCD_ShowChinese(72,40,"时间",RED,YELLOW,16,0);
		}
		else
		{
			LCD_ShowString(56,40,"1:",RED,LGRAY,16,0);
			LCD_ShowChinese(72,40,"时间",RED,LGRAY,16,0);
		}
		
		// 选项2
		if(Page1OptionIndex==2)
		{
			LCD_ShowString(56,56,"2:",RED,YELLOW,16,0);
			LCD_ShowChinese(72,56,"图片",RED,YELLOW,16,0);
		}
		else
		{
			LCD_ShowString(56,56,"2:",RED,LGRAY,16,0);
			LCD_ShowChinese(72,56,"图片",RED,LGRAY,16,0);
		}
		// 选项3
		if(Page1OptionIndex==3)
		{
			LCD_ShowString(56,72,"3:",RED,YELLOW,16,0);
			LCD_ShowChinese(72,72,"音乐",RED,YELLOW,16,0);
		}
		else
		{
			LCD_ShowString(56,72,"3:",RED,LGRAY,16,0);
			LCD_ShowChinese(72,72,"音乐",RED,LGRAY,16,0);
		}
	}
	if((PageIndex==2)||(PageIndex==3))//界面二和三
	{
		if(Page1OptionIndex==1)//时间显示
		{
			Time_Display();
		}
		if(Page1OptionIndex==2)//图片显示
		{
			PictureDisplay();
		}
		if(Page1OptionIndex==3)//音乐显示
		{
			MusicDisplay();
		}
	}
}
int main(void)
{	
	delay_init();	    //延时函数初始化
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置中断优先级分组为组2:2位抢占优先级,2位响应优先级
	KEY_Init();					//按键引脚初始化
	
	Ds1302_gpio_init();  //端口初始化
	DS1302_Init();
	LCD_Init();//LCD初始化
	LCD_Fill(0,0,LCD_W,LCD_H,LGRAY);
	LCD_ShowChinese(0,16,"欢迎进入屏显菜单系统",RED,LGRAY,16,0);
	delay_ms(5000);
	LCD_Fill(0,0,LCD_W,LCD_H,LGRAY);
	    
	ONE_LINE_VOL(10);
    delay_ms(30);     //一条指令发送完毕之后,需要间隔20ms在发送下一条指令 
	ONE_LINE_PLAY_SONG(1);
	ONE_LINE_PLAY();
	MUSIC1=1;
	MUSIC2=1;
	MUSIC3=1;
	while(1)
	{
		Key_Scan();
		DS1302_ReadTime();
		DisplayScreen();
	}
}