linux下的led驱动程序 (转载)

本文介绍了一个简单的Linux LED控制模块驱动程序的设计与实现,包括GPIO初始化、文件操作接口、内核空间与用户空间交互等关键部分,并提供了一个用户态测试程序。


/*
 * Copyright (c) 2009-~ Lan Peng
 *
 * This source code is released for free distribution under the terms of the
 * GNU General Public License
 *
 * Author: Lan Peng<lanpeng722@gmail.com>
 * Created Time: 2009年09月14日 星期一 18时02分17秒
 * File Name: led.c
 *
 * Description:
 */

#include <linux/init.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/device.h>
#include <linux/miscdevice.h>
#include <linux/platform_device.h>
#include <linux/types.h>
#include <linux/io.h>
#include <linux/delay.h>
#include <linux/irq.h>
#include <linux/interrupt.h>
#include <asm/uaccess.h>
#include <mach/irq.h>
#include <asm/io.h>
#include <asm/pgtable.h>
#include <asm/page.h>
#include <mach/hardware.h>
#include <mach/platform.h>
#include <mach/lpc32xx_gpio.h>

#define GPO_5_SET     (*(volatile unsigned int __force *)0xf4028004)//虚拟地址
#define GPO_5_CLR     (*(volatile unsigned int __force *)0xf4028008)//虚拟地址
#define GPO_5         (1<<5) //寄存器的第五位控制led灯
#define DEV_NAME    "ledlan"//设备文件名
#define IO_SET        1
#define IO_CLR        0

static int lan_led_open(struct inode *inode, struct file *file);
static int lan_led_release(struct inode *inode, struct file *file);
static ssize_t lan_led_write(struct file *file, const char __user *buff, ssize_t count, loff_t *ppos);
static ssize_t lan_led_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg);

static int lan_led_open(struct inode *inode, struct file *file)
{
    printk("Open......\n");
    try_module_get(THIS_MODULE);
    GPO_5_SET |= GPO_5;
    return 0;
}

static int lan_led_release(struct inode *inode, struct file *file)
{
    printk("Release......\n");
    module_put(THIS_MODULE);
    return 0;
}

static ssize_t lan_led_write(struct file *file, const char __user *buff, ssize_t count, loff_t *ppos)
{
    int i;
    unsigned char ctrl=0;
    if(count > 1)
        return -1;
    printk("write......\n");
    get_user(ctrl, (u8 *)buff);
    i = (ctrl - 0x30)&0x03;
    if(i == 0)
        GPO_5_CLR |= GPO_5;
    else if(i == 1)
        GPO_5_SET |= GPO_5;
    return count;
}

static ssize_t lan_led_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
{
    switch(cmd)
    {
        case IO_SET:
            GPO_5_SET |= GPO_5;
        break;
        case IO_CLR:
            GPO_5_CLR |= GPO_5;
        break;
        default:
            GPO_5_SET |= GPO_5;
        break;    
    }
    return 0;
}

static struct file_operations lan_led_fops = {
    .owner = THIS_MODULE,
    .write = lan_led_write,
    .ioctl     = lan_led_ioctl,
    .open = lan_led_open,
    .release = lan_led_release,
};

static struct miscdevice lan_led_miscdev = { /*杂设备*/
    .minor     = MISC_DYNAMIC_MINOR,
    .name     = DEV_NAME,
    .fops    = &lan_led_fops,
};

static int __init lan_init(void)
{
    int ret;
    printk("init......\n");
    ret = misc_register(&lan_led_miscdev);
    if(ret)
        printk("Failed to register miscdev");
    return 0;
}

static void __exit lan_exit(void)
{
    printk("byebye......\n");
    misc_deregister(&lan_led_miscdev);
}

module_init(lan_init);
module_exit(lan_exit);
MODULE_LICENSE("GPL");


//用户态测试程序:test_led.c:

/*
 * Copyright (c) 2009-~ Lan Peng
 *
 * This source code is released for free distribution under the terms of the
 * GNU General Public License
 *
 * Author:       Lan Peng<lanpeng722@gmail.com>
 * Created Time: 2009年09月14日 星期一 20时21分18秒
 * File Name:    test_led.c
 *
 * Description: 
 */

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
int main(int args, char *argv[])
{
    int fd;
    int i;
    char buf;
    fd = open("/dev/ledlan", O_RDWR);
    if(fd == -1)
    {
        printf("Open Error!\n");
        exit(1);
    }
#if 1   
    for(i = 0; i < 10; i++){
        buf = '1';
        write(fd, &buf, 1);
        usleep(300000);
        buf = '0';
        write(fd, &buf, 1);
        usleep(300000);
    }
#endif

#if 1
    printf("ioctl......");
    for(i = 0; i < 10; i++){
        ioctl(fd, 0, NULL);
        usleep(300000);
        ioctl(fd, 1, NULL);
        usleep(300000);
    }
#endif   
    return 0;

#include "menu.h" #include "lcd_app.h" int nSelectRecord[MAX_MENU_LAYERS]; int nCurrentLayer = 0; // -------------------------------------------------------------------------------- // 描 述: 初始化菜单 // 参 数: // pMenu 菜单指针 // bDirection 菜单的排列方向:DIRECTION_HORIZON 或 DIRECTION_VERTICAL // nRows,nCols 显示菜单的行数与列数,如果小于实际行数与列数将滚动显示 // nHDistance, nVDistance 菜单项之间的象素距离 // // 返回值: 无 // 注 意:  此函数应该在其它函数对该菜单的操作之前调用 // -------------------------------------------------------------------------------- void MenuInitialize(PPOSMENU pMenu, BOOL bDirection, int nRows, int nCols, int nHDistance, int nVDistance) { pMenu->nMenuItemCount = 0; pMenu->bCanBeCancel = FALSE; pMenu->bDirection = bDirection; pMenu->nCols = nCols; pMenu->nRows = nRows; pMenu->nHDistance = nHDistance; pMenu->nVDistance = nVDistance; } //-------------------------------------------------------------------------------- // 描 述: 清空菜单项,将菜单结构中的菜单项计数清零 // 参 数: // pMenu 需要清空的菜单指针 // // 返回值: 无 //-------------------------------------------------------------------------------- void MenuClearAllItems(PPOSMENU pMenu) { pMenu->nMenuItemCount = 0; } //-------------------------------------------------------------------------------- // 描 述: 设置菜单是否能够被 VK_CANCEL 键取消操作 // 参 数: // pMenu 需要清空的菜单指针 // // 返回值: 无 //-------------------------------------------------------------------------------- void MenuEnableCancel(PPOSMENU pMenu, BOOL bCanBeCancel) { pMenu->bCanBeCancel = bCanBeCancel; } //-------------------------------------------------------------------------------- // 描 述: 设置菜单风格 // 参 数: // pMenu 菜单指针 // pItemString 添加的菜单项的字符串 // // 返回值: 添加成功返回 TRUE,否则返回 FALSE(例如超过最大菜单项数) //-------------------------------------------------------------------------------- BOOL MenuAppendItem(PPOSMENU pMenu, const char *pItemString) { if(pMenu->nMenuItemCount>=MAX_MENU_ITEMS) return FALSE; if(strlen((char*)pItemString)>MAX_MENU_ITEM_LENGTH) { memcpy(pMenu->strMenuItems[pMenu->nMenuItemCount], pItemString, MAX_MENU_ITEMS); pMenu->strMenuItems[pMenu->nMenuItemCount][MAX_MENU_ITEM_LENGTH] = 0; } else strcpy((char*)(pMenu->strMenuItems[pMenu->nMenuItemCount]), (char*)pItemString); pMenu->nMenuItemCount++; return TRUE; } //-------------------------------------------------------------------------------- // 描 述: 绘制菜单滚动时出现的三角形 // 参 数: // pMenu 菜单指针 // nStartItem 当前屏第一行第一列的菜单项(起始菜单项) // nCurItem 高亮显示的菜单项,为-1时表示无高亮显示项 // // 返回值: 返回实际显示时位于第一行第一列的菜单项序号,即是当前屏菜单项的最小序号 //-------------------------------------------------------------------------------- void MenuDrawTriangle(int x, int y, int nDirection, unsigned char nColor) { int i, j; switch(nDirection) // 判断三角形箭头的方向 { case 1: // 向左 y+=4; for(i=0; i<4; i++) for(j=0; j<(i+1); j++) { putpixel(x+i, y+j, nColor); putpixel(x+i, y-j, nColor); } break; case 2: // 向右 y+=4; x+=4; for(i=0; i<4; i++) for(j=0; j<(i+1); j++) { putpixel(x-i, y+j, nColor); putpixel(x-i, y-j, nColor); } break; case 3: // 向下 x+=3; for(i=0; i<4; i++) for(j=0; j<(i+1); j++) { putpixel(x+j, y+i, nColor); putpixel(x-j, y+i, nColor); } break; case 4: // 向上 x+=3; y-=2; for(i=0; i<4; i++) for(j=0; j<(i+1); j++) { putpixel(x+j, y-i, nColor); putpixel(x-j, y-i, nColor); } break; } } // -------------------------------------------------------------------------------- // 描 述: 从第一行、第一列开始显示指定起始项的当前屏菜单项并高亮显示指定菜单项 // 参 数: // pMenu 菜单指针 // nStartItem 当前屏第一行第一列的菜单项(起始菜单项) // nCurItem 高亮显示的菜单项,为-1时表示无高亮显示项 // // 返回值: 返回实际显示时位于第一行第一列的菜单项序号,即是当前屏菜单项的最小序号 // -------------------------------------------------------------------------------- int MenuDisplay(int x, int y, PPOSMENU pMenu, int nStartItem, int nCurItem) { int i, row, col; int nMaxItem, uWidth, mWidth; if(nStartItem>pMenu->nMenuItemCount || nStartItem<1) return 0; if(nCurItem>pMenu->nMenuItemCount || nCurItem<1) return 0; uWidth = CaculateStringWidth(12, pMenu->strMenuItems[0]); if(!pMenu->bDirection) // 垂直方向排列 { // 计算当前屏显示菜单的最大序号和最小序号 nMaxItem = nStartItem + pMenu->nRows * pMenu->nCols -1; if(nMaxItem>pMenu->nMenuItemCount) nMaxItem = pMenu->nMenuItemCount; // 显示当前屏的菜单项 for(i=nStartItem; i<=nMaxItem; i++) { col = (i-nStartItem)/pMenu->nRows; row = (i-nStartItem)%pMenu->nRows; mWidth=CaculateStringWidth(12, pMenu->strMenuItems[nCurItem-1]); if(i==nCurItem) { DrawRect(x+col*(pMenu->nHDistance+uWidth), y+row*(pMenu->nVDistance+12)-1, x+col*(pMenu->nHDistance+uWidth)+mWidth-1, y+row*(pMenu->nVDistance+12)+12,1); TextOut12I(x+col*(pMenu->nHDistance+uWidth), y+row*(pMenu->nVDistance+12), pMenu->strMenuItems[i-1]); } else { DrawRect(x+col*(pMenu->nHDistance+uWidth), y+row*(pMenu->nVDistance+12)-1, x+col*(pMenu->nHDistance+uWidth)+mWidth-1, y+row*(pMenu->nVDistance+12)+12,0); TextOut12(x+col*(pMenu->nHDistance+uWidth), y+row*(pMenu->nVDistance+12), pMenu->strMenuItems[i-1]); } } // 菜单滚动时绘制箭头 row = y + pMenu->nRows*(pMenu->nVDistance+12); col = x + pMenu->nCols*(pMenu->nHDistance+uWidth)-pMenu->nHDistance-6; if(pMenu->nCols*pMenu->nRows < pMenu->nMenuItemCount) { // GUI_DrawRect(x+5, row+1, col-1, row+7); if(nMaxItem<pMenu->nMenuItemCount) MenuDrawTriangle(col, row, 2, 1); else MenuDrawTriangle(col, row, 2, 0); if(nStartItem>1) MenuDrawTriangle(x, row, 1, 1); else MenuDrawTriangle(x, row, 1, 0); } } else // 水平方向排列 { // 计算当前屏显示菜单的最大序号和最小序号 nMaxItem = nStartItem + pMenu->nCols * pMenu->nRows - 1; if(nMaxItem>pMenu->nMenuItemCount) nMaxItem = pMenu->nMenuItemCount; // 显示当前屏的菜单项 for(i=nStartItem; i<=nMaxItem; i++) { row = (i-nStartItem)/pMenu->nCols; col = (i-nStartItem)%pMenu->nCols; mWidth=CaculateStringWidth(12, pMenu->strMenuItems[nCurItem-1]); if(i==nCurItem) { DrawRect(x+col*(pMenu->nHDistance+uWidth), y+row*(pMenu->nVDistance+12)-1, x+col*(pMenu->nHDistance+uWidth)+mWidth-1, y+row*(pMenu->nVDistance+12)+12,1); TextOut12I(x+col*(pMenu->nHDistance+uWidth), y+row*(pMenu->nVDistance+12), pMenu->strMenuItems[i-1]); } else { DrawRect(x+col*(pMenu->nHDistance+uWidth), y+row*(pMenu->nVDistance+12)-1, x+col*(pMenu->nHDistance+uWidth)+mWidth-1, y+row*(pMenu->nVDistance+12)+12,0); TextOut12(x+col*(pMenu->nHDistance+uWidth), y+row*(pMenu->nVDistance+12), pMenu->strMenuItems[i-1]); } } // 菜单滚动时绘制箭头 row = y + pMenu->nRows*(pMenu->nVDistance+12)-pMenu->nVDistance; col = x + pMenu->nCols*(pMenu->nHDistance+uWidth)-pMenu->nHDistance+2; if(pMenu->nCols*pMenu->nRows < pMenu->nMenuItemCount) { // GUI_DrawRect(col, y+5, col+6, row-7); if(nMaxItem<pMenu->nMenuItemCount) MenuDrawTriangle(col, row, 4, 1); else MenuDrawTriangle(col, row, 4, 0); if(nStartItem>1) MenuDrawTriangle(col, y, 3, 1); else MenuDrawTriangle(col, y, 3, 0); } } return nStartItem; } // -------------------------------------------------------------------------------- // 描 述: 改变当前用户的菜单选项 // 参 数: // x,y 菜单的左上角屏幕坐标(象素) // pMenu 菜单指针 // pnMinItem,pnMaxItem 当前屏左上角菜单项序号和最大菜单项序号指针 // pnCurItem 当前所选的菜单项 // nNewItem 新菜单项 // 输  出: // 如果选择中菜单发生滚动,将自动改变 pnMinItem 和 pnMaxItem 所指向的值 // 如果改变菜单选项成功,新菜单项序号将保存在 pnCurItem 所指向的值中 // // 返回值: 如果新选项有效返回 TRUE,否则返回 FALSE //-------------------------------------------------------------------------------- BOOL MenuMoveSel(int x, int y, PPOSMENU pMenu, int *pnMinItem, int *pnMaxItem, int *pnCurItem, int nNewItem) { int nCurItem = *pnCurItem, nMinItem = *pnMinItem, nMaxItem = *pnMaxItem, uTemp; int row, col, uWidth,mWidth; if(nNewItem>pMenu->nMenuItemCount) nNewItem = pMenu->nMenuItemCount; else if(nNewItem<1) return FALSE; if(nCurItem == nNewItem) return TRUE; uWidth = CaculateStringWidth(12, pMenu->strMenuItems[0]); if(!pMenu->bDirection) // 如果菜单按照垂直方向排列 { if(nNewItem>=(*pnMinItem) && nNewItem<=(*pnMaxItem)) // 如果在当前屏,不需要滚动显示 { // 恢复旧选项的显示 col = (nCurItem-nMinItem)/pMenu->nRows; row = (nCurItem-nMinItem)%pMenu->nRows; mWidth=CaculateStringWidth(12, pMenu->strMenuItems[nCurItem-1]); DrawRect(x+col*(pMenu->nHDistance+uWidth), y+row*(pMenu->nVDistance+12)-1, x+col*(pMenu->nHDistance+uWidth)+mWidth-1, y+row*(pMenu->nVDistance+12)+12,0); TextOut12(x+col*(pMenu->nHDistance+uWidth), y+row*(pMenu->nVDistance+12), pMenu->strMenuItems[nCurItem-1]); // 高亮显示新选项 col = (nNewItem-nMinItem)/pMenu->nRows; row = (nNewItem-nMinItem)%pMenu->nRows; mWidth=CaculateStringWidth(12, pMenu->strMenuItems[nNewItem-1]); DrawRect(x+col*(pMenu->nHDistance+uWidth), y+row*(pMenu->nVDistance+12)-1, x+col*(pMenu->nHDistance+uWidth)+mWidth-1, y+row*(pMenu->nVDistance+12)+12,1); TextOut12I(x+col*(pMenu->nHDistance+uWidth), y+row*(pMenu->nVDistance+12), pMenu->strMenuItems[nNewItem-1]); LCD_ForceRefresh(); } else // 如果不在当前屏,需要滚动显示 { if(nNewItem>nMaxItem) // 如果需要向右滚动 { while(nMaxItem<nNewItem) { nMinItem += pMenu->nRows; nMaxItem += pMenu->nRows; for(uTemp=pMenu->nMenuItemCount+1; uTemp<=nMaxItem; uTemp++) { col = x + (uTemp-nMinItem)/pMenu->nRows*(pMenu->nHDistance+uWidth); row = y + (uTemp-nMinItem)%pMenu->nRows*(pMenu->nVDistance+12); FillRect(col, row-1, col+uWidth-1, row+12, 0); } if(nMaxItem>pMenu->nMenuItemCount) nMaxItem = pMenu->nMenuItemCount; } } else // 如果需要向左滚动 { while(nMinItem>nNewItem) { nMinItem -= pMenu->nRows; nMaxItem = nMinItem + pMenu->nRows*pMenu->nCols - 1; if(nMaxItem>pMenu->nMenuItemCount) nMaxItem = pMenu->nMenuItemCount; } } MenuDisplay(x, y, pMenu, nMinItem, nNewItem); *pnMinItem = nMinItem; *pnMaxItem = nMaxItem; LCD_ForceRefresh(); } } else // 如果菜单按照水平方向排列 { if(nNewItem>=(*pnMinItem) && nNewItem<=(*pnMaxItem)) // 如果在当前屏,不需要滚动显示 { // 恢复旧选项的显示 row = (nCurItem-nMinItem)/pMenu->nCols; col = (nCurItem-nMinItem)%pMenu->nCols; mWidth=CaculateStringWidth(12, pMenu->strMenuItems[nCurItem-1]); DrawRect(x+col*(pMenu->nHDistance+uWidth), y+row*(pMenu->nVDistance+12)-1, x+col*(pMenu->nHDistance+uWidth)+mWidth-1, y+row*(pMenu->nVDistance+12)+12,0); TextOut12(x+col*(pMenu->nHDistance+uWidth), y+row*(pMenu->nVDistance+12), pMenu->strMenuItems[nCurItem-1]); // 高亮显示新选项 row = (nNewItem-nMinItem)/pMenu->nCols; col = (nNewItem-nMinItem)%pMenu->nCols; mWidth=CaculateStringWidth(12, pMenu->strMenuItems[nNewItem-1]); DrawRect(x+col*(pMenu->nHDistance+uWidth), y+row*(pMenu->nVDistance+12)-1, x+col*(pMenu->nHDistance+uWidth)+mWidth-1, y+row*(pMenu->nVDistance+12)+12,1); TextOut12I(x+col*(pMenu->nHDistance+uWidth), y+row*(pMenu->nVDistance+12), pMenu->strMenuItems[nNewItem-1]); LCD_ForceRefresh(); } else { if(nNewItem>nMaxItem) // 如果需要向下滚动 { while(nMaxItem<nNewItem) { nMinItem += pMenu->nCols; nMaxItem += pMenu->nCols; for(uTemp=pMenu->nMenuItemCount+1; uTemp<=nMaxItem; uTemp++) { col = x + (uTemp-nMinItem)%pMenu->nCols*(pMenu->nHDistance+uWidth); row = y + (uTemp-nMinItem)/pMenu->nCols*(pMenu->nVDistance+12); FillRect(col, row-1, col+uWidth-1, row+12, 0); } if(nMaxItem>pMenu->nMenuItemCount) nMaxItem = pMenu->nMenuItemCount; } } else // 如果需要向上滚动 { while(nMinItem>nNewItem) { nMinItem -= pMenu->nCols; nMaxItem = nMinItem + pMenu->nRows*pMenu->nCols - 1; if(nMaxItem>pMenu->nMenuItemCount) nMaxItem = pMenu->nMenuItemCount; } } MenuDisplay(x, y, pMenu, nMinItem, nNewItem); *pnMinItem = nMinItem; *pnMaxItem = nMaxItem; LCD_ForceRefresh(); } } *pnCurItem = nNewItem; return TRUE; } // -------------------------------------------------------------------------------- // 描 述: 显示并让用户选择菜单 // 参 数: // x,y 菜单的左上角屏幕坐标(象素) // pMenu 菜单指针 // nDefaultItem 默认选择的菜单项,以1为基数 // // 返回值: 所选择的菜单项,按照菜单项的添加顺序为1,2,3,…,出现错误或被取消返回0 // -------------------------------------------------------------------------------- int MenuDoModal(int x, int y, PPOSMENU pMenu, int nDefaultItem) { int i, nWidth, nTemp; int nMinItem, nMaxItem; // 本屏显示的菜单项的最小序号和最大序号 int nCurItem = nDefaultItem; u32 uKey; if(nDefaultItem > pMenu->nMenuItemCount || nDefaultItem < 1) return 0; nWidth = CaculateStringWidth(12, pMenu->strMenuItems[0]); if(!pMenu->bDirection) // 如果菜单按照垂直方向排列 { // 计算当前屏菜单项最小序号(对应当前屏左上角第一行、第一列的菜单项)和最大序号 i = pMenu->nCols; nTemp = (int)nDefaultItem; while(nTemp>0 && i>0) { nTemp -= pMenu->nRows; i--; } nTemp += pMenu->nRows; nTemp = (nTemp-1)/pMenu->nRows * pMenu->nRows + 1; nMinItem = (int)nTemp; nMaxItem = nMinItem + pMenu->nCols * pMenu->nRows -1; if(nMaxItem>pMenu->nMenuItemCount) nMaxItem = pMenu->nMenuItemCount; MenuDisplay(x, y, pMenu, nMinItem, nDefaultItem); // 从指定位置开始显示菜单 LCD_ForceRefresh(); // 键盘处理--菜单的选择与滚动处理 /* uKey = WaitKey(); while(1) { // OSTimeDly(200); switch(uKey) { case VK_CANCEL: if(pMenu->bCanBeCancel) return 0; break; case VK_LOGOUT: return 0; case VK_SURE: return nCurItem; case VK_UP: MenuMoveSel(x, y, pMenu, &nMinItem, &nMaxItem, &nCurItem, nCurItem-1); break; case VK_DOWN: MenuMoveSel(x, y, pMenu, &nMinItem, &nMaxItem, &nCurItem, nCurItem+1); break; case VK_LEFT: MenuMoveSel(x, y, pMenu, &nMinItem, &nMaxItem, &nCurItem, nCurItem-pMenu->nRows); break; case VK_RIGHT: MenuMoveSel(x, y, pMenu, &nMinItem, &nMaxItem, &nCurItem, nCurItem+pMenu->nRows); break; case VK_SHIFT: if(nCurItem >= pMenu->nMenuItemCount) MenuMoveSel(x, y, pMenu, &nMinItem, &nMaxItem, &nCurItem, 1); else MenuMoveSel(x, y, pMenu, &nMinItem, &nMaxItem, &nCurItem, nCurItem+1); break; } uKey = WaitKey(); }*/ } else // 菜单项按水平方向排列 { // 计算当前屏菜单项最小序号和最大序号 i = pMenu->nRows; nTemp = nDefaultItem; while(nTemp>0 && i>0) { nTemp -= pMenu->nCols; i--; } nTemp += pMenu->nCols; nTemp = (nTemp-1)/pMenu->nCols * pMenu->nCols + 1; nMinItem = nTemp; nMaxItem = nMinItem + pMenu->nRows * pMenu->nCols -1; if(nMaxItem>pMenu->nMenuItemCount) nMaxItem = pMenu->nMenuItemCount; MenuDisplay(x, y, pMenu, nMinItem, nDefaultItem); LCD_ForceRefresh(); // 键盘处理--菜单的选择与滚动处理 /* uKey = WaitKey(); while(1) { switch(uKey) { case VK_CANCEL: if(pMenu->bCanBeCancel) return 0; break; case VK_LOGOUT: return 0; case VK_SURE: return nCurItem; case VK_UP: MenuMoveSel(x, y, pMenu, &nMinItem, &nMaxItem, &nCurItem, nCurItem-pMenu->nCols); break; case VK_DOWN: MenuMoveSel(x, y, pMenu, &nMinItem, &nMaxItem, &nCurItem, nCurItem+pMenu->nCols); break; case VK_LEFT: MenuMoveSel(x, y, pMenu, &nMinItem, &nMaxItem, &nCurItem, nCurItem-1); break; case VK_RIGHT: MenuMoveSel(x, y, pMenu, &nMinItem, &nMaxItem, &nCurItem, nCurItem+1); break; case VK_SHIFT: if(nCurItem >= pMenu->nMenuItemCount) MenuMoveSel(x, y, pMenu, &nMinItem, &nMaxItem, &nCurItem, 1); else MenuMoveSel(x, y, pMenu, &nMinItem, &nMaxItem, &nCurItem, nCurItem+1); break; } uKey = WaitKey(); }*/ } //for test // TextOut12(80,80,"门前大桥下"); // LCD_ForceRefresh(); return 0; }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值