zoukankan      html  css  js  c++  java
  • openwrt-安装-驱动-应用-lcd2004a实验

    1. 板子f403tech的RT5350的板子和

    (1)openWRT系统的定义和特点
            OpenWrt是一个高度模块化、高度自己主动化的嵌入式Linux系统。拥有强大的网络组件。经常被
    用于工控设备、电话、小型机器人、智能家居、路由器以及VOIP设备中。


            OpenWrt支持各种处理器架构。不管是对ARM。X86。PowerPC或者MIPS都有非常好的支持。


            其多达3000多种软件包。囊括从工具链(toolchain)。到内核(linux kernel),到软件包
    (packages)。再到根文件系统(rootfs)整个体系,使得用户仅仅需简单的一个make命令就可以方便快
    速地定制一个具有特定功能的嵌入式系统来制作固件。 其模块化设计也能够方便的移植各类功能
    到OpenWrt下,加快开发速度。

    2 实验mjpeg-streamer、uvc视频监控

    3 openwrt的下载安装

    <pre name="code" class="cpp">sudo apt-get install subversion
    sudo apt-get install git-core
    sudo apt-get install gcc g++ binutils patch bzip2 flex bison make autoconf gettext texinfo unzip sharutils zlib1g-dev libncurses5-dev gawk
    mkdir openwrt
    cd openwrt/
    svn co svn://svn.openwrt.org/openwrt/trunk
    cd trunk/
    ./scripts/feeds update -a
    ./scripts/feeds install -a
    (4) 配置编译openWRT系统
    a、选择CPU型号
    TargetSystem —> RalinkRT288x/RT3xxx
    b、选择CPU子型号
    Subtarget —> RT3x5x/RT5350basedboards
    c、选择详细路由器型号
    Targetprofile—>HAME-MPR-A2
    (5) 编译
    make V=99
    至此,完毕内核和文件系统镜像编译


    4 驱动开发流程
    进入/home/openwrt/trunk/package/kernel驱动文件夹,仿照參考其它的驱动。

    新建example目录,进入example目录。



    创建Makefile:
    #
    # Copyright (C) 2008-2012 OpenWrt.org
    #
    # This is free software, licensed under the GNU General Public License v2.
    # See /LICENSE for more information.
    # modify by 2014-10-23

    include $(TOPDIR)/rules.mk
    include $(INCLUDE_DIR)/kernel.mk

    PKG_NAME:=example
    PKG_RELEASE:=1

    include $(INCLUDE_DIR)/package.mk

    define KernelPackage/example
      SUBMENU:=Other modules
    #  DEPENDS:=@!LINUX_3_3
      TITLE:=Simple example driver
      FILES:=$(PKG_BUILD_DIR)/example.ko
    #  AUTOLOAD:=$(call AutoLoad,30,gpio-button-hotplug,1)
      KCONFIG:=
    endef

    define KernelPackage/example/description
     This is a example for the following in-kernel drivers:
     1) example one
     2) example two
    endef

    MAKE_OPTS:=
            ARCH="$(LINUX_KARCH)"
            CROSS_COMPILE="$(TARGET_CROSS)"
            SUBDIRS="$(PKG_BUILD_DIR)"

    define Build/Prepare
            mkdir -p $(PKG_BUILD_DIR)
            $(CP) ./src/* $(PKG_BUILD_DIR)/
    endef

    define Build/Compile
            $(MAKE) -C "$(LINUX_DIR)"
                    $(MAKE_OPTS)
                    modules
    endef

    $(eval $(call KernelPackage,example))

    新建srce目录。进入src目录。
    创建Makefile:
    obj-m += example.o
    创建example.c源文件
    #include <linux/module.h>
    #include <linux/version.h>
    #include <linux/kmod.h>
    
    
    
    
    static int __init example_init(void)
    {
            printk("hello example openwrt
    ");
            return 0;
    }
    
    static void __exit example_exit(void)
    {
            printk("hello example openwrt exit
    ");
    }
    
    module_init(example_init);
    module_exit(example_exit);
    
    MODULE_AUTHOR("zhaochuang8888@126.com");
    MODULE_DESCRIPTION("example driver");
    MODULE_LICENSE("GPL");
    MODULE_ALIAS("platform:" DRV_NAME);
    
    c.编译驱动的命令
    make package/kernel/example/compile V=99
    <pre name="code" class="cpp"><pre name="code" class="cpp">在/home/openwrt/trunk/bin/ramips/packages/base文件夹生成:kmod-example_3.14.18-1_ramips_24kec.ipk 
    
    
    
    5 应用开发流程
    进入/home/openwrt/trunk/package应用文件夹。參考其它的应用文件。
    创建helloworld目录。并进入。


    创建Makefile:
    ##############################################
    # OpenWrt Makefile for helloworld program
    #
    #
    # Most of the variables used here are defined in
    # the include directives below. We just need to
    # specify a basic description of the package,
    # where to build our program, where to find
    # the source files, and where to install the
    # compiled program on the router.
    #
    # Be very careful of spacing in this file.
    # Indents should be tabs, not spaces, and
    # there should be no trailing whitespace in
    # lines that are not commented.
    #
    ##############################################

    include $(TOPDIR)/rules.mk

    # Name and release number of this package
    PKG_NAME:=helloworld
    PKG_RELEASE:=1


    # This specifies the directory where we're going to build the program.
    # The root build directory, $(BUILD_DIR), is by default the build_mipsel
    # directory in your OpenWrt SDK directory
    PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME)


    include $(INCLUDE_DIR)/package.mk

     

    # Specify package information for this program.
    # The variables defined here should be self explanatory.
    # If you are running Kamikaze, delete the DESCRIPTION
    # variable below and uncomment the Kamikaze define
    # directive for the description below
    define Package/helloworld
        SECTION:=utils
        CATEGORY:=Utilities
        TITLE:=Helloworld -- prints a snarky message
    endef


    # Uncomment portion below for Kamikaze and delete DESCRIPTION variable above
    define Package/helloworld/description
            If you can't figure out what this program does, you're probably
            brain-dead and need immediate medical attention.
    endef

     

    # Specify what needs to be done to prepare for building the package.
    # In our case, we need to copy the source files to the build directory.
    # This is NOT the default.  The default uses the PKG_SOURCE_URL and the
    # PKG_SOURCE which is not defined here to download the source from the web.
    # In order to just build a simple program that we have just written, it is
    # much easier to do it this way.
    define Build/Prepare
        mkdir -p $(PKG_BUILD_DIR)
        $(CP) ./src/* $(PKG_BUILD_DIR)/
    endef


    # We do not need to define Build/Configure or Build/Compile directives
    # The defaults are appropriate for compiling a simple program such as this one


    # Specify where and how to install the program. Since we only have one file,
    # the helloworld executable, install it by copying it to the /bin directory on
    # the router. The $(1) variable represents the root directory on the router running
    # OpenWrt. The $(INSTALL_DIR) variable contains a command to prepare the install
    # directory if it does not already exist.  Likewise $(INSTALL_BIN) contains the
    # command to copy the binary file from its current location (in our case the build
    # directory) to the install directory.
    define Package/helloworld/install
        $(INSTALL_DIR) $(1)/bin
        $(INSTALL_BIN) $(PKG_BUILD_DIR)/helloworld $(1)/bin/
    endef


    # This line executes the necessary commands to compile our program.
    # The above define directives specify all the information needed, but this
    # line calls BuildPackage which in turn actually uses this information to
    # build a package.
    $(eval $(call BuildPackage,helloworld))
    创建src目录,并进入。
    创建Makefile:
    # build helloworld executable when user executes "make"

    helloworld: helloworld.o
            $(CC) $(LDFLAGS) helloworld.o -o helloworld

    helloworld.o: helloworld.c
            $(CC) $(CFLAGS) -c helloworld.c

    # remove object files and executable when user executes "make clean"
    clean:
            rm *.o helloworld
    创建helloworld.c:
    #include<stdio.h>
    int main(void)
    {
            printf("helloworld ");
            return 0;
    }

    make package/helloworld/motor/compile V=99
    在/home/openwrt/trunk/bin/ramips/packages/base文件夹生成:helloworld_1_ramips_24kec.ipk


    5 LCD2004实验

    lcd_204a_drv.c 驱动源程序:

    #include <linux/module.h>
    #include <linux/kernel.h>
    #include <linux/fs.h>
    #include <linux/init.h>
    #include <linux/delay.h>
    #include <linux/device.h>

    #include <asm/uaccess.h>
    #include <asm/irq.h>
    #include <asm/io.h>

    static struct class *lcddrv_class;
    static struct device *lcddrv_class_dev;

    volatile unsigned long *GPIOMODE;
    volatile unsigned long *I2C_CONFIG;
    volatile unsigned long *I2C_CLKDIV;
    volatile unsigned long *I2C_DEVADDR;
    volatile unsigned long *I2C_ADDR;
    volatile unsigned long *I2C_DATAOUT;
    volatile unsigned long *I2C_STATUS;
    volatile unsigned long *I2C_STARTXFR;
    volatile unsigned long *I2C_BYTECNT;

    static int lcd_204a_open(struct inode *inode, struct file *file)
    {
        return 0;
    }

    static ssize_t lcd_204a_write(struct file *file, const char __user *buf, size_t size, loff_t *ppos)
    {
        unsigned char val;

        copy_from_user(&val, buf, 1);

        *I2C_CONFIG = (0x6<<2)|(1<<1);                // 设备地址是7bit、不用发地址
        *I2C_DEVADDR = 0x20;                        // 设备地址为0x20

        *I2C_DATAOUT = val;

        *I2C_STARTXFR = 0x0;

        while(*I2C_STATUS & 0x1);
        
        return 1;
    }

    static struct file_operations sencod_drv_fops = {
        .owner        = THIS_MODULE,    /* 这是一个宏,推向编译模块时自己主动创建的__this_module变量 */
        .open        = lcd_204a_open,
        .write        = lcd_204a_write,
    };

    int major;
    static int lcd_204a_init(void)
    {
        major = register_chrdev(0, "lcd_204a", &sencod_drv_fops);

        lcddrv_class = class_create(THIS_MODULE, "lcd");
        lcddrv_class_dev = device_create(lcddrv_class, NULL, MKDEV(major, 0), NULL, "lcd"); /* /dev/204a */
        
        /* 映射对应的寄存器的地址 */
        GPIOMODE = (volatile unsigned long *)ioremap(0x10000060, 4);
        I2C_CONFIG = (volatile unsigned long *)ioremap(0x10000900, 4);
        I2C_CLKDIV = (volatile unsigned long *)ioremap(0x10000904, 4);
        I2C_DEVADDR = (volatile unsigned long *)ioremap(0x10000908, 4);
        I2C_ADDR = (volatile unsigned long *)ioremap(0x1000090C, 4);
        I2C_DATAOUT = (volatile unsigned long *)ioremap(0x10000910, 4);
        I2C_STATUS = (volatile unsigned long *)ioremap(0x10000918, 4);
        I2C_STARTXFR = (volatile unsigned long *)ioremap(0x1000091C, 4);
        I2C_BYTECNT = (volatile unsigned long *)ioremap(0x10000920, 4);

        /* 開始设置这些寄存器 */
        *GPIOMODE &= ~(1<<0);                        // I2C_GPIO_MODE
        *I2C_CLKDIV = 0x200;                            // IIC总线时钟 = 40MHz / 512 = 79KHz
        
        return 0;
    }

    static void lcd_204a_exit(void)
    {
        unregister_chrdev(major, "lcd_204a");
        device_unregister(lcddrv_class_dev);
        class_destroy(lcddrv_class);
        iounmap(GPIOMODE);
        iounmap(I2C_CONFIG);
        iounmap(I2C_CLKDIV);
        iounmap(I2C_DEVADDR);
        iounmap(I2C_ADDR);
        iounmap(I2C_DATAOUT);
        iounmap(I2C_STATUS);
        iounmap(I2C_STARTXFR);
        iounmap(I2C_BYTECNT);
    }

    module_init(lcd_204a_init);
    module_exit(lcd_204a_exit);

    MODULE_LICENSE("GPL");

    lcd2004的应用程序:


    #include <sys/types.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    #include <stdio.h>
    //依据LCD2004A和PCF8574T的引脚确定
    //RS:指令/数据 寄存器选择  RS = 0 : 指令寄存器 RS = 1 : 数据寄存器   依据原理图得:RS 与 PCF8574T的PO链接
    //RW:读/写 选择   R/W = 0 : 写     R/W = 1 : 读  依据原理图得:RW 与 PCF8574T的P1链接
    //CS:同意信号    表示从高电平到低电平,
    #define DATA(rs, rw, cs, data) (data<<4)|(cs<<2)|(rw<<1)|rs

    int fd;

    static void lcd_write_command(unsigned char command)
    {
        unsigned char data;

        /* 1.发送命令的高4位 */
        data = DATA(0, 0, 1, (command>>4));
        printf("h data = %d ", data);
        write(fd, &data, 1);
        usleep(20);
        data = DATA(0, 0, 0, (command>>4));
        printf("h data = %d ", data);
        write(fd, &data, 1);

        /* 2.发送命令的低4位 */
        data = DATA(0, 0, 1, (command&0x0f));
        printf("l data = %d ", data);
        write(fd, &data, 1);
        usleep(20);
        data = DATA(0, 0, 0, (command&0x0f));
        printf("l data = %d ", data);
        write(fd, &data, 1);
    }

    static void lcd_write_data(unsigned char wdata)
    {
        unsigned char data;

        /* 1.发送命令的高4位 */
        data = DATA(1, 0, 1, (wdata>>4));
        printf("h data = %d ", data);
        write(fd, &data, 1);
        usleep(20);
        data = DATA(1, 0, 0, (wdata>>4));
        printf("h data = %d ", data);
        write(fd, &data, 1);

        /* 2.发送命令的低4位 */
        data = DATA(1, 0, 1, (wdata&0x0f));
        printf("l data = %d ", data);
        write(fd, &data, 1);
        usleep(20);
        data = DATA(1, 0, 0, (wdata&0x0f));
        printf("l data = %d ", data);
        write(fd, &data, 1);
    }

    static void lcd_set_xy(unsigned char x, unsigned char y)
    {
        unsigned char address;

        if (y == 0)
            address = 0x80 + x;
        else
            address = 0xc0 + x;
        
        lcd_write_command(address);
    }

    /*
        函数名:
            lcd_write_char()
        功能:
            列x=0~15,行y=0,1
        使用方法:
    */
    static void lcd_write_char(unsigned char X,unsigned char Y,unsigned char Recdata)
    {
        lcd_set_xy(X, Y);
        lcd_write_data(Recdata);
    }

    static int lcd_PutStr(unsigned char *DData,int pos)
    {
        unsigned char i;
        
        if(pos==-1)
        {
            lcd_write_command(0x01); //清屏
            usleep(2);
            pos=0;
        }
        
        while((*DData)!='')
        {
            switch(*DData)
            {
                case ' ': //假设是 ,则换行   
                {
                    if(pos<21)
                    {
                        for(i=pos;i<20;i++)
                        lcd_write_char(i%20, i/20, ' ');
                        pos=20;
                    }
                    else
                    {
                        for(i=pos;i<40;i++)
                            lcd_write_char(i%20, i/20, ' ');
                        pos=40;
                    }
                    break;
                }

                case '': //假设是。则退格   
                {
                    if(pos>0)
                        pos--;
                    lcd_write_char(pos%20, pos/20, ' ');
                    break;
                }

                default:
                {
                    if((*DData)<0x20)
                    {
                        *DData=' ';
                    }

                    lcd_write_char(pos%20, pos/20,*DData);
                    pos++;
                    break;
                }
            }  
            DData++;
        }

        return(pos);
    }

    //从右边数。保留几位小数
    static int lcd_PutNum(unsigned long num,int XS,int pos)
    {
        unsigned long tmp=0;
        unsigned char numbits=0;
        
        if(pos==-1)
        {
            lcd_write_command(0x01);
            usleep(2);
            pos=0;
        }
        
        if(num==0)
        {
            lcd_write_char(pos%20, pos/20, '0');
            pos++;
        }
        else
        {
            if(num<0)
            {
                lcd_write_char(pos%20, pos/20, '-');
                num*=(-1);
                pos++;
            }

            while(num)
            {
                tmp=tmp*10+(num%10);
                num=num/10;
                numbits++;
            }
            
            while(tmp)
            {
                lcd_write_char(pos%20, pos/20, (tmp%10)+48);
                tmp=tmp/10;
                pos++;
                numbits--;
                if(numbits==XS)
                    pos=lcd_PutStr(".",pos); //显示小数点
            }
            
            while(numbits--)
            {
                lcd_write_char(pos%20, pos/20, '0');
                pos++;
            }
        }
        
        return(pos);
    }

    void lcd_put_char(unsigned char ch, unsigned int pos , int flag)
    {
        if(flag == 0)
        {
            lcd_write_command(0x80+pos);
        }
        if(flag == 1)
        {
            lcd_write_command(0xc0+pos);
        }
        lcd_write_data(ch);
    }

    void lcd_put_str(const char *str, int flag)
    {
        int cnt=0;
        while(*str !='')
        {
            lcd_put_char(*str, cnt, flag);
            cnt++;
            str++;
        }
    }
    /* seconddrvtest
      */
    int main(int argc, char **argv)
    {
        int p;
        
        fd = open("/dev/lcd", O_RDWR);
        if (fd < 0)
        {
            printf("can't open! ");
        }

        lcd_write_command(0x28);
        usleep(1000);
        lcd_write_command(0x28);
        usleep(1000);
        lcd_write_command(0x28);
        usleep(1000);

        lcd_write_command(0x0e);            // 显示开
        usleep(1000);
        lcd_write_command(0x01);            // 清屏
        usleep(1000);
        
    //    lcd_write_char(0, 0, "a");

        int i = 0;
        for(i=0; i<26; i++)
        {
            lcd_write_command(0x80+i);
            lcd_write_data('a'+i);
        }
        for(i=0; i<30; i++)
        {
            lcd_write_command(0xc0+i);
            lcd_write_data('2'+i);
        }

        
         sleep(10);    
        lcd_write_command(0x01);                        // 清屏
            usleep(1000);
        lcd_put_str("Welcome RT5350", 0);
        lcd_put_str("        --By Dreeam", 1);
        //p = lcd_PutStr("RT5350 By F403tech! ",0);    // 显示一段文字
        //usleep(1000);
        //p = lcd_PutStr("f403tech.taobao.com ",p);    // 显示一段文字
        //lcd_PutNum(1234,2,p);                // 显示12.34这个数

        return 0;
    }


    a.软件包管理经常使用命令
    opkg install xxx.ipk                        // 安装指定的软件包
    opkg remove xxx.ipk                            // 卸载已经安装过的指定的软件包
    opkg list                                                // 获取软件列表

    生成的驱动位于 /lib/modules/3.14.18/文件夹下。

    <pre name="code" class="cpp">生成的应用位于 /bin文件夹下。
    
    

    opkg help









    
    

    
       
    
  • 相关阅读:
    Java基础知识:正则表达式
    NodeJs 中 将表单数据转发到后台
    单片机的远程升级
    一些开源协议
    物联网的一些例子
    python一些开源特色库
    qt练习
    网页编程学习笔记
    PCB相关
    工业控制系统
  • 原文地址:https://www.cnblogs.com/tlnshuju/p/6995125.html
Copyright © 2011-2022 走看看