项目介绍
通过MSP430核心板的ADC监测IO板模拟输出管脚的变化,判断哪一个按键或编码器的旋转发生了变化,进而控制1.44寸LCD屏幕的菜单显示,实现了主菜单和二级菜单。
设计思路
1.按键检测
IO扩展板上的2个按键和旋转编码器的3个输入端口是通过R-2R电阻网络的方式连接在一起,生成一个模拟电压量。按下任何一个按键都会改变这个模拟电压量的值。这时,输出的电压就会发生变化,单片机不断采集ADC数据,通过读取电压值判断出哪一个按键被按下。
2.多级菜单
多级菜单的实现,大体分为两种设计思路:通过双向链表实现、通过数组查表实现。
总体思路都是把菜单的各个界面联系起来,可以从上级菜单跳到下级菜单,也可从下级菜单返回上级菜单。
数组查表的方式比较简单,易于理解,本篇就来使用数组查表发在MSP430上实现多级菜单的显示。
3.屏幕显示
通过SPI总线进行访问LCD屏幕,其为128*128分辨率的1.44寸彩色屏幕。
硬件介绍
MSP-EXP430F5529LP是一款针对MSP430F5529 USB微控 制器的廉价而简单的开发套件。它为MSP430 MCU提供了一种简单的方法,具有用于编程和调试的板载仿真,以及用于简单用户界面的按钮和LED。
- 支持 USB 2.0 的 MSP430F5529 16 位微控制器
- 高达 25 MHz
- 128KB 闪存和 8KB 内存
- 12 位 SAR 模数转换器
- 提供各种 USB 设备类示例和嵌入式软件库(CDC、HID、MSC)
- eZ-FET lite:带应用程序 UART 的开源板载调试器
- 通过使用板载 USB 集线器,为仿真器和目标提供 USB 连接
- USB 作为电源:5V 和 3.3V 通过高效 DC/DC 转换器
- 40 针 LaunchPad 标准,利用 BoosterPack 生态系统
扩展板包含如下功能:
- 按键、旋转编码器输入 - 以模拟信号的方式
- 双电位计控制输入 - 以数字信号的方式
- RGB三色LED显示
- 1.44寸128*128 LCD,SPI总线访问
- MMA7660三轴姿态传感器
- 电阻加热
- 温度传感器
- 与MSP430 Launch Pad开发板的接口
主要代码
识别编码器与按键动作
void adc_key_change(uint16_t adc)
{
static uint8_t adc_key = 0;
static uint8_t his_rev_key = 0;
if(adc >= 3900)
{
if(adc_key == 10) key_flag = 1;
else if(adc_key == 11) key_flag = 2;
adc_key = 0;
his_rev_key = 0;
}
else if(adc < 3000 && adc >= 2890) adc_key = 10;//2940
else if(adc < 2000 && adc >= 1800) adc_key = 11;//1921
else if(adc < 3900 && adc >= 3790) adc_key = 1; //3838
//else if(adc < 3620 && adc >= 3530) ; //3581
else if(adc < 3760 && adc >= 3660) adc_key = 2; //3709
if(adc_key != his_rev_key)
{
if(his_rev_key == 1 && adc_key == 2)
revolve_flag = 1;
else if(his_rev_key == 2 && adc_key == 1)
revolve_flag = 2;
his_rev_key = adc_key;
}
}
菜单定义
typedef struct
{
uint8_t current;
uint8_t up;
uint8_t down;
uint8_t enter;
uint8_t back;
void (*current_operation)();
} key_table;
key_table table[30]=
{
{0,2,1,3,0,(*fun0)},
{1,0,2,6,1,(*fun1)},
{2,1,0,8,2,(*fun2)},
{3,5,4,3,0,(*fun3)},
{4,3,5,4,0,(*fun4)},
{5,4,3,5,0,(*fun5)},
{6,7,7,6,1,(*fun6)},
{7,6,6,7,1,(*fun7)},
{8,9,9,8,2,(*fun8)},
{9,8,8,9,2,(*fun9)},
};
void fun0()
{
LCD_ShowString(0,0, "1.LED ",BLACK,WHITE,32,0);
LCD_ShowString(0,32,"2.KEY ",WHITE,BLACK,32,0);
LCD_ShowString(0,64,"3.LCD ",WHITE,BLACK,32,0);
LCD_ShowString(0,96," ",WHITE,BLACK,32,0);
}
void fun1()
{
LCD_ShowString(0,0, "1.LED ",WHITE,BLACK,32,0);
LCD_ShowString(0,32,"2.KEY ",BLACK,WHITE,32,0);
LCD_ShowString(0,64,"3.LCD ",WHITE,BLACK,32,0);
LCD_ShowString(0,96," ",WHITE,BLACK,32,0);
}
void fun2()
{
LCD_ShowString(0,0, "1.LED ",WHITE,BLACK,32,0);
LCD_ShowString(0,32,"2.KEY ",WHITE,BLACK,32,0);
LCD_ShowString(0,64,"3.LCD ",BLACK,WHITE,32,0);
LCD_ShowString(0,96," ",WHITE,BLACK,32,0);
}
void fun3()
{
LCD_ShowString(0,0, "1.LED1 ",BLACK,WHITE,32,0);
LCD_ShowString(0,32,"2.LED2 ",WHITE,BLACK,32,0);
LCD_ShowString(0,64,"3.LED3 ",WHITE,BLACK,32,0);
LCD_ShowString(0,96," ",WHITE,BLACK,32,0);
}
void fun4()
{
LCD_ShowString(0,0, "1.LED1 ",WHITE,BLACK,32,0);
LCD_ShowString(0,32,"2.LED2 ",BLACK,WHITE,32,0);
LCD_ShowString(0,64,"3.LED3 ",WHITE,BLACK,32,0);
LCD_ShowString(0,96," ",WHITE,BLACK,32,0);
}
void fun5()
{
LCD_ShowString(0,0, "1.LED1 ",WHITE,BLACK,32,0);
LCD_ShowString(0,32,"2.LED2 ",WHITE,BLACK,32,0);
LCD_ShowString(0,64,"3.LED3 ",BLACK,WHITE,32,0);
LCD_ShowString(0,96," ",WHITE,BLACK,32,0);
}
void fun6()
{
LCD_ShowString(0,0, "1.KEY1 ",BLACK,WHITE,32,0);
LCD_ShowString(0,32,"2.KEY2 ",WHITE,BLACK,32,0);
LCD_ShowString(0,64," ",WHITE,BLACK,32,0);
LCD_ShowString(0,96," ",WHITE,BLACK,32,0);
}
void fun7()
{
LCD_ShowString(0,0, "1.KEY1 ",WHITE,BLACK,32,0);
LCD_ShowString(0,32,"2.KEY2 ",BLACK,WHITE,32,0);
LCD_ShowString(0,64," ",WHITE,BLACK,32,0);
LCD_ShowString(0,96," ",WHITE,BLACK,32,0);
}
void fun8()
{
LCD_ShowString(0,0, "1.LCD1 ",BLACK,WHITE,32,0);
LCD_ShowString(0,32,"2.LCD2 ",WHITE,BLACK,32,0);
LCD_ShowString(0,64," ",WHITE,BLACK,32,0);
LCD_ShowString(0,96," ",WHITE,BLACK,32,0);
}
void fun9()
{
LCD_ShowString(0,0, "1.LCD1 ",WHITE,BLACK,32,0);
LCD_ShowString(0,32,"2.LCD2 ",BLACK,WHITE,32,0);
LCD_ShowString(0,64," ",WHITE,BLACK,32,0);
LCD_ShowString(0,96," ",WHITE,BLACK,32,0);
}
菜单控制
for(;;)
{
adc_key_change(ADC12MEM0);
if(revolve_flag > 0 || key_flag > 0)
{
if(revolve_flag == 1) func_index=table[func_index].down;
else if(revolve_flag == 2) func_index=table[func_index].up;
else if(key_flag == 1) func_index=table[func_index].enter;
else if(key_flag == 2) func_index=table[func_index].back;
table[func_index].current_operation();
revolve_flag = 0;
key_flag = 0;
}
}
实现的功能及图片展示
主菜单
二级菜单 一
二级菜单 二
二级菜单 三
遇到的主要难题及解决方法
问题:很难抓取到编码器的ADC数值变化,识别不出来旋转方向。
方法:对芯片进行倍频到25MHz,减少显示部分,让空闲时间都在采集ADC数据。但是在编码器旋转速度过快的情况下还是没有办法处理,以后再研究这个问题。
问题:刷新效果差,闪烁严重。
方法:不清屏,显示时多加几个空格,覆盖刷新。
未来的计划或建议
希望加热电路能够有硬件上的关闭开关,或者是把加热电路做成外部的单独模块,避免因为不小心开启加热电路后烫伤手。