项目需求
通过IO扩展板上的按键和旋转编码器控制并实现菜单功能。IO扩展板上的2个按键和旋转编码器的3个输入端口是通过R-2R电阻网络的方式连接在一起,生成一个模拟电压量。按下任何一个按键都会改变这个模拟电压量的值。IO扩展板上的LCD屏幕为128*128分辨率的1.44寸彩色屏幕,通过SPI总线进行访问要求:本任务需要通过MSP430核心板的ADC监测IO板模拟输出管脚的变化,判断哪一个按键或编码器的旋转发生了变化,进而控制1.44寸LCD屏幕的菜单显示,要求实现主菜单和至少二级菜单。
元器件及环境
MSP-EXP430F5529LP开发板
硬禾学堂提供的扩展版:按键、旋转编码器输入(以模拟信号形式输入)
1.44寸128*128 LCD(SPI总线访问)
(扩展板其余元器件在该项目完成过程中未涉及)
设计思路
完成这个项目需要解决两个最基本的问题:1,点亮LCD屏并实现对其的控制;2,调用和调试msp430f5529的ADC模块从而实现对于按钮输入的模拟信号的识别和处理。第一部分的完成我参考了中景园官方给出的1.44LCD屏相关参考资料,其中包括屏幕的驱动文件及例程,图像取模的辅助软件和相关教程等。我对官方给出的屏幕驱动进行修改使得它可以适用于这块扩展板的引脚分布,并利用官方例程中给出的draw函数实现了对于屏幕显示内容的控制。另外,中景园给出的一些绘图的头文件还有图像取模的方法也给我的界面设计提供了很大的帮助。第二部分是adc模块的使用。我需要通过MSP430F5529的adc模块来对旋钮和按键产生的不同的模拟电压量进行识别,并转化为不同的数字信号从而实现对于单片机的控制。这一部分我参考了TI官方MSP320ware中的adc例程文件,通过识别6.0端口的模拟电压值实现对屏幕的控制。对于模拟电压阈值的采样我是借助了ccs的debug模式,我再不同按钮的状态下运行程序,并在debug模式中观察寄存器ADC12MEM0的值,每一个按钮状态对应寄存器ADC12MEM0不同的数值,从而设置合适的阈值来区分不同按钮状态下的模拟电压值,来实现对于不同操作的区分。
实现流程图
实现过程与主要代码
#include <msp430.h>
#include "ST7735_prototypes.h"
void SetVcoreUp(unsigned int level)
{
// Open PMM registers for write
PMMCTL0_H = PMMPW_H;
// Set SVS/SVM high side new level
SVSMHCTL = SVSHE + SVSHRVL0 * level + SVMHE + SVSMHRRL0 * level;
// Set SVM low side to new level
SVSMLCTL = SVSLE + SVMLE + SVSMLRRL0 * level;
// Wait till SVM is settled
while ((PMMIFG & SVSMLDLYIFG) == 0)
;
// Clear already set flags
PMMIFG &= ~(SVMLVLRIFG + SVMLIFG);
// Set VCore to new level
PMMCTL0_L = PMMCOREV0 * level;
// Wait till new level reached
if ((PMMIFG & SVMLIFG))
while ((PMMIFG & SVMLVLRIFG) == 0)
;
// Set SVS/SVM low side to new level
SVSMLCTL = SVSLE + SVSLRVL0 * level + SVMLE + SVSMLRRL0 * level;
// Lock PMM registers for write access
PMMCTL0_H = 0x00;
}
void initClock(void)
{
// Increase Vcore setting to level3 to support fsystem=25MHz
// NOTE: Change core voltage one level at a time..
SetVcoreUp(0x01);
SetVcoreUp(0x02);
SetVcoreUp(0x03);
UCSCTL3 = SELREF_2; // Set DCO FLL reference = REFO
UCSCTL4 |= SELA_2; // Set ACLK = REFO
__bis_SR_register(SCG0); // Disable the FLL control loop
UCSCTL0 = 0x0000; // Set lowest possible DCOx, MODx
UCSCTL1 = DCORSEL_7; // Select DCO range 50MHz operation
UCSCTL2 = FLLD_0 + 762; // Set DCO Multiplier for 25MHz
// (N + 1) * FLLRef = Fdco
// (762 + 1) * 32768 = 25MHz
// Set FLL Div = fDCOCLK/2
__bic_SR_register(SCG0); // Enable the FLL control loop
// Worst-case settling time for the DCO when the DCO range bits have been
// changed is n x 32 x 32 x f_MCLK / f_FLL_reference. See UCS chapter in 5xx
// UG for optimization.
// 32 x 32 x 25 MHz / 32,768 Hz ~ 780k MCLK cycles for DCO to settle
__delay_cycles(782000);
// Loop until XT1,XT2 & DCO stabilizes - In this case only DCO has to stabilize
do
{
UCSCTL7 &= ~(XT2OFFG + XT1LFOFFG + DCOFFG);
// Clear XT2,XT1,DCO fault flags
SFRIFG1 &= ~OFIFG; // Clear fault flags
} while (SFRIFG1 & OFIFG); // Test oscillator fault flag
}
void dwar1(unsigned int x,unsigned int y)
{
draw(x+2 , y , 1 , 14, 0L);
draw(x-1 , y , 7 , 1, 0L);
draw(x-1 , y+14 , 7 , 1, 0L);
}
void dwar2(unsigned int x,unsigned int y)
{
draw(x+1 , y , 1 , 14, 0L);
draw(x+3 , y , 1 , 14, 0L);
draw(x-2 , y , 9 , 1, 0L);
draw(x-2 , y+14 , 9 , 1, 0L);
}
void dwar3(unsigned int x,unsigned int y)
{
draw(x+0 , y , 1 , 14, 0L);
draw(x+2 , y , 1 , 14, 0L);
draw(x+4 , y , 1 , 14, 0L);
draw(x-2 , y , 9 , 1, 0L);
draw(x-2 , y+14 , 9 , 1, 0L);
}
void dwark(unsigned int x,unsigned int y,unsigned long int s)
{
draw(x , y , 4 , 36, s);
draw(x , y , 100 , 4, s);
draw(x , y+32 , 100 , 4, s);
draw(x+100 , y , 4 , 36, s);
}
#define INDEX_MODULUS (sizeof(demoPal) / sizeof(demoPal[0]))
int unsigned f1 =0;
int unsigned f2 =0;
int unsigned leader = 0x0;
int unsigned fg = 0xfff;
int unsigned sy = 0x0;
int unsigned cd = 0x0;
int unsigned layern = 0x0;
int x;
int y;
/* (8 X 16 , 宋体 ) "!"*/
int main(void) {
WDTCTL = WDTPW | WDTHOLD; // Stop watchdog timer
ADC12CTL0 = ADC12SHT02 + ADC12ON; // Sampling time, ADC12 on
ADC12CTL1 = ADC12SHP; // Use sampling timer
ADC12IE = 0x01; // Enable interrupt
ADC12CTL0 |= ADC12ENC;
P6SEL |= 0x01; // P6.0 ADC option select
P4DIR |= BIT7; // P1.0 output
initClock();
P1DIR |= 0x01; // Set P1.0 to output direction - launchpad LED
// // DCO calibration
// DCOCTL = 0; // Select lowest DCOx and MODx settings
// BCSCTL1 = CALBC1_1MHZ; // Set range
// DCOCTL = CALDCO_1MHZ; // Set DCO step + modulation */
ST7735_if_init();
ST7735_display_init();
// clear the screen by writing zero to all parts of the 7735's display memory
// the actual display used may not be 132x160, could just be (as an example) 128x128
draw(0, 0, 132, 162, 0L); //设置整个屏幕为黑色
while(1){
if(cd == 0x0)
{
draw( 0, 0, 100, 38, 0XFF);//dwark(2,2,0XFF); //第一层界面背景及数字
dwar3(80,10);
draw(80-5 , 10 , 2 , 2, 0L);
draw( 0, 44, 100, 38, 0XFFFFFF);// dwark(2,44,0XFFFFFFF);
dwar2(80,54);
draw(80-5 , 54 , 2 , 2, 0L);
draw( 0, 88, 100, 38, 0XFFFFF);// dwark(2,84,0XFFFFF);
dwar1(80,98);
draw(80-5 , 98 , 2 , 2, 0L);
//第一层界面
if (leader == 0x01) //第一层光标1
{
draw(0, 0, 132, 162, 0L);
draw( 115, 20, 10, 2, 0L);
draw( 116, 19, 1, 1, 0L);
draw( 116, 22, 1, 1, 0L);
draw( 117, 18, 1, 1, 0L);
draw( 117, 23, 1, 1, 0L);
draw( 115, 60, 10, 2, 0L);
draw( 116, 59, 1, 1, 0L);
draw( 116, 62, 1, 1, 0L);
draw( 117, 58, 1, 1, 0L);
draw( 117, 63, 1, 1, 0L);
draw( 115, 100, 10, 2, 0XFFFFF);
draw( 116, 99, 1, 1, 0XFFFFF);
draw( 116, 102, 1, 1, 0XFFFFF);
draw( 117, 98, 1, 1, 0XFFFFF);
draw( 117, 103, 1, 1, 0XFFFFF);
sy = 0x1; //设置光标下一个指向的位置
layern = 0x1; //标记光标指向层数
}
else if(leader == 0x02)
{ //第一层光标2
draw( 115, 20, 10, 2, 0L);
draw( 116, 19, 1, 1, 0L);
draw( 116, 22, 1, 1, 0L);
draw( 117, 18, 1, 1, 0L);
draw( 117, 23, 1, 1, 0L);
draw( 115, 60, 10, 2, 0XFFFFFF);
draw( 116, 59, 1, 1, 0XFFFFFF);
draw( 116, 62, 1, 1, 0XFFFFFF);
draw( 117, 58, 1, 1, 0XFFFFFF);
draw( 117, 63, 1, 1, 0XFFFFFF);
draw( 115, 100, 10, 2, 0L);
draw( 116, 99, 1, 1, 0L);
draw( 116, 102, 1, 1, 0L);
draw( 117, 98, 1, 1, 0L);
draw( 117, 103, 1, 1, 0L);
sy = 0x2; //设置光标下一个指向的位置
layern = 0x2; //标记光标指向层数
}
else if(leader == 0x03)
{ //第一层光标3
draw( 115, 20, 10, 2, 0XFF);
draw( 116, 19, 1, 1, 0XFF);
draw( 116, 22, 1, 1, 0XFF);
draw( 117, 18, 1, 1, 0XFF);
draw( 117, 23, 1, 1, 0XFF);
draw( 115, 60, 10, 2, 0L);
draw( 116, 59, 1, 1, 0L);
draw( 116, 62, 1, 1, 0L);
draw( 117, 58, 1, 1, 0L);
draw( 117, 63, 1, 1, 0L);
draw( 115, 100, 10, 2, 0L);
draw( 116, 99, 1, 1, 0L);
draw( 116, 102, 1, 1, 0L);
draw( 117, 98, 1, 1, 0L);
draw( 117, 103, 1, 1, 0L);
sy = 0x0; //设置光标下一个指向的位置
layern = 0x3; //标记光标指向层数
}
ADC12CTL0 |= ADC12SC; // Start sampling/conversion
__bis_SR_register(LPM0_bits + GIE); // LPM0, ADC12_ISR will force exit
__no_operation(); // For debugger
} // 第一层菜单
else if(cd == 0x1 && layern == 0x3)
{
draw( 0, 0, 100, 38, 0XFF); //第二层界面3(红色)
draw( 0, 44, 100, 38, 0XFF);
draw( 0, 88, 100, 38, 0XFF);
dwar3(80,98); //第二层界面3数字
draw(80-5 , 98 , 2 , 2, 0L);
dwar1(55,98);
dwar3(80,54);
draw(80-5 , 54 , 2 , 2, 0L);
dwar2(55,54);
dwar3(80,10);
draw(80-5 , 10 , 2 , 2, 0L);
dwar3(55,10);
if (leader == 0x01) //第二层光标3
{
draw( 115, 20, 10, 2, 0L);
draw( 116, 19, 1, 1, 0L);
draw( 116, 22, 1, 1, 0L);
draw( 117, 18, 1, 1, 0L);
draw( 117, 23, 1, 1, 0L);
draw( 115, 60, 10, 2, 0L);
draw( 116, 59, 1, 1, 0L);
draw( 116, 62, 1, 1, 0L);
draw( 117, 58, 1, 1, 0L);
draw( 117, 63, 1, 1, 0L);
draw( 115, 100, 10, 2, 0XFF);
draw( 116, 99, 1, 1, 0XFF);
draw( 116, 102, 1, 1, 0XFF);
draw( 117, 98, 1, 1, 0XFF);
draw( 117, 103, 1, 1, 0XFF);
sy = 0x1;
}
else if(leader == 0x02)
{
draw( 115, 20, 10, 2, 0L);
draw( 116, 19, 1, 1, 0L);
draw( 116, 22, 1, 1, 0L);
draw( 117, 18, 1, 1, 0L);
draw( 117, 23, 1, 1, 0L);
draw( 115, 60, 10, 2, 0XFF);
draw( 116, 59, 1, 1, 0XFF);
draw( 116, 62, 1, 1, 0XFF);
draw( 117, 58, 1, 1, 0XFF);
draw( 117, 63, 1, 1, 0XFF);
draw( 115, 100, 10, 2, 0L);
draw( 116, 99, 1, 1, 0L);
draw( 116, 102, 1, 1, 0L);
draw( 117, 98, 1, 1, 0L);
draw( 117, 103, 1, 1, 0L);
sy = 0x2;
}
else if(leader == 0x03)
{
draw( 115, 20, 10, 2, 0XFF);
draw( 116, 19, 1, 1, 0XFF);
draw( 116, 22, 1, 1, 0XFF);
draw( 117, 18, 1, 1, 0XFF);
draw( 117, 23, 1, 1, 0XFF);
draw( 115, 60, 10, 2, 0L);
draw( 116, 59, 1, 1, 0L);
draw( 116, 62, 1, 1, 0L);
draw( 117, 58, 1, 1, 0L);
draw( 117, 63, 1, 1, 0L);
draw( 115, 100, 10, 2, 0L);
draw( 116, 99, 1, 1, 0L);
draw( 116, 102, 1, 1, 0L);
draw( 117, 98, 1, 1, 0L);
draw( 117, 103, 1, 1, 0L);
sy = 0x0;
}
ADC12CTL0 |= ADC12SC; // Start sampling/conversion
__bis_SR_register(LPM0_bits + GIE); // LPM0, ADC12_ISR will force exit
__no_operation(); // For debugger
}
else if (cd == 0x1 && layern == 0x2)
{
draw( 0, 0, 100, 38, 0XFFFFFF); //第二层界面2(白色)
draw( 0, 44, 100, 38, 0XFFFFFF);
draw( 0, 88, 100, 38, 0XFFFFFF);
dwar2(80,98); //第二层界面2光标
draw(80-5 , 98 , 2 , 2, 0L);
dwar1(55,98);
dwar2(80,54);
draw(80-5 , 54 , 2 , 2, 0L);
dwar2(55,54);
dwar2(80,10);
draw(80-5 , 10 , 2 , 2, 0L);
dwar3(55,10);//第二层界面2
if (leader == 0x01) //第二层光标
{
draw( 115, 20, 10, 2, 0L);
draw( 116, 19, 1, 1, 0L);
draw( 116, 22, 1, 1, 0L);
draw( 117, 18, 1, 1, 0L);
draw( 117, 23, 1, 1, 0L);
draw( 115, 60, 10, 2, 0L);
draw( 116, 59, 1, 1, 0L);
draw( 116, 62, 1, 1, 0L);
draw( 117, 58, 1, 1, 0L);
draw( 117, 63, 1, 1, 0L);
draw( 115, 100, 10, 2, 0XFFFFFF);
draw( 116, 99, 1, 1, 0XFFFFFF);
draw( 116, 102, 1, 1, 0XFFFFFF);
draw( 117, 98, 1, 1, 0XFFFFFF);
draw( 117, 103, 1, 1, 0XFFFFFF);
sy = 0x1;
}
else if(leader == 0x02)
{
draw( 115, 20, 10, 2, 0L);
draw( 116, 19, 1, 1, 0L);
draw( 116, 22, 1, 1, 0L);
draw( 117, 18, 1, 1, 0L);
draw( 117, 23, 1, 1, 0L);
draw( 115, 60, 10, 2, 0XFFFFFF);
draw( 116, 59, 1, 1, 0XFFFFFF);
draw( 116, 62, 1, 1, 0XFFFFFF);
draw( 117, 58, 1, 1, 0XFFFFFF);
draw( 117, 63, 1, 1, 0XFFFFFF);
draw( 115, 100, 10, 2, 0L);
draw( 116, 99, 1, 1, 0L);
draw( 116, 102, 1, 1, 0L);
draw( 117, 98, 1, 1, 0L);
draw( 117, 103, 1, 1, 0L);
sy = 0x2;
}
else if(leader == 0x03)
{
draw( 115, 20, 10, 2, 0XFFFFFF); //第二层界面1(黄色)
draw( 116, 19, 1, 1, 0XFFFFFF);
draw( 116, 22, 1, 1, 0XFFFFFF);
draw( 117, 18, 1, 1, 0XFFFFFF);
draw( 117, 23, 1, 1, 0XFFFFFF);
draw( 115, 60, 10, 2, 0L); //第二层界面1光标
draw( 116, 59, 1, 1, 0L);
draw( 116, 62, 1, 1, 0L);
draw( 117, 58, 1, 1, 0L);
draw( 117, 63, 1, 1, 0L);
draw( 115, 100, 10, 2, 0L);
draw( 116, 99, 1, 1, 0L);
draw( 116, 102, 1, 1, 0L);
draw( 117, 98, 1, 1, 0L);
draw( 117, 103, 1, 1, 0L);
sy = 0x0;
}
ADC12CTL0 |= ADC12SC; // Start sampling/conversion
__bis_SR_register(LPM0_bits + GIE); // LPM0, ADC12_ISR will force exit
__no_operation(); // For debugger
}
else if (cd == 0x1 && layern == 0x1)
{
draw( 0, 0, 100, 38, 0XFFFFF);
draw( 0, 44, 100, 38, 0XFFFFF);
draw( 0, 88, 100, 38, 0XFFFFF);
dwar1(80,98);
draw(80-5 , 98 , 2 , 2, 0L);
dwar1(55,98);
dwar1(80,54);
draw(80-5 , 54 , 2 , 2, 0L);
dwar2(55,54);
dwar1(80,10);
draw(80-5 , 10 , 2 , 2, 0L);
dwar3(55,10);//第二层界面3
if (leader == 0x01)
{
draw( 115, 20, 10, 2, 0L);
draw( 116, 19, 1, 1, 0L);
draw( 116, 22, 1, 1, 0L);
draw( 117, 18, 1, 1, 0L);
draw( 117, 23, 1, 1, 0L);
draw( 115, 60, 10, 2, 0L);
draw( 116, 59, 1, 1, 0L);
draw( 116, 62, 1, 1, 0L);
draw( 117, 58, 1, 1, 0L);
draw( 117, 63, 1, 1, 0L);
draw( 115, 100, 10, 2, 0XFFFFF);
draw( 116, 99, 1, 1, 0XFFFFF);
draw( 116, 102, 1, 1, 0XFFFFF);
draw( 117, 98, 1, 1, 0XFFFFF);
draw( 117, 103, 1, 1, 0XFFFFF);
sy = 0x1;
}
else if(leader == 0x02)
{
draw( 115, 20, 10, 2, 0L);
draw( 116, 19, 1, 1, 0L);
draw( 116, 22, 1, 1, 0L);
draw( 117, 18, 1, 1, 0L);
draw( 117, 23, 1, 1, 0L);
draw( 115, 60, 10, 2, 0XFFFFF);
draw( 116, 59, 1, 1, 0XFFFFF);
draw( 116, 62, 1, 1, 0XFFFFF);
draw( 117, 58, 1, 1, 0XFFFFF);
draw( 117, 63, 1, 1, 0XFFFFF);
draw( 115, 100, 10, 2, 0L);
draw( 116, 99, 1, 1, 0L);
draw( 116, 102, 1, 1, 0L);
draw( 117, 98, 1, 1, 0L);
draw( 117, 103, 1, 1, 0L);
sy = 0x2;
}
else if(leader == 0x03)
{
draw( 115, 20, 10, 2, 0XFFFFF);
draw( 116, 19, 1, 1, 0XFFFFF);
draw( 116, 22, 1, 1, 0XFFFFF);
draw( 117, 18, 1, 1, 0XFFFFF);
draw( 117, 23, 1, 1, 0XFFFFF);
draw( 115, 60, 10, 2, 0L);
draw( 116, 59, 1, 1, 0L);
draw( 116, 62, 1, 1, 0L);
draw( 117, 58, 1, 1, 0L);
draw( 117, 63, 1, 1, 0L);
draw( 115, 100, 10, 2, 0L);
draw( 116, 99, 1, 1, 0L);
draw( 116, 102, 1, 1, 0L);
draw( 117, 98, 1, 1, 0L);
draw( 117, 103, 1, 1, 0L);
sy = 0x0;
}
ADC12CTL0 |= ADC12SC; // Start sampling/conversion
__bis_SR_register(LPM0_bits + GIE); // LPM0, ADC12_ISR will force exit
__no_operation(); // For debugger
}
}
}
#if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
#pragma vector = ADC12_VECTOR
__interrupt void ADC12_ISR(void)
#elif defined(__GNUC__)
void __attribute__ ((interrupt(ADC12_VECTOR))) ADC12_ISR (void)
#else
#error Compiler not supported!
#endif
{
switch(__even_in_range(ADC12IV,34)) //ADC模块
{
case 0: break; // Vector 0: No interrupt
case 2: break; // Vector 2: ADC overflow
case 4: break; // Vector 4: ADC timing overflow
case 6: // Vector 6: ADC12IFG0
if ((ADC12MEM0 > 0xAff ) && (ADC12MEM0 <= 0xCff )) //识别上方按钮
{ P4OUT |= BIT7; //点亮4.7作为验证
P1OUT &= ~BIT0;
cd = 1; //控制进入下一层界面
f2 = 1; //防止电压波动引发误触
}
else if ((ADC12MEM0 <= 0xAff )&&(fg > ADC12MEM0)) //识别下方按钮
{ P4OUT &= ~BIT7; //点亮1.0作为验证
P1OUT |= BIT0;
cd = 0; //控制返回上一级菜单
f1 = 1; //防止电压波动引发误触
}
else if((f1 == 1)||(f2 == 1)) //识别旋钮电压变化
{
f1 =0; //灯灭作为验证
f2 =0;
}
else if ((ADC12MEM0 >= 0xCff) )// P1.0 = 0
{
if(fg >= ADC12MEM0 )
{P1OUT &= ~BIT0; //灯全亮作为旋钮信号的验证
P4OUT &= ~BIT7;
leader = 0x00; //控制菜单光标指向下一个位置
}
else if ((fg < ADC12MEM0) &&(sy == 0x0)) //通过变量sy指向下一个光标的位置
{
P1OUT |= BIT0;
P4OUT |= BIT7;
leader = 0x01;
}
else if ((sy == 0x1))
{
P1OUT |= BIT0;
P4OUT |= BIT7;
leader = 0x02;
}
else if ((sy == 0x2))
{
P1OUT |= BIT0;
P4OUT |= BIT7;
leader = 0x03;
}
fg = ADC12MEM0 + 15; //适当加上一个常数避免电压波动引发误判
}
__bic_SR_register_on_exit(LPM0_bits); // Exit active CPU
case 8: break; // Vector 8: ADC12IFG1
case 10: break; // Vector 10: ADC12IFG2
case 12: break; // Vector 12: ADC12IFG3
case 14: break; // Vector 14: ADC12IFG4
case 16: break; // Vector 16: ADC12IFG5
case 18: break; // Vector 18: ADC12IFG6
case 20: break; // Vector 20: ADC12IFG7
case 22: break; // Vector 22: ADC12IFG8
case 24: break; // Vector 24: ADC12IFG9
case 26: break; // Vector 26: ADC12IFG10
case 28: break; // Vector 28: ADC12IFG11
case 30: break; // Vector 30: ADC12IFG12
case 32: break; // Vector 32: ADC12IFG13
case 34: break; // Vector 34: ADC12IFG14
default: break;
}
}
以上是该项目主函数代码,代码关键部分已经有注释标注。其中有几点值得注意:
1、draw函数由官方给出的例程提供,在ST7735_prototypes.h头文件下,draw(x , y , m , l, c)函数用于绘制矩形,x、y分别为举行右下角的坐标,m、l为矩形的长、宽,c为矩形颜色的编号。利用这个draw函数,再加以取模软件、自己编写的函数即可完成屏幕上所有图形和符号的绘制。
2、在ADC模块中引入的f1、f2是由于在调试的过程中我观察到当我们按下进入下一级菜单或返回上一级菜单的按钮时,会同时出发按钮使得光标指向下一个选项,在检查了判断语句逻辑后仍不知道问题出在哪里,于是引入f1、f2这两个变量用于在进行按钮操作后禁止在本次循环执行旋钮的操作。
3、fg变量用于记录当前电压值,并保留到下一个下一次循环,用于判断模拟电压是否发生变化。理论上来说,当电压不在两个按钮对应电平所在区间,即可以认为按钮状态处于没有操作或者旋钮旋转状态。通过在旋钮旋转过程中观察debug模式下寄存器ADC12MEM0的值我们可以发现,当旋钮旋转时,电平会发生变化,所以我们只需要判断6.0引脚输入的电压是否发生变化即可区分无操作或者旋钮旋转状态。但在实际实验过程中我们发现6.0引脚采集到的电压会有很小的波动,于是我们在赋值时为fg加上一个常数,并设置变化的判断条件为fg < ADC12MEM0即可一定程度上防止误判的发生。
4、在程序的判断语句中,判断的结果除了用于控制屏幕显示之外,还可以控制p1.0和p4.7两处的小灯,我设置按下上方按钮时红灯(1.0)亮,按下下方按钮时绿灯亮(4.7),旋转旋钮时两个等都亮,没有操作时都不亮。这个功能为调试和纠错提供了很大的帮助。
结果展示
板卡上电后的屏幕界面如下图所示,左侧为一个箭头形状的光标,指向我们当前选定的菜单选项;右侧则是三个菜单选项,分别由黄、白、红和罗马数字一、二、三进行区分。
当我们旋转旋钮光标就会指向下一个菜单选项,光标也会变为相应菜单选项对应的颜色:
下图是第二层界面,当前展示的结果为光标指向第一个菜单选项时按下上方按钮所显示的结果,三个第二级菜单选项的颜色均变为一级菜单对应选项的颜色,并由两个罗马数字标注,这时如果按下下方按钮,即可回到上一级菜单。图片难以体现以上过程,具体结果的展示可以观看视频。
未来的规划及建议
该菜单仍有许多可以改进的地方,例如:
图形界面可以做的更加美观,解决色块和文字交替刷新,文字闪烁的现象;
按钮的控制或许还可以优化,做的更加灵敏和准确
进行文字取模和优化,使菜单界面现实的内容更加丰富
增加菜单的级数并改变每一级菜单选项的数量
引入扩展板上的的pwm摇杆来进行菜单控制,丰富菜单的控制方式
这次寒假一起练项目只是为我打开了一扇门,今后在单片机编程领域还有无尽的知识等待我去探索。