文章目录

  • 前言
  • 1 、第一次拿到开发板需要做什么
    • 1.1 、 开发板启动方式,接线方法
    • 1.2 、 开发板驱动安装
  • 2、U-BOOT的修改和完善
    • 2.1、简单的源码修改
      • 2.1.1、串口输出欢迎图案和语句
      • 2.1.2、lcd屏输出欢迎图案和语句
    • 2.2、增加u-boot命令
  • 3、内核裁剪
    • 3.1、裁剪过程
    • 3.2、裁剪方法和总结
  • 4、根文件系统制作,简单应用程序开发移植
    • 4.1、根文件系统制作
    • 4.2、sqlite移植
      • 4.2.1、sqlite移植方法
      • 4.2.2、基于sqlite的简单应用程序开发
    • 4.3、简单交互式应用开发
      • 4.3.1、驱动程序编写与测试
      • 4.3.2、基于按键,led,lcd的简单交互式应用开发
  • 5、代码附录

前言

使用基于S5PV210的TQ210开发板,从最底层的u-boot修改移植到简单交互式应用开发,一步一步修改移植,本文主要涉及移植和修改的方法,并给出在该过程中可能遇到的错误和解决错误的办法,主要讲解第一次拿到开发板需要做的事情,u-boot的修改和移植,linux内核裁剪,根文件系统制作和简单交互式应用开发。

1 、第一次拿到开发板需要做什么

1.1 、 开发板启动方式,接线方法

  • 拿到开发板后,首先要先了解开发板的启动方式,flash是nor还是nand,有几个串口等等一些基本信息。我拿到的是TQ210v4的7寸电容屏,基于S5PV210 Cortex_A8,1GHz主频,1GB DDR2和1GB NandFlash,2路5线RS232,4路TTL,1路RS485(复用),1路2.0下载接口;了解完上面信息后,拨码开关拨到off on off off则是NandFlash启动,第一次拿到开发板,一般板子里面的系统都是好的,都能启动到文件系统,7寸电容屏上会显示操作界面可以进行操作,如果拨到其他的位置,会使电容屏白屏,启动蜂鸣器。SD卡启动拨码是off on on off;USB启动的拨码方法只需要把OM5拨到on就行。
  • 由于配件里面只有一条两头都是母头的RS232线,所以我们需要自己购买一条公头的usb转RS232的线,这里只能用公头的usb线配上配件的双母头线才能使串口正常工作,是有区分直连串口线和交叉串口线的。串口要接COM1,原u-boot使能的只有COM1,只有接COM1才会打印调试信息,接COM2不会有东西打印。

1.2 、 开发板驱动安装

  • 开发板需要安装2个驱动,一个是串口驱动,一个是USB下载驱动,这两个驱动都可以在官方资料\Windows平台工具下找的到,首先我们需要打开电脑的设备管理器,点击更新驱动,按路径查找更新,把路径指定到官方资料\Windows平台工具,然后更新驱动,更新驱动的过程中可能会出现数字签名错误问题,解决方法就是重新设置一下电脑,打开电脑的高级启动选项–>选择立刻启动–>疑难解答–>高级选择–>启动设置–>按F7,禁止驱动强制数字签名;驱动安装成功后,用串口软件就可以看到开发板的调试信息了,我们可以在开机前,按住电脑的空格键,然后打开电源,就可以看到串口进入到u-boot菜单,我们可以在这个菜单重新烧写logo图,内核,根文件系统什么的;
  • 这里如果想要烧写logo图,首先我们需要接上串口线和usb下载线,再把我们准备的图片,通过官方资料\Windows平台工具\Image2LCD 里的软件工具,制作成一个bin文件(可烧写格式),然后在串口输入4,出现OTG cable Connected!Now, Waiting for DNW to transmit data,既表示可以下载了,然后用管理员身份打开官方资料\Windows平台工具\EmbedSkyDownLoadTool,点击USB下载–>UBOOT–>选择文件,选择我们之前生成的bin文件,烧进去就可以了,重新启动开发板就可以看到更改的logo图了;

2、U-BOOT的修改和完善

2.1、简单的源码修改

2.1.1、串口输出欢迎图案和语句

在uboot_TQ210_1.3.4\common\main.c里面修改代码,在代码的第613行,添加printf(“Welcome xujiayue”),就会在启动内核前输出一条Welcome xujiayue,到串口软件里面就可以看到;修改完代码后,我们要重新配置,编译,然后烧写进开发板,配置的命令用make TQ210_config ,编译用make(整个配置编译的过程不要在共享文件夹下);最后把u-boot文件复制到我们的window主机下,通过天嵌自带的下载软件,用u-boot菜单烧写进开发板;在此基础上我用printf输出了一个心型图,如下图所示。

2.1.2、lcd屏输出欢迎图案和语句

关于lcd的显示可以用这个函数Lcd_printf,根据实例Lcd_printf(0,16,RGB(0,0,0xff),0,1,"Welcome using TQ210 Board! ");0和16是lcd的行和列,其实0是08,16是116,代表第0行第一列,RGB是颜色函数,往里面写不同的值就显示什么颜色的字符串,0,1保持不变,最后加上要输出的字符串就行了;在这个的基础上我打印了欢迎图案和欢迎语句;

2.2、增加u-boot命令

  • 在修改完欢迎图案和语句后,我又想给u-boot命令加多一条,可以查找编辑者信息和所编辑的内容;这个主要在common目录下,新建一个命令文件cmd_editor.c;关于u-boot命令,首先我们在u-boot下,可以输入信息,串口接收信息后会解析信息,匹配信息,再而调用某个函数来执行这些命令,下面我就简单地介绍一下,具体代码的实现;

①在include/command.h下可以找到这样的一个结构体:

  • 这个结构体有:命令的名字,参数的最大值,是否重复(就是按回车是否重复上次输入的命令),函数指针,这个命令所要执行的函数,短帮助信息,长帮助信息。

②在链接脚本中可以看到这样子的信息:

  • 这里定义了__u_boot_cmd_star和__u_boot_cmd_end,这两个值表示.u_boot_cmd段存放的首地址和结束地址,这个.u_boot_cmd段主要是一些命令结构体代码,就是上面介绍的那个结构体;在command.c中会用到这两个值,从而快速地找到命令,分析命令;

③在command.h中有这样子的定义:
#define Struct_Section attribute ((unused,section (".u_boot_cmd")))

define U_BOOT_CMD(name,maxargs,rep,cmd,usage,help)
cmd_tbl_t _u_boot_cmd##name Struct_Section = {#name, maxargs, rep, cmd, usage, help}

④再随便打开一个命令文件,我打开了cmd_bootm.c可以看到:

结合bootm实例展开分析 U_BOOT_CMD这个宏结果为:
#define U_BOOT_CMD(name,maxargs,rep,cmd,usage,help)
cmd_tbl_t __u_boot_cmd_bootm attribute ((unused,section (".u_boot_cmd")))
= {bootm,
CFG_MAXARGS,
1,
do_bootm,
“bootm - boot application image from memory\n”,

“[addr [arg …]]\n - boot application image stored in memory\n”
“\tpassing arguments ‘arg …’; when booting a Linux kernel,\n”
“\t’arg’ can be the address of an initrd image\n”
#if defined(CONFIG_OF_LIBFDT)
“\tWhen booting a Linux kernel which requires a flat device-tree\n”
“\ta third argument is required which is the address of the\n”
“\tdevice-tree blob. To boot that kernel without an initrd image,\n”
“\tuse a ‘-’ for the second argument. If you do not pass a third\n”
“\ta bd_info struct will be passed instead\n”
#endif
#if defined(CONFIG_FIT)
“\t\nFor the new multi component uImage format (FIT) addresses\n”
“\tmust be extened to include component or configuration unit name:\n”
“\taddr:<subimg_uname> - direct component image specification\n”
“\taddr#<conf_uname> - configuration specification\n”
“\tUse iminfo command to get the list of existing component\n”
“\timages and configurations.\n”
#endif}

这段代码的意思是实例化宏U_BOOT_CMD的结果是定义一个cmd_tbl_t类型的结构体,这个结构体有个属性,就是强制将该结构体的段,设置为.u_boot_cmd段,剩下的就是填充结构体内容;

⑤在搞清楚这些后,剩下的就只需要实例化一个U_BOOT_CMD宏,然后编写一个函数执行命令就行了;下面是我的命令代码:

⑥在写好代码后还要对common目录下的makefile进行修改,把我们的命令文件加进去编译;增加COBJS-y += cmd_editor.o

⑦查看第一位编辑者的信息:

3、内核裁剪

3.1、裁剪过程

  1. 编译内核:
    复制Kernel_3.0.8_TQ210_coreB_Linux_v2.4.tar.bz2到虚拟机并解压,进入解压的文件夹中,使用命令cp config_for_TQ210_Linux_v2.1_CoreB .config,先使用天嵌的配置文件 ,再输入make menuconfig,会出现一个菜单配置框,第一次先默认保存,然后使用make zImage进行编译,生成zImage.bin;
  2. 第一次编译内核出错误:

    解决方法:将kernel/timeconst.pl中第373行的defined()去掉只留下@val就可以了
  3. 解决后又出现错误:

    大概了解后,主要有二个点可能出问题,mmu模块出错?交叉编译工具链在makefile里面没配置?一般内核文件是不可能出错的,所以重点放在了交叉编译工具链上,找了makefile文件发现确实没有配置,但配置上了还是不行,又看了.config文件发现在里面已经配置了,所以最后怀疑是交叉编译工具链的版本问题,换上天嵌自带的交叉编译工具链就成功了;
  4. 出现kernel/bounds.s问题:

    解决方法:这个报错的主要原因是makefile里面没有配置交叉编译工具,可以修改makefile也可以把原来的.config删除,复制一份config_for_TQ210_Linux_v2.1_CoreB为.config,然后编译就行了,这是因为出厂文件config_for_TQ210_Linux_v2.1_CoreB里面有配置交叉编译工具;或者在配置菜单中打开天嵌的配置文件,在这基础上进行修改配置,最后记得要点保存,才会生成.config,不然修改后的文件会被保存为天嵌的配置文件里面;
  5. 编译成功后,把zImage.bin烧进开发板后,发现不能启动根文件系统;

    根文件系统的init进程找不到,主要有三个问题:u-boot启动参数bootargs设置错了?根文件系统的init是否存在?根文件系统是否正常?这里主要是要验证内核是否正常,所以我直接重新烧写了份新的出厂镜像文件系统,就解决了,正常挂载。
  6. 第一次尝试修改配置菜单,把所有设备文件取消掉,看看现象,编译出现错误;

    解决方法:重新复制份出厂文件config_for_TQ210_Linux_v2.1_CoreB为.config;
  7. 一波乱裁剪:裁剪了大量的驱动后出现错误:


    解决方法:重新裁剪;
  8. 一步一步慢慢裁剪出错:

    解决方法:把usb host支持重新选上编译就不会报这个错了;

    解决方法:安全配置出错,菜单配置重新取消掉安全配置就行;

    解决方法:触摸屏需要与电源相关的配置,重新把电源的配置选上;
  9. 在最后裁剪完,只剩下2.2M,也能正常启动根文件系统,shell命令正常使用;

3.2、裁剪方法和总结

对内核的裁剪,我是一步一步慢慢来裁剪,然后编译,烧进开发板,以能启动文件系统为最终目标,如果可以启动文件系统,我就把根目录下的.config复制一份,保存起来,方便如果出错的话,可以后悔上一步操作,重新裁剪上一步;如果没有保存的话,又是裁剪了很久才发现有错误,可以先查看错误信息,一般都有报是哪个目录下哪个文件错误,这个可以通过它报错的目录下的文件名字,找到是在配置菜单的哪个选项的,我们把它重新选上或者去掉就行了;内核源码每个子目录中,都有一个Makefile文件和Kconfig,Kconfig用于配置内核,它是各种配置界面的源文件,内核配置工具读取各个Kconfig文件,生成我们所看到的配置界面;可以根据上面报错的那个文件的名字,我们找到所在的目录下的Kconfig,在里面可以找到这个文件在配置菜单里面所匹配的菜单选项名,然后在配置菜单的首页打入/,进行名字搜索,从而对其进行重新配置修改;如果想更加精确找到报错文件所对应的配置菜单名字,可以结合那个目录下的makefile,两个一起看,就能精确地找出来。

4、根文件系统制作,简单应用程序开发移植

4.1、根文件系统制作

  1. 将资料里面的busybox-1.20.0_for_TQ210_V1.0.tar.bz2拷贝到虚拟机下自己的文件夹下。
  2. 解压:tar xjf busybox-1.20.0_for_TQ210_V1.0.tar.bz2
  3. 进入解压后的文件夹下:cp config_TQ210_V1.0 .config
  4. 使用命令make后,make isntall,返回上层目录,可以看到一个文件夹root_TQ210_fs;
  5. 进入刚刚生成文件夹root_TQ210_fs,在这个目录下创建etc目录: mkdir etc cd etc vi inittab(在这个里面写入下面内容) console::askfirst:-/bin/sh
    ::sysinit:/etc/init.d/rcS
    mkdir init.d cd init.d vi rcS(在这个里面写入下面内容) mount -t proc none /proc chmod +x rcS
  6. 返回文件夹root_TQ210_fs,创建dev目录,并创建2个最简单的字符设备文件: mkdir dev cd dev mknod console c 5 1 mknod null c 1 3
  7. 返回文件夹root_TQ210_fs,创建lib目录,把我们交叉编译工具链文件夹里面的lib库复制过来: cp /usr/local/4.4.6/arm-embedsky-linux-gnueabi/embedssky/lib/.so .
  8. 创建proc文件夹,这个是空文件夹,一定要有;
  9. 制作文件系统镜像,如果没找到工具mkyaffs2image,可以参考⑩制作工具方法: mkyaffs2image -i root_TQ210_fs yaffs.bin
  10. mkyaffs2image工具制作:下载yaffs源文件压缩包yaffs2-source.tar,解压,然后进入解压后的根目录下的utils文件夹下,执行make命令,把生成的mkyaffs2image复制到/usr/bin下就行了;

4.2、sqlite移植

4.2.1、sqlite移植方法

  1. 去https://sqlite.org/download.html官网下载sqlite源码包,含有autoconf字样的;
  2. 把下载好的源码包放到虚拟机下自己的文件夹下,并解压,进入到解压后的目录下;
  3. 输入命令生成makefile: ./configure --host=arm-linux --prefix=/home/even/xu
    –host 指定的是交叉编译工具的名字
    –prefix 指定的是一个目录名,这个会存放后面安装生成与sqlite相关的文件
  4. 有了makefile后,就可以执行make,然后执行命令make install,安装生成与sqlite相关的文件;
  5. 回到之前prefix指定的目录名/home/even/xu,可以看到里面多了四个文件夹,这时候我们只需把/home/even/xu/bin/sqlite3复制到我们根文件系统目录root_TQ210_fs/bin目录下,再把/home/even/xu/lib/libsqlite3.so.0.8.6复制到我们根文件系统目录root_TQ210_fs/lib目录下,就算移植成功了;
  6. 将文件系统重新制作镜像,烧进开发板后出现下图既移植成功:

4.2.2、基于sqlite的简单应用程序开发

sqlite有API接口函数,可以实现对数据库的创建,打开,创建表,插入数据,更新数据,删除数据等等操作;

  1. nt sqlite3_open(char *path, sqlite3 **db); 功能:打开sqlite数据库,成功返回SQLITE_OK, 失败则返回错误码。 char *path为数据库路径。 sqlite3
    **db为数据库操作句柄。
  2. int sqlite3_close(sqlite3 *db); 功能:关闭sqlite数据库, 成功返回SQLITE_OK,失败则返回错误码。 sqlite3 **db为数据库操作句柄。
  3. const char *sqlite3_errmsg(sqlite3 *db); 功能:返回错误信息。 sqlite3 **db为数据库操作句柄。
  4. int sqlite3_exec(sqlite3 *db, const char *sql, int (*callback)(void * para, int f_num, char ** f_value, char **name),
    void *argv, char **errmsg); 功能:通过程序完成sql命令。 sqlite3 **db为数据库操作句柄。
    const char *sq为sql命令。 int (*callback)(void * para, int f_num, char **
    f_value, char **name)为回调函数。 void *argv为传给回调函数的参数。 char
    **errmsg为返回的错误信息。 执行成功返回SQLITE_OK,失败返回错误码。
  5. 在这些接口函数的基础上,写代码,写完代码要在开发板上能运行起来需要用下面的命令格式进行交叉编译: arm-linux-gcc -I /home/even/xu/include/ -L /home/even/xu/lib -o sql test.c -l sqlite3
    -I指定了sqlite3.h所在路径。
    -L指定sqlite3的lib库路径。
    -l sqlite3,提供API接口函数支持 。 最后生成一个在开发板可以执行的可执行文件sql。
  6. 在掌握了上面知识后,我编写了程序,创建了2个数据库,一个用来放用户名和密码,一个用来放温度记录数据;程序我设计了一个登录界面菜单和操作界面菜单,首先有个选项可以选是新用户还是老用户,新用户就把数据存进数据库,老用户就在数据库里面查找账号密码是否存在;成功登录后就可以操作温度记录数据库,进行插入,修改,删除等操作;全部代码参考最后的附录,下面是一些结果展示图。


4.3、简单交互式应用开发

4.3.1、驱动程序编写与测试

  1. 驱动程序编写:一个简单的交互式程序的开发方式有很多种方法,这里由于裸机编程不能运行再加上内核裁剪时我把很多驱动都去掉了,所以这里我最后选择了自己编写驱动程序;以led为例简单介绍一下怎么编写驱动程序,首先找到原理图,查看是哪个gpio口,再查看芯片手册,找到对应的gpio控制器,对应开发板的是cpc1的3和4号;gpc1con的地址为0xe0200080,再根据描述选择对应的输出方式,再找到gpc1dat,这个总共四位,往里面那位写0,gpc1的哪个口就低电平;然而写驱动程序不单单说这需要这些,还需要一个明确的框架,需要先把框架搭建好,open,read,write,close什么的,程序写完需要写一个Makefile文件,对驱动程序进行编译,下面是一些相关截图;


  2. Makefile文件的编写:
    Makefile:
    KERN_DIR =/home/even/xjy/opt/EmbedSky/TQ210/Kernel_3.0.8_TQ210_for_Linux_v2.4
    all:
    make -C $(KERN_DIR) M=pwd modules
    clean:
    make -C $(KERN_DIR) M=pwd modules clean
    rm -rf modules.order
    obj-m += led.o

KERN_DIR指的是我内核的根目录的位置;

  • 测试程序:驱动写好,还需要一个makefile文件和测试文件来测试驱动的正常与否,测试文件里面打开的是设备节点,名字要写准确;测试文件的编译要用arm-linux-gcc,最后生成在开发板的可执行文件;测试文件编译用make;最后生成一个以ko结尾的模块文件,这个文件可以放到文件系统中,在开发板中用insmod xxx.ko命令加载进去文件系统,最后我们还需要根据之前说的主设备号,创建设备节点,命令:mknod led c 249 0,led是这个设备节点的名字,c代表是字符设备,249是主设备号(这个可以在代码里面自己定义),0是次设备号;

4.3.2、基于按键,led,lcd的简单交互式应用开发

  • 最后我继续搞了个按键驱动和lcd驱动;最后测试没有问题后我重新编写了一个交互程序,其实也可以认为是一个测试程序,我把三者结合起来,实现8个按键分别按下时lcd显示不同的颜色,同时led灯反转,全部代码请参考后面附录;测试成功后,我想要板子一开始就可以运行这个程序,所以我在根文件系统的/etc/init.d/rcS里修改,这个文件是一个脚本文件,可以在里面添加想自动执行的命令;

rcS:
mount -t proc none /proc
stty erase ^H
insmod /ko/1.ko
insmod /ko/key.ko
mknod /dev/buttons c 252 0
mknod /dev/fb0 c 29 0
mknod /dev/led c 249 0
/xjy/./test on
/xjy/./main &
这里的&是因为我这个程序是个死循环,不加这个,在串口控制台我结束不了它;

5、代码附录

u-boot命令代码:
cmd_editor.c:

#include <common.h>
#include <command.h>
#include <net.h>
#include <lcd/s5pv210_fb.h>
int do_edit (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
{int i;if (argc!=2){printf("error.............\n");printf ("Usage:\n%s\n", cmdtp->usage);return 1;}if(strcmp(argv[1],"1\0")==0){printf ("##     This is information about the editor     ##\n");printf ("##          Major    : IOT                      ##\n");printf ("##          number   : 201811672224             ##\n");printf ("##          Name     : xujiayue                 ##\n");printf ("##      The last editing date is 2020-11-07     ##\n");printf ("\n");printf("First  : before starting the kernel, output the welcome statement on the serial port and LCD respectively\n");printf("         Modify in common/main.c ---- output welcome statement\n");printf("Second : added a u-boot command ---- editor\n");printf("         In the common directory, add a cmd_editor.c , and modify the makefile file in the common directory\n");printf ("\n");embedsky_lcd_ClearScr_Rectangle(0, 0, LCD_XSIZE_TFT, LCD_YSIZE_TFT, 0x0);Lcd_printf(26*8,16*12,RGB(0xff,0xff,0),0,1,"##     This is information about the editor     ##");Lcd_printf(26*8,16*13,RGB(0xff,0xff,0),0,1,"##          Major    : IOT                      ##");Lcd_printf(26*8,16*14,RGB(0xff,0xff,0),0,1,"##          number   : 201811672224             ##");Lcd_printf(26*8,16*15,RGB(0xff,0xff,0),0,1,"##          Name     : xujiayue                 ##");Lcd_printf(26*8,16*16,RGB(0xff,0xff,0),0,1,"##      The last editing date is 2020-11-07     ##");Lcd_printf(1*8,16*28,RGB(0x10,0,0xff),0,1,"      Please refer to serial port debugging information for detailed modification information     ");}else{embedsky_lcd_ClearScr_Rectangle(0, 0, LCD_XSIZE_TFT, LCD_YSIZE_TFT, 0x0);Lcd_printf(26*8,16*14,RGB(0xff,0xff,0),0,1,"##                   null                       ##");printf("null\n");}for(i=0;i<argc;i++){printf("argv[%d]: %s\n",i,argv[i]);}return 0;
}U_BOOT_CMD(editor, 5, 1,    do_edit,"editor  -for example:  editor 1 \n","View the information of the reviser and the content of the modification\n"   );

sqlite简单应用程序开发代码:
main.c:

#include "stdio.h"
#include "stdlib.h"
#include "sqlite3.h"
#include "string.h"void  do_insert(sqlite3 *db);
void  do_find(sqlite3 *db);
void  do_update(sqlite3 *db);
void  do_delete(sqlite3 *db);int do_check(sqlite3 *db);
void do_new(sqlite3 *db);
void do_old(sqlite3 *db);
int flag=1;
int main(int argc, char **argv)
{sqlite3    *db;sqlite3    *db1;char       *errmsg;int        cmd;if(sqlite3_open("user.db", &db1) != SQLITE_OK){printf("打开数据库失败, 原因是:%s.\n", sqlite3_errmsg(db1));return -1;}else{//printf("成功打开数据库。\n");}if(sqlite3_exec(db1, "create table user(Username char,Password char);", NULL, NULL, &errmsg) != SQLITE_OK){//printf("创建数据库user失败, 原因是:%s.\n", errmsg);}else{printf("创建数据库user成功!\n");}do_check(db1);if(sqlite3_open("temp.db", &db ) != SQLITE_OK){printf("打开数据库失败, 原因是:%s.\n", sqlite3_errmsg(db));return -1;}else{//printf("成功打开数据库。\n");}if(sqlite3_exec(db, "create table temp('姓名' char,'日期' char, '体温' float);", NULL, NULL, &errmsg) != SQLITE_OK){//printf("创建数据库temp失败, 原因是:%s.\n", errmsg);}else{printf("创建数据库temp成功!\n");}while(flag){printf("\n");printf("**********************************************************\n");printf("**                   [1] 插入数据                       **\n");printf("**                   [2] 查找数据                       **\n");printf("**                   [3] 更新数据                       **\n");printf("**                   [4] 删除数据                       **\n");printf("**                   [5] 退出菜单                       **\n");printf("**********************************************************\n");printf("\n");printf("\n请输入命令:\n");scanf("%d", &cmd);getchar();switch(cmd){case 1:do_insert(db);break;case 2:do_find(db);break;case 3:do_update(db);break;case 4:do_delete(db);break;case 5:sqlite3_close(db);exit(0);default:printf("无效输出,请重新输入。\n");break;}}return 0;
}int do_check(sqlite3 *db)
{int        cmd;printf("\n");printf("*******************\n");printf("**   [1] 新用户  **\n");printf("**   [2] 老用户  **\n");printf("*******************\n");printf("\n");printf("\n请输入命令:\n");scanf("%d", &cmd);getchar();switch(cmd){case 1:do_new(db);break;case 2:do_old(db);break;default:printf("无效输出,请重新输入。\n");flag=0;break;}return 0;}
void do_new(sqlite3 *db)
{char                date[64];char                name[64];char                sql[128]={};char                *errmsg;printf("请输入用户名:\n");scanf("%s", name );getchar();printf("请输入密码:\n");scanf("%s", date );getchar();printf("正在注册中...\n");memset(sql, 0, sizeof(sql));sprintf(sql, "insert into user values('%s','%s');", name,date);if(sqlite3_exec(db, sql, NULL, NULL, &errmsg) != SQLITE_OK){printf("登陆失败, 原因是: %s.\n", errmsg);}else{printf("登陆成功。\n");}}
void do_old(sqlite3 *db)
{char                date[64];char                name[64];char                sql[128]={};char                **resultp;char                *errmsg;int                 nrow;int                 ncolum;printf("请输入用户名:\n");scanf("%s", name );getchar();printf("请输入密码:\n");scanf("%s", date );getchar();printf("正在登陆中...\n");memset(sql, 0, sizeof(sql));sprintf(sql, "select * from user where Username='%s' and  Password='%s';",name,date);if(sqlite3_get_table(db, sql, &resultp, &nrow, &ncolum, &errmsg) != SQLITE_OK){printf("登陆失败, 原因是:%s.\n", errmsg);flag=0;}if(resultp[0]==NULL){flag=0;printf("登陆失败,账号或密码错误!\n");}else{printf("登陆成功!\n");  }}
void do_insert(sqlite3 *db)
{char                date[64];char                name[64];char                sql[128]={};char                *errmsg;float               temp;printf("请输入姓名:\n");scanf("%s", name );getchar();printf("请以如下格式输入日期:\n");printf("2017年7月8日则输入:2017/7/8\n");scanf("%s", date );getchar();printf("请输入温度:\n");scanf("%f",  &temp);getchar();memset(sql, 0, sizeof(sql));sprintf(sql, "insert into temp values('%s','%s', %f);", name,date,temp);if(sqlite3_exec(db, sql, NULL, NULL, &errmsg) != SQLITE_OK){printf("插入数据失败, 原因是: %s.\n", errmsg);}else{printf("数据插入成功。\n");}}void do_find(sqlite3 *db)
{char                       sql[128]={};char                       **resultp;char                       *errmsg;int                        nrow;int                        ncolum;int                        i,j,index;printf("正在查询...\n");memset(sql, 0, sizeof(sql));sprintf(sql, "select * from temp;");if(sqlite3_get_table(db, sql, &resultp, &nrow, &ncolum, &errmsg) != SQLITE_OK){printf("查询失败, 原因是:%s.\n", errmsg);}else{printf("查询成功!\n");index = ncolum;for(i=0; i< ncolum; i++)   //列名{printf("%-18s", resultp[i]);}printf("\n");for(i=0; i< nrow; i++)     //行{for(j=0; j< ncolum; j++) //列{printf("%-14s", resultp[index++]);}printf("\n");}}
}void do_delete(sqlite3 *db)
{char                 name[50]={};char                 sql[128]={};char                 *errmsg;printf("请输入你要删除的名字:\n");scanf("%s", name);getchar();sprintf(sql, "delete from temp where 姓名='%s';", name);if(sqlite3_exec(db, sql, NULL, NULL, &errmsg) != SQLITE_OK){printf("删除失败, 原因是: %s。\n", errmsg);}else{printf("删除成功!\n");}
}void do_update(sqlite3 *db)
{char                        sql[128];char                        name[64];char                        *errmsg;float                       temp;printf("请输入你要更新的名字:\n");scanf("%s", name);getchar();printf("请输入你要更新的温度:\n");scanf("%f", &temp);getchar();memset(sql, 0, sizeof(sql));sprintf(sql, "update temp set 体温=%f where 姓名='%s';", temp, name);if(sqlite3_exec(db, sql, NULL, NULL, &errmsg) != SQLITE_OK ){printf("更新失败, 原因是: %s.\n", errmsg);}else{printf("更新成功!\n");}}

驱动程序:
led驱动程序:

#include <linux/module.h>#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/delay.h>#include <asm/uaccess.h>
#include <asm/irq.h>#include <asm/io.h>
#include <mach/regs-gpio.h>
#include <mach/hardware.h>//device_create(),class_create()的头文件
#include <linux/device.h>//定义出这两寄存器
volatile  unsigned long *gpc0con = NULL;
volatile  unsigned long *gpc0dat = NULL;static struct class *leddrv_class;int major;
static int led_drv_open(struct inode *inode, struct file *file)
{printk("\n");printk("xu jia yue open led_drv\n");*gpc0con &= ~((0xf<<(3*4)) | (0xf<<(4*4)));*gpc0con |= ((0x1<<(3*4)) | (0x1<<(4*4)));return 0;
}static ssize_t led_drv_write(struct file *file, const char __user *buf, size_t count, loff_t * ppos)
{int val;//用户空间向内核空间传递数据copy_from_user(&val, buf, count);printk("val=%d\n",val);if(val == 1){//点灯*gpc0dat |= ((1<<3) | (1<<4)); printk("led on\n");}else{//灭灯*gpc0dat &= ~((1<<3) | (1<<4));printk("led off\n");}return 0;
}//定义了这样的一个结构
static struct file_operations led_drv_fops = {.owner  =   THIS_MODULE, //这是一个宏.open   =   led_drv_open,    .write  =   led_drv_write,
};//入口函数
int  led_drv_init(void)
{major = register_chrdev(249, "led_drv", &led_drv_fops);gpc0con = (volatile unsigned long *)ioremap(0xE0200060,16);gpc0dat = gpc0con + 1;return 0;
}void led_drv_exit(void)
{unregister_chrdev(major, "led_drv");iounmap(gpc0con);
}module_init(led_drv_init);
module_exit(led_drv_exit);
MODULE_LICENSE("GPL");

按键驱动:

#include <linux/types.h>
#include <linux/module.h>
#include <linux/cdev.h>
#include <linux/fs.h>
#include <linux/device.h>
#include <linux/gpio.h>
#include <linux/irq.h>
#include <linux/interrupt.h>
#include <linux/sched.h>
#include <linux/wait.h>
#include <linux/uaccess.h>static dev_t devno;
static struct cdev cdev;
static struct class* buttons_class;
static struct device* buttons_device;static wait_queue_head_t button_waitq;static volatile int pressed = 0;
static unsigned char key_val;struct key_desc{unsigned int  pin;unsigned char value;
};static struct key_desc key_descs[8] = {[0] = {.pin = S5PV210_GPH0(0),.value = 0x00,},[1] = {.pin = S5PV210_GPH0(1),.value = 0x01,},[2] = {.pin = S5PV210_GPH0(2),.value = 0x02,},[3] = {.pin = S5PV210_GPH0(3),.value = 0x03,},[4] = {.pin = S5PV210_GPH0(4),.value = 0x04,},[5] = {.pin = S5PV210_GPH0(5),.value = 0x05,},[6] = {.pin = S5PV210_GPH2(6),.value = 0x06,},[7] = {.pin = S5PV210_GPH2(7),.value = 0x07,},
};static irqreturn_t buttons_irq(int irq, void *dev_id){volatile struct key_desc *key = (volatile struct key_desc *)dev_id;if(gpio_get_value(key->pin)){key_val = key->value|0x80;}else{key_val = key->value;}pressed = 1;wake_up_interruptible(&button_waitq);return IRQ_RETVAL(IRQ_HANDLED);
}static int buttons_open(struct inode *inode, struct file *file){int ret;ret = request_irq(IRQ_EINT(0),   buttons_irq, IRQ_TYPE_EDGE_BOTH, "key1", &key_descs[0]);if(ret)return ret;ret = request_irq(IRQ_EINT(1),   buttons_irq, IRQ_TYPE_EDGE_BOTH, "key2", &key_descs[1]);if(ret)return ret;ret = request_irq(IRQ_EINT(2),   buttons_irq, IRQ_TYPE_EDGE_BOTH, "key3", &key_descs[2]);if(ret)return ret;ret = request_irq(IRQ_EINT(3),   buttons_irq, IRQ_TYPE_EDGE_BOTH, "key4", &key_descs[3]);if(ret)return ret;ret = request_irq(IRQ_EINT(4),   buttons_irq, IRQ_TYPE_EDGE_BOTH, "key5", &key_descs[4]);if(ret)return ret;ret = request_irq(IRQ_EINT(5),   buttons_irq, IRQ_TYPE_EDGE_BOTH, "key6", &key_descs[5]);if(ret)return ret;ret = request_irq(IRQ_EINT(22),  buttons_irq, IRQ_TYPE_EDGE_BOTH, "key7", &key_descs[6]);if(ret)return ret;ret = request_irq(IRQ_EINT(23),  buttons_irq, IRQ_TYPE_EDGE_BOTH, "key8", &key_descs[7]);if(ret)return ret;return 0;
}static ssize_t buttons_read(struct file * file, char __user *data, size_t count, loff_t *loff){if(count != 1){printk(KERN_ERR "The driver can only give one key value once!\n");return -ENOMEM;}wait_event_interruptible(button_waitq, pressed);pressed = 0;if(copy_to_user(data, &key_val, 1)){printk(KERN_ERR "The driver can not copy the data to user area!\n");return -ENOMEM;}return 0;
}static int buttons_close(struct inode *inode, struct file *file){free_irq(IRQ_EINT(0),  &key_descs[0]);free_irq(IRQ_EINT(1),  &key_descs[1]);   free_irq(IRQ_EINT(2),  &key_descs[2]);free_irq(IRQ_EINT(3),  &key_descs[3]);free_irq(IRQ_EINT(4),  &key_descs[4]);free_irq(IRQ_EINT(5),  &key_descs[5]);free_irq(IRQ_EINT(22), &key_descs[6]);free_irq(IRQ_EINT(23), &key_descs[7]);return 0;
}struct file_operations buttons_ops = {.open    = buttons_open,.read    = buttons_read,.release = buttons_close,
};int buttons_init(void){int ret;cdev_init(&cdev, &buttons_ops);cdev.owner = THIS_MODULE;ret = alloc_chrdev_region(&devno, 0, 1, "buttons");if(ret){printk(KERN_ERR "alloc char device region faild!\n");return ret;}ret = cdev_add(&cdev, devno, 1);if(ret){printk(KERN_ERR "add char device faild!\n");goto add_error;}buttons_class = class_create(THIS_MODULE, "buttonsdrv");if(IS_ERR(buttons_class)){printk(KERN_ERR "create class error!\n");goto class_error;}buttons_device = device_create(buttons_class, NULL, devno, NULL, "buttons");if(IS_ERR(buttons_device)){printk(KERN_ERR "create buttons device error!\n");goto device_error;}init_waitqueue_head(&button_waitq);return 0;device_error:class_destroy(buttons_class);
class_error:cdev_del(&cdev);
add_error:unregister_chrdev_region(devno,1);return -ENODEV;
}void buttons_exit(void){device_destroy(buttons_class, devno);class_destroy(buttons_class);cdev_del(&cdev);unregister_chrdev_region(devno, 1);
}module_init(buttons_init);
module_exit(buttons_exit);
MODULE_LICENSE("GPL");

lcd驱动: 这个我是直接配置内核菜单,把framebuffer给选上,这个是与lcd相关的一块内存空间,往里面写东西就可以改变lcd的显示颜色;在根文件系统下可以用命令cat
proc/device,查看是否有fb存在,然后根据它的主设备号29创建设备节点;

基于按键,led,lcd的简单交互程序代码:

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <unistd.h>
#include <signal.h>
#include <linux/fb.h>
#include <stdbool.h>char* plcd = NULL;
bool terminated = false;
//typedef void (*sighandler_t)(int);
void sighandler(int sig){switch(sig){case SIGINT:terminated = true;break;}
}void LCD_DrawPoint(unsigned long x , unsigned long y,  int color)
{int *p =(int *) plcd;*(p + y * 800 + x) = color;}//draw screen with color
void LCD_ClearScr(int color)
{unsigned long x, y;for (y = 0; y < 480; y++){for (x = 0; x < 800; x++){LCD_DrawPoint(x, y,  color) ;}}
}int main(int argc,char** argv){int fd1 = open("/dev/buttons", O_RDWR);if(fd1 < 0){printf("open /dev/buttons error");;return 0;}int val= 1;int fd2 = open("/dev/led",O_RDWR);if(fd2 < 0)printf("can't open  /dev/led!\n");unsigned char key;printf("hello xujiayue\n");signal(SIGINT,sighandler);//sighandler_t signal(int signum, sighandler_t handler);int fd = open("/dev/fb0",O_RDWR);if(fd == -1){perror("open /dev/fb0 error");exit(-1);}printf("open device %d\n",fd);/*2. get screen infomations*/struct  fb_var_screeninfo fbinfo;int r = ioctl(fd,FBIOGET_VSCREENINFO , &fbinfo);if (r == -1){perror("ioctl error:");return -1;}plcd = mmap(NULL, fbinfo.xres * fbinfo.yres * (fbinfo.bits_per_pixel / 8),PROT_WRITE,MAP_SHARED,fd,0);while(!terminated){read(fd1, &key, 1);printf("The key = %x\n", key);if( key==0){LCD_ClearScr(0xff);//blueval=~val;write(fd2, &val, 4);}if(key==1){LCD_ClearScr(0xff00);//greenval=~val;write(fd2, &val, 4);}if(key==2){LCD_ClearScr(0xff0000);//redval=~val;write(fd2, &val, 4);}if(key==3){LCD_ClearScr(0xffb6c1);//LightPinkval=~val;write(fd2, &val, 4);}if(key==4){LCD_ClearScr(0x00ffff);//Cyanval=~val;write(fd2, &val, 4);}if(key==5){LCD_ClearScr(0x7fffaa);//Auqamarinval=~val;write(fd2, &val, 4);}if(key==6){LCD_ClearScr(0xffff00);//Yellowval=~val;write(fd2, &val, 4);}if(key==7){LCD_ClearScr(0x808080);//Grayval=~val;write(fd2, &val, 4);}}munmap(plcd,fbinfo.xres * fbinfo.yres * (fbinfo.bits_per_pixel / 8));close(fd);close(fd1);close(fd2);return 0;
}

linux系统移植与开发相关推荐

  1. 迅为IMX6ULL教程更新至2060+页,裸机开发,Linux系统移植,驱动开发,构建文明系统,QT开发,系统编程

    教程更新至2060+页 彻底让零基础的同学真正学会 更完善的教程更全面的讲解更高效的学习 第一部分 总领及学习指引:主要探讨的学习方法,我们将尽量用比较简洁的方式,让大家明白嵌入式系统知识体系,以及它 ...

  2. 玩转开发板--Linux系统移植至开发板fl2440实践过程

    一.开发板介绍     CPU:S3C2440(SAMSUNG).ARM920T.400MHz     Pone/mic:耳机和话筒 JTAG:可以通过外部插入直接控制CPU,因此在初始化内存时,起到 ...

  3. 嵌入式Linux(5):驱动开发网络调试驱动设备的Linux系统移植

    驱动开发之网络调试驱动设备的Linux系统移植 1.Uboot移植到开发板 uboot移植 2.开发板网络通讯 nfs命令 tftp命令 3.Linux移植到开发板 4.BusyBox 构建根文件系统 ...

  4. 基于全志A33开发板linux系统移植学习记录(Boot0)

    基于全志A33开发板linux系统移植学习记录 第一章 Boot0基于ARMGCC的编译与修改 文章目录 基于全志A33开发板linux系统移植学习记录 前言 一.全志A33简介以及上电引导流程 二. ...

  5. STM32MP157 Linux系统移植开发篇4: BootLoader(Uboot)移植

    本文章为<STM32MP157 Linux系统移植开发篇>系列中的一篇,笔者使用的开发平台为华清远见FS-MP1A开发板(STM32MP157开发板).stm32mp157是ARM双核,2 ...

  6. STM32MP157 Linux系统移植开发篇17:Linux内核摄像头驱动移植

    本文章为<STM32MP157 Linux系统移植开发篇>系列中的一篇,笔者使用的开发平台为华清远见FS-MP1A开发板(STM32MP157开发板).stm32mp157是ARM双核,2 ...

  7. STM32MP157 Linux系统移植开发篇14:Linux内核RGB LCD驱动移植

    本文章为<STM32MP157 Linux系统移植开发篇>系列中的一篇,笔者使用的开发平台为华清远见FS-MP1A开发板(STM32MP157开发板).stm32mp157是ARM双核,2 ...

  8. STM32MP157 Linux系统移植开发篇11:Linux HDMI驱动移植

    本文章为<STM32MP157 Linux系统移植开发篇>系列中的一篇,笔者使用的开发平台为华清远见FS-MP1A开发板(STM32MP157开发板).stm32mp157是ARM双核,2 ...

  9. Linux系统移植:原厂 Kernel 移植到开发板

    文章目录 Linux系统移植:原厂 Kernel 移植到开发板 一.获取原厂内核并编译 二.内核启动测试 三.添加自己板子文件 3.1 板子配置文件 3.2 板子设备树 3.3 编译 四.重要配置修改 ...

最新文章

  1. C# 添加xml节点多了xmlns属性问题
  2. jeewx-qywx-api 1.0版发布,微信企业号Java SDK
  3. Python 2.x vs Python 3.x(四)—— TypeError: unhashable type
  4. 100行代码实现最简单的基于FFMPEG+SDL的视频播放器
  5. HOG特征提取算法解析
  6. ztree带有选项框的树形菜单使用
  7. 程序员应该知道的Mac工具
  8. 面试阿里(P8)竟被MySQL难倒,奋发图强二次面试斩获阿里offer
  9. python数据库模糊查询_python中的mysql数据库like模糊查询
  10. 【聚类模型①】k均值聚类算法
  11. 硬盘格式化怎么操作 硬盘格式化后数据还在吗
  12. 结婚戒指为什么要带在无名指上
  13. python怎么编写在线excel_超简单:用Python让Excel飞起来(零基础学python,用python实现办公自动化)...
  14. VSCode配置同步|VSCode高级玩家宝典之第三篇
  15. orcale报错 无效数字
  16. 百度飞桨蜜度文本智能较对大赛经验分享(17/685)
  17. 说说“腰椎间盘突出”的恢复和初步治疗
  18. ISO8601转换成Date类型
  19. 【软件安全实验2022】验证码——1
  20. python找出列表list中重复元素

热门文章

  1. 涉密资质是什么?有哪些好处
  2. 神器Markmap!!!
  3. 利用C语言实现文件的读写操作
  4. [转]JavaScript/Node.JS 中的 Promises
  5. 电脑灯不亮,电脑显示灯不亮原因有哪些 电脑显示灯不亮解决方法
  6. D3D12渲染技术之创建和启用纹理
  7. 使用unity做的绩点计算器
  8. 物流企业对计算机网络技术的投资,计算机网络技术在现代物流中的应用探究.doc...
  9. 电商带来物流变革物流行业
  10. 服务器怎么用u盘加载硬盘驱动,戴尔服务器安装用U盘加载硬盘控制卡驱动.pdf