嵌入式Linux之我行——u-boot-2009.08在2440上的移植详解(六)

发布者:大泉人家最新更新时间:2016-04-27 来源: eefocus关键字:Linux  u-boot 手机看文章 扫描二维码
随时随地手机看文章

一、移植环境

二、移植步骤

10)u-boot利用tftp服务下载内核和利用nfs服务挂载nfs文件系统。
 
知识点:
  1. tftp服务的安装与配置及测试;
  2. nfs服务的安装与配置及测试;
  3. u-boot到kernel的参数传递(重点)。

   我们知道使用tftp下载内核和使用nfs挂载文件系统的好处是,当我们重新编译内核或文件系统后不用重新把这些镜像文件再烧录到flash上,而是把这些镜像文件放到开发主机的tftp或nfs服务的主目录下,通过网络来加载他们,不用频繁的往flash上烧,这样一可以保护flash的使用寿命,二可以方便的调试内核或文件系统,提高开发效率。可见,让u-boot实现这个功能是一件很有意义的事情。

   实现这样的功能很简单,网上也有很多资料。但有很多细节的东西如果稍不注意就导致失败,这里就结合本人实现的过程进行讲述和一些问题的分析。

  • tftp服务的安装与配置及测试

   要使用tftp服务及测试它要安装两个软件包,一个就是tftp服务器,另外一个就是tftp客户端,这里安装客户端只是用于在主机本地测试tftp服务器是否正常运行的,来确保u-boot能够访问tftp服务(u-boot中已有tftp客户端的功能,其实在前面几篇中都已经使用了tftp下载内核或文件系统到开发板上,如果那里都做到了,这里就可以直接跳过)。

   首先使用rpm命令查看你的主机上是否已经安装了tftp服务器和客户端,如果没有安装就去下载这两个软件包进行安装或者可以使用yum命令进行在线安装,yum会自动的去搜索适合你主机平台的最新软件包进行下载安装,如果主机已经安装了,则会提示软件包已经安装了最新的版本。如下图所示:
嵌入式Linux之我行——u-boot-2009.08在2440上的移植详解(六)转

   配置tftp服务器,主要是配置tftp的主目录及访问权限。因tftp服务依赖于xinetd服务,所以一般tftp服务安装好后其配置文件一般会在/etc/xinetd.d/目录下: 

[root@localhost home]# vi /etc/xinetd.d/tftp 

service tftp
{
        disable     no
        socket_type dgram
        protocol    udp
        wait        yes
        user        root
        server      /usr/sbin/in.tftpd
        server_args -s /home/tftp-root -c  //主要是修改这里,指定tftp服务器的主目录,-c选项是指可以创建文件
        per_source  11
        cps         100 2
        flags       IPv4
}

 

   创建刚才指定的tftp服务器主目录,也要注意主目录的可读可写的权限:

[root@localhost home]#mkdir /home/tftp-root
[root@localhost home]#chmod 777 /home/tftp-root

 

   启动和测试tftp服务:

[root@localhost home]#service xinetd restart //重启xinetd服务就会启动其下的所有服务,也包括tftp服务
[root@localhost home]#service iptables stop //关闭防火墙
[root@localhost home]#tftp 主机IP地址 
 tftp>get 要下载的文件 

 tftp>put 要上传的文件 

 tftp>q
[root@localhost home]#

 

  • nfs服务的安装与配置及测试

   以root的身份在控制台输入setup,在系统服务选项中选中nfs服务,如下图:
嵌入式Linux之我行——u-boot-2009.08在2440上的移植详解(六)转 嵌入式Linux之我行——u-boot-2009.08在2440上的移植详解(六)转

   配置NFS服务器的共享主目录,也要注意权限问题:

[root@localhost home]# vi /etc/exports  //如果没有这个文件就创建它,添加下面一行配置信息,注意格式一定要正确,否则导致服务不正常

/home/filesystem *(rw,no_root_squash,sync)

注释:“/home/filesystem”是NFS服务器的主目录,注意目录的权限

     “*”表示所有的IP都可以访问NFS主目录

     “rw”表示可读可写

     ”no_root_squash“表示登入到NFS主机的用户如果是ROOT用户,他就拥有ROOT的权限

     “sync”表示同步

 

[root@localhost home]# service nfs restart //重新启动NFS服务,使配置文件生效

 

   测试NFS服务是否正常。将事先准备好的文件系统放到NFS主目录下,如下:

[root@localhost home]# ls /home/filesystem/
bin    dev  home      lib      mnt   root  sum100  tmp  var
debug  etc  hostname  linuxrc  proc  sbin  sys     usr
[root@localhost home]#

//在主机本地测试NFS服务,将NFS主目录下的文件系统挂载到/mnt目录下,192.168.1.101是主机的IP

[root@localhost home]#mount -o nolock -t nfs 192.168.1.101:/home/filesystem /mnt

 

   可以看到/mnt目录下的内容和NFS主目录/home/filesystem下的内容完全一致,说明NFS服务正常:
嵌入式Linux之我行——u-boot-2009.08在2440上的移植详解(六)转

  • u-boot到kernel的参数传递  

   我们知道,在kernel配置选项Boot options中有一个Default kernel command string参数项,而在u-boot参数中也有一个bootargs参数项,他们都是供内核启动用的,那他们又有什么区别呢,内核启动时到底是用哪一个呢?两种参数项分别如下图所示(kernel中的参数指定是从开发板Flash分区上挂载文件系统,u-boot中的参数指定的是从NFS挂载文件系统):
嵌入式Linux之我行——u-boot-2009.08在2440上的移植详解(六)转
嵌入式Linux之我行——u-boot-2009.08在2440上的移植详解(六)转

 
    实际上,内核中的参数项是内核默认提供的,在内核配置时去指定,而u-boot提供的则在u-boot启动时传递到内核中取代内核提供的参数。所以当u-boot没有提供bootargs参数时,内核启动就是用内核配置时指定的参数,当u-boot提供了bootargs参数时就使用u-boot的参数。
 
 

   那么,u-boot是如果将参数信息传递到内核中的呢?而内核又是怎么接收u-boot传递过来的参数呢?这就涉及到一点点ARM寄存器的知识了。

   我们知道,ARM有7种工作模式和37个寄存器(31个通用寄存器和6个状态寄存器),如下图:
嵌入式Linux之我行——u-boot-2009.08在2440上的移植详解(六)转

   ARM工作模式之间的转换就是利用这些寄存器进行,而u-boot参数的传递也利用了三个通用寄存器R0、R1和R2。关于ARM工作模式和寄存器在这里就不做讲叙了,以后再讲,这里你就理解成u-boot在启动的时候把参数存放到这三个寄存器中,到内核启动时再把寄存器中的参数取出,当然,他们并不是就这样简单的操作。下面我们看代码一一分析。

   首先,我们来分析一下u-boot是怎样处理和发送要传递的参数,而u-boot要传递的参数又有哪些呢?除了我们最容易知道的bootargs(即内核commandline)参数项外,要传递的参数还有MACH_TYPE(即我们所说的机器码)、系统根设备信息(标志,页面大小)、内存信息(起始地址,大小)、RAMDISK信息(起始地址,大小)、压缩的RAMDISK根文件系统信息(起始地址,大小)。由此可见要传递的参数很多,这时候,u-boot就提供一种叫做参数链表(tagged list)的方式把这些参数组织起来,链表结构体定义在:include/asm-arm/setup.h中,而实现链表的组织在lib_arm/bootm.c中:
   嵌入式Linux之我行——u-boot-2009.08在2440上的移植详解(六)转  嵌入式Linux之我行——u-boot-2009.08在2440上的移植详解(六)转

我们可以看到,链表的组织是由一系列函数实现,u-boot规定,链表必须以ATAG_CORE标记开始,以ATAG_NONE标记结束,中间就是一些参数标记项,这点从代码中可以体现出来。那么在这些函数中有一个bd的参数是至关重要的,它是一个bd_info类型的结构体,定义在include/asm-arm/u-boot.h中,而这个结构体又被一个global_data类型的结构体所引用,定义在include/asm-arm/global_data.h中,如下:
嵌入式Linux之我行——u-boot-2009.08在2440上的移植详解(六)转    嵌入式Linux之我行——u-boot-2009.08在2440上的移植详解(六)转 
那么,那个bd参数到底是做什么用的呢?从定义中可以得知,bd记录了机器码、u-boot参数链表在内存中的地址等信息,那又问,它在什么地方进行记录的呢?它就在我们自己开发板初始化代码中记录的,如:board/samsung/my2440/my2440.c中
嵌入式Linux之我行——u-boot-2009.08在2440上的移植详解(六)转

注意:bd_t被gd_t所引用,而在global_data.h中我们可以看到,u-boot定义了一个gd_t的全局指针变量*gd,所以在这里就可以直接使用gd来设置bd了。

好了,我们还是接着分析这个参数链表是如何被传递的,组织参数链表的系列函数在一个叫do_bootm_linux的函数中被调用的,还是定义在lib_arm/bootm.c中
嵌入式Linux之我行——u-boot-2009.08在2440上的移植详解(六)转

 
 
 
 
 
 
 
 
 
 
 
 
从这个函数中我们可以看到,要使参数传递生效必须需要CONFIG_SETUP_MEMORY_TAGS和CONFIG_CMDLINE_TAG这两个宏的支持,所以需要在include/configs/my2440.h中定义它们。原来我就是没定义它们,在使用NFS挂载文件系统时就出现问题。同时,theKernel这个函数指针是u-boot参数传递的至关点,我们知道,函数在内存中执行的时候其实就是一个地址,而在代码中首先将这个函数指针指向kernel的入口地址,最后还将0、机器码和u-boot参数项在内存中的地址带给这个入口地址,故执行这个入口地址的时候即kernel启动的时候可以有这三个参数进行接收。那么,这个入口地址(kernel启动地址或者说kernel入口地址)是怎么来的是谁指定的,又是多少呢?看代码,是从一个bootm_headers_t类型的结构体的成员ep取得的,而这个结构体是从调用do_bootm_linux的地方传递过来的。bootm_headers_t定义在include/image.h中,do_bootm_linux在common/cmd_bootm.c中被调用,如下:
嵌入式Linux之我行——u-boot-2009.08在2440上的移植详解(六)转   嵌入式Linux之我行——u-boot-2009.08在2440上的移植详解(六)转
 
从代码中可以清楚的看到对bootm_headers_t的成员ep进行了赋值,但是还是不够直观这个入口地址到底是多少?只知道是使用image_get_ep函数从bootm_headers_t中的legacy_hdr_os_copy上取得的,那它在什么地方被赋值的呢?原来在image_set_ep函数中,定义在tools/mkimage.c中,如下:
嵌入式Linux之我行——u-boot-2009.08在2440上的移植详解(六)转
 
我们再想想,这个mkimage.c是做什么用的?原来是用它来制作u-boot格式的内核——uImage,还记得怎样使用mkimage来制作uImage吧,在“u-boot-2009.08在2440上的移植详解(四)”中讲到,如下:
 

mkimage [-x] -A arch -O os -T type -C comp -a addr -e ep -n name -d data_file[:data_file...] image

选项:
-A:set architecture to 'arch'       //用于指定CPU类型,比如ARM
-O:set operating system to 'os'     //用于指定操作系统,比如Linux
-T:set image type to 'type'         //用于指定image类型,比如Kernel
-C:set compression type 'comp'      //指定压缩类型
-a:set load address to 'addr' (hex) //指定image的载入地址
-e:set entry point to 'ep' (hex)    //内核的入口地址,一般为image的载入地址+0x40(信息头的大小)
-n:set image name to 'name'         //image在头结构中的命名
-d:use image data from 'datafile'   //无头信息的image文件名
-x:set XIP (execute in place)       //设置执行位置

例如:
mkimage -n 'linux-2.6.30.4' -A arm -O linux -T kernel -C none -a 0x30008000 -e 0x30008000-d zImage uImage.img


呵呵,相信此时的你拨云见日,茅塞顿开了吧!这个入口地址就是0x30008000,这也正是为什么u-boot一定要使用uImage的格式来启动内核的原因之一。注意:这里有个kernel入口地址0x30008000,在上面还提到一个u-boot参数链表在内存中的地址0x30000100,试想如果这里指定的kernel入口地址覆盖了参数链表的地址会怎么样?

好了,把上面每个步骤从下往上看就可以知道u-boot参数项在u-boot端的传递的整个流程了,那么,接下来再分析u-boot参数项在kernel端是怎样接收的。

 
kernel启动的流程如下图所示:
嵌入式Linux之我行——u-boot-2009.08在2440上的移植详解(六)转
 
在文件arch/arm/boot/compressed/head.S中,start是zImage的起始点,部分代码如下:

start:
  ......  

  .word 0x016f2818  @ Magic numbers to help the loader
  .word start   @ absolute load/run zImage address
  .word _edata  @ zImage end address
1:mov r7, r1    @ save architecture ID
  mov r8, r2    @ save atags pointer
  ......

wont_overwrite: mov r0, r4
  mov r3, r7
  bl decompress_kernel
  call_kernel

......

call_kernel: bl cache_clean_flush
  bl cache_off
  mov r0, #0   @ must be zero
  mov r1, r7   @ restore architecture number
  mov r2, r8   @ restore atags pointer
  mov pc, r4   @ call kernel

......

首先,将u-boot传递过来的r1(机器码)、r2(参数链表在内在中的物理地址)分别保存到ARM寄存器r7、r8中,再将r7作为参数传递给解压函数decompress_kernel(),在这个解压函数中再将r7传递给全局变量__machine_arch_type,然后在跳转到vmlinux入口之前再将r7、r8还原到r1、r2中。

在arch/arm/kernel/head.S文件中,内核vmlinux入口的部分代码如下:

ENTRY(stext)
    setmode    PSR_F_BIT PSR_I_BIT SVC_MODE, r9 @ ensure svc mode and irqs disabled
    mrc    p15, 0, r9, c0, c0        @ get processor id
    bl     __lookup_processor_type   @ r5=procinfo r9=cpuid
    movs   r10, r5                   @ invalid processor (r5=0)?
    beq    __error_p                 @ yes, error 'p'
    bl     __lookup_machine_type     @ r5=machinfo
    movs   r8, r5                    @ invalid machine (r5=0)?
    beq    __error_a                 @ yes, error 'a'
    bl     __vet_atags
    bl     __create_page_tables

......


首先从ARM特殊寄存器(CP15)中获得ARM内核的类型,从处理器内核描述符(proc_info_list)表(__proc_info_begin—__proc_info_end)中查询有无此ARM 内核的类型,如果无就出错退出。处理器内核描述符定义在include/asm-arm/procinfo.h中,具体的函数实现在 arch/arm/mm/proc-xxx.S中,在编译连接过程中将各种处理器内核描述符组合成表。接着从机器描述(machine_desc)表(__mach_info_begin—__mach_info_end)中查询有无r1寄存器指定的机器码,如果没有就出错退出,所以这也说明了为什么在u-boot中指定的机器码一定要与内核中指定的一致,否则内核就无法启动。机器编号mach_type_xxx在arch/arm/tools/mach-types文件中说明,每个机器描述符中包括一个唯一的机器编号,机器描述符的定义在 include/asm-arm/mach/arch.h中,具体实现在arch/arm/mach-xxxx文件夹中,在编译连接过程中将基于同一种处理器的不同机器描述符组合成表。例如,S3C2440处理器的机器码为1008的机器描述符如下所示:

MACHINE_START(SMDK2440, "SMDK2440")
    
    .phys_io       S3C2410_PA_UART,
    .io_pg_offst   (((u32)S3C24XX_VA_UART) >> 18) 0xfffc,
    .boot_params   S3C2410_SDRAM_PA 0x100,//注意:这个地址就是与u-boot中参数链表在内存中的物理地址相对应

    .init_irq      s3c24xx_init_irq,
    .map_io        smdk2440_map_io,
    .init_machine  smdk2440_machine_init,
    .timer         &s3c24xx_timer,
MACHINE_END

最后就打开MMU,并跳转到 init/main.c的start_kernel()初始化系统。函数start_kernel()的部分代码如下:

asmlinkage void __init start_kernel(void)
{
   ......
   setup_arch(&command_line);
   ......
}

 

函数setup_arch在arch/arm/kernel/setup.c中实现,部分代码如下:

void __init setup_arch(char **cmdline_p)
{
   ......
   setup_processor();
   mdesc setup_machine(machine_arch_type);
   ......
   parse_tags(tags);
   ......
}


setup_processor()函数从处理器内核描述符表中找到匹配的描述符,并初始化一些处理器
变量。setup_machine()用机器编号(在解压函数decompress_kernel 中被赋值)作为参数返回机器描述符。从机器描述符中获得内核参数的物理地址,赋值给tags 变量。然后调用parse_tags()函数分析内核参数链表,把各个参数值传递给全局变量。这样内核就收到了u-boot传递的参数。 

 

  • tftp下载内核和nfs挂载文件系统

好了,上面tftp服务和nfs服务都已经准备好了,u-boot到kernel的参数传递也没问题了,接下来就设置一下u-boot环境变量中的参数项和kernel的配置选项使之能使用tftp自动下载kernal和通过网络自动挂载nfs文件系统。u-boot环境变量设置如下:
嵌入式Linux之我行——u-boot-2009.08在2440上的移植详解(六)转

bootcmd参数项就是使用tftp把主机tftp主目录下的uImage下载到开发板SDRAM中的0x31000000位置,接着使用bootm命令执行引导内核启动。

而bootargs参数项就是内核启动的命令行参数,u-boot就是把这个参数项传递给了内核,通过nfs挂载文件系统。这里一定要注意serverip和ipaddr的设置(即服务器IP或者开发主机IP和开发板的IP)。另外要注意,内核要能使用nfs也要配置相应的选项,如下:

File systems ---> 
        Network File Systems ---> 
            <*> NFS file system support ## 必选
                [*] Provide NFSv3 client support ## 可选
            [*] Root file system on NFS ## 必选
Networking ---> 
        [*] Networking support 
            Networking options ---> 
                [*] IP: kernel level autoconfiguration ## 必选

 


运行结果如下:

a. tftp下载内核,并引导内核启动:
嵌入式Linux之我行——u-boot-2009.08在2440上的移植详解(六)转  

b. u-boot传递的命令行参数被内核所接收:
嵌入式Linux之我行——u-boot-2009.08在2440上的移植详解(六)转

c. 内核通过nfs挂载文件系统:
嵌入式Linux之我行——u-boot-2009.08在2440上的移植详解(六)转

d. 查看挂载的nfs文件系统,发现完全与主机nfs服务器主目录中的文件系统一致,说明成功!
嵌入式Linux之我行——u-boot-2009.08在2440上的移植详解(六)转

关键字:Linux  u-boot 引用地址:嵌入式Linux之我行——u-boot-2009.08在2440上的移植详解(六)

上一篇:S3C2410的linux 下DMA驱动程序开发
下一篇:嵌入式Linux之我行——深入理解DM9000在mini2440上的驱动

推荐阅读最新更新时间:2024-03-16 14:51

s3c2440内存类设备访问原理
在嵌入式里面所谓内存类接口有SDRAM接口,NORFLASH接口,DM9000网卡接口等 ,他们都有一个共同点就是可以直接连S3C2440内存控制器,数据总线,地址总线;这三者缺一不可。 内存类接口可以通过地址直接访问内部数据,当然他们都有自己的一段可访问的地址范围。S3C2440将其1G地址空间划分为8个bank,每个bank有128M,所以芯片提供了8个片选信号线,每个片选信号线对应一个bank,一个片选信号连接一个设备,所以每个设备可访问的地址的范围是128M空间,128M=2的27次方个字节,所以芯片上面的地址线只有27跟,最大只能到A26。理论上32位的CPU应该有32跟地址线,因为最大可以到0xffffffff=2
[单片机]
s3c<font color='red'>2440</font>内存类设备访问原理
2440串口linux编程,S3C2440串口通讯的相关配置
UART配置的相关寄存器如下(按s3c2440手册中的顺序列出): 1.ULCONn寄存器:线性控制寄存器 功能:设置奇偶校验,停止位, 数据位(5-8位) 注意:一般设置为无校验,一个停止位,数据位为8位,也就是常说的“8N1”,此时寄存器值为0x3。(bit =0为正常模式,否则为红外模式); 2.UCONn寄存器:通道n控制器 功能:选择UART时钟源、设置UART中断方式 注意:可选择PCLK、UEXTCLK或FCLK/n。bit =1为回送模式,用于测试;bit 和bit 分别控制传输和接收模式,初学者常设置为中断请求或查询模式,bit =bit =01。 3.UFCONn寄存器:FIFO控制寄存器 功能:用于设
[单片机]
2440裸机编程之五 定时器
S3C2440A 具有5 个16 位定时器,每个定时器可以按照中断模式或DMA 模式工作。定时器0,1,2,3 具有PWM 功能。定时器4 是一个内部定时器,不具有对外输出口线。定时器0 还具有死区发生器,通常用于大电流设备。 定时器特性总结如下。 ● 5 个16 位定时器可以工作在中断模式或DMA 模式。 ● 包括2 个8 位预分频器、2 个4 位分割器。 ● 输出波形的占空比可用编程控制(即进行脉宽调制)。 ● 具有自动重载模式或单次触发模式。 ● 具有死区发生器。 与定时器相关的寄存器有:TCFG0、TCFG1、TCON、TCMPBn、TCNTBn、TCNTOn 定时器的频率由PCLK分频而来,即Ftimer = P
[单片机]
<font color='red'>2440</font>裸机编程之五 定时器
嵌入式Linux学习笔记之——代码重定位002_链接脚本的引入
① NOR启动: ② nand 启动: 上次讲到的g_char不能按照程序正确输出的原因是nor启动的时候g_char在nor flash中,其不可写的特性决定了输出结果。 现在能否修改Makefile让nor启动时讲代码拷贝到SDRAM中,这样就可以实现全局变量的可读可写了。 现在想在nor flash启动的时候将其中的代码段拷贝至SDRAM中0地址起始的空间,将全局变量g_char拷贝至0x30000000起始的空间。 编译之后发现.bin文件变成了800M,805306369-- 0x30000001,符合程序中的g_char所占1字节的设置。 但是nor flash一共才2M,不可实现。 解决方
[单片机]
嵌入式<font color='red'>Linux</font>学习笔记之——代码重定位002_链接脚本的引入
基于嵌入式Linux流媒体播放器系统软硬件解决方案
摘要:本系统选用TQ2440 开发板作为硬件平台,采用嵌入式Linux 操作系统给出流媒体播放器系统具体的软硬件解决方案,设计了一款基于嵌入式Linux 的机顶盒媒体播放器。完成了其与网络接口的实现,通过TS 流的解析实现,提供了对主流的MPEG- 2、MPEG- 4、H.264 等格式文件的支持。该系统具有良好的可移植性和可扩展性,能够满足不断变化的市场需求。   1 引言   计算机多媒体技术和网络技术飞速发展使得基于流媒体的多媒体应用也被运用在多种领域,特别是网络可视电话、远程监控、视频点播领域。伴随着计算机多媒体压缩技术的成熟和网络传输技术的发展,开发实时可靠、多功能、数字化、操作简单的基于计算机网络通讯技术和多媒体应
[模拟电子]
基于嵌入式<font color='red'>Linux</font>流媒体播放器系统软硬件解决方案
使用JLink间接烧写S3C2410、S3C2440开发板Nor、Nand Flash的方法
1. 简要说明 JLink的调试功能、烧写Flash的功能都很强大,但是对于S3C2410、S3C2440的Flash操作有些麻烦:烧写Nor Flash时需要设置SDRAM,否则速率很慢;烧写Nand Flash只是从理论上能够达到,但是还没有人直接实现这点。 本文使用一个间接的方法来实现对S3C2410、S3C2440开发板的Nor、Nand Flash的烧写。原理为:JLink可以很方便地读写内存、启动程序,那么可以把一个特制的程序下载到开发板上的SDRAM去,并运行它,然后使用这个程序来烧写。 2. 操作步骤 2.1 连接硬件 对于大多数的S3C2410、S3C2440开发板而言,它们所用的JTAG接口一般有3种(
[单片机]
使用JLink间接烧写S3C2410、S3C<font color='red'>2440</font>开发板Nor、Nand Flash的方法
嵌入式Linux平台的GPS数据采集研究
随着GPS(全球定位系统)和便携移动设备的飞速发展,各种各样以GPS为基础的便携式定位系统相继出现.嵌入式Linux以其开放性、安全性、健壮性和 稳定性越来越成为各种便携设备的主要开发平台,因此GPS模块与嵌入式Linux平台之间的通信成了实现定位系统的基础. GPS模块与嵌入式Linux平台之间进行数据传送,大多采用异步串行传送方式,GPS作为终端设备(DTE)与嵌入式平台之间通过RS-232C串行通 信接口进行数据交换.因此,与GPS的数据通信在实现上即是LinuX下的串口编程,对于两者之间的通信协议,可选的协议有很多种,而NMEA0183是 目前普遍采用的一种。 1 NMEA0183通信协议 NMEA0183是G
[测试测量]
小广播
添点儿料...
无论热点新闻、行业分析、技术干货……
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved