天天看點

基于STM32F103C8T6的OLED菜單界面(IIC控制)基于STM32F103C8T6的簡單版OLED菜單界面

基于STM32F103C8T6的簡單版OLED菜單界面

之前做了個的測試電機轉速的測試闆,還有不知道什麼時候買的OLED屏(還隻有IIC接口),剛好用來做個菜單練練手,顯示效果如下:

基于STM32F103C8T6的OLED菜單界面(IIC控制)基于STM32F103C8T6的簡單版OLED菜單界面

環境:

1.核心闆:STM32F103C8T6最小系統闆以及一些按鍵開關
2.OLED顯示子產品:IIC接口(因為我買的OLED是老)
3.編譯環境:Keil MDK
           

要OLED子產品做個簡單的三級菜單顯示,其實隻要做好界面顯示就行了,這個網上有很多例程,由于我的OLED子產品隻有IIC的腳位,我就簡要說說我怎麼通過配置IIC來實作OLED子產品的三級菜單顯示。

首先要像點燈一樣先把OLED點亮,借鑒了一下網上的例程,做了些更改,大緻如下:

首先看下main函數:

int main (void)
{
	delay_init();
	LED_Init();
	key_init();
	
	I2C_Configuration();
	OLED_Init();

	//Adc_init();
	//TIM1_Encoder_Init(1024-1,0);
	//TIM2_Encoder_Init(1024-1,0);
	TIM3_init(1000-1,72-1);

	OLED_CLS();//清屏
	while(1)
	{
		deal_allkey_press();//處理各種按鍵事件
		Mision_1ms();//1ms掃描任務
		//show_num();//數位管顯示
		show_UI();//OLED顯示
	}
}
           

然後是IIC的配置

void I2C_Configuration(void)
{
	I2C_InitTypeDef  I2C_InitStructure;
	GPIO_InitTypeDef  GPIO_InitStructure; 

	RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1,ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);

	/*STM32F103C8T6晶片的硬體I2C: PB6 -- SCL; PB7 -- SDA */
	GPIO_InitStructure.GPIO_Pin =  GPIO_Pin_6 | GPIO_Pin_7;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;//I2C必須開漏輸出
	GPIO_Init(GPIOB, &GPIO_InitStructure);

	I2C_DeInit(I2C1);//使用I2C1
	I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;
	I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;
	I2C_InitStructure.I2C_OwnAddress1 = 0x30;//主機的I2C位址,随便寫的
	I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;
	I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
	I2C_InitStructure.I2C_ClockSpeed = 400000;//400K

	I2C_Cmd(I2C1, ENABLE);
	I2C_Init(I2C1, &I2C_InitStructure);
}

void I2C_WriteByte(uint8_t addr,uint8_t data)
{
//固件庫
    while(I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY));
	
	I2C_GenerateSTART(I2C1, ENABLE);//開啟I2C1
	while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT));/*EV5,主模式*/

	I2C_Send7bitAddress(I2C1, OLED_ADDRESS, I2C_Direction_Transmitter);//器件位址 -- 預設0x78
	while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));

	I2C_SendData(I2C1, addr);//寄存器位址
	while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED));

	I2C_SendData(I2C1, data);//發送資料
	while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED));
	
	I2C_GenerateSTOP(I2C1, ENABLE);//關閉I2C1總線
}

void WriteCmd(unsigned char I2C_Command)//寫指令
{
	I2C_WriteByte(0x00, I2C_Command);
}

void WriteDat(unsigned char I2C_Data)//寫資料
{
	I2C_WriteByte(0x40, I2C_Data);
}
           

接着根據一些例子改寫的OLED子產品的配置,當然下面還需要一個對應的取模頭檔案codetab.h

#include "oled_iic.h"
#include "codetab.h"
#include "timer.h"
#include "led.h"
#include <stdio.h>


void OLED_Init(void)
{
//	delay_ms(100); //這裡的延時很重要
	
	delay_ms(50); //這裡的延時很重要

	WriteCmd(0xAE); //display off
	WriteCmd(0x20);	//Set Memory Addressing Mode	
	WriteCmd(0x10);	//00,Horizontal Addressing Mode;01,Vertical Addressing Mode;10,Page Addressing Mode (RESET);11,Invalid
	WriteCmd(0xb0);	//Set Page Start Address for Page Addressing Mode,0-7
	WriteCmd(0xc8);	//Set COM Output Scan Direction
	WriteCmd(0x00); //---set low column address
	WriteCmd(0x10); //---set high column address
	WriteCmd(0x40); //--set start line address
	WriteCmd(0x81); //--set contrast control register
	WriteCmd(0xff); //亮度調節 0x00~0xff
	WriteCmd(0xa1); //--set segment re-map 0 to 127
	WriteCmd(0xa6); //--set normal display
	WriteCmd(0xa8); //--set multiplex ratio(1 to 64)
	WriteCmd(0x3F); //
	WriteCmd(0xa4); //0xa4,Output follows RAM content;0xa5,Output ignores RAM content
	WriteCmd(0xd3); //-set display offset
	WriteCmd(0x00); //-not offset
	WriteCmd(0xd5); //--set display clock divide ratio/oscillator frequency
	WriteCmd(0xf0); //--set divide ratio
	WriteCmd(0xd9); //--set pre-charge period
	WriteCmd(0x22); //
	WriteCmd(0xda); //--set com pins hardware configuration
	WriteCmd(0x12);
	WriteCmd(0xdb); //--set vcomh
	WriteCmd(0x20); //0x20,0.77xVcc
	WriteCmd(0x8d); //--set DC-DC enable
	WriteCmd(0x14); //
	WriteCmd(0xaf); //--turn on oled panel

}

void OLED_SetPos(unsigned char x, unsigned char y) //設定起始點坐标
{ 
	WriteCmd(0xb0+y);
	WriteCmd(((x&0xf0)>>4)|0x10);
	WriteCmd((x&0x0f)|0x01);
}

void OLED_Fill(unsigned char fill_Data)//全屏填充
{
	unsigned char m,n;
	for(m=0;m<8;m++)
	{
		WriteCmd(0xb0+m);		//page0-page1
		WriteCmd(0x00);		//low column start address
		WriteCmd(0x10);		//high column start address
		for(n=0;n<128;n++)
		{
			WriteDat(fill_Data);
		}
	}
}


void OLED_CLS(void)//清屏
{
	OLED_Fill(0x00);
}

void OLED_data_up(unsigned char fill_Data)
{
	unsigned char m,n;
	for(m=0;m<2;m++)
	{
		WriteCmd(0xb2+m);		//page0-page1
		WriteCmd(0x00);		//low column start address
		WriteCmd(0x10);		//high column start address
		for(n=0;n<128;n++)
		{
			WriteDat(fill_Data);
		}
	}
}

void up_data(void)//重新整理顯示
{
	OLED_data_up(0x00);
}

void OLED_time_up(unsigned char fill_Data)
{
	unsigned char m,n;
	for(m=0;m<2;m++)
	{
		WriteCmd(0xb4+m);		//page0-page1
		WriteCmd(0x00);		//low column start address
		WriteCmd(0x10);		//high column start address
		for(n=0;n<128;n++)
			{
				WriteDat(fill_Data);
			}
	}
}

void up_time(void)//重新整理顯示
{
	OLED_time_up(0x00);
}


//--------------------------------------------------------------
// Prototype      : void OLED_ON(void)
// Calls          : 
// Parameters     : none
// Description    : 将OLED從休眠中喚醒
//--------------------------------------------------------------
void OLED_ON(void)
{
	WriteCmd(0X8D);  //設定電荷泵
	WriteCmd(0X14);  //開啟電荷泵
	WriteCmd(0XAF);  //OLED喚醒
}

//--------------------------------------------------------------
// Prototype      : void OLED_OFF(void)
// Calls          : 
// Parameters     : none
// Description    : 讓OLED休眠 -- 休眠模式下,OLED功耗不到10uA
//--------------------------------------------------------------
void OLED_OFF(void)
{
	WriteCmd(0X8D);  //設定電荷泵
	WriteCmd(0X10);  //關閉電荷泵
	WriteCmd(0XAE);  //OLED休眠
}

//--------------------------------------------------------------
// Prototype      : void OLED_ShowChar(unsigned char x, unsigned char y, unsigned char ch[], unsigned char TextSize)
// Calls          : 
// Parameters     : x,y -- 起始點坐标(x:0~127, y:0~7); ch[] -- 要顯示的字元串; TextSize -- 字元大小(1:6*8 ; 2:8*16)
// Description    : 顯示codetab.h中的ASCII字元,有6*8和8*16可選擇
//--------------------------------------------------------------
void OLED_ShowStr(unsigned char x, unsigned char y, unsigned char ch[], unsigned char TextSize)
{
	unsigned char c = 0,i = 0,j = 0;
	switch(TextSize)
	{
		case 1:
		{
			while(ch[j] != '\0')
			{
				c = ch[j] - 32;
				if(x > 126)
				{
					x = 0;
					y++;
				}
				OLED_SetPos(x,y);
				for(i=0;i<6;i++)
					WriteDat(F6x8[c][i]);
				x += 6;
				j++;
			}
		}break;
		case 2:
		{
			while(ch[j] != '\0')
			{
				c = ch[j] - 32;
				if(x > 120)
				{
					x = 0;
					y++;
				}
				OLED_SetPos(x,y);
				for(i=0;i<8;i++)
					WriteDat(F8X16[c*16+i]);
				OLED_SetPos(x,y+1);
				for(i=0;i<8;i++)
					WriteDat(F8X16[c*16+i+8]);
				x += 8;
				j++;
			}
		}break;
	}
}

//--------------------------------------------------------------
// Prototype      : void OLED_ShowCN(unsigned char x, unsigned char y, unsigned char N)
// Calls          : 
// Parameters     : x,y -- 起始點坐标(x:0~127, y:0~7); N:漢字在codetab.h中的索引
// Description    : 顯示codetab.h中的漢字,16*16點陣
//--------------------------------------------------------------
void OLED_ShowCN(unsigned char x, unsigned char y, unsigned char N)
{
	unsigned char wm=0;
	unsigned int  adder=32*N;
	OLED_SetPos(x , y);
	for(wm = 0;wm < 16;wm++)
	{
		WriteDat(F16x16[adder]);
		adder += 1;
	}
	OLED_SetPos(x,y + 1);
	for(wm = 0;wm < 16;wm++)
	{
		WriteDat(F16x16[adder]);
		adder += 1;
	}
}

//--------------------------------------------------------------
// Prototype      : void OLED_DrawBMP(unsigned char x0,unsigned char y0,unsigned char x1,unsigned char y1,unsigned char BMP[]);
// Calls          : 
// Parameters     : x0,y0 -- 起始點坐标(x0:0~127, y0:0~7); x1,y1 -- 起點對角線(結束點)的坐标(x1:1~128,y1:1~8)
// Description    : 顯示BMP位圖
//--------------------------------------------------------------
void OLED_DrawBMP(unsigned char x0,unsigned char y0,unsigned char x1,unsigned char y1,unsigned char BMP[])
{
	unsigned int j=0;
	unsigned char x,y;

  if(y1%8==0)
		y = y1/8;
  else
		y = y1/8 + 1;
	for(y=y0;y<y1;y++)
	{
		OLED_SetPos(x0,y);
    for(x=x0;x<x1;x++)
		{
			WriteDat(BMP[j++]);
		}
	}
}

//顯示界面
void show_UI(void)
{
	
	//滾動顯示所有界面
//	show_first_interface();
//	delay_ms(500);
//	show_menu();
//	delay_ms(500);
//	show_chosen_current();
//	delay_ms(500);
//	show_current_test();
//	delay_ms(500);
//	show_chosen_rotation();
//	delay_ms(500);
//	show_rotation_test();
//	delay_ms(500);
//	show_chosen_all();
//	delay_ms(500);
//	show_all_test();
//	delay_ms(500);

	if(time13 >= 500)
	{
		time13 = 0;
		INTERFACE_Statment();//狀态機顯示菜單
	}
	
}


void show_chosen_current(void)
{
	unsigned char table[20]  = ">>";
	unsigned char table1[10]  = "  ";

	OLED_ShowStr(0, 0, table, 2);    //>>
	OLED_ShowStr(0, 2, table1, 2);    //
	OLED_ShowStr(0, 4, table1, 2);    //
}


void show_chosen_rotation(void)
{

	unsigned char table[20]  = ">>";
	unsigned char table1[10]  = "  ";
	
	OLED_ShowStr(0, 0, table1, 2);    //>>
	OLED_ShowStr(0, 2, table, 2);    //>>
	OLED_ShowStr(0, 4, table1, 2);    //>>
	
}


void show_chosen_all(void)
{

	unsigned char table[20]  = ">>";
	unsigned char table1[10]  = "  ";

	
	OLED_ShowStr(0, 0, table1, 2);    //>>
	OLED_ShowStr(0, 2, table1, 2);    //>>
	OLED_ShowStr(0, 4, table, 2);    //>>
		
}


void show_menu(void)
{

	unsigned char table0[20] = "1.";
	unsigned char table1[20] = "2.";
	unsigned char table2[20] = "3.";
		
	OLED_ShowStr(16, 0, table0, 2);  //1.
	OLED_ShowCN(32, 0, 5);			//電
	OLED_ShowCN(48, 0, 7);			//流
	OLED_ShowCN(64, 0, 9);			//檢
	OLED_ShowCN(80, 0, 10);			//測
	
	
	OLED_ShowStr(16, 2, table1, 2);  //2.
	OLED_ShowCN(32, 2, 3);			//轉
	OLED_ShowCN(48, 2, 4);			//速
	OLED_ShowCN(64, 2, 9);			//檢
	OLED_ShowCN(80, 2, 10);			//測
	
	
	OLED_ShowStr(16, 4, table2, 2);  //3.
	OLED_ShowCN(32, 4, 15);			//一
	OLED_ShowCN(48, 4, 16);			//鍵
	OLED_ShowCN(64, 4, 9);			//檢
	OLED_ShowCN(80, 4, 10);			//測
	
	
	OLED_ShowCN(0, 6, 11);			//确
	OLED_ShowCN(16, 6, 12);			//認
	
	OLED_ShowCN(96, 6, 13);			//返
	OLED_ShowCN(112, 6, 14);		//回
}


void show_current_test(void)
{

	//顯示經取模軟體設定好的漢字
	unsigned char table0[20] = ":xx  ";
	unsigned char table1[20] = ":xx  ";
	unsigned char table5[20] = ":       ";
	
	if((IDC_mA_left >= 999)||(IDC_mA_right >= 999))
	{
		IDC_mA_left = 0;
		IDC_mA_right = 0;
	}
	
	sprintf((char *)table0,":%d mA", (int)read_IDC_mA_left());
	sprintf((char *)table1,":%d mA", (int)read_IDC_mA_right());
	

	OLED_ShowCN(32, 0, 5);			//電
	OLED_ShowCN(48, 0, 7);			//流
	OLED_ShowCN(64, 0, 9);			//檢
	OLED_ShowCN(80, 0, 10);			//測
	
	
	OLED_ShowCN(0, 2, 0);		     //左
	OLED_ShowCN(16, 2, 2);			 //側
	OLED_ShowCN(32, 2, 5);		     //電
	OLED_ShowCN(48, 2, 7);			 //流
	
	
	OLED_ShowCN(0, 4, 1);		     //右
	OLED_ShowCN(16, 4, 2);			 //側
	OLED_ShowCN(32, 4, 5);		     //電
	OLED_ShowCN(48, 4, 7);			 //流
	
	
	OLED_ShowCN(0, 6, 9);			//檢
	OLED_ShowCN(16, 6, 10);			//測
	
	
	OLED_ShowCN(96, 6, 13);			//返
	OLED_ShowCN(112, 6, 14);		//回
	
	if(time >= 500)
	{
		time = 0;
		//清資料
		OLED_ShowStr(64, 2, table5, 2); 
		OLED_ShowStr(64, 4, table5, 2);
		OLED_ShowStr(64, 2, table0, 2);  //顯示對應的數值
		OLED_ShowStr(64, 4, table1, 2);  //顯示對應的數值
	}
}

void show_rotation_test(void)
{
	//顯示經取模軟體設定好的漢字
	unsigned char table0[20] = ":xx  ";
	unsigned char table1[20] = ":xx  ";
	unsigned char table5[20] = ":       ";
	
	if((rotation_left_value >= 999)||(rotation_right_value >= 999))
	{
		rotation_left_value = 0;
		rotation_right_value = 0;
	}
	
	sprintf((char *)table0,":%d rpm", (int)rotation_left_value);
	sprintf((char *)table1,":%d rpm", (int)rotation_right_value);
	
	
	OLED_ShowCN(32, 0, 3);			//轉
	OLED_ShowCN(48, 0, 4);			//速
	OLED_ShowCN(64, 0, 9);			//檢
	OLED_ShowCN(80, 0, 10);			//測
	
	
	OLED_ShowCN(0, 2, 0);		     //左
	OLED_ShowCN(16, 2, 2);			 //側
	OLED_ShowCN(32, 2, 3);		     //轉
	OLED_ShowCN(48, 2, 4);			 //速

	
	OLED_ShowCN(0, 4, 1);		     //右
	OLED_ShowCN(16, 4, 2);			 //側
	OLED_ShowCN(32, 4, 3);		     //轉
	OLED_ShowCN(48, 4, 4);			 //速
	
	
	OLED_ShowCN(0, 6, 9);			//檢
	OLED_ShowCN(16, 6, 10);			//測
	
	
	OLED_ShowCN(96, 6, 13);			//返
	OLED_ShowCN(112, 6, 14);		//回
	
	if(time >= 500)
	{
		time = 0;
		//清資料
		OLED_ShowStr(64, 2, table5, 2); 
		OLED_ShowStr(64, 4, table5, 2);
		
		OLED_ShowStr(64, 2, table0, 2);  //顯示對應的數值
		OLED_ShowStr(64, 4, table1, 2);  //顯示對應的數值
	}
}

void show_all_test(void)
{
	int i;

	//顯示經取模軟體設定好的漢字
//	unsigned char table[20]  = "DSpower";
	unsigned char table[20]  = ":xx  ";
	unsigned char table0[20] = ":xx  ";
	unsigned char table1[20] = ":xx  ";
	unsigned char table2[20] = ":xx  ";
	unsigned char table3[20] = ":           ";//左輪轉向
	unsigned char table4[20] = ":           ";//右輪轉向
	unsigned char table5[20] = ":           ";
	unsigned char table6[20] = ":       ";
	
	unsigned char ccw [10] = "ccw";
	unsigned char cw  [10] = " cw";
	unsigned char stop[10] = "Q_Q";
	
	if(Rotation_speed_difference >= 0)
	{
		Rotation_speed_difference = Rotation_speed_difference;
	}
	else if(Rotation_speed_difference < 0)
	{
		Rotation_speed_difference = -Rotation_speed_difference;
	}
	
	 sprintf((char *)table2,":%d rpm", rotation_left_value);
	 sprintf((char *)table0,":%d rpm", rotation_right_value);
	 sprintf((char *)table, ":%d rpm", (int)Rotation_speed_difference);
	 sprintf((char *)table1,":%d mA", (int)read_IDC_mA());
	 
	
		
	
		
		OLED_ShowCN(0, 0, 3);//轉
		OLED_ShowCN(16, 0, 6);//差
//		OLED_ShowCN(97, 0, 3);//轉
//		OLED_ShowCN(113, 0, 8);//向
				
		OLED_ShowCN(0, 2, 0);		     //左
		OLED_ShowCN(16, 2, 2);			 //側
//		OLED_ShowCN(32, 4, 3);		     //轉
//		OLED_ShowCN(48, 4, 4);			 //速

		OLED_ShowCN(0, 4, 1);		     //右
		OLED_ShowCN(16, 4, 2);			 //側
//		OLED_ShowCN(32, 2, 3);		     //轉
//		OLED_ShowCN(48, 2, 4);			 //速
		
		OLED_ShowCN(0, 6, 5);           //電
		OLED_ShowCN(16, 6, 7);			 //流
		
		OLED_ShowCN(96, 6, 13);			//返
		OLED_ShowCN(112, 6, 14);		//回
		
		
	if(time >= 500)
	{
		time = 0;

		//清資料
		OLED_ShowStr(32, 0, table5, 2);
		OLED_ShowStr(32, 2, table5, 2); 
		OLED_ShowStr(32, 4, table5, 2);
		OLED_ShowStr(32, 6, table6, 2);	
		
		OLED_ShowStr(32,0,table,2);//
		OLED_ShowStr(32, 2, table2, 2);//
		OLED_ShowStr(32, 4, table0, 2);// 
		OLED_ShowStr(32, 6, table1, 2);//
		OLED_ShowStr(104, 2, table3, 2);//cw  0  ccw   左輪z
		OLED_ShowStr(104, 4, table4, 2);//  cw  0  ccw    右輪
	}
}

void show_first_interface(void)
{
//	show_bmp(1);
	show_bmp(2);
}

void show_bmp(u8 a)
{
	switch(a)
	{
		case 1:
				OLED_DrawBMP(0,0,127,7,BMP1);
			break;
			
		case 2:
				OLED_DrawBMP(0,0,127,7,BMP2);
			break;
			
		case 3:
				OLED_DrawBMP(0,0,127,7,BMP3);
			break;
			
		case 4:
				OLED_DrawBMP(0,0,127,7,BMP4);
			break;
			
		default:
			break;
			
	}
	
}

           

接下來是自己寫的的按鍵驅動程式,包括單擊輕按兩下和長按,如果需要可以在評論區回複;由于這裡隻用到了單擊,那我也貼出部分代碼吧:

//#define KEY7 PBin(9)這個放在頭檔案裡

u16 key7up_flag = 1; u16 key7down_flag = 0;//按鍵彈起标志   按鍵按下标志 
u16 key7up_cnt = 0; u16 key7down_cnt = 0;//按鍵彈起後計數值   按鍵按下後計數值
u16 key7_short_flag = 0;//短按标志
u16 key7_idle_flag = 0;//非空閑
u16 key7up_cnt2 = 0;

void key7_scan(void)//key7作為 ADD
{
	//當按鍵持續按下
		 if(0 == ( GPIOB->IDR & (1<<9)))
		{
			  key7down_cnt++;
			 if(key7down_cnt >= 10)//去抖時間
			{
				key7down_flag = 1;
				key7up_flag = 0;//擡起清零
				key7up_cnt = 0;
				
				if(key7_idle_flag)
				{
					key7_idle_flag = 0;
				}
			}
		}
		 //如果按鍵松開
		else
		{
			if(key7_idle_flag)
				return;
			key7up_cnt ++;
			
			//負防抖  ***************************************
			if(key7up_cnt >= 50)
			{
				key7up_flag = 1;
				key7down_flag = 0;
				key7down_cnt = 0;
			}
			
			//按下時間大于100ms,判斷為單擊
			if(key7down_cnt >= 50) 
			{
				key7_short_flag = 1;//****************  短按(單擊)
				key7down_flag = 0;
				key7down_cnt = 0;
			}
			
			else  //按下時間小于50ms,忽略
			{
				key7up_cnt = 0;//彈起計數清零
				key7up_flag = 0;
				key7down_cnt = 0;//清零按下抖動的次數
				key7_short_flag = 0;
				key7down_flag = 0;//按下标志清零
				key7_idle_flag = 1;//如果擡起持續1s沒動作,就判斷為空閑狀态
			}		
		}
	if(key7_short_flag)
	{
		key7_short_flag = 0;
		key7_press = 1;
	}
}

void deal_key7_press(void)
{
	if(key7_press)
		{
			key7_press = 0;
			Menu_Key_Down();
			
		}
}

           

最後菜單的顯示用的是狀态機,不過剛剛學的狀态機可能用的還不太好,以下是menu.c

#include "menu.h"


//用狀态機做菜單顯示
INTERFACE_OPTIONS  interfece;


void INTERFACE_Statment(void)
{

	switch(interfece)
	{
		case MAIN_INTERFACE:
			show_first_interface();
			break;
		
		case MENU_INTERFACE:
			show_menu(); 
			break;
		
		case CURRENT_CHOSEN:
			show_chosen_current();
			show_menu();
			break;
		
		case ROTATION_CHOSEN:
			show_chosen_rotation(); 
			show_menu();
			break;
		
		case ALL_TEST_CHOSEN:
			show_chosen_all();
			show_menu();
			break;
		
		case CURRENT_TEST_INTERFACE:
			show_current_test();
			break;
		
		case ROTATION_TEST_INTERFACE:
			show_rotation_test();
			break;
		
		case ALL_TEST_INTERFACE:
			show_all_test();
			break;
		
		default:
			break;
	}
}



void Menu_Key_Enter(void)
{
	OLED_CLS();//清屏
	if(interfece == MAIN_INTERFACE)
	{
		interfece = MENU_INTERFACE;
	}
	else if(interfece == MENU_INTERFACE)
	{
		interfece = CURRENT_CHOSEN;
	}
	else if(interfece == CURRENT_CHOSEN)
	{
		interfece = CURRENT_TEST_INTERFACE;
	}
	else if(interfece == ROTATION_CHOSEN)
	{
		interfece = ROTATION_TEST_INTERFACE;
	}
	else if(interfece == ALL_TEST_CHOSEN)
	{
		interfece = ALL_TEST_INTERFACE;
	}
}

void Menu_Key_Return(void)
{
	OLED_CLS();//清屏
	if(interfece == MENU_INTERFACE)
	{
		interfece = MAIN_INTERFACE;
	}
	if(interfece == CURRENT_CHOSEN)	
	{
		interfece = MENU_INTERFACE;
	}
	if(interfece == ROTATION_CHOSEN)	
	{
		interfece = MENU_INTERFACE;
	}
	if(interfece == ALL_TEST_CHOSEN)	
	{
		interfece = MENU_INTERFACE;
	}
	if(interfece == CURRENT_TEST_INTERFACE)	
	{
		interfece = CURRENT_CHOSEN;
	}
	if(interfece == ROTATION_TEST_INTERFACE)	
	{
		interfece = ROTATION_CHOSEN;
	}
	if(interfece == ALL_TEST_INTERFACE)	
	{
		interfece = ALL_TEST_CHOSEN;
	}
}

void Menu_Key_Up(void)
{
//	OLED_CLS();//清屏
	if(interfece == CURRENT_CHOSEN)
	{
		interfece = ALL_TEST_CHOSEN;
	}
	else if(interfece == ALL_TEST_CHOSEN)
	{
		interfece = ROTATION_CHOSEN;
	}
	else if(interfece == ROTATION_CHOSEN)
	{
		interfece = CURRENT_CHOSEN;
	}
}

void Menu_Key_Down(void)
{
//	OLED_CLS();//清屏
	if(interfece == CURRENT_CHOSEN)
	{
		interfece = ROTATION_CHOSEN;
	}
	else if(interfece == ROTATION_CHOSEN)
	{
		interfece = ALL_TEST_CHOSEN;
	}
	else if(interfece == ALL_TEST_CHOSEN)
	{
		interfece = CURRENT_CHOSEN;
	}
}
           

以上就是本人用OLED子產品做的三級菜單顯示,首先是OLED子產品的顯示了(這一步做好了才有菜單,先做一個界面,再自按自己的意願自由改變界面顯示,然後再考慮布局、美觀等),菜單顯示部分主要是用到狀态機,另外就是按鍵驅動部分(這個網上也有很多例程),這期間或許了解還不到位或者還沒見識到更進階的處理,需要大家多多指出和互相交流,本文不足之處希望大家多多指出,非常感謝。