原创 触摸屏菜单实现及其它

2008-10-18 12:28 5574 7 9 分类: MCU/ 嵌入式
在21IC中看到有人在探讨关于触摸屏上菜单实现的问题,附件是我在一个项目中的部分代码,里面有我自己设计的实现规则菜单的算法,所谓规则菜单就是批菜单的条目呈均匀的行列摆放,且每个条目在高度和宽度一样,这样可以极大的简化算法。我的处理方法是,对每个菜单定义一组结构,
/*********************************************************
菜单按钮组结构体
*********************************************************/
typedef struct
{
    u8 row;//行数
    u8 col;//列数
    u8 y;//左上角y座标
    u16 x;//左上角x座标
    u8 h;//高度
    u16 w;//宽度
    u8 dy;//y方向间隔
    u16 dx;//x方向间隔
    u8 titlelen;//按钮内容长度
    u16 tx;//按钮内容x方向偏移量
    u8 ty;//按钮内容y方向偏移量
    u8 cfont;//按钮内容字形
    u8 cstyle;//按钮内容粗体及反显
    const u8 * title;//按钮内容字符串
}manu_buttonsTypeDef;

/******************************************************************
菜单框架结构体
*******************************************************************/
typedef struct
{
    u8 y0;//左上角y座标
    u16 x0;//左上角x座标
    u8 h;//高度
    u16 w;//宽度
    u8 thick;//两外框间距离
    u8 ty;//按钮内容y方向偏移量
    u16 tx;//按钮内容x方向偏移量
    u8 cfont;//按钮内容字形
    u8 cstyle;//按钮内容粗体及反显
    const u8 * title;//按钮内容字符串
}manu_frameTypeDef;
/**************************************************************
菜单结构体
**************************************************************/
typedef struct
{
    manu_frameTypeDef frame;
    manu_buttonsTypeDef buttons;
}manuTypeDef;

在实际使用一个菜单时需根据菜单排布情况给出结构体中的各值,如下图
点击看大图
所示画面的菜单完整定义为
const u8 testmanu0_title[] =
    "测试系统主菜单";
const u8 testmanu0_buttontitle[] =
    "复 位 周 期32 分 周 期A  路 模 拟启 动 电 机B  路 模 拟停 止 电 机两 路 模 拟同 步 两 路";

const manuTypeDef testmanu0 =
    {
        {
            5,        //u8 y0;//左上角y座标
            5,        //u16 x0;//左上角x座标
            229,    //u8 h;//高度
            309,    //u16 w;//宽度
            3,        //u8 thick;//两外框间距离
            13,        // ty;//标题y方向偏移量
            43,        //u16 tx;//标题x方向偏移量
            CFNT_2,    //char_fontTypeDef font;//按钮内容字形
            CFNT_BOLDREVERSE,//char_styleTypeDef style;//按钮内容粗体及反显
            testmanu0_title//const u8 * string;//按钮内容字符串
        },
        {
            4,        //u8 row;//行数
            2,        //u8 col;//列数
            62,        //u8 y;//左上角y座标
            34,        //u16 x;//左上角x座标
            35,        //u8 h;//高度
            99,        //u16 w;//宽度
            44,        //u8 dy;//y方向间隔
            152,    //u16 dx;//x方向间隔
            11,        //u8 titlelen;//按钮内容长度
            6,        //u16 tx;//按钮内容x方向偏移量
            2,        //u8 ty;//按钮内容y方向偏移量
            CFNT_12,    //char_fontTypeDef font;//按钮内容字形
            CFNT_NORMAL,//char_styleTypeDef style;//按钮内容粗体及反显
            testmanu0_buttontitle//const u8 * string;//按钮内容字符串
        }
    };
显示菜单时调用下面函数即可
/********************************************************
显示一屏菜单
********************************************************/
void display_manu(const manuTypeDef* pmd)
{
    u8 row, col, x, y, k;
    const u8 * pti;
    lcm_set_access_2layers();
    set_active_window(0,0,40,240);
    lcm_clr();
    lcm_set_access_layer1();

    set_text_mode();
    //显示主标题
    lcm_set_style(pmd->frame.cstyle);
    lcm_set_font(pmd->frame.cfont);
    display_string((pmd->frame.x0 + pmd->frame.tx) / 8, pmd->frame.y0 + pmd->frame.ty, (u8 *)pmd->frame.title == 0 ? multiple_manu_title : (u8 *)pmd->frame.title, 0x20);
    //显示按钮内容
    lcm_set_style(pmd->buttons.cstyle);
    lcm_set_font(pmd->buttons.cfont);
    pti = (pmd->buttons.title == 0 ? multiple_manu_buttontitle : pmd->buttons.title);
    for(row = 0, y = pmd->buttons.y + pmd->buttons.ty; row < pmd->buttons.row; row++, y += pmd->buttons.dy)
    {
        for(col = 0, x = pmd->buttons.x + pmd->buttons.tx; col < pmd->buttons.col; col++, x += pmd->buttons.dx)
        {
            set_position(x / 8, y);
            for(k = 0; k < pmd->buttons.titlelen; k++)
            {
                lcm_data_write(*pti++);
            }
        }
    }
   
    set_graph_mode();
    //显示外框
    rectangle(pmd->frame.x0 - pmd->frame.thick, pmd->frame.y0 - pmd->frame.thick, pmd->frame.x0 + pmd->frame.w + pmd->frame.thick, pmd->frame.y0 + pmd->frame.h + pmd->frame.thick, 1, 0);
    rectangle(pmd->frame.x0, pmd->frame.y0, pmd->frame.x0 + pmd->frame.w, pmd->frame.y0 + pmd->frame.h, 1, 0);
    //显示按钮
    for(row = 0, y = pmd->buttons.y; row < pmd->buttons.row; row++, y += pmd->buttons.dy)
    {
        for(col = 0, x = pmd->buttons.x; col < pmd->buttons.col; col++, x += pmd->buttons.dx)
        {
            rectangle(x, y, x + pmd->buttons.w, y + pmd->buttons.h, 1, 0);
        }
    }
}

比如要显示上面图片中的菜单,则简单地调用即可,如下
display_manu(testmanu0);

显示出菜单之后,要确定触摸了哪个菜单条目,这也很简单,只要调用下面的函数即可
/***********************************************************
分析触摸到的按钮
pmfd 指向标识按钮组的数据
返回触摸到的按键,按从左到右从高到低排列,左上角键值为1
***********************************************************/
uint8_t analyze_touch(const manu_buttonsTypeDef * pmfd)
{
    //取得行数和列数
    u8 i,j;
    u16 x;
    u8 y;

    //行扫描
   
    for(i = 0, y = pmfd->y; i < pmfd->row; i++, y += pmfd->dy)
    {
        if((touch_y >= y) && (touch_y <= (y + pmfd->h)))
        {
            break;
        }
    }
           
    if(i >= pmfd->row)
    {
        return 0;
    }
           
    for(j = 0, x = pmfd->x; j < pmfd->col; j++, x += pmfd->dx)
    {
        if((touch_x >= x) && (touch_x <= (x + pmfd->w)))
        {
            return (i * pmfd->col + j + 1);
        }
    }
   
    return 0;
}

在这个函数中的touch_x及touch_y是公共变量,分别是触摸点的座标,要注意的是座标值要与显示点位置一一对应。

分析上图菜单的程序大体是这样的
display_manu(&testmanu0);//显示画面
/***********************************************************
在这里启动触摸屏扫描程序
***********************************************************/
while(1)
{
   cmd = 0;
   if(0x00 != get_touch())//检测是否有触摸
   {
      //有触摸,取得触摸的菜单条目
      cmd = analyze_touch(&testmanu00.buttons);
   }
   swtich(cmd)
   {
       case 0:
           //没有触摸到菜单条目
           break;
       case 1:
           //复位周期
           break;
       case 2:
           //32分周期
           break;
       ...
       ...
       ...
       case 8:
           //同步两路
           break;
       default:
           break;
   }
}

附件中包含完整项目代码及相关部分的原理图。
由于实际项目中对菜单处理要求会复杂一些,所以相关代码不一定与上面给出的代码相同。
本文所用的LCM是TOPWAY公司的LM2029R,其控制器是RA8803, 触摸屏使用STM32的ADC进行控制。
如果仔细看一下代码,你可能还会有其它的收获。
未经本人同意,请勿转载本文。
https://static.assets-stash.eet-china.com/album/old-resources/2008/10/18/bb3a580d-5082-48f1-8393-9723be1f3f6f.rar

PARTNER CONTENT

文章评论5条评论)

登录后参与讨论

用户1713248 2009-7-26 13:29

太感谢了。。

用户166140 2009-3-13 11:08

????????????

用户1354403 2008-12-26 17:19

还有提升的空间 建议参考ucgui和zlggui 如果只针对简单的界面建议看看tc的ide的实现(虽然DOS离我们有些距离了)

用户161838 2008-12-18 10:49

非常感谢,学到好多东西!

用户168318 2008-10-19 19:37

very good!!!

用户168318 2008-10-19 19:37

very good!!!
相关推荐阅读
用户18170 2009-01-17 11:47
面向工控的学习板主控制部分已经完成
前段时间说的学习板已经于08年12月中旬将板画完了,一直忙,没时间整理,今天将其整理一下,发上来,由于众所周知的原因,目前资金奇紧,做板只能是无限期延后了。板上只集成了中心控制部分,外部隔离驱动都放在...
用户18170 2009-01-03 16:25
MOS管驱动产生的奇怪现象
在一个系统中通过一PMOS管(PA002)控制传感器电源,PMOS管的G极直接由单片机(ATMEGA169)的IO口控制,调试时发现一奇怪现象,在打开传感器电源时,单片机会出现复位,真是莫名其妙,反复...
用户18170 2008-11-13 15:12
一个完整的简单的工控板项目(基于AVR)
这段时间都在做一个新的项目,所以学习板就放了一段时间,新项目接近尾声,将项目的板照传上来给大家排砖,我会将原理图整理出来了,也传上来供大家参考指正,我想技术是要通过交流而不断进步的,所以我也真诚希望有...
用户18170 2008-10-24 11:54
基于MDK322和万利199开发版的USART实战训练项目
啥也不说了,有兴趣的自己看吧https://static.assets-stash.eet-china.com/album/old-resources/2008/10/24/6175dc52-3b3d...
用户18170 2008-10-20 21:04
FSMC初接触--分析MANLEY399学习板使用FSMC驱动LCM的方法
FSMC应用要点(仅针对本标题)  * RCC使能    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_FSMC, ENABLE);    FSMC的时钟直接来自AHB时钟,...
我要评论
5
7
关闭 站长推荐上一条 /3 下一条