项目的实现和关键(末尾有项目文件)
项目需求:
使用msp430,lunchpad和io拓展版上的1.44寸屏幕和一个旋转编码器以及两个按键实现一个简单的二级菜单。旋转编码器和按键作为上翻、下翻和确定键。
程序流程图:
完成的功能:
1.按键检测
本次项目的重点在于检测2个按键和1个旋转编码器的状态,通过读取adc值,判断按键是否被按下,以及旋转编码器的旋转和按下。我们将第一个按键作为上翻键,第二个按键作为下翻键,旋转编码器按下作为确定键,旋转编码器的旋转作为一些操作键,比如调节字体的颜色和大小中使用。
经过实验:
- 没有按键按下时,电压值在3.13V
- 当按键1按下时,电压值在2.35V
- 当按键2按下时,电压值在1.54V
- 旋转编码器按下,电压在2.75V
- 旋转编码器顺时针旋转,电压在3.06V
- 旋转编码器逆时针旋转,电压在2.95V
在代码中,先读取adc,再判断adc值符不符合上述的电压值,由于adc有一定的偏差,在判断时需要加上一定的误差范围。
float fabs(float m)
{
if(m>=0) return m;
else return -m;
}
uint8_t key_scan(KEY_FIFO* fifo)
{
float volat = Read_AD()*3.3/4096;
if(fabs(volat-2.35)<=0.05) //按键1按下
{
key_fifo_push(fifo,KEY1DOWN);
return KEY1DOWN;
}
else if(fabs(volat-1.54)<=0.05) //按键2按下
{
key_fifo_push(fifo,KEY2DOWN);
return KEY2DOWN;
}
else if(fabs(volat-2.75)<=0.05) //旋转编码器按下
{
key_fifo_push(fifo,ENCODERDWON);
return ENCODERDWON;
}
else if(fabs(volat-3.06)<=0.02)
{
key_fifo_push(fifo,ENCODERROTATING);//旋转编码器顺时针旋转
return ENCODERROTATING;
}
else if(fabs(volat-2.95)<=0.02)
{
key_fifo_push(fifo,ENCODERREVERSE);//旋转编码器逆时针旋转
return ENCODERREVERSE;
}
else return 0;
}
在这里,同时使用了一个循环队列,但是效果并不是很好。
2.菜单实现
菜单的实现使用了数组查表法,主要是将每个菜单进行编号,使用结构体关联上下和确认后的菜单,并将菜单放入菜单数组中,将菜单编号和数组下标对应,如此就能实现菜单的选择,上翻和下翻。
typedef struct menu{
uint8_t current;
uint8_t down;
uint8_t up;
uint8_t next;
void (*operation)();
}menu_t;
比如当我们当前的下标为1,执行fun1,显示主菜单指针指向了Image,当我们按下下时,下标跳转为2,执行fun2对应函数。
每个菜单结构体中,还有一个执行函数,用于执行对应菜单的功能。
menu_t menu_list[22] =
{
//第0层
{0,1,1,1,(*fun0)},
//第1层
{1,2,4,5,(*fun1)},//image
{2,3,1,8,(*fun2)},//font_size
{3,4,2,11,(*fun3)},//game
{4,1,3,0,(*fun4)},//back
//第2层
//图片
{5,6,7,14,(*fun5)},//1
{6,7,5,15,(*fun6)},//2
{7,5,6,1,(*fun7)},//back
//字体
{8,9,10,16,(*fun8)},//size
{9,10,8,17,(*fun9)},//color
{10,8,9,2,(*fun10)},//back
//游戏
{11,12,13,20,(*fun11)},//snake
{12,13,11,21,(*fun12)},//box
{13,11,12,3,(*fun13)},//back
//last
{14,14,14,5,(*fun14)},//image1
{15,15,15,6,(*fun15)},//image2
{16,16,16,8,(*fun16)},//size
{17,18,19,9,(*fun17)},//color_r
{18,19,17,9,(*fun18)},//color_g
{19,17,18,9,(*fun19)},//color_b
{20,20,20,11,(*fun20)},//snake
{21,21,21,12,(*fun21)}//box
};
在主函数中,首先检测按键状态,如果有按键按下,就改变当前的菜单下标。
void main()
{
WDT_A_hold(WDT_A_BASE);
GPIO_setAsOutputPin(GPIO_PORT_P1,GPIO_PIN4);
GPIO_setOutputLowOnPin(GPIO_PORT_P1,GPIO_PIN4);
SystemClock_Init();
spi_init();
Lcd_Init();
Lcd_Clear(BLACK);
ADC_Init();
__bis_SR_register(GIE);
void (*operation)()=menu_list[menu_index].operation;
KEY_FIFO* KEY_BUF = NULL;
KEY_BUF = key_fifo_init(fifosize);
fifodatatype key_down = 0;
operation();
while(1)
{
key_scan(KEY_BUF);
key_down = key_fifo_pop(KEY_BUF);
while(key_down==KEY_BUF->data[KEY_BUF->tail]&&(key_down==ENCODERROTATING||key_down==ENCODERREVERSE))
{
key_down = key_fifo_pop(KEY_BUF);
}
if(key_down)
{
switch (key_down)
{
case KEY1DOWN:
menu_index = menu_list[menu_index].up;
if(operation == menu_list[21].operation) dinosaur_jump_flag = 1;
break;
case KEY2DOWN:
menu_index = menu_list[menu_index].down;
break;
case ENCODERDWON:
menu_index = menu_list[menu_index].next;
turn_flag = 0;
break;
case ENCODERROTATING:
incerment_flag = 1;
break;
case ENCODERREVERSE:
decerment_flag = 1;
break;
default:
break;
}
if(turn_flag == 0)
{
Lcd_Clear(BLACK);
turn_flag = 1;
}
operation = menu_list[menu_index].operation;
(*operation)();
}
if(operation == menu_list[21].operation)(*operation)();
else delay_ms(100);
}
}
- 菜单结构
3.主要功能展示:
(1).图片显示,将图片数据存储在了栈区,能存储的数据比较有限。
2.字体大小和颜色调整
使用旋转编码器的旋转可以调整字体的大小,颜色。
3.谷歌小恐龙
按上键可以实现跳跃,但是当前没有加入游戏分数,结束判断等。
4.问题
这个项目的问题主要在于旋转编码器旋转的检测上,当金属触点卡在了中间是,会不断检测到旋转编码器的旋转,在旋转时,由于会有两次触点接触,会先后先后检测到两次不同方向的旋转,为了解决这个问题,应该要判断两次adc值,结合两次的adc值来判断旋转编码器的旋转状态。
当前的菜单不支持增加菜单选项。
- 附件连接链接:
https://pan.baidu.com/s/1DYqOYtpBAvTm0-sx-8mxfA?pwd=6666
提取码:6666