通过前两节的介绍,使ucgui成功运行在stm32板子的ecos系统,实现了让ucgui在ecos中跑起来的目标。接下来就是实现触摸功能。

ucgui触摸功能的移植也相对比较容易,前提是你的触摸驱动已经调试好了。我的STM32板子使用的是TSC2046触摸驱动芯片,其驱动在前面章节已经介绍过了。详情点击:http://velep.com/archives/617.html

TSC2046触摸驱动

eCos TSC2046触摸驱动芯片源码下载地址:http://52ecos.net/thread-647-1-1.html

这个驱动是参考eCos MINI STM32上TSC2046触摸驱动修改的。主要是修改了读取触摸AD采样值函数read_ts()。一个非常奇怪的问题是:相同的触摸驱动芯片,在MINI STM32和在我的STM32板子上,AD采样值的计算有不同。当前驱动的AD采样值是参考安富莱例程提供的计算公式。

ucgui添加触摸支持

在ucgui中,除了把GUI_SUPPORT_TOUCH宏的值定义为1表示ucgui支持触摸功能外,还需要两个源文件,分别是GUITouchConf.h和GUI_X_Touch.c。其中,GUI_X_Touch.c拷贝于ucgui源码Sample/GUI_X目录下的同名文件。

image

在很多ucgui移植说明中,并未明确说明GUI_X_Touch.c文件应该放在哪里,所以我就把这个文件放到ucgui的Config目录下,使之与GUI_X_eCos.c同在一个目录下。

GUITouchConf.h文件

#ifndef GUITOUCH_CONF_H 
#define GUITOUCH_CONF_H

#define GUI_TOUCH_AD_LEFT        128 
#define GUI_TOUCH_AD_RIGHT        3856 
#define GUI_TOUCH_AD_TOP        128 
#define GUI_TOUCH_AD_BOTTOM        3729

#define GUI_TOUCH_SWAP_XY        0 
#define GUI_TOUCH_MIRROR_X        0 
#define GUI_TOUCH_MIRROR_Y        0

#endif /* GUITOUCH_CONF_H */

这个文件主要是定义了触摸AD采样边界值。这4个AD采样边界值是个模糊值,不必太精确。

GUI_X_Touch.c文件

#include "GUI.h"
#include "GUI_X.h"

#if ECOS
#include <unistd.h>
#include <fcntl.h>
#endif

static int touch_screen_read(short * px, short * py, short * pb)
{
#if ECOS
    static int pd_fd = -1;
    short data[4];/* read a data point */
    int bytes_read;

    if (pd_fd < 0) {
        if ((pd_fd = open("/dev/ts", O_RDONLY | O_NONBLOCK)) < 0) {
           return 0;
        }
    }

    bytes_read = read(pd_fd, data, sizeof(data));
    if (bytes_read != sizeof(data)) {
        return 0;
    }

    *px = data[1];
    *py = data[2];

    *pb = (data[0] ? 0x01 : 0);

    if (! *pb ) {
        return 3;          /* only have button data */
    } else {
        return 2;          /* have full set of data */
    }

#endif
    return  0;
}

void GUI_TOUCH_X_ActivateX(void) {
}

void GUI_TOUCH_X_ActivateY(void) {
}

int  GUI_TOUCH_X_MeasureX(void)
{
    short px = 0, py = 0, pb = 0;
    touch_screen_read(&px, &py, &pb);
    //diag_printf("MeasureX: px = %d, py = %d\n", px, py);
    return px;
}

int  GUI_TOUCH_X_MeasureY(void)
{
    short px = 0, py = 0, pb = 0;
    touch_screen_read(&px, &py, &pb);
    //diag_printf("MeasureY: px = %d, py = %d\n", px, py);
    return py;
}

这文件也很简单,实质就是读取触摸屏AD采样X、Y值。注意,返回的是物理值。

根据别人的移植说明,读取触摸屏AD采样X、Y值,是由用户程序触发的。在eCos中,有3种方法可用:

  • 设定触摸屏的一个引脚为外部触发,触摸点击时,电平变化触发中断,在中断函数中调用GUI_TOUCH_Exec()函数,让UCGUI更新TOUCH时间数据。
  • 设定一个10ms的定时器中断不断查询,在中断函数中调用GUI_TOUCH_Exec()。
  • 开启一个线程,周期调用GUI_TOUCH_Exec()函数;

第1个方案,看似更为合适,不占用CPU,让CPU可以处理其他事情。但是UCGUI的触摸事件,一次触摸只会读取一个轴的AD值,也就是说一次读取X轴AD,下一次再读取Y轴AD值。这样导致获得的数据都是错误的。uCGUI 有处理抖动的函数_StoreUnstable(x, y),会将误差较大的数据过滤,两次点击事件时间很短的话,也至少会是一次正确坐标,一次错误坐标。而且外部中断的方法,只能获得触摸点击的事件,无法获得触摸移动的事件。

本次移植为求简单,采用了第3种方法,在用户测试程序中,开启一个线程不断轮询触摸AD采样值,如下代码:

#if GUI_SUPPORT_TOUCH
static void gui_touch_thread(cyg_addrword_t data)
{
    while (1) {
        GUI_TOUCH_Exec();
        GUI_Exec();
        GUI_Delay(10);
    }
}
#endif

/* Thread variables */
#define UCGUI_THREAD_STACK_SIZE         (CYGNUM_HAL_STACK_SIZE_TYPICAL/* * 2 */)
static cyg_handle_t UCGUI_thread_handle;
static cyg_thread   UCGUI_thread_block;
static char         UCGUI_thread_stack[UCGUI_THREAD_STACK_SIZE];

#if GUI_SUPPORT_TOUCH
#define UCGUI_TOUCH_THREAD_STACK_SIZE   (CYGNUM_HAL_STACK_SIZE_TYPICAL/* * 2 */)
static cyg_handle_t UCGUI_TOUCH_thread_handle;
static cyg_thread   UCGUI_TOUCH_thread_block;
static char         UCGUI_TOUCH_thread_stack[UCGUI_TOUCH_THREAD_STACK_SIZE];
#endif

void cyg_user_start(void)
{
    /* Create GUI thread */
    cyg_thread_create(7,    /* Priority */
                      gui_thread,
                      0,
                      "GUI thread",
                      UCGUI_thread_stack,
                      sizeof(UCGUI_thread_stack),
                      &UCGUI_thread_handle,
                      &UCGUI_thread_block);
    cyg_thread_resume(UCGUI_thread_handle);/* Starting thread */

#if GUI_SUPPORT_TOUCH
    /* Create GUI touch thread */
    cyg_thread_create(8,    /* Priority, must lower than gui_thread */
                      gui_touch_thread,
                      0,
                      "GUI touch thread",
                      UCGUI_TOUCH_thread_stack,
                      sizeof(UCGUI_TOUCH_thread_stack),
                      &UCGUI_TOUCH_thread_handle,
                      &UCGUI_TOUCH_thread_block);
    cyg_thread_resume(UCGUI_TOUCH_thread_handle);/* Starting thread */
#endif

    cyg_scheduler_start();/* Scheduler start */
}
#endif

在调试过程中发现,触摸线程的优先级(Priority)必须比GUI主线程的优先级低,否则程序会挂掉,原因暂时未知。

添加多线程支持

由于存在多个地方同时调用ucgui的API接口,所以必须为ucgui的API接口加上锁功能。因此,必须完成GUI_X_eCos.c文件的多任务接口函数,如下代码:

void  GUI_X_InitOS (void)
{
    GUI_MUTEX_init();
}

void  GUI_X_Lock (void)
{
    GUI_MUTEX_LOCK();
    if (++GUI_mutex_cnt > 1) {
        diag_printf("Error in GUITASK.c module ...\n");
    }
}

void  GUI_X_Unlock (void)
{
    GUI_mutex_cnt--;
    GUI_MUTEX_UNLOCK();
}

U32  GUI_X_GetTaskId (void)
{
    return (U32)cyg_thread_get_id(cyg_thread_self());
}

其中,相关宏定义在该文件的开头,如下代码:

static cyg_uint32  GUI_mutex_cnt = 0;   // For debugging only ... Not required
static cyg_mutex_t GUI_mutex;
#define GUI_MUTEX_init()       cyg_mutex_init(&GUI_mutex)
#define GUI_MUTEX_LOCK()       cyg_mutex_lock(&GUI_mutex)
#define GUI_MUTEX_UNLOCK()     cyg_mutex_unlock(&GUI_mutex)

触摸功能测试

在测试程序中,添加GUI_CURSOR_Show();函数调用,显示鼠标,用于测试触摸屏。注意:必须打开窗口功能,即把宏GUI_WINSUPPORT定义为1。

在LCD显示界面中,点击LCD,则可以看到鼠标会移动到点击地点,说明触摸功能移植成功。

» 文章出处: reille博客—http://velep.com , 如果没有特别声明,文章均为reille博客原创作品
» 郑重声明: 原创作品未经允许不得转载,如需转载请联系reille#qq.com(#换成@)
分享到:

 Leave a Reply

(必须)

(我会替您保密的)(必须)

*

This site uses Akismet to reduce spam. Learn how your comment data is processed.

   
© 2012 velep.com | reille blog | 管理| 粤ICP备15065318号-2| 谷歌地图| 百度地图| Suffusion theme|Sayontan Sinha

无觅相关文章插件,快速提升流量