首页资源分类嵌入式开发嵌入式系统 > ARM - S3C2410 - Linux

ARM - S3C2410 - Linux

已有 460448个资源

下载专区


TI最新应用解决方案

工业电子 汽车电子 个人消费电子

上传者其他资源

文档信息举报收藏

标    签: ARMS3C2410Linux说明书

分    享:

文档简介

ARM - S3C2410 - Linux说明书

文档预览

广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 第 1 章 MagicARM2410 实验箱硬件结构 ..........................................................5 1.1 功能特点...................................................................................................................6 1.1.1 硬件资源...........................................................................................................6 1.1.2 软件资源...........................................................................................................7 1.1.3 可选硬件...........................................................................................................8 1.2 S3C2410A 芯片简介 ................................................................................................8 1.3 硬件原理................................................................................................................. 11 1.3.1 DeviceARM2410 核心板 ...............................................................................11 1.3.2 实验箱主板.....................................................................................................24 1.3.3 构建 ARM7 教学实验开发平台....................................................................45 1.4 硬件结构.................................................................................................................46 1.4.1 跳线器说明.....................................................................................................47 1.4.2 连接器说明.....................................................................................................50 1.5 硬件资源分配情况.................................................................................................51 1.6 温馨提示.................................................................................................................53 第 2 章 基础实验.................................................................................................54 2.1 ADS 1.2 集成开发环境练习..................................................................................54 2.2 汇编指令实验 1......................................................................................................59 2.3 汇编指令实验 2......................................................................................................62 2.4 汇编指令实验 3......................................................................................................65 2.5 ARM 处理器工作模式实验...................................................................................68 2.6 C 语言程序实验 .....................................................................................................72 2.7 C 语言调用汇编程序实验 .....................................................................................74 2.8 GPIO 输出控制实验 ..............................................................................................76 2.9 GPIO 输入实验 ......................................................................................................82 2.10 外部中断实验.........................................................................................................85 2.11 UART 通讯实验 .....................................................................................................90 2.12 I2C 接口实验 ..........................................................................................................95 2.13 定时器实验...........................................................................................................104 2.14 PWM DAC 实验...................................................................................................107 2.15 ADC 实验 ............................................................................................................. 111 2.16 RTC 实验 ..............................................................................................................114 2.17 步进电机控制实验...............................................................................................120 2.18 直流电机控制实验...............................................................................................123 第 3 章 基于µC/OS-II 基础实验 ......................................................................127 3.1 µC/OS-II 移植实验...............................................................................................127 3.2 蜂鸣器实验...........................................................................................................136 3.3 串行通信实验.......................................................................................................140 3.4 图形液晶控制实验...............................................................................................144 3.5 Modbus RTU 主从通讯实验 ...............................................................................147 第 4 章 构建嵌入式 Linux 开发平台 ...............................................................159 4.1 基础知识...............................................................................................................159 4.1.1 交叉编译.......................................................................................................159 4.1.2 宿主机要求...................................................................................................159 -1- 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 4.2 构建交叉开发环境...............................................................................................160 4.2.1 安装交叉编译器...........................................................................................160 4.2.2 安装 ARM Linux 内核 .................................................................................161 4.2.3 安装 NFS 根文件系统 .................................................................................162 4.3 构建嵌入式 Linux 目标平台 ...............................................................................166 4.3.1 相关文件.......................................................................................................166 4.3.2 下载 Bootloader ............................................................................................168 4.3.3 下载 Linux 内核和文件系统 .......................................................................168 4.3.4 启动 Linux 操作系统 ...................................................................................170 4.4 Linux 启动参数的设定方法 ................................................................................171 4.4.1 ZLG/BOOT 的运行过程 ..............................................................................171 4.4.2 Linux 启动参数的含义 ................................................................................172 4.4.3 Linux 启动参数文件的制作 ........................................................................173 第 5 章 Linux 应用程序编写 ............................................................................175 5.1 HelloWorld 程序实验 ...........................................................................................175 5.2 Linux 定时器实验 ................................................................................................178 5.3 多进程实验...........................................................................................................180 5.4 多线程实验...........................................................................................................183 5.5 文件和目录操作实验...........................................................................................187 5.6 UDP 实验..............................................................................................................189 5.7 TCP 实验 ..............................................................................................................194 5.8 Webserver 实验.....................................................................................................200 第 6 章 Linux 高级实验 ....................................................................................205 6.1 Linux 内核编译实验 ............................................................................................205 6.2 Linux 根文件系统实验 ........................................................................................206 6.3 CAT1025 读/写实验 .............................................................................................207 6.4 ZLG7290 键盘读取 ..............................................................................................213 6.5 USB-E2PROM 编程器实验..................................................................................218 6.6 SD/MMC 卡实验..................................................................................................230 6.7 触摸屏实验...........................................................................................................235 6.8 PCMCIA 接口 CF 卡实验....................................................................................239 6.9 IDE 硬盘实验 .......................................................................................................245 6.10 USB 主机驱动编译与加载实验 ..........................................................................250 6.11 U 盘驱动程序编译与使用实验 ...........................................................................253 6.12 USB 键盘与鼠标应程序实验 ..............................................................................256 6.13 FrameBuffer 模块应用实验 .................................................................................261 6.14 video4linux 模块应用实验...................................................................................268 6.15 USB 摄像头实验 ..................................................................................................274 6.16 无线网络实验.......................................................................................................280 6.17 CAN 接收实验 .....................................................................................................284 6.18 CAN 发送实验 .....................................................................................................292 6.19 CAN 通信参数设置实验 .....................................................................................294 6.20 busybox 移植实验 ................................................................................................298 6.21 boa 移植实验........................................................................................................299 -2- 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 6.22 Madplay 移植实验................................................................................................301 第 7 章 嵌入式 Linux 驱动开发 .......................................................................305 7.1 Linux 驱动编写概述 ............................................................................................305 7.1.1 设备号...........................................................................................................305 7.1.2 文件层接口...................................................................................................305 7.1.3 驱动层接口...................................................................................................307 7.1.4 中断...............................................................................................................308 7.1.5 I/O 操作 ........................................................................................................310 7.1.6 设备注册和注销...........................................................................................311 7.1.7 模块化...........................................................................................................312 7.1.8 初始化...........................................................................................................313 7.1.9 编译...............................................................................................................313 7.2 Devfs 驱动程序编写 ............................................................................................314 7.2.1 设备的注册和注销.......................................................................................315 7.2.2 加载驱动.......................................................................................................316 7.3 LED 驱动程序 ......................................................................................................316 7.3.1 LED 驱动程序编写 ......................................................................................316 7.3.2 LED 驱动测试程序 ......................................................................................321 7.4 按键驱动程序.......................................................................................................323 7.4.1 按键驱动程序编写.......................................................................................323 7.4.2 按键驱动测试程序.......................................................................................328 第 8 章 嵌入式图形用户界面-Qt/Embedded ................................................331 8.1 Qt 介绍..................................................................................................................331 8.1.1 全面的 Qt .....................................................................................................331 8.1.2 跨平台的 Qt..................................................................................................331 8.1.3 深入了解 Qt .................................................................................................332 8.2 Qt/Embedded 介绍................................................................................................332 8.3 Qtopia 介绍...........................................................................................................333 8.3.1 简介...............................................................................................................333 8.3.2 Qtopia 平台的核心特征 ...............................................................................334 8.3.3 Qtopia PDA 版本简介 ..................................................................................335 8.4 Qt/Embedded 和 Qtopia 开发模式.......................................................................336 8.5 建立宿主机 Qt/Embedded 与 Qtopia 开发环境..................................................337 8.5.1 安装 tmake ....................................................................................................337 8.5.2 安装 Qt/X11..................................................................................................337 8.5.3 解压 Qtopia...................................................................................................340 8.5.4 安装 Qt/Embedded........................................................................................340 8.5.5 编译安装 Qtopia...........................................................................................341 8.5.6 运行 Qtopia...................................................................................................341 8.5.7 在 PC 上运行 Hello 程序 .............................................................................344 8.6 建立交叉编译的 Qt/Embedded 开发环境...........................................................345 8.6.1 安装开发环境...............................................................................................345 8.6.2 在 ARM 中运行 Hello 程序.........................................................................346 第 9 章 Qt/Embedded 编程实战 .......................................................................348 -3- 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 9.1 9.2 9.3 9.4 9.5 9.6 9.7 9.8 9.9 9.10 9.11 9.12 第 10 章 10.1 10.2 10.3 10.4 10.5 附录 A 附录 B Hello 程序.............................................................................................................348 按钮.......................................................................................................................350 Qt 信号和插槽......................................................................................................352 对话框...................................................................................................................354 Qt 布局..................................................................................................................357 进度条...................................................................................................................360 文本输入...............................................................................................................364 菜单.......................................................................................................................367 Qt 绘图..................................................................................................................371 国际化...................................................................................................................374 往 Qtopia 中安装应用程序 ..................................................................................381 Designer 设计器 ...................................................................................................382 MiniGUI 图形界面实验.......................................................................386 MiniGUI 移植实验...............................................................................................386 对话框应用编程实验...........................................................................................398 简易编辑器实验...................................................................................................402 位图显示实验.......................................................................................................405 GDI 绘图实验.......................................................................................................407 USB 分析仪 USB Analyst-I 简介 ........................................................409 LA1032 逻辑分析仪简介 ....................................................................411 -4- 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 第1章 MagicARM2410 实验箱硬件结构 MagicARM2410 实验箱是由广州致远电子有限公司开发的一款可使用μC/OS-II、Linux 和 WinCE 操作系统、支持 QT、MiniGUI 图形系统、集众多功能于一身的 ARM9 教学实验 开发平台。MagicARM2410 实验箱采用 ARM920T 内核的 S3C2410A 微处理器,扩展有充足 的存储资源(SDRAM、NAND Flash、NOR Flash 和 E2PROM 等),具有 10/100M 以太网接口、 USB HOST 接口、USB Device 接口、CAN 接口、PCMCIA 存储卡接口、IDE 硬盘接口、CF 卡接口、SD 卡接口、IrDA 接口、IIS 数字音频接口,8 英寸 640×480 真彩 TFT 液晶屏(带 触摸屏),可使用 JTAG 仿真调试。模块化的功能设计,便于实验操作的工艺设计,保留有 外设 PACK 和 GPIO 输出接口,可以实现目前几乎所有的嵌入式接口实验,非常适用于教学 实验。 MagicARM2410 实验箱参考图片如图 1.1 所示。 图 1.1 MagicARM2410 实验箱产品外观图 MagicARM2410 实验箱功能框图如图 1.2 所示。 -5- 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 9针D型串行接口 (2个) RS232转换器 UART0 BUS + I/O 10/100M以太网 (DM9000E) RJ45以太网接口 JTAG接口 (20针) RS485接口 RS485转换器 UART1 ISA转PC卡主适配器 (CL-PD6710) IRDA红外模块 (RPM851A) IRDA开关电路 TOUT1 UART2 DeviceARM2410 (DIMM200接口) 音频接口 (输出/输入) 数字音频编解码 器 (UDA1341TS) IIS BUS LCD 外设PACK接口 (双排针, 2个) CAN接口电路 (SJA1000) 液晶屏触摸屏接 口电路 (TFT & STN) 小喇叭 功率放大 (TDA2822M) USB HOST接口 (4个) USB HUB电路 (AU9254A21) DN0 DN1 DP0 DP1 USB Device接口 (1个) ADC I2C BUS A/D转换(2路) 键盘与LED数码管 (ZLG2790) 独立按键 (1个) 独立LED灯 (4个) 蜂鸣器 (直流) PCMCIA接口 CF 卡接口 IDE硬盘接口 CAN接口 (1路) 直流电机 (1个) 步进电机 (1个) PWM DAC (TOUT0输出) SD卡接口 GPRS PACK (使用UART0) VGA PACK (使用LCD接口) 其它接口 (插针) SPI接口 I2C接口 ADC接口 中断及GPIO UART接口(TTL) RTC后备电池 (3.0V) 图 1.2 MagicARM2410 实验箱功能框图 1.1 功能特点 1.1.1 硬件资源 处理器:核心板 ARM920T 处理器 S3C2410A,工作频率高达 203MHz。 SDRAM:核心板 64M 字节。 NAND Flash:核心板 64M 字节。 NOR Flash:核心板 2M 字节。 E2PROM:核心板 256 字节。 液晶屏:8 英寸 640×480 真彩 TFT 液晶屏。 触摸屏:4 线电阻式。 以太网接口:支持 10/100M 以太网。 USB 接口:USB 1.1,4 个 USB 主机口,1 个 USB 设备口。 音频接口:IIS 数字音频输入/输出接口 (有 2 个扬声器和 1 个咪头)。 PCMCIA 接口:1 个 68Pin PCMCIA 接口。 CF 卡接口:1 个 (PCMCIA 接口扩展)。 IDE 硬盘接口:1 个 (PCMCIA 接口扩展)。 SD/MMC 卡接口:1 个。 RS232:2 路。 IrDA:1 路。 RS485:1 路。 CAN 接口:1 路(CAN 控制器 SJA1000)。 ADC:CPU 内置,2 路直流电压测量。 DAC:1 路 PWM DAC 输出。 直流电机:1 个。 步进电机:1 个。 -6- 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 1.1.2 RTC:CPU 内置,实验箱上有 RTC 后备电池。 WDT:CPU 内置。 数码管:8 位动态数码管 (ZLG7290 驱动)。 键盘:16 键小键盘(ZLG7290 驱动)。 独立按键:1 个 (接到中断输入引脚)。 蜂鸣器:1 个,直流蜂鸣器。 独立 LED:4 个。 GPRS PACK 接口:1 个,用来扩展 GPRS 模块。 VGA PACK 接口:1 个,用来扩展 VGA 输出接口。 总线扩展接口:2 个(1 个 16 位总线的、1 个 32 位总线的)。 JTAG 接口:20PIN JTAG 调试接口。 JTAG 仿真器:EasyJTAG-H 仿真器。 软件资源 Linux (v2.4.18)嵌入式操作系统 MiniGUI 图形用户界面学习版软件包(Linux/uCLinux) Qt/Embedded 和 Qtopia 支持 LED、蜂鸣器驱动(for Linux) 按键驱动(for Linux) I2C 驱动程序 (for Linux) USB Device 驱动程序 (for Linux) USB HUB 驱动(for Linux) USB HID 驱动(鼠标、键盘,for Linux) USB 大容量驱动(for Linux) 基于 OV511 芯片的 USB 摄像头驱动(for Linux) video4linux 视频软件(for Linux) PCMCIA 驱动(for Linux) IDE 驱动(for Linux) SD/MMC 卡驱动程序 (for Linux) Framebuffer 驱动——TFT 640×480 液晶屏 (for Linux) 触摸屏驱动(for Linux) 10M/100M 以太网卡 DM9000 驱动 (for Linux) Madplay、boa 移植 (for Linux) uC/OS-II (v2.52)移植代码 ZLG/FS 文件管理系统软件包 ZLG/FFS 支持写平衡的 NAND Flash 驱动软件包 (for uC/OS-II) ZLG/FTP-S 嵌入式 FTP 服务器软件包 (for uC/OS-II) 支持 RS485/422 MODBUS RTU 协议软件包 (for uC/OS-II) ZLG/GPS 软件包 (for uC/OS-II) ZLG/GPRS 软件包 (for uC/OS-II) 串口软件包 I2C 软件包 实验源代码,芯片数据手册 -7- 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 1.1.3 可选硬件 GPRS 模块:选配。 GPS 模块:选配。 VGA PACK 板:VGA 接口,在 Linux 和 Win CE 系统下均不闪烁。 10M 以太网:CS8900 (PACK)。 摄像头 (USB 接口)。 PC 键盘 (USB 接口)。 鼠标 (USB 接口)。 1.2 S3C2410A 芯片简介 S3C2410A 是 Samsung 公司推出的 16/32 位 RISC 处理器(ARM920T 内核),适用于手持 设备、POS 机、数字多媒体播放设备等等,具有低价格、低功耗、高性能等特点。S3C2410A 提供了以下丰富的内部设备:16KB 的指令 Cache 和 16KB 数据 Cache,MMU 虚拟存储器管 理,LCD 控制器(支持 STN&TFT),支持 NAND Flash 系统引导,系统管理器(片选逻辑和 SDRAM 控制器),3 通道 UART,4 通道 DMA,4 通道 PWM 定时器,I/O 端口,RTC,8 通道 10 位 ADC 和触摸屏接口,I2C 总线接口,IIS 总线接口,USB 主机接口,USB 设备接 口,SD 卡&MMC 卡接口,2 个 SPI 总线接口以及内部 PLL 时钟倍频器。 S3C2410A 采用了 ARM920T 内核,0.18um 工艺的 CMOS 标准宏单元和存储器单元。 它的低功耗、精简和出色的全静态设计特别适用于对成本和功耗敏感的应用。同样它还采用 了 Advanced Microcontroller Bus Architecture(AMBA)新型总线结构。 S3C2410A 提供了一系列完整的系统外围设备,消除了为系统配置额外器件的需要,大 大减少了整个系统的成本。S3C2410A 主要的特征如下: 203MHz 的 ARM920T 内核,支持 JTAG 仿真调试; 16KB 的 I-Cache 和 16KB 的 D-Cache; 具有 MMU,支持 WinCE、EPOC32、Linux 等操作系统; 外部存储器控制器(SDRAM 控制和片选逻辑),共分 8 个 Bank,每个 Bank 可访问 128MB 空间; 片内 4KB SRAM,可用作 NAND Flash 系统引导的缓冲区; LCD 控制器(最大支持 4K 色 STN 和 256K 色 TFT),1 通道 LCD 专用 DMA; 4 通道 DMA,有外部请求引脚; 3 个 UART (IrDA1.0,16 字节 Tx FIFO,16 字节 Rx FIFO); 2 个 SPI 总线接口; 1 个多主 I2C 总线接口; 1 个 IIS 总线接口; 兼容 SD 主接口协议 1.0 版和 MMC 卡协议 2.11 兼容版; NAND Flash/SM 卡接口,支持 NAND Flash 系统引导; 2 个 USB 主机接口,1 个 USB 设备接口(V1.1); 4 个 PWM 定时器和 1 个内部定时器; 看门狗定时器; 117 个通用 I/O 口; 24 个外部中断; 8 通道 10 位 ADC 和触摸屏接口; 具有日历和时钟功能的 RTC; -8- 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 1.8V 内核供电,3.3V 存储器供电,3.3V 外部 I/O 供电; 功耗控制模式:普通,慢速,空闲和掉电模式; 具有片内 PLL 时钟发生器。 S3C2410A 芯片内部结构框图如图 1.3 所示。 图 1.3 S3C2410A 内部结构框图 S3C2410A 芯片引脚定义如图 1.4、图 1.5 、图 1.6 所示(由于芯片引脚较多,所以将其 分为三部分)。 -9- 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com G1 G5 D17 E15 E16 E14 E17 F15 C16 G13 E13 R14 U15 H2 G2 H3 H4 nXBACK/GPB5 nXBREQ/GPB6 nGCS0 nGCS1/GPA12 nGCS2/GPA13 nGCS3/GPA14 nGCS4/GPA15 nGCS5/GPA16 nOE nWAIT nWE OM0 OM1 nXDACK0/GPB9 nXDACK1/GPB7 nXDREQ0/GPB10 nXDREQ1/GPB8 B14 D14 A14 C13 B13 D13 A13 C12 B12 G12 D12 E12 B11 A11 C11 G11 A10 B10 E10 D10 F10 A9 D9 E9 B9 C9 E8 ADDR0/GPA0 ADDR1 ADDR2 ADDR3 ADDR4 ADDR5 ADDR6 ADDR7 ADDR8 ADDR9 ADDR10 ADDR11 ADDR12 ADDR13 ADDR14 ADDR15 ADDR16/GPA1 ADDR17/GPA2 ADDR18/GPA3 ADDR19/GPA4 ADDR20/GPA5 ADDR21/GPA6 ADDR22/GPA7 ADDR23/GPA8 ADDR24/GPA9 ADDR25/GPA10 ADDR26/GPA11 U1A S3C2410A (Address,Data,ADC,Clock,DMA,Timmer) DATA0 DATA1 DATA2 DATA3 DATA4 DATA5 DATA6 DATA7 DATA8 DATA9 DATA10 DATA11 DATA12 DATA13 DATA14 DATA15 DATA16 DATA17 DATA18 DATA19 DATA20 DATA21 DATA22 DATA23 DATA24 DATA25 DATA26 DATA27 DATA28 DATA29 DATA30 DATA31 B8 A8 D7 E7 C7 B7 A7 C6 F7 B6 D6 A5 C5 B5 D5 A4 A3 B3 A2 A1 B2 C3 B1 C2 C1 D2 D4 D1 E3 E2 E4 E1 TOUT0/GPB0 TOUT1/GPB1 TOUT2/GPB2 TOUT3/GPB3 TCLK0/GPB4 TCLK1/EINT19/GPG11 EXTCLK CLKOUT0/GPH9 CLKOUT1/GPH10 MPLLCAP UPLLCAP OM2 OM3 XTIpll XTOpll XTIrtc XTOrtc AIN0 AIN1 AIN2 AIN3 AIN4 AIN5 AIN6 AIN7 Vref F2 F1 F4 G3 G4 R11 J11 R12 U12 P17 L13 U14 T13 H17 H16 P16 R17 U16 T15 U17 T16 R15 T17 R16 N13 N12 图 1.4 S3C2410A 引脚定义(a) P11 U11 T11 M11 T12 P13 N11 M10 T7 U9 U7 R9 P8 R10 T8 L9 T5 P5 N6 U5 U6 L7 M8 XMON/EINT20/GPG12 nXPON/EINT21/GPG13 YMON/EINT22/GPG14 nYPON/EINT23/GPG15 DN0 DP0 DN1/PDN0 DP1/PDP0 SPIMISO0/GPE11 SPIMISO1/EINT13/GPG5 SPIMOSI0/GPE12 SPIMOSI1/EINT14/GPG6 SPICLK0/GPE13 SPICLK1/EINT15/GPG7 nSS0/EINT10/GPG2 nSS1/EINT11/GPG3 I2SLRCK/GPE0 I2SSCLK/GPE1 CDCLK/GPE2 I2SSDI/nSS0/GPE3 I2SSDO/I2SSDI/GPE4 IICSCL/GPE14 IICSDA/GPE15 A17 B16 C15 A16 F16 F17 C14 B15 D16 F13 F14 G14 H12 R13 U13 G17 G16 G15 T6 P6 R6 N7 P7 R7 nBE0:nWBE0:DQM0 nBE1:nWBE1:DQM1 nBE2:nWBE2:DQM2 nBE3:nWBE3:DQM3 nSCS0:nGCS6 nSCS1:nGCS7 nSCAS nSRAS SCKE SCLK0 SCLK1 ALE/GPA18 CLE/GPA17 R/nB NCON nFCE/GPA22 nFRE/GPA20 nFWE/GPA19 SDCLK/GPE5 SDCMD/GPE6 SDDATA0/GPE7 SDDATA1/GPE8 SDDATA2/GPE9 SDDATA3/GPE10 VD0/GPC8 VD1/GPC9 VD2/GPC10 VD3/GPC11 VD4/GPC12 VD5/GPC13 VD6/GPC14 VD7/GPC15 VD8/GPD0 U1B VD9/GPD1 VD10/GPD2 VD11/GPD3 VD12/GPD4 S3C2410A VD13/GPD5 VD14/GPD6 VD15/GPD7 VD16/GPD8 VD17/GPD9 (Nand Flash, SD Card , UART , LCD , SPI, I2C, I2S) VD18/GPD10 VD19/GPD11 VD20/GPD12 VD21/GPD13 VD22/nSS1/GPD14 VD23/nSS0/GPD15 L1 L2 L4 M3 M4 M2 N1 N3 N2 N4 P1 P3 P2 T1 R2 U1 T2 R3 R4 U2 T3 U3 T4 P4 LEND/GPC0 VCLK/GPC1 VLINE:HSYNC/GPC2 VFRAME:VSYNC/GPC3 VM:VDEN/GPC4 LCDVF0/GPC5 LCDVF1/GPC6 LCDVF2/GPC7 LCD_PWREN/EINT12/GPG4 nCTS0/GPH0 nRTS0/GPH1 TXD0/GPH2 RXD0/GPH3 TXD1/GPH4 RXD1/GPH5 nRTS1/TXD2/GPH6 nCTS1/RXD2/GPH7 UCLK/GPH8 nTRST TCK TDI TDO TMS J4 J2 J6 K4 K2 K6 L6 L3 P9 H5 H6 J1 J5 J3 L14 L12 K15 K17 K16 K14 K13 K12 L16 图 1.5 S3C2410A 引脚定义(b) - 10 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com G7 K3 L5 M7 N10 R1 N5 P14 L11 D11 C4 C17 C8 J13 J17 J15 M12 P15 G6 J14 VDDiarm (1.8V) VDDiarm (1.8V) VDDiarm (1.8V) VDDiarm (1.8V) VDDiarm (1.8V) VDDiarm (1.8V) VDDiarm (1.8V) VDDi_MPLL (1.8V) VDDi_UPLL (1.8V) VDDi (1.8V) VDDi (1.8V) VDDi (1.8V) VDDi (1.8V) VDDi (1.8V) nBATT_FLT PWREN RTCVDD (1.8V) VDDA_ADC (3.3V) VDDalive (1.8V) VDDalive (1.8V) J12 J16 nRESET nRSTOUT/GPA21 N14 N17 M16 M17 M15 M14 L15 L17 R8 U8 U10 T10 P10 EINT0/GPF0 EINT1/GPF1 EINT2/GPF2 EINT3/GPF3 EINT4/GPF4 EINT5/GPF5 EINT6/GPF6 EINT7/GPF7 EINT8/GPG0 EINT9/GPG1 EINT16/GPG8 EINT17/GPG9 EINT18/GPG10 VDDMOP (SCLK 66MHz:1.8V,85:2.5V,100:3.3V) VDDMOP (SCLK 66MHz:1.8V,85:2.5V,100:3.3V) VDDMOP (SCLK 66MHz:1.8V,85:2.5V,100:3.3V) VDDMOP (SCLK 66MHz:1.8V,85:2.5V,100:3.3V) VDDMOP (SCLK 66MHz:1.8V,85:2.5V,100:3.3V) VDDMOP (SCLK 66MHz:1.8V,85:2.5V,100:3.3V) VDDMOP (SCLK 66MHz:1.8V,85:2.5V,100:3.3V) D8 E11 A15 A6 E5 B4 H14 U1C VDDOP (3.3V) VDDOP (3.3V) VDDOP (3.3V) VDDOP (3.3V) K1 M6 N16 N9 S3C2410A (External Interrupt , Reset , Power) VSSA_ADC VSSi VSSi VSSi VSSi VSSi T14 F6 F9 B17 F11 H15 VSSi_MPLL VSSi_UPLL M13 N15 VSSMOP VSSMOP VSSMOP VSSMOP VSSMOP VSSMOP VSSMOP VSSMOP VSSMOP VSSOP VSSOP VSSOP VSSOP VSSOP VSSOP VSSiarm VSSiarm VSSiarm VSSiarm VSSiarm VSSiarm VSSiarm F12 E6 A12 D3 G9 F8 F3 C10 D15 F5 H13 K5 T9 P12 R5 H1 J7 M1 N8 M5 M9 U4 图 1.6 S3C2410A 引脚定义(c) 1.3 硬件原理 MagicARM2410 实验箱的硬件电路主要由 DeviceARM2410 核心板、实验箱主板、电源 板 和 各 种 PACK 板 等 组 成 , 以 下 将 分 别 说 明 DeviceARM2410 核 心 板 的 硬 件 结 构 和 MagicARM2410 实验箱主板各部分电路的原理。 说明:DeviceARM2410 是一块独立的系统核心板,可以在不同的用户板(即底板)上使用, 比如 MagicARM2410 实验箱主板。 1.3.1 DeviceARM2410 核心板 1. 功能简介 DeviceARM2410 是广州致远电子有限公司开发的基于 S3C2410A 处理器的 ARM9 核心 板,采用 6 层板工艺,具有超强的扰干扰能力。 DeviceARM2410 核心板的功能特点如下: 处理器。采用 Samsung 公司的 ARM920T 处理器 S3C2410A。工作频率高达 203MHz,外部总线频率高达 100~133MHz。 SDRAM。Hynix 公司的 HY57V561620,PC100/PC133 兼容,64MB。 NAND Flash:Samsung 公司 K9F1208,64MB。 NOR Flash:SST 公司的 SST39VF1601,2MB。可根据用户需要裁减。 操作系统:可支持 Linux、uCLinux、WinCE、uC/OS-II 等操作系统。 E2PROM:I2C 总线接口,256 字节。 晶振:12MHz 晶振,CPU 内部倍频至 203MHz。 电源:单 3.3V 电源供电,板内自带 1.8V LDO 芯片。 - 11 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 接口:SO-DIMM200 标准接口(插卡式),200 个引脚输出。 尺寸规格:67.6mm × 40.6mm。 LED 指示灯:1 个红色电源指示灯,1 个可编程功能的绿色指示灯。 2. 尺寸规格 DeviceARM2410 核心板外观及尺寸如图 1.7 所示。 厚度:约 7mm (包括表面元件,如晶振) 图 1.7 DeviceARM2410 元件布局图 3. 引脚定义 DeviceARM2410 核心板是通过 SO-DIMM200 接口与应用板连接,接口定义如图 1.8 所示,各信号的意义如表 1.1 所列。接口的绝大部分引脚都是 S3C2410A 的功能脚,详细 的引脚功能说明请参考 S3C2410A 芯片的数据手册。 说明:在 DeviceARM2410 核心板的 PCB 上标记有“A1”、“B1”引脚位置。 - 12 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com OM0 1 nRSTIN 3 nRSTOUT 5 nTRST 7 TMS 9 TCK 11 TDI 13 TDO 15 GND 17 LADDR0 19 LADDR1 21 LADDR2 23 LADDR3 25 LADDR4 27 LADDR5 29 LADDR6 31 LADDR7 33 LADDR8 35 LADDR9 37 LADDR10 39 LADDR11 41 LADDR12 43 LADDR13 45 LADDR14 47 LADDR15 49 LADDR16 51 LADDR17 53 LADDR18 55 LADDR19 57 LADDR20 59 LADDR21 61 LADDR22 63 LADDR23 65 LADDR24 67 LADDR25 69 LADDR26 71 nGCS1 73 nGCS2 75 nGCS3 77 nGCS4 79 nGCS5 81 nGCS7 83 LnGCS0 85 LnWBE0 87 LnWBE1 89 LnWBE2 91 LnWBE3 93 nXDACK0 95 nXDACK1 97 GND 99 A1 B1 A2 B2 A3 B3 A4 B4 A5 B5 A6 B6 A7 B7 A8 B8 A9 B9 A10 B10 A11 B11 A12 B12 A13 B13 A14 B14 A15 B15 A16 B16 A17 B17 A18 B18 A19 B19 A20 B20 A21 B21 A22 B22 A23 B23 A24 B24 A25 B25 A26 B26 A27 B27 A28 B28 A29 B29 A30 B30 A31 B31 A32 B32 A33 B33 A34 B34 A35 B35 A36 B36 A37 B37 A38 B38 A39 B39 A40 B40 A41 B41 A42 B42 A43 B43 A44 B44 A45 B45 A46 B46 A47 B47 A48 B48 A49 B49 A50 B50 2 LDATA0 4 LDATA1 6 LDATA2 8 LDATA3 10 LDATA4 12 LDATA5 14 LDATA6 16 LDATA7 18 LDATA8 20 LDATA9 22 LDATA10 24 LDATA11 26 LDATA12 28 LDATA13 30 LDATA14 32 LDATA15 34 LDATA16 36 LDATA17 38 LDATA18 40 LDATA19 42 LDATA20 44 LDATA21 46 LDATA22 48 LDATA23 50 LDATA24 52 LDATA25 54 LDATA26 56 LDATA27 58 LDATA28 60 LDATA29 62 LDATA30 64 LDATA31 66 LnWE 68 LnOE 70 nXBACK 72 nXBREQ 74 nWAIT 76 nXDREQ0 78 nXDREQ1 80 TOUT0 82 TOUT1 84 TOUT2 86 TOUT3 88 TCLK0 90 GND 92 VD0 94 VD1 96 VD2 98 VD3 100 VD4 I2SLRCK 101 I2SSDI 103 I2SSDO 105 I2SSCLK 107 CDCLK 109 I2CSCL 111 I2CSDA 113 SDCLK 115 SDCMD 117 SDDATA0 119 SDDATA1 121 SDDATA2 123 SDDATA3 125 nSS-SPI0 127 SPIMISO0 129 SPIMOSI0 131 SPICLK0 133 nSS-SPI1 135 SPIMISO1 137 SPIMOSI1 139 SPICLK1 141 CLKOUT0 143 CLKOUT1 145 nRTS0 147 nCTS0 149 TXD0 151 RXD0 153 TXD1 155 RXD1 157 TXD2 159 RXD2 161 UCLK 163 GND 165 EINT0 167 EINT1 169 EINT2 171 EINT3 173 EINT4 175 EINT5 177 EINT6 179 EINT7 181 EINT8 183 EINT9 185 EINT16 187 EINT17 189 EINT18 191 EINT19 193 GND 195 GND 197 GND 199 A51 A52 A53 A54 A55 A56 A57 A58 A59 A60 A61 A62 A63 A64 A65 A66 A67 A68 A69 A70 A71 A72 A73 A74 A75 A76 A77 A78 A79 A80 A81 A82 A83 A84 A85 A86 A87 A88 A89 A90 A91 A92 A93 A94 A95 A96 A97 A98 A99 A100 B51 B52 B53 B54 B55 B56 B57 B58 B59 B60 B61 B62 B63 B64 B65 B66 B67 B68 B69 B70 B71 B72 B73 B74 B75 B76 B77 B78 B79 B80 B81 B82 B83 B84 B85 B86 B87 B88 B89 B90 B91 B92 B93 B94 B95 B96 B97 B98 B99 B100 102 VD5 104 VD6 106 VD7 108 VD8 110 VD9 112 VD10 114 VD11 116 VD12 118 VD13 120 VD14 122 VD15 124 VD16 126 VD17 128 VD18 130 VD19 132 VD20 134 VD21 136 VD22 138 VD23 140 LEND 142 VCLK 144 LCD-PWR 146 VM 148 VLINE 150 VFRAME 152 LCDVF0 154 LCDVF1 156 LCDVF2 158 XMON 160 YMON 162 nXPON 164 nYPON 166 Vref 168 AIN0 170 AIN1 172 AIN2 174 AIN3 176 AIN4 178 AIN5 180 AIN6 182 AIN7 184 GND 186 DN0 188 DP0 190 DN1 192 DP1 194 VDDRTC 196 PVDD33 198 PVDD33 200 PVDD33 引脚 A1 A2 A3 A4 A5 A6 A7 A8 A9 A10 A11 A12 图 1.8 DeviceARM2410 核心板接口定义 表 1.1 DeviceARM2410 核心板引脚功能 标号 OM0 nRSTIN nRSTOUT nTRST TMS TCK TDI TDO GND LADDR0 LADDR1 LADDR2 功能 启动方式选择 手动复位控制输入 (低电平时复位) 复位信号输出 备注 接地:NAND Flash 启动方式 悬空:Bank0 启动方式(16bit) 接一个复位按键到地,用于手 动复位;或者悬空此引脚。 低电平有效的复位信号 nTRST、TCK、TDI 和 TMS 需 JTAG 仿真调试接口信号 要接上拉电阻(如 10KΩ)。 电源地 地址总线 - 13 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 引脚 A13 A14 A15 A16 A17 A18 A19 A20 A21 A22 A23 A24 A25 A26 A27 A28 A29 A30 A31 A32 A33 A34 A35 A36 A37 A38 A39 A40 A41 A42 A43 A44 A45 A46 A47 A48 A49 A50 A51 A52 标号 LADDR3 LADDR4 LADDR5 LADDR6 LADDR7 LADDR8 LADDR9 LADDR10 LADDR11 LADDR12 LADDR13 LADDR14 LADDR15 LADDR16 LADDR17 LADDR18 LADDR19 LADDR20 LADDR21 LADDR22 LADDR23 LADDR24 LADDR25 LADDR26 nGCS1 nGCS2 nGCS3 nGCS4 nGCS5 nGCS7 LnGCS0 LnWBE0 LnWBE1 LnWBE2 LnWBE3 nXDACK0 nXDACK1 GND I2SLRCK I2SSDI 功能 续表 1.1 备注 地址总线 S3C2410 的 6 个 Bank 片 选信号 支持 ROM、SRAM (nGCS6 被 核 心 板 用 来 扩 展 SDRAM 存储器) S3C2410 的 nGCS0 片选 信号(可用于启动引导) 支持 SDRAM、ROM、SRAM 当核心板内没有 NOR Flash 时,此片选信号方可使用 写字节使能 外部 DMA 应答 电源地 IIS 总线 与 nXDREQ[1:0]配合使用 - 14 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 引脚 A53 A54 A55 A56 A57 A58 A59 A60 A61 A62 A63 A64 A65 A66 A67 A68 A69 A70 A71 A72 A73 A74 A75 A76 A77 A78 A79 A80 A81 A82 A83 A84 A85 A86 A87 A88 A89 A90 A91 A92 A93 标号 I2SSDO I2SSCLK CDCLK I2CSCL I2CSDA SDCLK SDCMD SDDATA0 SDDATA1 SDDATA2 SDDATA3 nSS-SPI0 SPIMISO0 SPIMOSI0 SPICLK0 nSS-SPI1 SPIMISO1 SPIMOSI1 SPICLK1 CLKOUT0 CLKOUT1 nRTS0 nCTS0 TXD0 RXD0 TXD1 RXD1 TXD2 RXD2 UCLK GND EINT0 EINT1 EINT2 EINT3 EINT4 EINT5 EINT6 EINT7 EINT8 EINT9 功能 IIS 总线 I2C 总线 续表 1.1 备注 核心板内置有 4.7KΩ的上拉 电阻 SD 卡主接口 SPI0 接口 SPI1 接口 SPI 接口 时钟输出 请求发送、发送允许(被 清零时,可以发送数据) UART0 接口 UART1 接口 异步串行口(UART) UART2 接口 异步串行口时钟信号 电源地 外部中断 - 15 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 引脚 A94 A95 A96 A97 A98 A99 A100 B1 B2 B3 B4 B5 B6 B7 B8 B9 B10 B11 B12 B13 B14 B15 B16 B17 B18 B19 B20 B21 B22 B23 B24 B25 B26 B27 B28 B29 B30 B31 B32 B33 B34 标号 EINT16 EINT17 EINT18 EINT19 GND GND GND LDATA0 LDATA1 LDATA2 LDATA3 LDATA4 LDATA5 LDATA6 LDATA7 LDATA8 LDATA9 LDATA10 LDATA11 LDATA12 LDATA13 LDATA14 LDATA15 LDATA16 LDATA17 LDATA18 LDATA19 LDATA20 LDATA21 LDATA22 LDATA23 LDATA24 LDATA25 LDATA26 LDATA27 LDATA28 LDATA29 LDATA30 LDATA31 LnWE LnOE 功能 外部中断 电源地 数据总线 写使能信号 读使能信号 续表 1.1 备注 - 16 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 引脚 B35 B36 B37 B38 B39 B40 B41 B42 B43 B44 B45 B46 B47 B48 B49 B50 B51 B52 B53 B54 B55 B56 B57 B58 B59 B60 B61 B62 B63 B64 B65 B66 B67 B68 B69 B70 B71 B72 B73 B74 B75 标号 nXBACK nXBREQ nWAIT nXDREQ0 nXDREQ1 TOUT0 TOUT1 TOUT2 TOUT3 TCLK0 GND VD0 VD1 VD2 VD3 VD4 VD5 VD6 VD7 VD8 VD9 VD10 VD11 VD12 VD13 VD14 VD15 VD16 VD17 VD18 VD19 VD20 VD21 VD22 VD23 LEND VCLK LCD-PWR VM VLINE VFRAME 功能 总线占用应答 总线占用请求 等待信号 外部 DMA 请求 定时器输出 外部计数输入 电源地 LCD 数据总线 LCD 时序控制线 续表 1.1 备注 用来请求延长总线周期 与 nXDACK[1:0]配合使用 定时器/PWM 单元 用于 LCD 显示控制 - 17 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 引脚 B76 B77 B78 B79 B80 B81 B82 B83 B84 B85 B86 B87 B88 B89 B90 B91 B92 B93 B94 B95 B96 B97 B98 B99 B100 标号 LCDVF0 LCDVF1 LCDVF2 XMON YMON nXPON nYPON Vref AIN0 AIN1 AIN2 AIN3 AIN4 AIN5 AIN6 AIN7 GND DN0 DP0 DN1 DP1 VDDRTC VDD33 VDD33 VDD33 功能 LCD 时序控制线 触摸屏控制线 ADC 参考电源 (通常采用 3.3V) 续表 1.1 备注 与 2 个 ADC 输入引脚配合使 用,实现触摸屏输入 ADC 输入引脚 (输入电压范围:0~3.3V) A/D 转换 电源地 USB 接口(主/从设备) DN1、DP1 可设置为 USB 从设 备接口(PDN0、PDP0) RTC 电源 1.8±0.15V,DC 3.3V 电源 3.3±0.1V,DC 4. 应用举例 应用电路原理图 DeviceARM2410 核心板应用电路的例子如图 1.9 所示。其中,左边的虚线框部分是用 户需要注意的,包括系统电源、复位控制、系统启动方式选择等电路,用户可以参考图 1.9 的设计方法,或者根据自己的要求来设计。 - 18 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 系统电源 +5V U1 SPX1117M3-3.3 3 VIN C1 104 GND VOUT 2 C2 C3 104 10uF/16V 1 RTC电源 D1 D2 1N4148 1N4148 BT1 3V VDDRTC=3-0.65-0.65=1.7V 启动方式选 择 R1 VDD33 10K JP1 NAND Flash 复位控制 VDD33 R2 RST 10K DeviceARM2410 DIMM200 VDD33 GND nTRST、TDI、TMS TCK、TDO VDDRTC nGCSx、LADDR[26:0] LDATA[31:0]、LnWE LnOE、nWAIT 等等 OM0 nRSTOUT DN[1:0]、DP[1:0] PDN0、PDP0 JTAG 接口 1 U2 2 AND 总线设备 (部分控制线可用作 GPIO, 如nXBACK) 控制设备复位 3 USB 1.1 接口 (HOST/Device) nRSTIN 其它功能引脚 如I2C、UART等 相应的功能 (或用作GPIO) L1 VDD33 10uH Vref ADC参考电压 C4 0.1uF AIN[7:0] A/D测量 图 1.9 DeviceARM2410 应用原理图 应用注意事项 使用 DeviceARM2410 时,需要注意以下引脚: VDD33 引脚——系统电源输入,直流 3.3±0.1V,电流为 400mA 以上; VDDRTC 引脚——RTC 电源输入,直流 1.8±0.15V; Vref 引脚——ADC 参考电源输入,直流 3.3V,参考电源的精度和稳定性会直接影 响 A/D 结果; nRSTIN 引脚——手动复位控制输入端,当 nRSTIN 为低电平时系统复位。此引脚 可以悬空,这样系统只使用上电复位; OM0 引脚——启动方式选择输入,当 OM0 为低电平时,NAND Flash 启动方式(即 核心板上的 K9F1208U0B);当 OM0 为高电平或悬空时,Bank0 启动方式(即核心 板上的 SST39VF1601,NOR Flash),16 位总线宽度; nRSTOUT 引脚——系统复位信号输出,用户可以用来控制一些设备的复位。若需 要控制的设备较多,请使用逻辑芯片(如 74LV08)来增强信号的驱动能力; LnGCS0 引脚——Bank0 存储块的片选信号,当核心板没有焊接 SST39VF1601 芯 片时,用户才能使用此信号。 对于地址总线、数据和控制总线信号,如果要连接的控制设备较多,请使用总线驱动芯 片(如 74LV245、74LVCH162245 等等)来提高总线的驱动能力。 - 19 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 指示灯 电源指示灯(红色),指示电源供电情况。当给 DeviceARM2410 系统电源(3.3V)供电时, 红色电源指示灯点亮。 可编程功能指示灯(绿色),指示的功能由用户自己定义,比如指示系统正常运行、Flash 擦除/编程操作。此状态指示灯是由 S3C2410A 的 GPA21 口控制,GPA21 输出低电平时指 示灯点亮,GPA21 输出高电平时指示灯熄灭。 5. 电路原理分析 (1) DeviceARM2410 总体框图 DeviceARM2410 总体框图如图 1.10 所示。 1.8V电源电路 RESET电路 I2C LDO稳压 256字节E2PROM CAT1025JI-30 电源指示灯 核心板接口 SO-DIMM200 (200引脚,金手指) 3.3V BUS + I/O 状态指示灯(1个) GPA21 12MHz晶振 内部倍频至203MHz 32768Hz晶振 RTC时钟源 NAND Flash 64MB K9F1208U0B NAND Flash BUS SDRAM 32MB SDRAM 32MB (use nGCS6) HY57V561620 (use nGCS6) HY57V561620 S3C2410A-20 (ARM920T) (16KB I-Cache, 16KB D-Cache) EMC BUS NOR Flash 2MB (use nGCS0) SST39VF1601 图 1.10 DeviceARM2410 总体框图 如图 1.10 所示,S3C2410A 通过外部总线接口扩展了 1 片 NOR Flash(SST39VF1601)和 2 片 SDRAM(HY57V561620),这两种存储器是用来运行程序。其中,NOR Flash 使用了 nGCS0 片选信号,这样就可以使用此 NOR Flash 启动引导程序运行。SDRAM 部分使用 2 片 16 位 总线宽度的存储芯片来组成 32 位总线宽度,以取得更高的系统性能。 数据存储器(NAND Flash,电子硬盘)使用的是 K9F1208U0B,通过 S3C2410A 的 NAND Flash 控制器对它进行读/写操作。S3C2410A 支持 NAND Flash 启动引导程序运行。 为了提高整个系统的可靠性,复位电路采用了带手动复位的电源监控复位芯片 CAT1025JI-30。CAT1025JI-30 内置有 256 字节的 E2PROM 存储器,I2C 总线接口。 系统时钟采用外部 12MHz 晶振,RTC 晶振采用 32768Hz 晶振。 由于 S3C2410A 需要 1.8V 和 3.3V 两组电源,而核心板的电源引脚只有 3.3V 的,所以 需要使用 LDO 芯片稳压产生 1.8V 电源。LDO 芯片使用的是 SPX1117M3-1.8。 DeviceARM2410 核心板上还设计有 2 个 LED 灯,1 个是红色的电源指示灯,另 1 个是 可编程功能(即指示的功能由用户自己定义)的绿色指示灯。可编程功能的绿色指示灯是由 S3C2410A 的 I/O 口控制的。 (2) 电源电路 DeviceARM2410 核心板只需要用户板(即底板)提供一组 3.3V 电源,而 S3C2410A 所需 的内核 1.8V 电源是通过核心板上的 LDO 芯片产生,电路如图 1.11 所示。 SPX1117 系列 LDO 芯片输出电流可达 800mA,输出电压的精度在±1%以内,还具有电 流限制和热保护功能,广泛用户在手持式仪表、数字家电、工业控制等领域。使用时,其输 - 20 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 出端需要一个至少 10uF 的钽电容来改善瞬态响应和稳定性。 GND GND GND 181 183 185 187 189 191 193 195 197 199 A90 A91 A92 A93 A94 A95 A96 A97 A98 A99 A100 B90 B91 B92 B93 B94 B95 B96 B97 B98 B99 B100 182 184 186 188 190 192 194 196 VDD33 198 VDD33 200 VDD33 VDD33 U2 SPX1117M3-1.8 3 VIN VOUT 2 GND C1 100nF 1 J1B DIMM200 VDD18 C2 100nF C33 10uF/16V 图 1.11 系统电源电路 (3) 复位电路 由于 ARM 芯片的高速、低功耗、低工作电压导致其噪声容限低,对电源的纹波、瞬态 响应性能、时钟源的稳定性、电源监控可靠性等诸多方面也提出了更高的要求。 DeviceARM2410 核心板的复位电路使用了内置 E2PROM 存储器的电源监控复位芯片 CAT1025JI-30(复位门槛电压为 3.0~3.15V),提高了系统的可靠性,电路原理如图 1.12 所 示。 在图 1.12 中,nRSTIN 信号是由用户板(即底板)输入的复位控制信号,用户板(即底板) 上可以将 nRSTIN 引脚接一个复位按键(接到地),用于手动复位,也可以悬空 nRSTIN 引脚 不用。若用户板(即底板)上悬空 nRSTIN 引脚,则由图 1.12 中的电阻 R16 确保 CAT1025JI-30 的 MR 引脚为高电平。 nRESET 信号为 CAT1025JI-30 输出的复位信号,此信号连接到 S3C2410A 芯片的复位 输入引脚上,实现系统复位控制。 nRSTOUT 信号为复位信号输出,用户板(即底板)上可以使用这个信号去复位某些芯片 或电路。 VDD33 VDD33 R16 10K U3 nRSTIN 1 3 7 R15 4 MR VCC RESET RESET WP SCL VSS SDA 8 2 6 5 10K CAT1025JI-30 R17 R8 R9 10K 4.7K 4.7K nRESET To U1C R19 0 R20 0 I2CSDA I2CSCL From U1B R24 nRSTOUT 图 1.12 系统复位电路 (4) 系统时钟 S3C2410A 可以使用外部晶振或外部时钟输入作为系统时钟,外部晶振频率范围是 10MHz~20MHz。DeviceARM2410 核心板采用了 12MHz 外部晶振,所以将 S3C2410A 的 OM2、OM3 引脚接为低电平(即设置 OM[3:2]=00b),将外部时钟输入引脚 EXTCLK 接为高 电平(3.3V),电路原理如图 1.13 所示。通过 S3C2410A 内部的锁相环,可以将时钟倍频至 203MHz,作为处理器的主时钟(FCLK)。 - 21 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com S3C2410A 具有一个独立时钟源、独立电源供电的 RTC(实时时钟),所以要在 XTOrtc、 XTIrtc 引脚接上 32768Hz 石英晶振,如图 1.13 所示。 EXTCLK XTIpll XTOpll XTIrtc XTOrtc OM2 OM3 U1 S3C2410A VDD33 J11 H17 H16 P16 R17 U14 T13 X1 12MHz X2 32768Hz C45 15pF R22 1M C46 15pF C47 22pF C48 22pF 图 1.13 系统时钟电路 (5) 系统存储器电路 DeviceARM2410 核心板上扩展有 1 片 NOR Flash(SST39VF1601),使用了 S3C2410A 的 nGCS0 片选信号,电路原理如图 1.14 所示。为了能使用 SST39VF1601 启动引导系统,所 以将其分配到 Bank0 存储块空间,即使用 nGCS0 片选信号。 如图 1.14 所示,SST39VF1601 是 16 位宽度的存储器,即每进行一次读操作可取得 2 字节数据,对于 S3C2410A 来说相应于半字对齐,操作地址最小的变化值为 0x00000002。 因此将 S3C2410A 的 ADDR1 引脚与 SST39VF1601 的 A0 引脚连接,忽略(不使用)S3C2410A 的 ADDR0 引脚,其它地址依次递增连接即可。图 1.14 中的 LADDRx 信号一一对应于 S3C2410A 的地址总线 ADDRx。 另 外 , 为 了 能 够 兼 容 使 用 更 大 容 量 的 SST39VF3201 、 SST39VF6401 芯 片 , 把 SST39VF1601 的第 10、13 脚(当作 A20、A21)也连接到 S3C2410A 的地址总线上。 SST39VF1601 的 nRST 引脚与系统复位信号 nRESET(见图 1.12)相连接,当系统复位时, SST39VF1601 同时被复位,然后返回到默认的读模式状态。与 SST39VF1601 的 nWP 引脚 相连的是 2 个电阻,分别为 R5、R6(图 1.14 中的虚线框部分),这是 2 选 1 电阻,当允许写 Flash 时选用 R5(使 nWP 为 1),若要禁止写 Flash 则选用 R6(使 nWP 为 0)。 说明:DeviceARM2410 默认配置时,选用 R5,允许对 SST39VF1601 进行写操作。 DeviceARM2410 核心板上扩展有 2 片 SDRAM (HY57V561620),使用了 S3C2410A 的 nGCS6 片选信号,电路原理如图 1.15 所示。使用 2 片 16 位总线宽度的存储芯片来组成 32 位总线宽度,即 U4 与数据总线的低 16 位相连,U5 与数据总线的高 16 位相连。 2 片 SDRAM 组成了 32 位宽度的存储器,即每进行一次读操作可取得 4 字节数据,对 于 S3C2410A 来说相应于字对齐,操作地址最小的变化值为 0x00000004。因此将 S3C2410A 的 ADDR2 引脚与 HY57V561620 的 A0 引脚连接,忽略(不使用)S3C2410A 的 ADDR0、ADDR1 引脚,其它地址依次递增连接即可。为了能够正确访问 HY57V561620 高/低位字节数据,所 以将 S3C2410A 的确 nWBEx 信号与 HY57V561620 的 UDQM/LDQM 相连。 HY57V561620 的 BA0、BA1 引脚是 SDRAM 内部 bank 选择地址线,也就代表了 SDRAM 内存地址的最高位。如果 DRAM 内存共有 64MB,那就需要 26 根地址线(226=64MB)来进行 寻址,所以 BA0、BA1 应连接到 S3C2410A 的 ADDR24、ADDR25 引脚。另外,由于 SDRAM - 22 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 内存的行地址和列地址是复用的,所以地址线的数目并不需要 26 根那么多。 其它控制信号按照 HY57V561620 的引脚功能一一对应连接即可,如 HY57V561620 的 nSRAS 引脚与 S3C2410A 的 nSRAS 相连接。 LADDR[26:0] BUS-CON LADDR1 LADDR2 LADDR3 LADDR4 LADDR5 LADDR6 LADDR7 LADDR8 LADDR9 LADDR10 LADDR11 LADDR12 LADDR13 LADDR14 LADDR15 LADDR16 LADDR17 LADDR18 LADDR19 LADDR20 LADDR21 LADDR22 nGCS0 LnOE LnWE U6 25 24 23 22 21 20 19 18 8 7 6 5 4 3 2 1 48 17 16 9 10 13 A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 A10 A11 A12 A13 A14 A15 A16 A17 A18 A19 NC NC 26 28 11 CE OE WE SST39VF1601 DQ0 DQ1 DQ2 DQ3 DQ4 DQ5 DQ6 DQ7 DQ8 DQ9 DQ10 DQ11 DQ12 DQ13 DQ14 DQ15 NC NC nWP nRST Vdd Vss Vss LDATA[31:0] 29 LDATA0 31 LDATA1 33 LDATA2 35 LDATA3 38 LDATA4 40 LDATA5 42 LDATA6 44 LDATA7 30 LDATA8 32 LDATA9 34 LDATA10 36 LDATA11 39 LDATA12 VDD33 41 LDATA13 43 LDATA14 45 LDATA15 R5 47 15 14 VDD33 R11 4.7K 4.7K 12 nRESET From CAT1025 R6 0 37 VDD33 27 C21 46 100nF 图 1.14 NOR Flash 存储器电路 LADDR[26:0] LADDR2 LADDR3 LADDR4 LADDR5 LADDR6 LADDR7 LADDR8 LADDR9 LADDR10 LADDR11 LADDR12 LADDR13 LADDR14 LADDR24 LADDR25 LnWBE0 LnWBE1 LSCKE LSCLK0 From U1B U4 23 24 25 26 29 30 31 32 33 34 22 35 36 A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 A10 A11 A12 20 21 BA0 BA1 15 39 LDQM UDQM 37 38 SCKE SCLK 28 41 54 VSS0 VSS1 VSS2 6 12 46 52 VSSQ0 VSSQ1 VSSQ2 VSSQ3 DQ0 DQ1 DQ2 DQ3 DQ4 DQ5 DQ6 DQ7 DQ8 DQ9 DQ10 DQ11 DQ12 DQ13 DQ14 DQ15 nSCS nSRAS nSCAS nWE VDD0 VDD1 VDD2 VDDQ0 VDDQ1 VDDQ2 VDDQ3 NC HY57V561620B LDATA[31:0] 2 LDATA0 4 LDATA1 5 LDATA2 7 LDATA3 8 LDATA4 10 LDATA5 11 LDATA6 13 LDATA7 42 LDATA8 44 LDATA9 45 LDATA10 47 LDATA11 48 LDATA12 50 LDATA13 51 LDATA14 53 LDATA15 19 LnGCS6 18 LnSRAS From U1B 17 LnSCAS 16 LnWE 1 14 VDD33 27 3 9 43 49 40 U5 LADDR2 23 LADDR3 24 LADDR4 25 LADDR5 26 LADDR6 29 LADDR7 30 LADDR8 31 LADDR9 32 LADDR10 33 LADDR11 34 LADDR12 22 LADDR13 35 LADDR14 36 LADDR24 20 LADDR25 21 LnWBE2 15 LnWBE3 39 LSCKE 37 LSCLK1 38 From U1B 28 41 54 6 12 46 52 A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 A10 A11 A12 BA0 BA1 LDQM UDQM SCKE SCLK VSS0 VSS1 VSS2 VSSQ0 VSSQ1 VSSQ2 VSSQ3 DQ0 DQ1 DQ2 DQ3 DQ4 DQ5 DQ6 DQ7 DQ8 DQ9 DQ10 DQ11 DQ12 DQ13 DQ14 DQ15 nSCS nSRAS nSCAS nWE VDD0 VDD1 VDD2 VDDQ0 VDDQ1 VDDQ2 VDDQ3 NC HY57V561620B LDATA[31:0] 2 LDATA16 4 LDATA17 5 LDATA18 7 LDATA19 8 LDATA20 10 LDATA21 11 LDATA22 13 LDATA23 42 LDATA24 44 LDATA25 45 LDATA26 47 LDATA27 48 LDATA28 50 LDATA29 51 LDATA30 53 LDATA31 19 LnGCS6 18 LnSRAS From U1B 17 LnSCAS 16 LnWE 1 14 VDD33 27 3 9 43 49 40 图 1.15 SDRAM 存储器电路 (6) NAND Flash 存储器电路 DeviceARM2410 核心板上扩展了 64MB 的 NAND FLASH(芯片型号为 K9F1208U0B), 使用 S3C2410A 的 NAND Flash 控制引脚与其相连,如图 1.16 所示。 如图 1.16 所示,K9F1208U0B 的 I/O0~I/O7 引脚直接与 S3C2410A 的数据总线 DATA0~ DATA7 相连,通过数据总线发送地址、命令和数据。 - 23 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com NAND Flash VDD33 U7 1 2 R21 3 0 4 5 6 RnB 7 nFRE 8 nFCE 9 10 VDD33 11 12 13 14 15 CLE 16 ALE 17 nFWE 18 19 R14 4.7K 20 21 22 23 24 NC NC NC NC NC NC R/B RE CE NC NC Vcc Vss NC NC CLE ALE WE WP NC NC NC NC NC NC NC NC NC I/O7 I/O6 I/O5 I/O4 NC NC NC Vcc Vss NC NC NC I/O3 I/O2 I/O1 I/O0 NC NC NC NC K9F1208U0B-PCB0 48 47 46 45 44 LDATA7 43 LDATA6 42 LDATA5 41 LDATA4 40 39 38 VDD33 37 36 35 34 33 32 LDATA3 31 LDATA2 30 LDATA1 29 LDATA0 28 27 26 25 LDATA[31:0] 图 1.16 NAND Flash 存储器电路 (7) E2PROM 存储器电路 CAT1025JI-30 内置 256 字节 E2PROM 存储器,I2C 总线接口,所以使用了 S3C2410A 芯 片的 I2C 总线接口与其连接,电路原理如图 1.12 所示。 如图 1.12 所示,I2C 总线上拉电阻 R8、R9 的大小为 4.7KΩ。CAT1025JI-30 的器件地 址为 0xA0,如果用户板(即底板)上需要使用地址为 0xA0 的 I2C 器件,或者需要将 I2CSDA、 I2CSCL 用作 GPIO,则可以将电阻 R19、R20 拆除(图 1.12 中的虚线框部分)。 说明:DeviceARM2410 默认配置时,R19、R20 是焊接的。 6. 硬件资源地址 DeviceARM2410 核 心 板 上 使 用 的 存 储 器 及 它 们 的 地 址 如 表 1.2 所 列 。 其 中 , CAT1025JI-30 芯片是与 S3C2410A 的 I2C 总线引脚相连,总线上拉电阻的阻值为 4.7KΩ。 表 1.2 DeviceARM2410 核心板上的存储器地址 存储器类别 NOR Flash SDRAM NAND Flash E2PROM 芯片型号 SST39VF1601 HY57V561620 K9F1208U0B CAT1025 地址 0x00000000~0x001FFFFF 0x30000000~0x33FFFFFF —— 从地址为 0xA0 备注 OM[1:0] = 01b 时 2 片 HY57V561620 由 NAND Flash 控制器操作 I2C 总线接口 1.3.2 实验箱主板 1. 电源电路 MagicARM2410 实验箱使用了一块专门的电源板进行供电,电源板所提供的电源有+5V 和+12V,所以在实验箱主板上还需要设计一个系统电源电路,使用 LDO 芯片(低压差电源 芯片)将 5V 电源转换得到 3.3V 系统电源。 系统电源电路如图 1.17 所示,电源供电由 J28 连接器输入实验箱主板,5V 电源经过 C70、C71 和 C125 滤波后,由两片 LDO 芯片 U41、U42 稳压输出两组 3.3V 电源,其中一 组用来给主板供电 (图 1.17 中的标号 VDD33),另一组用来给核心板供电(图 1.17 中的标号 - 24 - 广州致远电子有限公司 PVDD33)。 J28 4 +5V 3 2 1 12V ATX-4PIN Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 1 GND D13 POWER U41 SPX1117-3.3 3 VIN VOUT C70 0.1uF VCC 2 (供主板) VDD33 C61 10uF/16V R179 3K U42 SPX1117-3.3 3 VIN VOUT 2 GND C125 C71 220uF/25V 0.1uF (供核心板) PVDD33 C62 10uF/16V 1 图 1.17 系统电源电路 注意:MagicARM2410 实验箱使用的电源是 220V/50Hz 交流电源,正确连接电源线后, 打开实验箱电源,实验箱主板上的 POWER 指示灯应点亮。 2. 复位电路 由于 DeviceARM2410 核心板上使用了带 I2C 存储器的电源监控芯片 CAT1025JI-30(复位 门槛电压为 3.0~3.15V),所以实验箱主板上只需要加入一个手动复位按键即可控制 CPU 复 位,电路原理如图 1.18 所示(虚线框部分电路是在 DeviceARM2410 核心板上)。 在图 1.18 中,信号 nRESET 连接到 S3C2410A 芯片的复位脚 nRESET,当复位按键 RST 按下时,CAT1025JI-30 的 RESET 引脚立即输出复位信号,使 S3C2410A 芯片复位。 注意:使用 CAT1025JI-30 芯片时,其 RESET、 RESET 引脚上的下拉电阻、上拉电阻都 是不能省略的。 VDD33 VDD33 VDD33 R54 R16 R17 10K 10K RST 10K U3 nRSTIN 1 3 7 R15 4 MR VCC RESET RESET WP SCL VSS SDA 8 2 6 5 nRESET 10K CAT1025JI-30 图 1.18 系统复位电路 DeviceARM2410 核心板可以选择 NAND Flash 启动方式或者 NOR Flash 启动方式,这 是通过配置 OM0 引脚来实现的,电路如图 1.19 所示。当 JP8 跳线短接时,OM0 为 0 电平, 选择 NAND Flash 启动方式;当 JP8 跳线断开时,OM0 由 R38 上拉为 1 电平,选择 NOR Flash 启动方式。 注意:使用 ADS 调试具有中断功能的程序时,需要设置 Nand Flash 启动方式。 - 25 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com R38 VDD33 10K OM0 JP8 NAND Flash 图 1.19 复位启动选择电路 说明:在 MagicARM2410 实验箱主板上,J1 连接器是 DeviceARM2410 核心板的插座,主 板上的所有 I/O 控制线和系统总线均来自 J1,所以图 1.19 中使用了“J1-Port”端口表明 连接到 J1 连接器。后面的电路原理图中会有同样的表达方法。 3. JTAG 接口电路 采用 20 脚 JTAG 仿真调试接口,JTAG 信号的定义及与 S3C2410A 的连接如图 1.20 所 示(虚线框部分电路是在 DeviceARM2410 核心板上)。在图 1.20 中,JTAG 接口 J29 上的信 号 nTRST 连接到 S3C2410A 芯片的TRST 引脚,达到控制 S3C2410A 内部 JTAG 接口电路 复位的目的。根据 S3C2410A 数据手册中说明,nTRST、TDI、TMS 和 TCK 引脚上需要连 接一个 10KΩ的上拉电阻。 另外,为了能够使用 Multi-ICE 仿真器,设置了一个 0Ω电阻 R1 将 JTAG 接口的 PIN3 与 PIN15 短接。 VDD33 1 2 3 4 U1 nTRST TDI TMS TCK TDO H5 J1 J3 H6 J5 S3C2410A 5 6 7 8 RP30 10K nTRST TDI TMS TCK VDD33 TDO VDD33 R37 10K R60 R1 0 4.7K R1: use Multi-ICE J29 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 JTAG VDD33 图 1.20 JTAG 接口电路 4. RS232 接口电路 S3C2410A 具有 3 个 UART 口,在 MagicARM2410 实验箱上将其 UART0、UART1 用 作 RS232 接口,电路原理如图 1.21 所示。由于系统是 3.3V 系统,所以使用了 SP3232E 进 行 RS232 电平转换,SP3232E 是 3.3V 工作电源的 RS232 转换芯片。 由于 GPRS PACK 接口复用了 UART0,为了避免 RXD0 信号冲突,所以设计了 JP1 跳 线。当需要使用 RS232 接口 CZ11 时,请将 JP1 跳线短接,然后将 PC 的串口(如 COM1)与 实验箱上的 CZ11 相连;当需要使用 GPRS 模块时,请将 JP1 跳线断开。 注意:CZ11 安装在 MagicARM2410 实验箱的机箱右侧,这样设计是为了在每次做完 实验之后,不用拔出串口连接线就可以盖上实验箱。 - 26 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 由于 RS485 接口电路复用了 UART1,为了避免 RXD1 信号冲突,所以设计了 JP2 跳线。 当需要使用 RS232 接口 CZ1 时,请将 JP2 跳线短接到“232R”端,然后将 PC 的串口(如 COM1)与实验箱上的 CZ1 相连;当需要使用 RS485 接口时,请将 JP2 跳线短接到“485R” 端,然后把 RS485 总线连接到 J3 上。 若用户需要直接使用 TXD0、RXD0、TXD1 和 RXD1 引脚信号,可以通过 J2 插针引出。 CZ11 UART0 CZ1 UART1 TP1 TP8 TP9 TP22 TP23 GND PC-RXD0 PC-TXD0 PC-RXD1 PC-TXD1 nCTS0 RXD0 RXD1 RXD2 GND PC-RXD0 PC-TXD0 PC-RXD1 PC-TXD1 1 VDD33 6 2 U1 7 3 VDD33 16 VCC C1+ 1 C3 8 4 9 2 6 V+ V- C1C2+ 3 4 0.1uF C1 C2 C4 5 0.1uF 0.1uF 15 GND C2- 5 0.1uF J2 1 2 3 4 5 6 7 8 9 10 UART-TTL 1 PC-RXD0 PC-TXD0 14 13 T1OUT T1IN R1 IN R1OUT 11 12 TXD0 JP1 RXD0 6 PC-RXD1 2 PC-TXD1 7 7 8 T2OUT T2IN R2 IN R2OUT 10 9 RXD1-232 RXD0 TXD1 3 8 SP3232E JP2 4 9 5 3 2 1 RXD1-485 RXD1 RXD1 nRTS0 TXD0 TXD1 TXD2 J1-Port 图 1.21 RS232 串口电路 5. RS485 接口电路 MagicARM2410 实验箱主板上有 RS485 转换电路,电路原理如图 1.22 所示。由于系统 是 3.3V 系统,所以使用了 SP3485 进行 RS485 电平转换,SP3485 是 3.3V 工作电源的半双 工 RS485 收发器。在图 1.22 中,使用 GPE13(网络标号为 SPICLK0)连接到 RS3485 的 DE 引脚和 RE 引脚,当 GPE13 输出低电平时,RS3485 的接收器使能,RS485 总线上的数据将 会从 RO 引脚输出,而 S3C2410A 则使用 RXD1 进行接收;当 GPE13 输出高电平时,RS3485 的驱动器使能,S3C2410A 使用 TXD1 进行数据发送。 由于 RS232 接口电路复用了 UART1,为了避免 RXD1 信号冲突,所以设计了 JP2 跳线。 当需要使用 RS485 接口时,请将 JP2 跳线短接到“485R”端即可。 在 RS485 总线中,终端通常需要接一个终端电阻,如图 1.22 所示电阻 R44,当需要使 用此电阻时将 JP12 短接即可。 TP3 GND TP12 485-A TP13 485-B GND 485-A 485-B J1-Port (GPE13) SPICLK0 RXD1-485 TXD1 R11 10K U14 1 RO 2 RE 3 DE 4 DI SP3485 VCC B A GND VDD33 8 7 6 R44 5 JP12 120 RT-EN RS485-A RS485-B J3 3 2 1 RS485 图 1.22 RS485 接口电路 - 27 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 6. IrDA 驱动电路 S3C2410A 的 UART 接口都支持 IrDA(v1.0)发送和接收,MagicARM2410 实验箱主板上 使用了 UART2+RPM851A(专用的 IrDA 无线收发模块)组成 IrDA 接口,电路原理如图 1.23 所示。 如图 1.23 所示,IrDA 数据发送是由 1 个“与”门(即 U2B)进行控制,当 GPB1(网络标 号为 TOUT1)输出高电平时,允许 IrDA 数据发送;当 GPB1 输出低电平时,禁止 IrDA 数据 发送。 TP2 GND TP10 IRDA-R TP11 IRDA-T VDD33 GND IRDA-R IRDA-T J1-Port (GPB1) IRDA-TXD-EN TOUT1 TXD2 R9 10K 4 U2B 5 R10 10K 74LV08 RXD2 R2 22 R43 2 6 IRDA-T R59 5.1 4 3 6 22 VDD33 5 IRDA-R 10 8 11 VDD33 C63 3.3nF 9 R40 12 C58 49.9 C64 13 0.47uF 1 10uF/16V 7 U3 LED NC LEDDRV TXD LEDVCC RXDSIR NC BIAS PWDOWN VCC PINVCC GND GND RPM851A 图 1.23 IrDA 驱动电路 7. 独立 LED 及蜂鸣器控制电路 MagicARM2410 实验箱主板上设计有 4 个独立的发光二极管 LED1~LED4,分别由 GPE11、GPE12、GPH4 和 GPH6 输出控制,控制 I/O 输出高电平时对应的 LED 点亮,输出 低电平时对应的 LED 熄灭,电路原理如图 1.24 所示。 说明:由于 GPH4、GPH6 是与 TXD1、TXD2 复用口线,所以当使用 UART1、UART2 进行数据发送时,LED3 和 LED4 会闪烁。 VDD33 LED1 R139 470 LED2 R140 470 Q9 8050 R101 1K SPIMISO0 J1-Port (GPE11) LED3 R142 470 Q11 8050 R102 1K SPIMOSI0 (GPE12) LED4 R143 470 Q10 8050 R103 1K TXD1 (GPH4) Q12 8050 R104 1K TXD2 (GPH6) 图 1.24 独立 LED 控制电路 如图 1.25 所示,蜂鸣器使用 PNP 三极管 Q13 进行驱动控制,当控制 GPH10(网络标号 - 28 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 为 CLKOUT1)输出低电平时,Q13 导通,蜂鸣器蜂鸣;当控制 GPH10 输出高电平时,Q13 截止,蜂鸣器停止蜂鸣;若把 JP9 断开,Q13 截止,蜂鸣器停止蜂鸣。 VDD33 CLKOUT1 (GPH10) JP9 BEEP R141 1K Q13 8550 R183 18 图 1.25 蜂鸣器控制电路 B1 BUZZER 8. 键盘及 LED 数码管显示电路 MagicARM2410 实验箱主板上具有 8 位动态 LED 数码管和 16 个按键,使用了 I2C 接口 的键盘与 LED 驱动芯片 ZLG7290 进行控制,电路如图 1.26 所示。ZLG7290 是一款功能强 大的键盘与 LED 驱动芯片,最大支持 64 个按键及 8 位共阴 LED 数码管。 ZLG7290 的电源采用 3.3V,使用 DeviceARM2410 核心板的 nRSTOUT 信号(经过驱动 后的网络标号为 nRST)控制 ZLG7290 复位,在系统复位时将同时复位 ZLG7290。由于 ZLG7290 采用 3.3V 电源,为了提高 LED 数码显示的亮度,LED 限流电阻 R148~R150、 R153~R157 的阻值选用 220Ω。16 个按键分别与 ZLG7290 的 SEGA、SEGB 引脚连接,这 样做的好处就是键盘的扫描值是连续的,即 S1~S16 按键的扫描值为 1~16,方便应用程序 的设计。ZLG7290 的键盘中断输出信号与 S3C2410A 的中断引脚 EINT4 相连,当有按键按 下时,ZLG7290 将会输出中断信号通知 S3C2410A。 注意:独立按键 KEY1 也使用了 S3C2410A 的 EINT4 功能引脚。 S1 0 S2 4 S3 8 S4 Enter_C S5 1 S6 5 S7 9 S8 -_D S9 2 S10 6 S11 DOT_A S12 *_E S13 3 S14 7 S15 +_B S16 /_F D3 KSG0 1N4148 D4 KSG1 1N4148 C3 C2 a b c d e f g h 11 SEG0 7 SEG1 4 SEG2 2 SEG3 1 SEG4 10 SEG5 5 SEG6 3 SEG7 C1 C0 LED8 C3 C2 a b c d e f g h 11 SEG0 7 SEG1 4 SEG2 2 SEG3 1 SEG4 10 SEG5 5 SEG6 3 SEG7 C1 C0 LED9 DIG0 6 DIG1 8 DIG2 9 DIG3 12 DIG4 6 DIG5 8 DIG6 9 DIG7 12 9 R130 R131 R132 R133 R134 R135 R136 K 1K 1K 1K 1K 1K 1K 1K DIG0 DIG4 DIG1 DIG5 DIG2 DIG6 DIG3 DIG7 GND I2CSDA I2CSCL EINT4 TP4 TP14 TP15 TP16 GND SDA SCL nKINT J1-Port DIG7 DIG6 DIG5 DIG4 DIG3 DIG2 DIG1 DIG0 I2CSDA I2CSCL EINT4 R151 220 U25 13 12 21 22 3 4 5 6 Dig7 Dig6 Dig5 Dig4 Dig3 Dig2 Dig1 Dig0 20 19 14 11 SDA SCL /INT GND SegA SegB SegC SegD SegE SegF SegG SegH VCC OSC2 OSC1 /RES ZLG7290 ZLG7290 Addr:0x70 23 KSG0 24 KSG1 1 2 7 8 9 10 R148 R149 R150 R153 R154 R155 R156 R157 220x8 SEG0 SEG1 SEG2 SEG3 SEG4 SEG5 SEG6 SEG7 16 18 VDD33 C114 20pF 17 15 X4 6MHz R152 C115 20pF nRST 图 1.26 键盘及 LED 显示电路 - 29 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 9. 彩色液晶屏及触摸屏驱动电路 S3C2410A 内置有液晶控制器,可以支持最大 256K 色 TFT 彩色液晶屏、最大 4K 色 STN 彩色液晶屏。MagicARM2410 实验箱上标准配置有 8 英寸 640×480 TFT 液晶屏(型号为 LQ080V3DG01),它与 S3C2410A 的电路连接如图 1.27 所示(左半部分)。LQ080V3DG01 液 晶屏采用 5V 电源供电,根据其数据手册可知,它的 VIH 最小值为 2.3V,所以直接使用 S3C2410A 的控制口线与它相连,不需要加电平转换电路。LQ080V3DG01 液晶屏有 18 根数 据线(R、G、B 各 6 根),S3C2410A 的控制器应选用 16BPP 模式,将 S3C2410A 的 VD2~ VD7 与液晶屏的 B0~B5 相连,VD10~VD15 与 G0~G5 相连,VD18~VD23 与 R0~R5 相连。 图 1.27 的右半部分是 STN 彩色液晶屏 LFUBK9111 的驱动电路,LFUBK9111 液晶屏采 用 5V 电源供电,由于电平匹配问题,所以使用了 74HCT244 芯片进行电平转换(此芯片的 VIH 最小值为 2.0V)。驱动 LFUBK9111 只需要使用 8 根数据线 VD0~VD7,控制信号 VFRAME、VLINE、VCLK 分别连接 LFUBK9111 的 FRAME、LOAD、CP 引脚,控制信号 LCD_PWREN(网络标号为 LCD-PWR)用来控制液晶屏显示/关闭。 LQ080V3DG01 和 LFUBK9111 液晶屏都是使用冷阴极背光灯管(CCFL),需要高压交流 电源供电,所以设计了液晶屏背光灯管驱动电路,如图 1.27 中的 CXA_L10A 模块部分电路。 液晶屏背光灯管驱动电路的供电电源是通过 JP7 跳线来连接的,当需要使用液晶屏进行图形 显示时,请将 JP7 跳线短接。 注意:由于液晶屏背光灯管的功耗较大,所以在不使用液晶屏时请将 JP7 跳线断开。另 外,要求在关断实验箱总电源之后,再进行短接/断开 JP7 跳线操作。 J1-Port U31 GND 1 VCLK 2 VLINE 3 VFRAME 4 GND 5 VD18 6 VD19 7 VD20 8 VD21 9 VD22 10 VD23 11 GND 12 VD10 13 VD11 14 VD12 15 VD13 16 VD14 17 VD15 18 GND 19 VD2 20 VD3 21 VD4 22 VD5 23 VD6 24 VD7 25 GND 26 VM 27 28 +5V 29 30 31 32 GND CK Hsync Vsync GND R0 R1 R2 R3 R4 R5 GND G0 G1 G2 G3 G4 G5 GND B0 B1 B2 B3 B4 B5 GND ENAB VCC VCC R/L U/D GND LQ080V3DG01 VD7 8 RP36 22 1 VD6 7 2 VD5 6 3 VD4 5 4 VD3 8 1 VD2 7 2 VD1 6 3 VD0 5 4 RP35 22 VFRAME 8 RP37 1 VLINE 7 2 LCD-PWR 6 3 VCLK 5 4 22 R29 10K U33 19 1 OE2 VCC OE1 GND 2 4 6 8 17 15 13 11 I0 I1 I2 I3 I4 I5 I6 I7 O0 O1 O2 O3 O4 O5 O6 O7 74HCT244 U34 19 1 OE2 VCC OE1 GND 2 4 6 8 17 15 13 11 I0 I1 I2 I3 I4 I5 I6 I7 O0 O1 O2 O3 O4 O5 O6 O7 74HCT244 +5V 20 10 18 UD3 16 UD2 14 UD1 12 UD0 3 LD3 5 LD2 7 LD1 9 LD0 +5V 20 10 18 FRAME 16 LOAD 14 LCDCP 12 DISP-EN 3 5 7 9 JP7 2 1 J25 VLIGHT 1 2 3 4 EXT5V EXT-GND C120 10uF/16V C121 4.7uF U37 1 VCC OUT1 OUT2 3 4 2 GND OGND 5 CXA_L10A +5V J23 1 2 VHP UD3 UD2 UD1 UD0 LD3 LD2 LD1 LD0 FRAME LOAD LCDCP DISP-EN 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 LFUBK9111X J9 V-OUT 1 2 3 4 J26 1 2 图 1.27 彩色液晶屏接口电路 MagicARM2410 实验箱的彩色液晶屏上带有触摸屏(为四线电阻式触摸屏),用于检测屏 幕触摸输入信号,有利于提高人机交互的友好性。在使用触摸屏时,需要一套切换控制及 ADC 转换电路,用于切换触摸屏的 X、Y 轴输入,并进行 A/D 转换。触摸屏驱动电路如图 1.28 所示,直接使用 S3C2410A 内置的触摸屏接口 + ADC 进行采样,其中 U39 和 U40 是双 MOS 管(P&N 沟道),J27 是连接触摸屏的连接插座。 - 30 - TSXP TSYP GND 广州致远电子有限公司 J1-Port TP17 TSXP TP18 TSYP TP6 GND Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com YMON U39 1 G1_N D1_N 6 VDD33 2 S2_P S1_N 5 nXPON 3 G2_P D2_P 4 FDC6321 AIN7 C122 1nF R124 4.7K XMON U40 1 G1_N D1_N 6 VDD33 2 S2_P S1_N 5 nYPON 3 G2_P D2_P 4 FDC6321 AIN5 C123 1nF R125 4.7K TSYM TSXP TSXM TSYP J27 4 X+ 3 Y2 X1 Y+ Touch 图 1.28 触摸屏驱动电路 11. IIS 数字音频输入输出电路 S3C2410A 内置有 IIS 音频接口,只需要外接一个数字音频编解码器即可实现音频输入/ 输出。MagicARM2410 实验箱上使用的数字音频编解码器为 UDA1341TS,电路原理如图 1.29 所示。UDA1341TS 具有数字电源和模拟电源引脚,为了防止相互的干扰,所以使用了 几个磁珠(FB1~FB3)来隔离这两组电源,如图 1.29 的上半部分。 VDD33 FB1 CBG201209U151B C130 220uF/16V DVDD33 C21 0.1uF VDD33 FB2 CBG201209U151B C131 220uF/16V FB3 CBG201209U151B AVDD33 C22 0.1uF 12V R137 5.1 C20 0.1uF AVDD12 C132 220uF/16V DVDD33 R127 5.1 AVDD33 R128 5.1 C6 C7 C19 0.1uF 0.1uF 0.1uF U7 10 DVDD 11 DVSS 3 7 25 AVDD(ADC) Vpref(ADC) AVDD(DAC) 1 5 27 AVSS(ADC) Vnref(ADC) AVSS(DAC) J1-Port 9 22 OVERFL AGCSTAT CDCLK R75 22 I2SSCLK I2SLRCK I2SSDI I2SSDO TOUT2 TCLK0 TOUT3 12 16 17 18 19 SYSCLK BCK WS DATAO DATAI 13 14 15 L3MODE L3CLOCK L3DATA UDA1341TS 5 4 3 2 1 E D C B A VOUTL 26 C74 47uF/16V R55 100 R26 VOUTR 24 C75 47uF/16V R56 100 R27 VINL1 VINR1 VINL2 VINR2 TEST1 TEST2 QMUTE 2 4 6 C73 8 C81 20 21 23 R24 R25 10K 10K C77 10uF/16V 10uF/16V 10uF/16V C82 220pF C119 220pF Vref(ADC&DAC) 28 C10 0.1uF C76 47uF/16V R21 R22 R23 10K 10K 10K R79 6.8K AVDD33 R57 100 C78 10uF/16V R147 5.6K R170 5.6K R145 R146 5.6K 5.6K 1 2 3 4 5 A B C D E 1 2 3 4 5 A B C D E CZ3 PHONE 51K SPKR 51K SPKL CZ4 MIC-STE J33 MIC CZ5 LINEIN 图 1.29 IIS 数字音频输入输出电路 S3C2410A 的 IIS 总线 CDCLK、I2SSCLK、I2SLRCK、I2SSDI、I2SSDO 分别连接到 - 31 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com UDA1341TS 的 SYSCLK、BCK、WS、DATAO、DATAI 引脚上,UDA1341TS 的 L3MODE 由 GPB2 信号(网络标号为 TOUT2)控制,UDA1341TS 的 L3CLOCK 由 GPB4 信号(网络标号 为 TCLK0)控制,UDA1341TS 的 L3DATA 由 GPB3 信号(网络标号为 TOUT3)控制。 为了方便用户的使用,MagicARM2410 实验箱上设计有双声道功率放大电路,并安装 有两个 0.5W 的小喇叭,电路如图 1.30 所示,其中 W3 用于音量调节。 说明:如果用户在 CZ3 接口上插入了耳机插头,则实验箱上的小喇叭就没有声音输出。 1 2 3 SPKR 4 5 6 SPKL 10K R122 10K R123 10K R121 R126 10K 10K C66 C68 1nF 1nF C86 47uF/16V U16 7 8 6 5 +IN1 VCC -IN1 OUT1 +IN2 OUT2 -IN2 GND TDA2822M C87 47uF/16V AVDD12 2 1 C88 3 4 220uF/16V C11 0.1uF R81 5.1 SP1 1W/4R C89 220uF/16V C12 0.1uF R82 5.1 SP2 1W/4R 图 1.30 音频功率放大电路 12. USB HOST/Device 接口电路 S3C2410A 具有 2 路 USB v1.1 接口,1 路固定为 HOST 接口(下行口),另 1 路可配置为 HOST 或 Device 接口。这两个下行口对于芯片的引脚为 DN0、DP0 和 DN1、DP1,其中 DN1、 DP1 引脚与 USB 设备端(即 Device)的引脚复用。由于我们使用了 DN1、DP1 引脚作为 USD 设备端使用,所以在本实验箱中只使用了 DN0、DP0 引脚作唯一的下行口。 仅有一个 USB 下行口,无法满丰富 USB 外设的需求,为此我们设计了一个 USB 集线 器电路,通过集线器可以扩展出 4 个 USB 下行口,电路如图 1.31 所示。 +5V R100 1K C60 C13 10uF/16V 0.1uF USB2-DM 1 USB2-DP 2 USB3-DM 3 USB3-DP 4 USB4-DM 5 USB4-DP 6 7 8 9 10 11 VCC3V 12 13 14 R53 10K +5V U24 USB2_DM USB1_DP USB2_DP USB1_DM USB3_DM USB_DP USB3_DP USB_DM USB4_DM DP3_OVRCUR USB4_DP DP4_OVRCUR DP4_PWRUP DP3_PWRUP DP2_PWRUP XTAL2 BUS_PWRED XTAL1 VCC50/VCC51K AGND/AND0 GND50/GND51 Empty Pin VCC3V DP2_OVRCUR DP1_PWRUP SUSPEND GANGPOWER DP1_OVRCUR AU9254A21 28 USB1-DP 27 USB1-DM 26 25 24 23 22 21 20 19 18 17 16 SUSPEND 15 VCC3V C14 C105 R111 0.1uF 10uF/16V 1.5K R107 33 R108 33 R106 33 X2 R109 33 R138 15K 12MHz C103 39pF R1101M C104 39pF DP0 DN0 R144 15K J1-Port USB2-DM USB2-DP USB1-DM USB1-DP R113 R115 R117 R119 15K 15K 15K 15K R105 1K Q1 8550 D1 +5V GRN J36 +5V J37 +5V 1 2 3 USB3-DM USB3-DP 1 2 3 USB4-DM USB4-DP 4 4 USB-CON1 USB-CON2 USB4-DM USB4-DP USB3-DM USB3-DP R64 R65 R73 R74 15K 15K 15K 15K +5V 1 2 3 4 CZ7 Vbus DM DP GND 5 6 SHIELD SHIELD USB-A C133 0.01U/1KV +5V 1 2 3 4 CZ6 Vbus DM DP GND 5 6 SHIELD SHIELD USB-A C134 0.01U/1KV USB_COM PACK +5V 1 2 3 4 CZ13 Vbus DM DP GND 5 6 SHIELD SHIELD USB-A C1 0.01U/1KV +5V 1 2 3 4 CZ14 Vbus DM DP GND 5 6 SHIELD SHIELD USB-A C2 0.01U/1KV 图 1.31 USB HOST 接口电路 USB 集线器控制器芯片采用了 MICRO 公司生产的 AU9254。该芯片电路简单,性价比 高,在 USB 集线器设备产品中被广泛使用。整个集线器电路与系统连接的只有 4 根线:+5V、 - 32 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com GND、DP0 和 DN0,其与外接一个 USB 集线器电路相似。 USB Device 接口电路如图 1.32 所示,为了使 S3C2410A 的软件可以更灵活地控制 USB 设备与主机之间的连接,使用 GPG9 引脚(网络标号为 EINT17)来实现软连接。当 GPG9 输 出低电平时,Q2 导通,D+线通过 R114(1.5K)上拉到 VDD33,通知 USB 主机——USB 设备要与其建立连接;当 GPG9 输出高电平时,Q2 关断,D+线断开与 VDD33 的连接,通 知 USB 主机——USB 设备已经断开与 USB 主机的连接。USB 总线的 D+和 D-线都要串接 一个匹配电阻,阻值为 22 欧。 Q2选用的是P沟道MOS管2SJ355,而不能选用普通的PNP三极管,其原因是隔离D+线与 GPG9之间的电流联系。当USB总线正常通信时,D+线上的信号频率12MHz,如果用GPG9 来直接控制软连接,那么等于在S3C2410A的I/O口上引入了一个时钟信号,这种设计是不合 理的。而MOS管是用电压来控制开通与关断的,当MOS管导通时,GPG9与D+线没有电流 联系,D+线上的时钟信号也不会影响到S3C2410A了。 J1-Port DN1 DP1 VDD33 R3 22 R4 22 Q2 2SJ355 R114 1.5K R116 R118 1M 1M CZ10 1 2 3 4 VBUS DD+ GND USB Device EINT17 (USB-EN) (GPG9) R112 1K 图 1.32 USB Device 接口电路 13. 总线驱动电路 DeviceARM2410 核心板为用户板(即底板)提供了 32 位总线接口,6 个 Bank 的存储空间, 供用户扩展外部总线设备使用。为了提高系统的可靠性,MagicARM2410 实验箱主板上使 用了 74LVC245 芯片进行总线驱动,地址总线驱动电路如图 1.33 所示,控制总线驱动电路 如图 1.34 所示,数据总线驱动电路如图 1.35 所示。 由于地址总线 ADDR0~ADDR26 和控制信号 nWE、nOE、nWBE0~nWBE3 总是输出, 所以对应的驱动器 U5、U10~U13 的 DIR 引脚直接与 VCC(即 3.3V 电源)连接即可。U5、 U10~U13 的 G 引脚固定接为低电平,保持使能输出状态。由于总线上的频率往往比较高, 所以在地址总线、控制信号的输出端串接 22Ω的小电阻(图 1.33、图 1.34 中的 RP1~RP9), 能够使总线上的信号上升/下降变得较平滑,达到有效地抑制 EMI 的目的。在后面的使用到 总线的电路原理图中,也使用了串接小电阻的方法来抑制 EMI。 说明:经过驱动后的总线信号,其网络标号没有“L”字符(第一个字符)。如图 1.33 所 示,经过驱动后的信号均连接到“EMC-BUS”端口,而后面的电路原理图中也会使用到 “EMC-BUS”端口,表明连接的信号是由总线驱动电路输出的信号。 - 33 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com J1-Port U5 19 VDD33 1 G DIR LADDR7 2 LADDR6 3 LADDR5 4 LADDR4 5 LADDR3 6 LADDR2 7 LADDR1 8 LADDR0 9 A1 A2 A3 A4 A5 A6 A7 A8 B1 B2 B3 B4 B5 B6 B7 B8 18 17 16 15 14 13 12 11 5 RP2 6 7 8 5 6 7 8 RP1 22 4 ADDR7 3 ADDR6 2 ADDR5 1 ADDR4 4 ADDR3 3 ADDR2 2 ADDR1 1 ADDR0 22 74LVC245 U10 19 VDD33 1 G DIR LADDR15 2 LADDR14 3 LADDR13 4 LADDR12 5 LADDR11 6 LADDR10 7 LADDR9 8 LADDR8 9 A1 A2 A3 A4 A5 A6 A7 A8 B1 B2 B3 B4 B5 B6 B7 B8 18 17 16 15 14 13 12 11 5 RP5 6 7 8 5 6 7 8 RP3 22 4 ADDR15 3 ADDR14 2 ADDR13 1 ADDR12 4 ADDR11 3 ADDR10 2 ADDR9 1 ADDR8 22 74LVC245 19 VDD33 1 LADDR23 2 LADDR22 3 LADDR21 4 LADDR20 5 LADDR19 6 LADDR18 7 LADDR17 8 LADDR16 9 U11 G DIR A1 A2 A3 A4 A5 A6 A7 A8 B1 B2 B3 B4 B5 B6 B7 B8 18 17 16 15 14 13 12 11 5 RP6 22 4 ADDR23 6 3 ADDR22 7 2 ADDR21 8 1 ADDR20 5 4 ADDR19 6 3 ADDR18 7 2 ADDR17 8 1 ADDR16 RP4 22 74LVC245 19 VDD33 1 LADDR26 2 LADDR25 3 LADDR24 4 5 6 7 8 9 U13 G DIR A1 A2 A3 A4 A5 A6 A7 A8 B1 B2 B3 B4 B5 B6 B7 B8 18 17 16 15 14 13 12 11 5 RP9 22 4 ADDR26 6 3 ADDR25 7 2 ADDR24 8 1 74LVC245 EMC-BUS 图 1.33 地址总线驱动电路 J1-Port U12 19 VDD33 1 nRSTOUT 2 LnOE 3 LnWE 4 LnWBE3 5 LnWBE2 6 LnWBE1 7 LnWBE0 8 9 G DIR A1 A2 A3 A4 A5 A6 A7 A8 B1 B2 B3 B4 B5 B6 B7 B8 18 17 16 15 14 13 12 11 5 RP7 22 4 nRST 6 3 nOE 7 2 nWE 8 1 nWBE3 5 4 nWBE2 6 3 nWBE1 7 2 nWBE0 8 1 RP8 22 74LVC245 EMC-BUS 图 1.34 控制总线驱动电路 数据总线 D0~D31 既需要输出也需要输入,所以驱动器 U4、U6、U8 和 U9 的 DIR 引 脚不能固定连接 VCC 或 GND,而是由 nOE 信号进行控制,当 nOE 为低电平时(读操作), DIR 引脚也为低电平,驱动器 U4、U6、U8 和 U9 的方向为输入。当 nOE 为高电平时(不是 读操作),DIR 引脚也为高电平,驱动器 U4、U6、U8 和 U9 的方向为输出。 J1-Port BUS-EN = nGCS1 & nGCS2 & nGCS3 & nGCS4 & nGCS5 & nGC SJA-CS = LADDR4 # nGCS4; SJA-ALE = !(LADDR2 # nGCS4); 1 nGCS7 2 nGCS5 3 nGCS4 4 nGCS3 5 nGCS2 6 nGCS1 7 LADDR3 8 9 10 U15 I/CLK VCC I I/O I I/O I I/O I I/O I I/O I I/O I I/O I I/O GND I/OE ATF16LV8C VDD33 20 19 18 17 SJA-CS 16 SJA-ALE 15 14 13 LADDR2 12 BUS-EN 11 SJA-CON 19 LnOE 1 LDATA0 2 LDATA1 3 LDATA2 4 LDATA3 5 LDATA4 6 LDATA5 7 LDATA6 8 LDATA7 9 19 LnOE 1 LDATA8 2 LDATA9 3 LDATA10 4 LDATA11 5 LDATA12 6 LDATA13 7 LDATA14 8 LDATA15 9 U4 G DIR B1 B2 A1 B3 A2 B4 A3 B5 A4 B6 A5 B7 A6 B8 A7 A8 74LVC245 U6 G DIR B1 B2 A1 B3 A2 B4 A3 B5 A4 B6 A5 B7 A6 B8 A7 A8 74LVC245 18 DATA0 17 DATA1 16 DATA2 15 DATA3 14 DATA4 13 DATA5 12 DATA6 11 DATA7 18 DATA8 17 DATA9 16 DATA10 15 DATA11 14 DATA12 13 DATA13 12 DATA14 11 DATA15 19 LnOE 1 LDATA16 2 LDATA17 3 LDATA18 4 LDATA19 5 LDATA20 6 LDATA21 7 LDATA22 8 LDATA23 9 19 LnOE 1 LDATA24 2 LDATA25 3 LDATA26 4 LDATA27 5 LDATA28 6 LDATA29 7 LDATA30 8 LDATA31 9 U8 G DIR B1 B2 A1 B3 A2 B4 A3 B5 A4 B6 A5 B7 A6 B8 A7 A8 74LVC245 U9 G DIR B1 B2 A1 B3 A2 B4 A3 B5 A4 B6 A5 B7 A6 B8 A7 A8 74LVC245 18 DATA16 17 DATA17 16 DATA18 15 DATA19 14 DATA20 13 DATA21 12 DATA22 11 DATA23 18 DATA24 17 DATA25 16 DATA26 15 DATA27 14 DATA28 13 DATA29 12 DATA30 11 DATA31 EMC-BUS J1-Port 图 1.35 数据总线驱动电路 需要注意的是,当对 DeviceARM2410 核心板内的资源进行访问时(地址空间为 Bank0、 Bank6 块的地址空间),驱动器 U4、U6、U8 和 U9 应该处于三态状态(以免产生数据总线冲 突),所以驱动器 U4、U6、U8 和 U9 的 G 引脚要由 S3C2410A 的 nGCS1~nGCS5、nGCS7 - 34 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 进行控制(控制信号由这些片选信号相“与”产生,这是由图 1.35 中的 U15 芯片实现的)。 这样只有在访问 S3C2410A 的 Bank1~Bank5、Bank7 块的地址空间时,驱动器 U4、U6、 U8 和 U9 才使能,用户板(即底板)的数据总线才真正的有效。 14. 以太网接口电路 MagicARM2200 实验箱主板上有 1 路的 10/100M 以太网接口电路,电路原理如图 1.36 所示。该电路的核心芯片是 DM9000E 10/100M 以太网控制器。电路使用 16 位总线方式进 行控制,数据总线 DATA0~DATA15 与芯片的 SD0~SD15 连接,地址线也进行相对应的连接, 片选线 nGCS3 与芯片的 AEN 相连。DM9000E 10/100M 以太网控制器的工作基地址为 0x300, 而 S3C2410A 的地址线 ADDR2 与芯片的命令/数据使能端 CMD 相连,所以对其进行操作时 的地址是 0x300(地址端口)或 0x304(数据端口),而结合 DeviceARM2410 的片选线得到 的 32 位地址为 0x18000300(地址端口)或 0x18000304(数据端口)。DM9000E 的应用及连 接方法的详细说明请参考 DM9000E 芯片的数据手册。 V33A C101 J1-Port (GPG2) VDD33 5 20 36 55 72 73 90 EMC-BUS DATA0 DATA1 DATA2 DATA3 DATA4 DATA5 DATA6 DATA7 DATA8 DATA9 DATA10 DATA11 DATA12 DATA13 DATA14 DATA15 nOE nWE ADDR2 nGCS3 (NET-AEN) EINT0 (NET-INT) nSS-SPI0 (NET-RST) 5 RP13 22 4 6 6 3 7 7 2 8 8 1 9 5RP10 4 10 6 3 11 7 2 12 8 1 13 8RP11 7 1 89 2 88 6 3 87 5 4 86 8RP12 7 1 85 2 84 6 3 83 5 4 82 93 94 95 96 97 VDD33 98 1 2 3 4 92 91 100 14 VDD33 16 17 18 19 48 VDD33 68 69 70 R58 71 4.7K 78 79 PW-RST 80 + C106 10uF/16V U22 SD0 SD1 SD2 SD3 SD4 SD5 SD6 SD7 SD8 SD9 SD10 SD11 SD12 SD13 SD14 SD15 EX_BUS SA4 SA5 SA6 SA7 SA8 SA9 IOR IOW AEN IOWAIT CMD IO16 INT RST TEST1 TEST2 TEST3 TEST4 Miscell TEST5 GPIO0 GPIO1 GPIO2 GPIO3 LINK_O WAKEUP PW_RST DM9000E 15 23 42 58 63 76 81 99 DGND DGND DGND DGND DGND DGND DGND DGND DVDD DVDD DVDD DVDD DVDD DVDD DVDD 74 75 77 NC NC NC SD AGND BGRES AVDD AVDD RXI+ RXIPHY/AAFiGGbNNerDD TXO+ TXOAVDD 24 25 26 27 28 29 30 31 32 33 34 35 SD31/LINK_I SD30/RXD0 SD29/RXD1 SD28/RXD2 SD27/RXD3 SD26/CRS SD25/COL SD24/RX_DV SD23/RX_ER MSISIDD2221//RTXX__CCLLKK SD20/TXD0 SD19/TXD1 SD18/TXD2 SD17/TXD3 NC/TX_EN SD16/MDIO IO32/MDC 37 38 39 40 41 43 44 45 46 47 49 50 51 52 53 54 56 57 LINKACT LED DUP SPEED 62 61 60 X2_25M CLKCLXK12_02M5MO 21 22 59 EEDI EEEPEEEDCOK EECS 64 65 66 67 AGND1 C91 R80 0.1uFAGND1 6.8K R88 R86 49.9 49.9 V33A AGND1 R87 49.9 R89 49.9 R49 0 C92 0.1uF 1 2 3 4 5 6 7 8 C93 0.1uF 0.01uF/1KV U23 TPOUT+TX+ MT EMT TPOUT- TXNC NC NC NC TPIN+ RX+ MR EMR TPIN- RX- 16 15 14 13 12 11 10 9 HR601680 AGND1 C100 0.01uF/1KV R96 R97 R98 R99 75 75 75 75 CZ8 1 2 3 4 5 6 7 8 9 RJ45 C90 0.1uF V33A AGND1 R90 AGND1 0 AGND1 VDD33 VDD33 V33A L6 CBG201209U151B LED5 GRN R51 R50 470 1K R52 470 C107 22P X3 25MHz C108 R28 22P 10K LED6 GRN LED7 RED VDD33 V33A C94 0.1uF C95 0.1uF C96 0.1uF C97 0.1uF C98 0.1uF C99 0.1uF AGND1 图 1.36 以太网接口电路 15. CAN 接口电路 MagicARM2410 实验箱上采用 SJA1000 CAN 控制器扩展 1 路 CAN 接口,电路原理如 图 1.37 所示。SJA1000 是 PHILIPS 公司的经典 CAN 控制器,支持 CAN2.0A、B 协议,在 实际应用产品中占有绝对的市场比率。不过它的设计是基于早期的 80C51 单片机应用,内 嵌锁存器可以使 80C51 单片机无需任何外接器件就可以直接连接。但是,S3C2410A 的地址 总线和数据总线是分开的,不能直接连接 SJA1000,所以需要模拟出类似 80C51 单片机的 外部存储器时序才能使用。在图 1.37 的电路中,使用了一个“或”门和一个“或非”门的 组合,配合地址总线,首先模拟出一个 ALE(地址锁存信号),把 SJA1000 的内部寄存器地 址写入锁存器,然后再向 SJA1000 内部寄存器写入数据。这样,使用 ARM 的两条外部存储 器访问指令,就可以模拟出 SJA1000 所需要的时序了。 图 1.37 中虚线框部分的“或”门和“或非”门逻辑电路,是由 GAL 芯片 ATF16LV8C - 35 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 芯片(标号为 U15)实现,参考如图 1.35 所示。 EMC-BUS J1-Port DATA0 5 RP31 4 D0C DATA1 6 3 D1C DATA2 7 2 D2C DATA3 8 1 D3C 470 DATA4 5 RP32 4 D4C DATA5 6 3 D5C DATA6 7 2 D6C DATA7 8 1 D7C 470 LADDR2 nCGS4 LADDR3 2 U43A 3 1 SJA-ALE 74LV02 1 U44A 2 3 SJA-CS 74LV32 +5V 1 TC0 R68 470 3 U19 VDD GND TLP113 R70 0 CAN-V0 6 R76 10K 5 4 CAN-G0 RC0 +5V R69 10K 6 5 U20 VDD 4 GND TLP113 R71 0 1 CAN-V0 3 R85 470 R66 0 +5V CAN-V0 2 Vin +Vout 4 1 GND 0V 3 U18 BO5O5-W25 C8 C9 R72 0.1uF 0.1uF 470 R67 0 CAN-G0 C83 30pF X1 16MHz C84 30pF R185 SJA-CLKO 10K D6C 1 D7C 2 SJA-ALE 3 SJA-CS 4 nOE 5 nWE 6 SJA-CLKO 7 GND 8 9 10 +5V 11 12 TC0 13 14 R83 10K U17 SJA1000T AD6 AD7 ALE/AS CS RD/E WR CLKOUT VSS1 XTAL1 XTAL2 MODE VDD3 TX0 TX1 AD5 AD4 AD3 AD2 AD1 AD0 VDD1 VSS2 RX1 RX0 VDD2 RST INT VSS3 28 D5C 27 D4C 26 D3C 25 D2C 24 D1C 23 D0C 22 21 +5V 20 GND 19 RC0 18 17 16 +5V nRST 15 VDD33 R84 10K EINT5 TX1-OC CAN-G0 CAN-V0 RX1-OC U21 PCA82C251T 1 TXD S 2 GND CANL 3 VCC CANH 4 RXD Vref C85 8 30pF 6 R77 5.1 7 5 R78 5.1 C102 30pF CAN-G0 J7 CANH CANL 3 2 1 CAN-G0 CAN CAN-G0 图 1.37 CAN 接口电路 为了增强 CAN 总线节点的抗干扰能力,SJA1000 控制器引出端并不是直接和总线收发 器的 TXD、RXD 相连,而是经过高速光耦 TLP113 隔离后才与总线收发器 PCA82C251 相连, 这样就很好的实现了总线上各 CAN 节点间的电气隔离。其中重要的一点是,光耦两端的电 源也必须完全隔离(CAN-V0 与+5V,CAN-G0 与 GND),不然使用光耦就失去了意义,所以 板上增加了 DC-DC 电源隔离模块 BO5O5-W25。CANH 接总线的高电平端,CANL 接总线 的低电平端。如果该节点为 CAN 总线的终端节点,那么应在总线两端跨接 120 欧终端电阻。 但作为实验目的,不必要使用这种复杂隔离机制。为了使电路简单明了, MagicARM2410 实际上使用了 R70、R71 两个 0Ω电阻直接取代了光耦;用 R66、R67 取代 了 DC-DC 电源隔离模块;实验箱主板上保留光耦和电源隔离模块的电路,如果在实际工业 现场中使用,那么隔离部分的元件是一定要使用的。 SJA1000 的详细资料可以参考 PHILIPS 的芯片数据手册,需要注意的地方如下: SJA1000 有三对不同的电源 VDD1/VSS1 ——内部逻辑(数字) VDD2/VSS2——输入比较器(模拟) VDD2/VSS2——输出驱动器(模拟) 振荡器 SJA1000 能使用片内振荡器和片外时钟源工作。即能用外部晶体振荡器和外部时钟输入 两种模式。同时 SJA1000 的时钟输出(CLKOUT 引脚)可以作为其他电路的时钟源使用。 CPU 接口 SJA1000 支持两种最常用的总线接口形式——Intel 和 Motorola,两种模式可以通过引脚 的电平来进行选择。 MODE=1,接口为 Intel 模式。(支持 8051) MODE=0,接口为 Motorola 模式。(68xx) - 36 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com TX1 和 RX1 引脚 值得注意的是,TX1 和 RX1 不是另一对 CAN 的收发引脚,而是特殊功能引脚。如 TX1 可以作为接收的中断使用,RX1 可以作为输入比较使用。 16. ADC 电路 S3C2410A 具有 8 路 10 位 ADC 转换器,其参考电压由芯片的 Vref 引脚输入, MagicARM2410 实验箱上采用 3.3V 参考电压,电路如图 1.39 所示。 MagicARM2410 实验箱主板提供了两路直流电压测量电路,如图 1.38 所示,可调电阻 W1、W2 用于调整 ADC 的输入电压,用户可以在 VIN1、VIN2 测试点上用万能表检查当前 电压值。 J1-Port VIN1 VDD33 AIN0 R7 W1 22 10K AIN1 VIN2 VDD33 R8 W2 22 10K 图 1.38 ADC 实验电路 VDD33 L8 10uH C126 0.1uF Vref 图 1.39 ADC 参考电压源 17. PWM DAC 电路 由于 S3C2410A 没有 DAC 功能,所以使用了一个 PWM 输出口 TOUT0 输出 PWM 信号, 经过 R82 和 C127 进行 RC 滤波,实现 PWM DAC 控制控制,电路如图 1.40 所示。在 PWMDAC 测试点上可直接测量 PWM DAC 的电压值。 PWMDAC TOUT0 JP11 R82 PWM 10K C127 1uF/16V 图 1.40 PWM DAC 实验电路 - 37 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 18. SD 卡接口电路 由于 S3C2410A 已经提供了 MMC/SD/SDIO 主机控制器接口,因此设计 SD/MMC 卡接 口电路时,只须将这些接口相应地接到 SD 卡卡座就可以了,电路如图 1.41 所示。SDATA0 ~ SDATA3、SDCMD 信号线都使用一个电阻上拉至 3.3V,是为了使本电路可以同时兼容 SD 卡与 MMC 卡。 EINT18 信号线用于检测 SD/MMC 卡是否插入,由于卡的插入是随机的,所以使用 S3C2410A 的一个中断引脚 EINT18 来检测(当卡插入时,发生中断)。对于本电路,当卡未 完全插入卡座时,nCD-SD 为高电平(被 R13 拉高);当卡完全插入卡座时,nCD-SD 被卡 座的 CARD_INSERT 引脚拉低。因此,卡完全插入卡座时,将发生一个下降沿中断。 GPH8信号线(网络标号为UCLK)用于检测卡是否有写保护,其检测原理和检测卡是否插 入的原理相同。对于本电路,卡写保护时卡座输出高电平,否则输出低电平。 注意:对于不同的卡座,卡插入检测电平和写保护检测电平可能有所不同。 J1-Port (GPG10) (GPH8) VDD33 R12 R15 R16 R17 R18 10K 10K 10K 10K 10K SDDATA2 SDDATA3 SDCMD SDCLK SDDATA0 SDDATA1 EINT18 (nCD-SD) UCLK (WP-SD) VDD33 R13 10K R14 10K R41 47 R42 47 C65 10uF/16V C69 0.1uF CZ2 1 2 3 4 5 6 7 8 9 10 11 12 DAT2 DAT3/CS CMD/DI VSS1 VDD CLK/SCK VSS2 DAT0/DO DAT1/IRQ CARD_INSERT GND CARD_WP SD CARD 图 1.41 SD 卡接口电路 19. PCMCIA 接口电路 PCMCIA 接口不仅在笔记本电脑上得到了广泛的应用,在许系统嵌入式产口,如数 码相机、PDA、手持设备、机顶盒、车载设备等方面也不断地采用,为此在本系统中也 设计了一个 PCMCIA 接口。由于 S3C2410A 内部并没有集成 PCMCIA 卡接口,所以采 用 Cirrus Logic 公司生产的专用 PCMCIA 桥接芯片 CL-PD6710。 CL-PD6710 与微处理器连接是以 ISA 总线方式连接的。而在 ISA 总线接口中,I/O 空间和内存空间独立寻址的,所以 S3C2410 的总线没法直接支持 CL-PD6710,需要设计 一些逻辑门电路实现对 CL-PD6710 的控制。PCMCIA 接口电路如图 1.42 所示。 在 ARM 的体系结构中,I/O 空间和内存空间是统一寻址,我们使用高位地址 ADDR24 来区分 I/O 空间和内存空间的读写:当 ADDR24 为逻辑 1(高电平)时,对 Bank2 总线操作时可对 CL-PD6710 的 I/O 空间访问;当 ADDR24 为逻辑 0(低电平)时, 对 Bank2 总线操作时可对 CL-PD6710 的内存空间访问。 系统使用了 CL-PD6710 芯片的中断信号有两个:-INTR 和 IRQ,它们分别与微处理 器的 EINT3 和 EINT8 连接。其中-INTR 信号报告的中断是关于 PCMCIA 接口管理的, 例如卡的拔出与插入、电池电量报警或是 READY 信号的变化等。而 IRQ 中断信号有多 个,可以通过设置 CL-PD6710 芯片的寄存器来决,系统中选用了 IRQ3。 电源管理采用 TI 公司的 TPS2211 芯片,该芯片其实就是根据输入信号来选通给 - 38 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com PCMCIA 接口供电的 Vcc 和 Vpp。 EMC-BUS nGCS2 nWE 4 9 U29C 8 5 10 74LV32 U29B 6 74LV32 EMC-BUS ADDR24 12 U29D 11 1 U29A nOE 13 3 74LV32 2 74LV32 X5 nGCS2 VDD33 4 1 VCC OUT NC GND 3 2 25MHz R61 VDD33 4.7K R92 0 PC-CARD R93 0 nWBE1 R94 0 U35A 1 12 2 13 74LV04 U35B 3 74LV04 49 10 EMC-BUS ADDR24 nOE U30D 11 74LV32 U30C 8 74LV32 nWE EMC-BUS VDD33 (IRQ-PCMCIA) EINT8 109 110 111 ADDR7 112 ADDR8 113 ADDR9 114 ADDR10 115 116 ADDR11 117 ADDR12 118 119 ADDR13 120 ADDR14 121 ADDR15 122 ADDR16 123 nIOR-P 124 nIOW-P 125 nGCS2 nWAIT R6 22 DATA0 1 RP28 22 8 126 127 128 129 DATA1 2 7 130 DATA2 3 6 131 DATA3 4 5 132 133 134 DATA4 1 RP29 22 8 135 136 DATA5 2 7 137 DATA6 3 6 138 DATA7 4 5 139 140 nRST 141 142 EINT3 (nIRQ-PCMCIA) 143 144 IRQ3 SA7 IRQ4 SA8 IRQ5 SA9 SA10 IRQ7 SA11 SA12 REFRESH* SA13 SA14 SA15 SA16 IOR* IOW* AEN IOCHRDY GND5 SD0 SD1 ZWS* SD2 GND6 SD3 ISA_VCC2 SD4 SD5 IRQ9 SD6 SD7 PWRGOOD SPKR_OUT*/C_SEL -INTR N/C U36 CL-PD6710-VC-B R30 10K +5V VDD33 VDD33 nVCC-5 nVCC-3 +5V R63 1K U38 1 2 3 4 5 6 7 8 nVCCD0 nSHDN nVCCD1 VPPD0 3.3V VPPD1 3.3V AVCC 5V AVCC 5V AVCC GND AVPP nOC 12V TPS2211 12V 16 R31 10K 15 14 13 12 11 10 9 R95 0 +5V C23 0.1uF C24 0.1uF SKT-VCC (Thick line) SKT-VPP C129 0.1uF VS1 PnREG PD3 PnCD1 PD4 PD11 PD5 PD12 PD6 PD13 SKT-VCC PD7 PD14 PnCE1 PD15 PA10 PnCE2 PnOE PA11 PnIORD PA9 PnIOWR PA8 PA17 PA13 PA18 PA14 PA19 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 +5V VPP_PGM VPP_VCC -VPP_VALID -VCC_3 -VCC_5 5V_DET -REG D3 -CD1 D4 D11 D5 D12 D6 CORE_VDD1 D13 SOCKET_VCC1 D7 GND1 D14 -CE1 D15 A10 -CE2 -OE A11 -IORD A9 -IOWR A8 A17 A13 A18 A14 A19 SA6 SA5 SA4 ALE SA3 SA2 CLK SA1 SA0 MEMCS16* SBHE* IOCS16* LA23 IRQ10 LA22 IRQ11 LA21 CORE_VDD2 IRQ12/LED_OUT* LA20 IRQ15/RI_OUT* LA19 IRQ14 LA18 LA17 MEMR* MEMW* SD8 SD9 SD10 GND4 SD11 ISA_VCC1 SD12 SD13 SD14 108 107 106 105 104 103 102 101 100 99 98 97 96 95 94 93 92 91 90 89 88 87 86 85 84 83 82 81 80 79 78 77 76 75 74 73 ADDR6 ADDR5 ADDR4 ADDR3 ADDR2 ADDR1 ADDR0 ADDR23 ADDR22 ADDR21 ADDR20 ADDR19 ADDR18 ADDR17 1 RP26 22 8 2 7 3 6 4 5 1 RP27 22 8 2 7 3 6 4 5 VDD33 DATA8 DATA9 DATA10 DATA11 DATA12 DATA13 DATA14 DATA15 EMC-BUS GND3 SD15 -CD2 WP/-IOIS16 D10 D2 D9 D1 D8 D0 BVD1/-STSCHG/-RI A0 BVD2/-SPKR/-LED A1 A2 -INPACK A3 -WAIT GND2 A4 SOCKEY_VCC2 RESET A5 A6 A25 A7 A24 A12 A23 A15 A22 A16 A21 RDY/-IREQ A20 -WE 72 71 70 69 68 67 66 65 64 63 62 61 60 59 58 57 56 55 54 53 52 51 50 49 48 47 46 45 44 43 42 41 40 39 38 37 PnCD2 PIOIS16 PD10 PD2 PD9 PD1 PD8 PD0 PBVD1 PA0 PBVD2 PA1 PA2 PINPACK PA3 PnWAIT PA4 SKT-VCC PRESET PA5 PA6 PA25 PA7 PA24 PA12 PA23 PA15 PA22 PA16 PA21 PnIREQ PA20 PnWR PCMCIA +5V R32 10K PnCD1 PD11 PD12 PD13 PD14 PD15 PnCE2 VS1 PnIORD PnIOWR PA17 PA18 PA19 PA20 PA21 SKT-VCC SKT-VPP PA22 PA23 PA24 PA25 VS2/rsv PRESET PnWAIT PINPACK PnREG PBVD2 PBVD1 PD8 PD9 PD10 PnCD2 CZ12 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 GND GND CD1# D3 D11 D4 D12 D5 D13 D6 D14 D7 D15 CE1# CE2# A10 VS1#/Refresh OE# rsv/IORD# A11 rsv/IOWR# A9 A17 A8 A18 A13 A19 A14 A20 WE# A21 READY/IREQ# VCC VCC VPP2 VPP1 A22 A16 A23 A15 A24 A12 A25 A7 VS2#/rsv A6 RESET A5 WAIT# A4 rsv/INPACK# A3 REG# A2 BVD2/SPKR# A1 BVD1/STSCHG# A0 D8 D0 D9 D1 D10 D2 CD2# WP/IOIS16# GND GND 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 PCMCIA PD3 PD4 PD5 PD6 PD7 PnCE1 PA10 PnOE PA11 PA9 PA8 PA13 PA14 PnWR PnIREQ SKT-VCC SKT-VPP PA16 PA15 PA12 PA7 PA6 PA5 PA4 PA3 PA2 PA1 PA0 PD0 PD1 PD2 PIOIS16 图 1.42 PCMCIA 接口电路 20. CF 卡及 IDE 硬盘接口电路 MagicARM2410 实验箱主板上的 CF 卡及 IDE 硬盘接口是由 PCMCIA 存储卡接口扩展 出来的,电路连接如图 1.43 所示。CF(Compact Flash)卡的电气接口与 PCMCIA 的电气 接口完全兼容,只是物理接口有所不同。对于 CF 卡的三种工作模式,PC I/O 模式、PC MEMORY 模式和 ATA 模式,CL-PD6710 都支持,所以系统中的 CF 卡硬件是支持所有的 CF 卡设备。 CL-PD6710 的 ATA 模式,可以支持 ATA 接口设备,如 CDROM、DVDROM、IDE 硬 盘、软盘等等。IDE 硬盘也是 ATA 设备中的一个特例,所以 PD7610 也可以提供一个 IDE 接口,实现对 IDE 硬盘、CDROM 等设备的支持。IDE 接口与 PCMCIA 接口连接原理图如 图 1.43 所示。 图 1.43 中,JP13 跳线为 IDE 硬盘检测引脚上的跳线,当需要使用 IDE 硬盘时,请将 JP13 全部短接,否则系统将无法判断硬盘存在,导致不能正确操作硬盘。 注意:在使用 CF 卡或 PCMCIA 接口时,不能短接 JP13,否则操作出错。 - 39 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com PCMCIA (DMARQ) PnIREQ R120 (DMACK) 10K JP13 2 4 (DASP) 1 PnCD1 3 PnCD2 PRESET PD7 PD6 PD5 PD4 PD3 PD2 PD1 PD0 GND PINPACK PnIOWR PnIORD PnWAIT PnREG PnIREQ PA1 PA0 PnCE1 PBVD2 PBVD2 J8 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 IDE R62 1K PD8 PD9 PD10 PD11 PD12 PD13 PD14 PD15 PA25 GND PIOIS16 PBVD1 PA2 PnCE2 (CSEL) (-PDIAG) D2 SKT-VCC IDE C129 0.1uF GND 1 PD3 2 PD4 3 PD5 4 PD6 5 PD7 6 PnCE1 7 PA10 8 PnOE 9 PA9 10 PA8 11 PA7 12 SKT-VCC 13 PA6 14 PA5 15 PA4 16 PA3 17 PA2 18 PA1 19 PA0 20 PD0 21 PD1 22 PD2 23 PIOIS16 24 PnCD2 25 CZ9 1 26 2 27 3 28 4 29 5 30 6 31 7 32 8 33 9 34 10 35 11 36 12 37 13 38 14 39 15 40 16 41 17 42 18 43 19 44 20 45 21 46 22 47 23 48 24 49 25 50 CompactFlash 26 PnCD1 27 PD11 28 PD12 29 PD13 30 PD14 31 PD15 32 PnCE2 33 VS1 34 PnIORD 35 PnIOWR 36 PnWR 37 PnIREQ 38 SKT-VCC 39 PA25 40 VS2/rsv 41 PRESET 42 PnWAIT 43 PINPACK 44 PnREG 45 PBVD2 46 PBVD1 47 PD8 48 PD9 49 PD10 50 图 1.43 CF 卡及 IDE 硬盘接口电路 PCMCIA 卡接口与 CF 卡、IDE 接口引脚连接表如表 1.3 所示。 表 1.3 PC 卡与 CF 卡 IDE 接口引脚连接 PC 卡接 口名称 D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 D10 D11 D12 D13 D14 D15 -IOIS16 -IREQ -IORD -IOWR RESET -WAIT PC 卡 接口 引脚 CF 卡 接口 引脚 IDE 接口 引脚 30 21 17 31 22 15 32 23 13 2 2 11 3 3 9 4 4 7 5 5 5 6 6 3 64 47 4 65 48 6 66 49 8 37 27 10 38 28 12 39 29 14 40 30 16 41 31 18 33 24 32 16 37 31 44 34 25 45 35 23 58 41 1 59 42 27 IDE 接口 名称 PC 卡 接口名 称 PC 卡 接口 引脚 CF 卡 接口 引脚 IDE 接 口引 脚 IDE 接 口名称 D0 A0 29 20 35 A0 D1 A1 28 19 33 A1 D2 A2 27 D3 A3 26 D4 A4 25 D5 A5 24 D6 A6 23 D7 A7 22 D8 A8 12 D9 A9 11 D10 A10 8 D11 A11 10 D12 A12 21 D13 A13 13 D14 A14 14 D15 A15 20 -IOIS16 A16 19 IREQ A17 46 -IORD A18 47 -IOWR A19 48 -RESET A20 49 IORDY A21 50 18 17 16 15 14 12 11 10 8 —— —— —— —— —— —— —— —— —— —— —— 36 —— —— —— —— —— —— —— —— —— —— —— —— —— —— —— —— —— —— —— A2 —— —— —— —— —— —— —— —— —— —— —— —— —— —— —— —— —— —— —— - 40 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 续表 1.3 PC 卡接 PC 卡 CF 卡 IDE IDE 接口 PC 卡 PC 卡 CF 卡 IDE 接 IDE 接 口名称 接口 接口 接口 名称 接口名 接口 接口 口引 口名称 引脚 引脚 引脚 称 引脚 引脚 脚 -REG 61 44 29 1 -DMACK A22 53 —— —— —— -INPACK 60 43 21 1 DMARQ A23 54 —— —— —— -STSCHG 63 46 34 1 -PDIAG A24 55 —— —— —— -SPKR 62 45 39 -DASP A25 56 39 28 3 CSEL -CD1 36 26 22 -CD1 VS1 43 33 —— —— -CD2 67 25 40 2 CD2 VS2 57 40 —— —— -CE1 7 7 37 -CS0 VCC 51 38 —— —— -CE2 42 32 38 -CS1 VCC 17 13 —— —— GND 1 1 19 GND -OE 9 9 —— —— GND 34 50 22 GND -WE 15 36 —— —— GND 35 24 GND VPP1 18 —— —— —— GND 68 26 GND VPP2 52 —— —— —— 30 GND —— —— —— 20 4 Key 注意: 1.CL-PD6710 系统芯片不支持。 2.CL-PD6710 是通过-CD1 和-CD2 来检测设备是否插入,IDE 硬盘没有提供这相应的引脚,由于 IDE 硬盘的 2 和 40 引脚与 19、22、24、26、30 是共地的,所以在系统中使用 2 和 40 引脚来检测 硬盘是否存在。 3.该引脚用于选择 IDE 硬盘的主盘和从盘。 4.这是一个空的引脚,不需要连接。 21. 步进电机控制电路 MagicARM2410 实验箱上采用了达林顿管驱动芯片 ULN2003 来驱动四相步进电机,其 控制口线为 GPC0、GPC5、GPC6 和 GPC7,只要正确输出 I/O 控制时序,即可控制步进电 机转动,电路原理如图 1.44 所示。 2 1 JP5 MV+ +5V MV+ C110 C80 0.1uF 10uF/16V LCDVF0 LCDVF1 LCDVF2 LEND JP6 1 3 5 7 2 BA 4 BB 6 BC 8 BD U26 1 2 3 4 5 6 7 8 IN 1 IN 2 IN 3 IN 4 IN 5 IN 6 IN 7 COMMON OUT 1 OUT 2 OUT 3 OUT 4 OUT 5 OUT 6 OUT 7 CLAMP ULN2003A 16 15 14 13 12 11 10 9 MV+ R164 5 /1W R165 5 /1W BA-COM BB-COM MV+ R166 5 /1W MV+ R167 5 /1W BC-COM BD-COM MS1 MOTOR STEPPER 图 1.44 步进电机驱动电路 由于 ULN2003 的控制电压 Vi(on)最大值为 2.4V(当 Ic=200mA 时),Ii(on)典型值为 0.93mA(当 Vi=3.85V 时),而 S3C2410A 输出拉电流可达 6mA,所以可以直接使用 S3C2410A 的 I/O 控制。图 1.44 中,电阻 R64~R67 为电机线圈上的阻流/保护电阻。JP6 可以断开步 - 41 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 进电机控制电路与 S3C2410A 的连接。 注意:使用步进电机电路时,要将电源跳线 JP5 短接,将 JP6 跳线短接。 22. 直流电机控制电路 MagicARM2410 实验箱主板上具有直流电机及控制电路,电路原理如图 1.45 所示。直 流电机控制使用了 H 桥驱动电路,控制口线为 GPB0、GPH9。JP3 可以断开直流电机控制 电路与 S3C2410A 的连接。 如图 1.45 所示,当 GPB0 输出高电平时(即 ZDJ_A 点为 3.3V),则 Q3、Q6 导通 Q7 导通 MOTOR_B 点为 MGV+,Q6 导通 MOTOR_A 点为 GND,此时直流电机将会正转。 由于 Q6 的集电极通过一个二极管 D7 连接到 H 桥的另一个控制端 ZDJ_B,将 ZDJ_B 控制 端电压钳在 1.0V 以下,所以不管 GPH9 输出是高电平还是低电平,Q4、Q5 都会截止 Q8 截止,不会造成 H 桥短路故障。 当 GPB0 输出为低电平时(即 ZDJ_A 点为 0V),则 Q3、Q6 截止 Q7 截止,GPH9 的输 出电平可以控制电机反转或停机。若 GPH9 输出高电平(即 ZDJ_B 点为 3.3V),则 Q4、Q5 导通 Q8 导通 MOTOR_A 点为 MGV+,Q5 导通 MOTOR_B 点为 GND,此时直流电机 将会反转。当 GPH9 输出低电平时,Q4、Q5 都会截止 Q8 截止,电机停机。 二极管 D8~D11 为续流二极管,用于释放电机线圈上产生的反电动势。电阻 R162、R163 为限流/保护电阻。 注意:使用直流电机电路时,要将电源跳线 JP4 短接,将 JP3 跳线短接。 JP4 MGV+ +5V MGV+ C79 C72 0.1uF 10uF/16V Q7 8550 MGV+ R162 5.1 VF R163 5.1 C113 0.1uF IN4148 Vf IN4148 J1-Port 2 1 (GPB0) JP3 TOUT0 1 CLKOUT0 3 (GPH9) 2 ZDJ-A 4 R158 10K R160 1K C111 10nF Q3 8050 D8 D9 Q8 8550 ZDJ-B R159 10K R161 1K C112 10nF MOTOR-A MG1 MOTOR DC MOTOR-B D7 IN4148 Q4 8050 R168 100 Q5 8050 IN4148 IN4148 D11 D10 Q6 8050 J17 2 1 MOTOR-B MOTOR-A MG-COM R169 100 图 1.45 直流电机驱动电路 - 42 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 23. 外设 PACK 接口电路 MagicARM2410 实验箱主板上设计了一个外设 PACK 接口,电路如图 1.46 所示,具有 24 根地址总线 ADDR0~ADDR23,16 根数据总线 DATA0~DATA15,读/写信号 nOE、nWE、 nWBE0 和 nWBE1,片选信号为 nGCS1,所以外设 PACK 上可用的地址为 0x08000000~ 0x08FFFFFF。用户可以使用 nGCS2 信号及高位地址进行译码,达到地址再次分配的目的。 外设 PACK 上还有 6 个 I/O 口,有 2 个 I/O 为外部中断引脚,这样就极大的方便了与外部 I/O 器件进行连接。 说明:MagicARM2410 实验箱上还有一个 32 位总线宽度的扩展接口 J15、J16,用户可 以通过些接口引出 32 位总线使用。 EMC-BUS EMC-BUS DATA0 5 DATA1 6 DATA2 7 DATA3 8 DATA4 5 DATA5 6 DATA6 7 DATA7 8 DATA8 5 DATA9 6 DATA10 7 DATA11 8 DATA12 5 DATA13 6 DATA14 7 DATA15 8 RP14 22 4 D0B 3 D1B 2 D2B 1 D3B RP15 22 4 D4B 3 D5B 2 D6B 1 D7B RP16 22 4 D8B 3 D9B 2 D10B 1 D11B RP17 22 4 D12B 3 D13B 2 D14B 1 D15B D0B D2B D4B D6B D8B D10B D12B D14B GND EINT1 J18 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 PARK_B D1B D3B D5B D7B D9B D11B D13B D15B GND EINT2 ADDR8 ADDR10 ADDR12 ADDR14 ADDR16 ADDR18 ADDR20 ADDR22 J20 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 PARK_M ADDR9 ADDR11 ADDR13 ADDR15 ADDR17 ADDR19 ADDR21 ADDR23 J1-Port ADDR0 ADDR2 ADDR4 ADDR6 +5V nGCS1 nOE nWBE0 nXDACK0 nXDACK1 J19 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 PARK_A ADDR1 ADDR3 ADDR5 ADDR7 GND VDD33 nWE nWBE1 nXDREQ0 nXDREQ1 图 1.46 外设 PACK 接口电路 24. PGRS PACK 接口电路 MagicARM2410 实验箱主板上有一个 GPRS PACK 接口,此接口提供了+12V、+5V 电 源和 S3C2410A 的 UART0 接口(TXD0、RXD0、nCTS0 和 nRTS0),电路如图 1.47 所示。由 于 S3C2410A 没有完整的 Modem 接口,所以使用了 EINT19 作为振铃检测 RI,而 DSR 与 DTR 经过 0Ω电阻 R91 短接在一起,使 GPRS 模块处于就绪状态。 将 GPRS 模块插入到此接口,即可进行 GPRS 的实验。 J1-Port (DCD) (DSR) (RXD) (CTS) (RI) (DTR) (TXD) (RTS) J22 DSR RXD0 nCTS0 EINT19 DTR TXD0 nRTS0 GND GND +5V 12V 1 3 5 7 9 11 13 15 17 19 21 23 2 4 6 8 10 12 14 16 18 20 22 24 DSR RXD0 nCTS0 EINT19 DTR TXD0 nRTS0 GND GND +5V 12V DSR R91 0 DTR J21 1 2 3 4 5 6 7 8 9 10 图 1.47 GPRS PACK 接口电路 25. VGA PACK 接口电路 MagicARM2410 实验箱主板上设计有一个 VGA PACK 接口,此接口使用了 S3C2410A 的 LCD 接口信号,有 VD0~VD23、VFRAME、VLINE、VCLK、VM 等,电路如图 1.48 所示。另外,VGA PACK 接口上还连接了 I2C 总线,用于 VGA 转换芯片(如 CH7013B-D 芯 片)的初始化控制。 将 VGA PACK 板插入到此接口,即可连接和使用 CRT 显示器。 - 43 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com J1-Port VD0 8 RP38 22 1 VD0-P VD1 7 2 VD1-P VD2 6 3 VD2-P VD3 5 4 VD3-P VD4 8 1 VD4-P VD5 7 2 VD5-P VD6 6 3 VD6-P VD7 5 4 VD7-P RP39 22 VD8 VD9 VD10 VD11 VD12 VD13 8 RP40 7 6 5 8 7 6 5 22 1 2 3 4 1 2 3 4 VD8-P VD9-P VD10-P VD11-P VD12-P VD13-P +5V VDD33 VD0-P VD2-P VD4-P VD6-P VD8-P VD10-P VD12-P J34 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 VGA_A +5V VDD33 VD1-P VD3-P VD5-P VD7-P VD9-P VD11-P VD13-P J1-Port VD14 VD15 VD16 VD17 VD18 VD19 VD20 VD21 1 RP42 2 3 4 1 2 3 4 RP43 22 8 7 6 5 8 7 6 5 22 VD14-P VD15-P VD16-P VD17-P VD18-P VD19-P VD20-P VD21-P VD22 1 VD23 2 VFRAME 3 VLINE 4 VM 1 LCD-PWR2 VCLK 3 4 RP44 22 8 VD22-P 7 VD23-P 6 VFRAME-P 5 VLINE-P 8 VM-P 7 LCD-PWR-P 6 VCLK-P 5 J35 VD14-P VD16-P VD18-P VD20-P VD22-P VFRAME-P VM-P VCLK-P 1 3 5 7 9 11 13 15 2 4 6 8 10 12 14 16 17 18 19 20 VGA_B VD15-P VD17-P VD19-P VD21-P VD23-P VLINE-P LCD-PWR-P I2CSDA I2CSCL 图 1.48 VGA PACK 接口电路 26. VGA PACK 板电路 MagicARM2410 实验箱可以选配 VGA PACK 板,这样就可以连接和使用 CRT 显示器。 VGA PACK 板使用了 VGA 转换芯片 CH7013B-D,电路原理如图 1.49 所示。在图 1.49 中, CH7013B-D 直接与 S3C2410A 的 LCD 接口信号相连,只要正确设置好 S3C2410A 的 LCD 控制器,CH7013B-D 即可输出正确的 VGA 扫描信号,不需要另外编写 VGA 显示驱动程序。 为了使 VGA 接口电路正常工作,S3C2410A 的 LCD 控制器应选用 16BPP 模式,所以 将 S3C2410A 的 VD3~VD7 与 CH7013 的 D0~D4 相连,VD10~VD15 与 D5~D10 相连, VD19~VD23 与 D11~D15 相连。 VDD33 C3 C4 10uF/16V 10uF/16V C5 0.1uF C6 0.1uF C7 0.1uF +5V FB1 CBG201209U151B C8 100uF/16V FB2 CBG201209U151B AVDD5 C9 C10 0.1uF 0.1uF AGND +5V VDD33 VD0 VD2 VD4 VD6 VD8 VD10 VD12 VD14 VD16 VD18 VD20 VD22 VFRAME VM VCLK NC J1 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 VGA_A J2 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 VGA_B +5V VDD33 VD1 VD3 VD5 VD7 VD9 VD11 VD13 VD15 VD17 VD19 VD21 VD23 VLINE LCD-PWR I2CSDA I2CSCL VD6 VD7 VD10 VD11 VD12 VD13 VD14 VD15 VD19 C1 22pF C2 22pF VDD33 X1 14.31818MHz R1 10K R2 0 R4 360 36 35 34 33 32 31 30 29 28 27 26 25 VM R3 0 VCLK VLINE VFRAME VD3 VD4 VD5 VCLK C11 180pF D3 D4 D5 D6 DVDD D7 D8 DGND D9 D10 D11 NC 37 38 39 40 41 42 43 44 45 46 47 48 NC AGND BCO DGND P-OUT DVDD XCLK H V D0 D1 D2 XO XI AVDD DVDD ADDR DGND SC SD VDD RSET GND NC U1 CH7013B-D Y C CVBS GND DGND CSYNC DVDD D15 D14 D13 D12 NC 24 23 22 21 20 19 18 17 16 15 14 13 I2CSCL I2CSDA AVDD5 AGND VD23 VD22 VD21 VD20 1 2 3 4 5 6 7 8 9 10 11 12 VDD33 R5 75/1% R6 75/1% R7 75/1% R8 75/1% AGND 1 2 3 VLINE 13 VFRAME 14 5 10 6 7 AGND 8 4 12 11 9 15 CZ1 Red Green Blue HSync VSync GND Sync GND Red GND Green GND Blue GND Monitor ID2 Monitor ID1 Monitor ID0 NC NC VGA-CN 2 CZ2 2 TV 11 AGND 图 1.49 VGA PACK 板电路 27. GPRS PACK 板电路 MagicARM2410 实验箱可以选配 GPRS 模块(即 PACK 板),进行 GPRS 实验。选配的 GPRS PACK 板电路使用了 BENQ 公司的 M22 GPRS 模块,可以支持 GPRS 手机开发,电 路原理如图 1.50 所示。 图 1.50 中的 U1 是 M22 模块的接口,共 44 个引脚;蜂鸣器用于来电铃声提示;J3、J4 接口用于连接耳机和话筒,实现接听电话的功能;U4 是一个 SP3238 的 MODEM 驱动器, 用户可以通过该接口进行 AT 指令的发送;JP1 是用于连接 MagicARM2410 实验箱主板,实 现主板对模块的控制,用户可以通过 CPU 发送 AT 指令来控制 GPRS 模块;板上由一个 LM2576 开关电源提供 4V 的工作电压;U3 是手机的 SIM 卡接口,使用 GPRS 模块前用户 - 44 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 需要先插上手机卡。 VBATT GND GND GND GND LEDA ROW4 TXD2 DCD GND SIM_CLK SIM_IO SIM_RST MICBIAS MICIP MICIN GND EARP EARN TXD RTS DTR RXD CTS RI DSR DCD 1 2 3 4 5 6 7 8 J7 CON8 TXD_1 RTS_1 DTR_1 RXD_1 CTS_1 RI_1 DSR_1 DCD_1 J8 1 2 3 4 5 6 7 8 CON8 U1 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 VBTBB GND0 GND1 GND2 GND3 LEDA ROW4 TXD2 IO12/DCD GND4 SIM_CLK SIM_IO SIM_RST NC MICBIAS MICIP MICIN AUXI GND5 EARP EARN AUXOP GND9 VBATRF1 VBATRF2 VBATRF3 GND8 IO10 PWON RXD2 BU GND7 TXD RXD RTS CTS DSR IO8/DTR IO13 IO11 GND6 IO6 IO1/RI VRSIM 44 43 42 41 40 39 38 37 36 35 34 33 32 31 30 29 28 27 26 25 24 23 GND VBATT VBATT VBATT GND IO10 PWON RXD2 BUZZER GND TXD RXD RTS CTS DSR DTR IO13 IO11 GND IO6 RI VRSIM VBATT R1 4.7K C14 104 S1 SW-PB IO13 C6 1U J9 1 2 3 4 5 6 7 8 CON8 M22A CONNECTOR C7 MICIN R14 1K MICBIAS R15 1U R19 GND 330 C18 C19 1.5K R16 0.1U 0.1U R18 J3 1 330 MICIP R17 C1.85K 2 3 1K MIC 1U JP2 DCD_1 DTR_1 TXD_1 RTS_1 RI_1 DSR_1 RXD_1 CTS_1 GND GND 5V 12V 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 JP1 HEADER 12X2 DCD_1 DTR_1 TXD_1 RTS_1 RI_1 DSR_1 RXD_1 CTS_1 GND GND 5V 12V J1 1 2 3 4 5 6 7 8 9 10 CON10 RXD -> TXD DSR -> DTR CTS -> RTS DCD -> DCD RI -> RI 3V3 R11 0 C9 474 R7 R8 R9 R10 R12 47K 47K 47K 47K 47K RXD_A CTS_A RI_A DSR_A DCD_A RI_A DCD_A RXD_A CTS_A DSR_A U4 SP3238E 26 VCC 2 GND 14 15 /FORCERFF /INVALID 13 FORCEON C1+ C1- 28 25 C2+ C2- 1 3 V+ V- 27 4 24 23 22 19 17 T1IN T2IN T13N T4IN T5IN 21 20 18 R1OUT R2OUT R3OUT 16 R1OUTB T1OUT T2OUT T3OUT T4OUT T5OUT 5 6 7 10 12 R1IN R2IN R3IN 8 9 11 3V3 C10 474 C11 474 C12 474 J2 1 6 2 7 3 8 4 9 5 DB9 R22 240K C26 10P R23 240K C2710P EARN C28 10P EARP J4 1 2 3 ER SAI D1 1N4148 B1 BUZZER R6 47 VBATT R2 100 3V3 BUZZER R4 Q1 NPN D2 LED IO13 TXD GND IO10 GND PWON 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 HEADER 8X2 GND RXD IO11 GND IO6 ROW4 GND J10 3 12V 2 1 CON3 + C16 100uF/16V D3 1N4001 U5 LM117MPX-3.3 3 IN OUT1 4 OUT2 2 C29 104 1 GND 3 5 SIM_IO VRSIM 3V3 + C17 220uF/16V R13 3.9 R3 10K U3 C15 105 4 GND VCC 5 3 VCC RST 6 2 I/O CLK 7 GND SIM SOCKET_6PIN J6 1 VBATT GND + C21 U6 LM2576-ADJ 4 1 FEEDBACK VIN 2 OUTPUT C22 GND D4 C30 220uF/16V 474 104 /ON1ONF5F822 R5 20 J5 1 VBATT L1 100H/3A 1K SIM_RST SIM_CLK LEDA R24 RES1 VBATT R20 220 W1 100K VBATT VBATT C+23 C24 470uF/10V 104 R21 100 D5 LED C25 100pF 图 1.50 GPRS PACK 板电路图 1.3.3 构建 ARM7 教学实验开发平台 为了满足不同的教学要求,MagicARM2410 实验箱的电路设计考虑了兼容使用 ARM7 处理器 S3C44B0(Samsung 公司的 ARM7 处理器),设计要点为液晶屏控制电路、RTC 电源 和 I/O 资源分配等内容。 在生产时安装 STN 伪彩色液晶屏(型号为 LFUBK9111),将 DeviceARM44B0 核心板(选 配件)插入 MagicARM2410 实验箱主板,然后把 JP10 跳线短接,这样 MagicARM2410 就变 成了 ARM7 教学实验开发平台。 1. 伪彩液晶屏 由 于 S3C44B0 只 能 支 持 STN 伪 彩 液 晶 屏 , 不 支 持 真 彩 色 TFT 液 晶 屏 , 所 以 MagicARM2410 实验箱主板上设计了 STN 伪彩色液晶屏接口电路,如图 1.27 所示。 由于 STN 伪彩色液晶屏 LFUBK9111 需要 24V 左右的液晶驱动电压,所以设计了如图 - 45 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 1.51 所示的升压电路,采用 MC34063 芯片。其中,R35、R36 和 C17、C109 构成了 RC 滤 波电路,R48 和 R33、R34、R47 用来调节反馈电压(可以控制输出电压 VHP 的大小)。 12V R36 R35 33 33 R45 0.33 C109 F/16V R46 180 C17 0.1uF L7 220uH U27 8 DRVC SWC 7 IPK SWE 6 VCC CT 5 CMPR GND MC34063 VHP1 D12 1N5819 1 VHP 2 C116 3 4 470pF R48 47K C18 0.1uF + C117 10uF/50V C118 4.7uF R47 2K R33 1K R34 1.5K 图 1.51 STN 液晶驱动电压电路 2. RTC 电源 由于 S3C44B0 的 RTC 电源为 2.5V~3.0V,与 S3C2410A 的 1.8V 不相同,为了能够在 MagicARM2410 实验箱主板上使用 S3C44B0 的核心板,所以设置了 JP10 跳线,当 JP10 跳 线短接时,将会给核心板提供 3.0V 的 RTC 电源,电路原理如图 1.52 所示。 JP10 44B0-RTC R180 22 D5 1N4148 BT1 3V D6 1N4148 VDDRTC 图 1.52 RTC 电源电路 3. 部分功能不能使用 由于 S3C44B0 的 I/O 比 S3C2410A 要少,比如没有 NAND Flash 接口、只有 8 个外部中 断、没有 SD/MMC 卡接口、UART 口只有 2 个,所以使用 DeviceARM44B0 核心板时, MagicARM2410 实验箱主板有一些功能不能使用,具体参考 ARM7 教学实验开发平台产品 配套光盘中的文档说明。 1.4 硬件结构 MagicARM2410 实验箱主板上按排有少量的跳线器,跳线器的名称均以“JP”开头,比 如 JP1、JP2。跳线器的位置均放置在相应的电路模块旁边,比如直流电机控制电路的跳线 JP3、JP4,它们的位置都是在直流电机控制电路旁边。这些跳线可分为两种类型,一种是模 块电路电源跳线,另一种是模块电路 I/O 连接跳线,当需要使用某一模块电路时,则需要将 电源跳线和 I/O 连接跳线短接。另外,通过跳线用户可以将 I/O 连接到外面(实验箱之外)的 实验电路,也可以重新分配模块电路所使用的 I/O 口(将跳线器取出,使用连接导线从其它 跳线上连接控制 I/O)。 - 46 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 注意:只有直流电机、步进电机和液晶屏背光电路是有电源跳线的。部分 I/O 资源是复 用的,使用时需要避免 I/O 冲突。 1.4.1 跳线器说明 MagicARM2410 教学实验箱跳线器说明如表 1.4 所示,跳线器的布局如图 1.53 所示。 表 1.4 MagicARM2410 跳线器一览表 跳线器 标号 JP1 RXD0 I/O RXD0/GPH3 JP2 JP3 JP4 JP5 JP6 JP7 JP8 JP9 JP10 RXD1 RXD1/GPH5 ZDJ_A ZDJ_B MGV+ MV+ BA BB BC BD VLIGHT TOUT0/GPB0 GPH9 — — GPC5 GPC6 GPC7 GPC0 — BOOT-SEL — BUZZER GPH10 44B0-Vrtc — JP11 JP12 JP13 PWM RT-EN IDE_CD1 IDE_CD2 TOUT0/GPB0 — — — 功能说明 RXD0 信号连接选择 (RS232 接口 CZ11) RXD1 信号连接选择 (RS232 接口 CZ1 或 RS485 接口) 直流电机控制口线连接 直流电机控制电路的电源跳线 步进电机控制电路的电源跳线 复用情况 J2、J22 J2 JP11 — — — — — 步进电机控制口线连接 — — 液晶屏背光电路的电源跳线 — 启动方式选择 — (NAND Flash 或 NOR Flash) 蜂鸣器控制口线连接 — S3C44B0 的 RTC 电源选择 — PWM DAC 电路的控制口线连接 RS485 总线终端电阻选择 IDE 硬盘检测引脚跳线 JP3 — CZ9、CZ12 CZ9、CZ12 备注 CZ11 安装在机箱 右侧 保留,请不要短接 此跳线 电压测试点为 PWMDAC 使 用 CF 卡 、 PCMCIA 接口时, 不能短接此跳线 - 47 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 图 1.53 MagicARM2410 实验箱跳线器布局 1. JP1、JP2 RS232/RS485 接口电路 MagicARM2410 实验箱主板上的 RS232 接口电路(CZ11 连接器)使用了 S3C2410A 的 UART0,同时 GPRS PACK 接口电路也复用了 UART0,为了避免 RXD0 信号冲突,所以设 置了 JP1 跳线来断开 RS232 接口电路与 S3C2410A 的 RXD0 的连接。 当需要使用 RS232 接口 CZ11 时,请将 JP1 跳线短接。JP1 跳线器说明见表 1.5。 表 1.5 JP1 跳线 JP1 短接 断开 I/O RXD0 与 RS232 接口 CZ11 连接 RXD0 与 RS232 接口 CZ11 断开 功能 RS232 数据接收 使用 GPRS 模块 默认值 短接 MagicARM2410 实验箱主板上的 RS232 接口电路(CZ1 连接器)使用了 S3C2410A 的 UART1,同时 RS485 接口电路也复用了 UART1,为了避免 RXD1 信号冲突,所以设置了 JP2 跳线来选择 RXD1 是连接到 RS232 接口电路,还是连接到 RS485 接口电路。 若需要使用 RS232 接口 CZ1,请将 JP2 短接到“232R”端;若需要使用 RS485 接口电 路,请将 JP2 短接到“485R”端。JP2 跳线器说明见表 1.6。 表 1.6 JP2 跳线 JP2 选择 232R 选择 485R I/O RXD1 与 RS232 接口 CZ1 连接 RXD1 与 RS485 接口电路连接 功能 RS232 数据接收 RS485 数据接收 默认值 485R - 48 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 2. JP3、JP4 直流电机控制电路 MagicARM24100 实验箱主板上的直流电机控制电路使用了 GPB0 和 GPH9 两个 I/O, 通过 JP3 跳线器可以将这些 I/O 断开与直流电机控制电路的连接。JP3 跳线器说明见表 1.7。 JP4 为直流电机控制电路的电源跳线,需要使用直流电机时请短接 JP4。 表 1.7 JP3 跳线 JP3 I/O 功能 ZDJ_A ZDJ_B 直流电机驱动电路与 GPB0 连接 直流电机驱动电路与 GPH9 连接 直流电机运转控制 说明:GPB0 口具有 TOUT0 功能,可以输出 PWM 来控制直流电机的转速。 默认值 全部断开 3. JP5、JP6 步进电机控制电路 MagicARM2410 实验箱主板上的步进电机驱动电路使用了 GPC0、GPC5~GPC7 等 4 个 I/O,通过 JP6 跳线器可以将这些 I/O 断开与步进电机控制电路的连接。JP6 跳线器说明见表 1.8。 JP5 为步进电机控制电路的电源跳线,需要使用步进电机时请短接 JP5。 表 1.8 JP6 跳线 JP6 BA BB BC BD I/O 步进电机驱动电路与 GPC5 连接 步进电机驱动电路与 GPC6 连接 步进电机驱动电路与 GPC7 连接 步进电机驱动电路与 GPC0 连接 功能 默认值 步进电机各相线 全部断开 圈的控制 4. JP7 彩色液晶屏背光电路 JP7 为彩色液晶屏背光电路的电源跳线,需要使用彩色液晶屏时请短接 JP7,这样液晶 屏才会点亮。由于液晶背光灯管耗电较大,所以在不使用液晶屏时请将 JP7 跳线断开(要求 在关断实验箱总电源之后,再进行短接/断开 JP7 跳线操作)。 5. JP8 启动方式选择 在 MagicARM2410 实验箱主板上,通过 JP8 跳线可以选择 NAND Flash 启动方式或者 NOR Flash 启动方式。 若需要从 NAND Flash 启动引导程序运行,请将 JP8 跳线短接;若需要从 NOR Flash 启 动引导程序运行,请将 JP8 跳线断开。JP8 跳线器说明见表 1.9。 表 1.9 JP8 跳线 JP8 短接 断开 I/O S3C2410A 的 OM0 引脚为低电平 S3C2410A 的 OM0 引脚为高电平 功能 NAND Flash 启动 NOR Flash 启动 默认值 断开 6. JP9 蜂鸣器电路 JP9 跳线器用于设置 GPH10 口线是否与蜂鸣器电路连接,当 JP9 短接时,通过 GPH10 控制蜂鸣器蜂鸣。JP9 跳线器说明见表 1.10。 - 49 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com JP9 短接 断开 表 1.10 JP9 跳线 I/O GPH10 与蜂鸣器电路连接 GPH10 与蜂鸣器电路断开 功能 控制蜂鸣器 - 默认值 短接 7. JP10 S3C44B0 的 RTC 后备电源 由于 S3C44B0(Samsung 公司的 ARM7 处理器)的 RTC 电源为 2.5V~3.0V,与 S3C2410A 的 1.8V 不相同,为了能够在 MagicARM2410 实验箱主板上使用 S3C44B0 的核心板,所以 设置了 JP10 跳线,当 JP10 跳线短接时,将会给核心板提供 3.0V 的 RTC 电源。 注意:JP10 跳线为保留功能的跳线,请不要短接。 8. JP11 PWM DAC 电路 MagicARM2410 实验箱主板上的 PWM DAC 电路使用的 I/O 口线为 GPB0(具有 TOUT0 功 能),通过 JP11 跳线器可以将此 I/O 断开与 PWM DAC 电路的连接。JP11 跳线器说明见表 1.11。 表 1.11 JP11 跳线 JP11 短接 断开 I/O TOUT0/GPB0 与 PWM DAC 电路连接 TOUT0/GPB0 与 PWM DAC 电路断开 功能 PWM DAC 输出 - 默认值 短接 9. JP12 RS485 终端电阻 JP12 为 RS485 接口电路的终端电阻跳线,若需要使用终端电阻,请把 JP12 短接,否则 把 J12 断开。 10. JP13 IDE 硬盘检测引脚 JP13 跳线为 IDE 硬盘检测引脚上的跳线,当需要使用 IDE 硬盘时,请将 JP13 全部短接, 否则系统将无法判断硬盘存在,导致不能正确操作硬盘。JP13 跳线器说明见表 1.12。 表 1.12 JP13 跳线 JP13 I/O 功能 默认值 IDE_CD1 PCMCIA 接口的 PnCD1 与 GND 的连接 IDE 硬盘是否存在 断开 IDE_CD2 PCMCIA 接口的 PnCD2 与 GND 的连接 注意:在使用 CF 卡或 PCMCIA 接口时,不能短接 JP13,否则操作出错。 1.4.2 连接器说明 MagicARM2410 实验箱主板上具有众多接口,比如 RS232 接口、RS485 接口等等,这 些接口的连接器(用于连接的硬件)大部分都安装实验箱主板的边上,以方便使用。 MagicARM2410 实验箱主板上的连接器说明如表 1.13 所列。其中,J10~J13 为电源输 出接口,可以向用户板提供 12V、5V 和 3.3V 电源,但要求负载功率不要过重,也不要与其 它电源连接,否则可能导致器件损坏。 - 50 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 表 1.13 MagicARM2410 连接器一览表 连接器 说明 备注 CZ1 UART1 接口 RS232 电平 CZ2 SD/MMC 存储卡卡座 CZ3 耳机接口 IIS 音频输出 CZ4 MIC 接口 MIC 输入(音频) CZ5 LINEIN 接口 线路输入(音频) CZ6、CZ7、CZ13、CZ14 USB HOST 接口 CZ8 以太网接口 RJ45 接口 CZ9 CF 存储卡卡座 CZ10 USB Device 接口 CZ11 UART0 接口 RS232 电平,安装在机箱右侧 CZ12 PCMCIA 卡卡座 J1 核心板接口 SO-DIMM200 标准接口 J2 UART 接口 TTL 电平 (口线复用) J3 RS485 接口 J4 中断接口 EINT0~EINT7 (口线复用) J5 SPI 接口 SPI0 和 SPI1 (口线复用) J6 I2C 接口 J7 CAN 接口 1路 J8 IDE 硬盘接口 J15、J16 总线扩展接口 32 位总线宽度 PACK 外设 PACK 接口 (包括 J18、J19、 用于扩展外部总线设备 J20) (使用 Bank1 地址) GPRS PACK GPRS PACK 接口(包括 J21、J22) 用于 GPRS PACK 板 J29 JTAG 接口 用于仿真调试 J30 ADC 接口 AIN2~AIN7 (口线复用) VGA PACK J10~J13 VGA PACK 接口(包括 J34、J35) 用于扩展 VGA 接口 电源输出接口 包括 12V、5V、3.3V 和 GND 注:“口线复用”表示指定口线有一部分已在实验箱上使用。 1.5 硬件资源分配情况 1. 外围器件地址分配 MagicARM2410 实验箱上使用的核心板为 DeviceARM2410 核心板,其存储器的地址如 表 1.2 所列。 MagicARM2410 实验箱主板上的外围器件地址分配如表 1.14 所列。 表 1.14 外围器件地址分配表 外围器件 外设 PACK CL-PD6710 (PCMCIA 接口) 片选信号 nGCS1 nGCS2 地址范围 0x08000000~0x08FFFFFF 0x10000000~0x17FFFFFF 备注 16 位总线接口,24 根地址线,I/O 有 GPB7~GPB10、EINT1、EINT2 -INTR 中断:EINT3 IRQ 中断:EINT8 - 51 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 外围器件 DM9000E (以太网控制器) SJA1000 (CAN 控制器) 片选信号 nGCS3 nGCS4 地址范围 0x18000000~0x1FFFFFFF 0x20000000~0x27FFFFFF 续表 1.14 备注 中断:EINT0 复位控制:GPG2 中断:EINT5 2. I/O 口分配 MagicARM2200 实验箱主板部分 I/O 器件的 I/O 分配表见表 1.15。 表 1.15 I/O 口分配表 I/O 器件 跳线器设置 蜂鸣器 JP9:短接 独立按键 KEY1 —— LED1 LED2 LED3 —— LED4 ZLG7290 (ZLG7290 控 制 键 盘 及 —— LED 数码管) PWM DAC JP11:短接 W1 可调电阻 —— W2 可调电阻 —— 直流电机 JP3:全部短接 步进电机 JP6:全部短接 I/O 备注 GPH10 输出 0,蜂鸣器蜂鸣; 输出 1,蜂鸣器不蜂鸣 GPF4/EINT4 GPE11 GPE12 GPH4 输出 1,LED 点亮 GPH6 I2CSCL、 I2CSDA、 EINT4 从机地址:0x70 中断:EINT4 TOUT0 D/A 输出测试点:PWMDAC AIN0 电压测试点 VIN1 AIN1 电压测试点 VIN2 GPB0、GPH9 电源跳线 JP4 要短接 GPC0、GPC5、 电源跳线 JP5 要短接 GPC6、GPC7 3. 没有使用的 I/O MagicARM2410 实验箱上还有部分 I/O 没有使用,如表 1.16 所列,用户可以通过相应 的连接器将它们引出使用。 表 1.16 MagicARM2410 空闲的 I/O I/O 名称 nGCS5、nGCS7 nXBREQ 、nXBACK EINT6、EINT7 EINT9、EINT16 AIN2~4、AIN6 SPICLK1 、 SPIMOSI1 、 nSS-SPI1、SPIMOSI1 连接器 J16 J5 J4 J15 J30 J5 备注 片选信号 总线占用请求/应答 中断输入口 中断输入口 ADC 输入口 SPI1 接口信号 - 52 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 1.6 温馨提示 在 MagicARM2410 教学实验开发平台的产品配套光盘中,有 MagicARM2410 实验箱主 板和 GPRS PACK 板的电路原理图(电子档),以及板上所使用器件的数据手册或相关资料, 所在光盘位置为“\第 1 章_MagicARM2410 实验箱硬件结构”目录下。 由于本书的篇幅有限,关于 ADS 集成开发环境和 JTAG 仿真器的使用说明在产品配套 光盘附带文档“ADS 集成开发环境及 JTAG 仿真器应用.pdf”中,在进行本书第 2 章的实验 之前请先阅读这一部分内容。 - 53 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 第2章 基础实验 本章的实验可分为两部分,第一部分从 2.1 节至 2.7 节,介绍如何在 ADS 1.2 集成开发 环境进行编译和模拟仿真调试,该部分实验是脱离硬件电路进行;第二部分从 2.8 节至 2.18 节介绍在无操作系统下的嵌入式系统基本接口应用实验,该部分实验基于 MagicARM2410 教学实验开发平台进行。 模拟仿真和硬件仿真调试的具体操作分别请参考 2.1 节和 2.8 节。MagicARM2410 专用 工程模板和仿真器的详细说明请参考产品配套光盘附带文档“ADS 集成开发环境及 JTAG 仿真器应用.pdf”的相关说明。 2.1 ADS 1.2 集成开发环境练习 1. 实验目的 了解 ADS 1.2 集成开发环境的使用方法。 2. 实验设备 硬件:PC 机 一台 软件:Windows98/XP/2000 系统,ADS 1.2 集成开发环境 3. 实验内容 (1)建立一个新的工程。 (2)建立一个汇编文件,并添加到工程中。 (3)设置文本编辑器支持中文。 (4)设置编译链接控制选项。 (5)编译链接工程。 (6)调试工程。 4. 实验预习要求 仔细阅读产品配套光盘附带文档“ADS 集成开发环境及 JTAG 仿真器应用.pdf”或其它 ADS 相关资料,了解 ADS 工程编辑的内容。(本实验使用软件仿真) 5. 实验步骤 (1)在 D:\新建一个目录,目录名为 experiment。启动 ADS1.2 IDE 集成开发环境,选 择【File】->【New…】,使用 ARM Executable Image 工程模板建立一个工程,工程名称为 ADS,工程目录为 D:\experiment,见图 2.1。 - 54 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 图 2.1 建立 ARM 指令代码的工程 (2)选择【File】->【New…】建立一个新的文件 TEST1.S,设置直接添加到项目中, 见图 2.2。输入如程序清单 2.1 所示的代码,并保存,此时在工程窗口中可以看到 TEST1.S 文件,见图 2.3。 图 2.2 新建文件 TEST1.S - 55 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com START 程序清单 2.1 TEST1.S 文件代码 AREA Example1,CODE,READONLY ; 声明代码段 Example1 ENTRY ; 标识程序入口 CODE32 MOV R0,#15 ; 声明 32 位 ARM 指令 ; 设置参数 MOV R1,#8 ADDS R0,R0,R1 ; R0 = R0 + R1 B START END 图 2.3 添加了 TEST1.S 的工程管理窗口 (3)由于 ADS 安装以后默认字体是 Courier New,对于中文支持不完善,因此建议修 改字体。选择【Edit】->【Perferences…】,可以看见以下对话框,如图 2.4 所示。在 Font 选项设置字体是 Fixedsys,Script 是 CHINESE_GB2312 。由于 Tab 在不同文本编辑器解释 不同,建议在 Tab Inserts Spaces 前打勾,使 Tab 键插入的是多个空格。 - 56 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 图 2.4 字体和 Tab 设置 (4)选择【Edit】->【DebugRel Settings…】,在 DebugRel Settings 对话框的左边选择 ARM Linker 项,然后在 Output 页设置链接地址(见图 2.5),在 Options 页设置调试入口地址 (见图 2.6)。 图 2.5 工程链接地址设置 - 57 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 图 2.6 工程调试入口地址设置 (5)选择【Project】->【Make】,将编译链接整个工程。如果编译成功,见图 2.7,Errors & Warnings 对话框会报告编译错误为 0,那么就可以对工程进行仿真。 图 2.7 编译错误和警告对话框 (6)选择【Project】->【Debug】,或者按下快捷键 F5。IDE 环境就会启动 AXD 调试 软件,见图 2.8,接着可以执行单步、全速运行调试。注意,要在 AXD 的 Choose Target 窗 口中选用 ARMUL 软件仿真。 断点调试方法:首先设置断点,只需要在第 6 行灰色区域双击鼠标即可,如果出现红色 - 58 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 实心圆点,那么表示断点设置成功,然后选择【Execute】->【Go】全速运行,可以发现程 序停止在第 6 行。还有一种比较方便的调试方法就是 Run to Cursor,单击鼠标第 8 行灰色区 域,如果 AXD 将第 8 行高亮就表示设置成功,然后选择【Execute】->【Run to Cursor】运 行到光标,可以发现程序停止在第 8 行。通过断点调试可以观察 ARM 寄存器数值变化,具 体的操作方法在后面的实验会具体介绍。 图 2.8 AXD 调试窗口 6. 思考 (1)工程模板有何作用?(提示:编译控制设置) (2)如何强行重新编译工程的所有文件?(提示:选择【Project】->【Remove Object Code…】删除工程中的*.obj 文件) 2.2 汇编指令实验 1 1. 实验目的 (1)了解 ADS 1.2 集成开发环境及 ARMulator 软件仿真。 (2)掌握 ARM7TDMI 汇编指令的用法,并能编写简单的汇编程序。 (3)掌握指令的条件执行和使用 LDR/STR 指令完成存储器的访问。 2. 实验设备 硬件:PC 机 一台 软件:Windows98/XP/2000 系统,ADS 1.2 集成开发环境 3. 实验内容 (1)使用 LDR 指令读取 0x40003100 上的数据,将数据加 1,若结果小于 10 则使用 STR 指令把结果写回原地址,若结果大于等于 10,则把 0 写回原地址。然后再次读取 0x40003100 上的数据,将数据加 1,判断结果是否小于 10……周而复此循环。 - 59 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com (2)使用 ADS 1.2 软件仿真,单步、全速运行程序,设置断点,打开寄存器窗口(Processor Registers)监视 R0、R1 的值,打开存储器观察窗口(Memory) 监视 0x40003100 上的值。 4. 实验预习要求 (1)仔细阅读参考文献[1]第 5 章 ARM 指令集的内容。 (2)仔细阅读产品配套光盘附带文档“ADS 集成开发环境及 JTAG 仿真器应用.pdf” 或其它 ADS 相关资料,了解 ADS 工程编辑和 AXD 调试的内容。(本实验使用软件仿真) 5. 实验步骤 (1)启动 ADS 1.2,使用 ARM Executable Image 工程模板建立一个工程 Instruction1。 (2)建立汇编源文件 TEST2.S,编写实验程序,然后添加到工程中。 (3)设置工程链接地址 RO Base 为 0x40000000,RW Base 为 0x40003000。设置调试 入口地址 Image entry point 为 0x40000000。 (4)编译链接工程,选择【Project】->【Debug】,启动 AXD 进行软件仿真调试。 (5)打开寄存器窗口(Processor Registers),选择 Current 项监视 R0、R1 的值。打开存 储器观察窗口(Memory) 设置观察地址为 0x40003100,显示方式 Size 为 32Bit,监视 0x40003100 地址上的值。 说明:在 Memory 窗口中点击鼠标右键,Size 项中可以选择显示格式为 8Bit、16Bit 或 32Bit,如图 2.9 所示。 可以单步运行程序,可以设置/取消断点,或者全速运行程序,停止程序运行,调试时 观察寄存器和 0x40003100 地址上的值。运行结果见图 2.10。 图 2.9 Memory 窗口显示格式设置 - 60 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 图 2.10 汇编实验 1 程序运行结果 6. 实验参考程序 汇编指令实验 1 的参考程序见程序清单 2.2。 程序清单 2.2 汇编指令实验 1 参考程序 COUNT EQU 0x40003100 ; 定义一个变量,地址为 0x40003100 START AREA Example2,CODE,READONLY ENTRY CODE32 LDR R1,=COUNT MOV R0,#0 STR R0,[R1] ; 声明代码段 Example2 ; 标识程序入口 ; 声明 32 位 ARM 指令 ; R1 <= COUNT ; R0 <= 0 ; [R1] <= R0,即设置 COUNT 为 0 LOOP LDR R1,=COUNT LDR R0,[R1] ADD R0,R0,#1 CMP R0,#10 MOVHS R0,#0 STR R0,[R1] ; R0 <= [R1] ; R0 <= R0 + 1 ; R0 与 10 比较,影响条件码标志 ; 若 R0 大于等于 10,则此指令执行,R0 <= 0 ; [R1] <= R0,即保存 COUNT B LOOP - 61 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com END 7. 思考 (1)若使用 LDRB/STRB 代替程序清单 2.2 中的所有加载/存储指令(LDR/STR),程序 会得到正确的执行吗? (2)LDR 伪指令与 LDR 加载指令的功能和应用有何区别,举例说明?(提示:LDR 伪 指令的形式为“LDR Rn,=expr”) (3)LDR/STR 指令的前索引偏移指令如何编写?指令是怎样操作的? (4)在 AXD 调试时如何复位程序?(提示:选择【File】->【Reload Current Image】重 新加载映象文件) 2.3 汇编指令实验 2 1. 实验目的 (1)掌握 ARM 数据处理指令的使用方法。 (2)了解 ARM 指令灵活的第 2 个操作数。 2. 实验设备 硬件:PC 机 一台 软件:Windows98/XP/2000 系统,ADS 1.2 集成开发环境 3. 实验内容 (1)使用 MOV 和 MVN 指令访问 ARM 通用寄存器。 (2)使用 ADD、SUB、AND、ORR、CMP、TST 等指令完成数据加减运算及逻辑运 算。 4. 实验预习要求 (1)仔细阅读参考文献[1]第 5 章 ARM 指令集的内容。 (2)仔细阅读产品配套光盘附带文档“ADS 集成开发环境及 JTAG 仿真器应用.pdf” 或其它 ADS 相关资料,了解 ADS 工程编辑和 AXD 调试的内容。(本实验使用软件仿真) 5. 实验步骤 (1)启动 ADS 1.2,使用 ARM Executable Image 工程模板建立一个工程 Instruction2。 建立汇编源文件 TEST3.S,编写实验程序,然后添加到工程中。 (2)设置工程链接地址 RO Base 为 0x40000000,RW Base 为 0x40003000,设置调试 入口地址 Image entry point 为 0x40000000。 (3)编译链接工程,选择【Project】->【Debug】,启动 AXD 进行软件仿真调试。 打开寄存器窗口(Processor Registers),选择 Current 项监视各寄存器的值。 说明:使用鼠标左键选择某一个寄存器,然后点击鼠标右键,Format 项中选择显示格 - 62 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 式 Hex、Decimal 等等。如图 2.11 所示。 图 2.11 设置寄存器显示格式 (4)单步运行程序,观察寄存器值的变化。 说明:有变化的寄存器会以红色显示。如图 2.12 所示。 图 2.12 寄存器值更新的显示 6. 实验参考程序 汇编指令实验 2 的参考程序见程序清单 2.3。 程序清单 2.3 汇编指令实验 2 参考程序 X Y BIT23 EQU EQU EQU 11 8 (1<<23) ; 定义 X 的值为 11 ; 定义 Y 的值为 8 ; 定义 BIT23 的值为 0x00800000 - 63 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com START AREA Example3,CODE,READONLY ; 声明代码段 Example3 ENTRY ; 标识程序入口 CODE32 ; 声明 32 位 ARM 指令 ; 使用 MOV、ADD 指令实现:R8 = R3 = X + Y MOV R0,#X ; R0 <= X,X 的值必须是 8 位图数据 MOV R1,#Y ; R1 <= Y,Y 的值必须是 8 位图数据 ADD R3,R0,R1 ; 即是 R3 = X + Y MOV R8,R3 ; R8 <= R3 ; 使用 MOV、MVN、SUB 指令实现:R5 = 0x5FFFFFF8 - R8 * 8 MVN R0,#0xA0000007 ; 0xA0000007 的反码为 0x5FFFFFF8 SUB R5,R0,R8,LSL #3 ; R8 左移 3 位,结果即是 R8 * 8 ; 使用 CMP 指令判断(5*Y/2)>(2*X)吗?若大于则 R5 = R5&0xFFFF0000,否则 R5 = R5|0x000000FF MOV R0,#Y ADD MOV R0,R0,R0,LSL #2 R0,R0,LSR #1 ; 计算 R0 = Y + 4*Y = 5*Y ; 计算 R0 = 5*Y/2 MOV R1,#X MOV CMP R1,R1,LSL #1 R0,R1 ; 计算 R1 = 2*X ; 比较 R0 和 R1,即(5*Y/2)和(2*X)进行比较 LDRHI R2,=0xFFFF0000 ; 若(5*Y/2)>(2*X),则 R2 <= 0xFFFF0000 ANDHI R5,R5,R2 ; 若(5*Y/2)>(2*X),则 R5 = R5&R2 ORRLS R5,R5,#0x000000FF ; 若(5*Y/2)≤(2*X),则 R5 = R5|0x000000FF ; 使用 TST 指令测试 R5 的 bit23 是否为 1,若是则将 bit6 位清零(使用 BIC 指令) TST R5,#BIT23 BICNE R5,R5,#0x00000040 B START END 7. 思考 (1)指令 MOV R0,#0x12345678 是否正确?为什么? ( 2 ) 将 参 考 程 序 中 应 用 CMP 指 令 的 代 码 , 功 能 改 为 若 (5*Y/2)>(2*X) 则 R5 = R5|0x000000FF,否则 R5 = R5&0xFFFF0000,程序应如何修改? (3)更改参考程序的 X 的值为 200,Y 的值为 163,单步运行程序,每执行一步程序 的结果是多少? (4)如何实现 64 位加法运算(R6、R5) = (R6、R5) + (R3、R2)?(提示:使用 ADC 指 令) - 64 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 2.4 汇编指令实验 3 1. 实验目的 通过实验了解如何使用 ARM 汇编指令实现结构化程序编程。 2. 实验设备 硬件:PC 机 一台 软件:Windows98/XP/2000 系统,ADS 1.2 集成开发环境 3. 实验内容 (1)使用 ARM 汇编指令实现 if 条件执行。 (2)使用 ARM 汇编指令实现 for 循环结构。 (3)使用 ARM 汇编指令实现 while 循环结构。 (4)使用 ARM 汇编指令实现 do…while 循环结构。 (5)使用 ARM 汇编指令实现 switch 开关结构。 4. 实验预习要求 (1)仔细阅读参考文献[1]第 5 章 ARM 指令集的内容。 (2)仔细阅读产品配套光盘附带文档“ADS 集成开发环境及 JTAG 仿真器应用.pdf” 或其它 ADS 相关资料,了解 ADS 工程编辑和 AXD 调试的内容。(本实验使用软件仿真) 5. 实验步骤 (1)思考如何使用 ARM 汇编指令实现结构化编程,具体的条件自己设定。比如 if 条 件执行,if(x>y) z=0,设 x 为 R0,y 为 R1,z 为 R2,汇编代码如何编写。 (2)启动 ADS 1.2,使用 ARM Executable Image 工程模板建立一个工程 Instruction3。 (3)建立汇编源文件 TEST4.S,编写实验程序,然后添加到工程中。 (4)设置工程链接地址 RO Base 为 0x40000000,RW Base 为 0x40003000。设置调试 入口地址 Image entry point 为 0x40000000。 (5)编译链接工程,选择【Project】->【Debug】,启动 AXD 进行软件仿真调试。 (6)打开寄存器窗口(Processor Registers),选择 Current 项监视各寄存器的值。 (7)单步运行程序,判断程序是否按设计的程序逻辑执行。 6. 实验参考程序 汇编指令实验 3 的参考程序见程序清单 2.4。 程序清单 2.4 汇编指令实验 3 参考程序 START AREA Example4,CODE,READONLY ; 声明代码段 Example4 ENTRY ; 标识程序入口 CODE32 ; 声明 32 位 ARM 指令 ; if(x>y) z=100; ; else z=50; - 65 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com ; 设 x 为 R0,y 为 R1,z 为 R2 (x、y、z 均为无符号整数) MOV R0,#76 ; 初始化 x 的值 MOV R1,#243 ; 初始化 y 的值 CMP R0,R1 ; 判断 x>y? MOVHI R2,#100 ; x>y 条件正确,z=100 MOVLS R2,#50 ; 条件失败,z=50 FOR_L1 ; for(i=0; i<10; i++) ; { x++; ;} ; 设 x 为 R0,i 为 R2 (i、x 均为无符号整数) MOV R0,#0 ; 初始化 x 的值 MOV R2,#0 ; 设置 i=0 CMP BHS R2,#10 FOR_END ; 判断 i<10? ; 若条件失败,退出循环 ADD R0,R0,#1 ; 循环体,x++ ADD R2,R2,#1 ; i++ B FOR_L1 FOR_END NOP ; while(x<=y) ; { x *= 2; ;} ; 设 x 为 R0,y 为 R1 (x、y 均为无符号整数) MOV R0,#1 ; 初始化 x 的值 MOV R1,#20 ; 初始化 y 的值 B WHILE_L2 ; 首先要判断条件 WHILE_L1 MOV R0,R0,LSL #1 ; 循环体,x *= 2 WHILE_L2 WHILE_END CMP BLS NOP R0,R1 WHILE_L1 ; 判断 x≤y? ; 若条件正确,继续循环 ; do ; { x--; ; } while(x>0); ; 设 x 为 R0 (x 为无符号整数) MOV R0,#5 ; 初始化 x 的值 DOWHILE_L1 ADD R0,R0,#-1 ; 循环体,x-- - 66 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com DOWHILE_L2 DOWHILE_END MOVS BNE NOP R0,R0 ; R0 <= R0,并影响条件码标志 DOWHILE_L1 ; 若 R0 不为 0(即 x 不为 0),则继续循环 ; switch(key&0x0F) ; { case 0: ; case 2: ; case 3: x = key + y; ; break; ; case 5: x = key - y; ; break; ; case 7: x = key * y; ; break; ; default: x = 168; ; break; ;} ; 设 x 为 R0,y 为 R1,key 为 R2 (x、y、key 均为无符号整数) MOV R1,#3 ; 初始化 y 的值 MOV R2,#2 ; 初始化 key 的值 SWITCH AND R2,R2,#0x0F ; switch(key&0x0F) CASE_0 CASE_2 CASE_3 CMP CMPNE CMPNE BNE ADD B R2,#0 ; case 0: R2,#2 ; case 2: R2,#3 ; case 3: CASE_5 R0,R2,R1 ; x = key + y SWITCH_END ; break CASE_5 CMP BNE SUB B R2,#5 ; case 5: CASE_7 R0,R2,R1 ; x = key - y SWITCH_END ; break CASE_7 CMP BNE MUL B R2,#7 ; case 7: DEFAULT R0,R2,R1 ; x = key * y SWITCH_END ; break DEFAULT MOV SWITCH_END NOP R0,#168 ; default: x = 168 HALT B END HALT - 67 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 7. 思考 (1) 使用 ARM 汇编指令结构化程序编程,如何在 for、while 结构中实现 break、continue? (2) 使用 ARM 汇编指令结构化程序编程,如何实现嵌套条件语句?嵌套条件语句描述 如下: if (表达式 1) { if (表达式 2) 语句 1; else 语句 2; } else { if (表达式 3) 语句 3; else 语句 4; } 2.5 ARM 处理器工作模式实验 1. 实验目的 (1)掌握如何使用 MRS/MSR 指令实现 ARM 处理器工作模式的切换。 (2)了解在各个工作模式下的寄存器。 2. 实验设备 硬件:PC 机 一台 软件:Windows98/XP/2000 系统,ADS 1.2 集成开发环境 3. 实验内容 (1)使用 MRS/MSR 指令切换工作模式,并初始化各种模式下堆栈指针。 (2)观察 ARM 处理器在各种模式下寄存器的区别。 4. 实验预习要求 (1)仔细阅读参考文献[1]第 2 章 ARM 体系结构的内容。 (2)仔细阅读产品配套光盘附带文档“ADS 集成开发环境及 JTAG 仿真器应用.pdf” 或其它 ADS 相关资料,了解 ADS 工程编辑和 AXD 调试的内容。(本实验使用软件仿真) 5. 实验步骤 (1)启动 ADS 1.2,使用 ARM Executable Image 工程模板建立一个工程 MODE。 (2)建立汇编源文件 TEST5.S,编写实验程序,然后添加到工程中。 (3)设置工程链接地址 RO Base 为 0x40000000,RW Base 为 0x40003000。设置调试 入口地址 Image entry point 为 0x40000000。 (4)编译链接工程,选择【Project】->【Debug】,启动 AXD 进行软件仿真调试。 (5)打开寄存器窗口(Processor Registers),选择 Current 项监视各寄存器的值。 (6)单步运行程序,注意观察 CPSR、SPSR、R13(SP)、R14(LR)、R15(PC)寄存器。 - 68 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 说明:CPSR 寄存器显示方式如图 2.13 所示。显示分为两部分,一部分是各个标志位, 另一部分是工作模式。 标志位 NZCVQ 为条件码标志 N、Z、C、V、Q,显示为大写字母,表示该位为 1;显 示为小写字母,表示该位为 0。Q 标志在 ARM 体系结构 v5 及以上版本的 E 变量中才有效。 标志位 IFT 为 IRQ 中断禁止位 I、FIQ 中断禁止位 F、ARM 处理器状态位 T,显示为大 写字母,表示该位为 1;显示为小写字母,表示该位为 0。T 标志在 ARM 体系结构 v4 及以 上版本的 T 变量中才有效。 工作模式指示 ARM 处理器当前的工作模式,包括 User(用户模式)、FIQ(FIQ 中断模式)、 IRQ(IRQ 中断模式)、SVC(管理模式)、Abort(中止模式)、Undef(未定义模式)、SYS(系统模 式)。 图 2.13 CPSR 寄存器显示方式 6. 实验参考程序 ARM 处理器工作模式实验的参考程序见程序清单 2.5。 程序清单 2.5 ARM 处理器工作模式实验参考程序 ;定义堆栈的大小 USR_STACK_LEGTH EQU 64 SVC_STACK_LEGTH EQU 0 FIQ_STACK_LEGTH EQU 16 IRQ_STACK_LEGTH EQU 64 ABT_STACK_LEGTH EQU 0 UND_STACK_LEGTH EQU 0 - 69 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com START AREA Example5,CODE,READONLY ; 声明代码段 Example5 ENTRY CODE32 ; 标识程序入口 ; 声明 32 位 ARM 指令 MOV R0,#0 MOV R1,#1 MOV R2,#2 MOV R3,#3 MOV R4,#4 MOV R5,#5 MOV R6,#6 MOV R7,#7 MOV R8,#8 MOV R9,#9 MOV R10,#10 MOV R11,#11 MOV R12,#12 BL InitStack ; 初始化各模式下的堆栈指针 ; 打开 IRQ 中断 (将 CPSR 寄存器的 I 位清零) MRS R0,CPSR ; R0 <= CPSR BIC R0,R0,#0x80 MSR CPSR_cxsf,R0 ; CPSR <= R0 ; 切换到用户模式 MSR CPSR_c, #0xd0 MRS R0,CPSR HALT ; 切换到管理模式 MSR CPSR_c, #0xdf MRS R0,CPSR B HALT ; 名称:InitStack ; 功能:堆栈初始化,即初始化各模式下的堆栈指针。 ; 入口参数:无 ; 出口参数:无 ; 说明:在特权模式下调用此子程序,比如复位后的管理模式 InitStack MOV R0, LR ; R0 <= LR,因为各种模式下 R0 是相同的 ;设置管理模式堆栈 MSR CPSR_c, #0xd3 LDR SP, StackSvc ;设置中断模式堆栈 - 70 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com MSR LDR ;设置快速中断模式堆栈 MSR LDR ;设置中止模式堆栈 MSR LDR ;设置未定义模式堆栈 MSR LDR ;设置系统模式堆栈 MSR LDR MOV CPSR_c, #0xd2 SP, StackIrq CPSR_c, #0xd1 SP, StackFiq CPSR_c, #0xd7 SP, StackAbt CPSR_c, #0xdb SP, StackUnd CPSR_c, #0xdf SP, StackUsr PC, R0 StackUsr StackSvc StackIrq StackFiq StackAbt StackUnd DCD DCD DCD DCD DCD DCD UsrStackSpace + (USR_STACK_LEGTH - 1)*4 SvcStackSpace + (SVC_STACK_LEGTH - 1)*4 IrqStackSpace + (IRQ_STACK_LEGTH - 1)*4 FiqStackSpace + (FIQ_STACK_LEGTH - 1)*4 AbtStackSpace + (ABT_STACK_LEGTH - 1)*4 UndtStackSpace + (UND_STACK_LEGTH - 1)*4 ; 分配堆栈空间 AREA MyStacks, DATA, NOINIT, ALIGN=2 UsrStackSpace SvcStackSpace SPACE USR_STACK_LEGTH * 4 SPACE SVC_STACK_LEGTH * 4 ; 用户(系统)模式堆栈空间 ; 管理模式堆栈空间 IrqStackSpace SPACE IRQ_STACK_LEGTH * 4 ; 中断模式堆栈空间 FiqStackSpace AbtStackSpace SPACE FIQ_STACK_LEGTH * 4 SPACE ABT_STACK_LEGTH * 4 ; 快速中断模式堆栈空间 ; 中止义模式堆栈空间 UndtStackSpace SPACE UND_STACK_LEGTH * 4 ; 未定义模式堆栈 END 7. 思考 (1)在用户模式或系统模式下读取 SPSR 寄存器会有何结果? (2)在非特权模式下能否对 CPSR 寄存器设置?能否读取 CPSR 寄存器的值?(提示: 参考实验程序有相应的代码,运行测试一下) (3)在非特权模式下如何使能/禁止 IRQ 或 FIO 中断?(提示:可以先使用 SWI 指令切 换到管理模式) (4)程序中能不能通过 MSR 指令直接修改 CPSR 中的 T 位来实现 ARM 状态/Thumb 状态的切换? - 71 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 2.6 C 语言程序实验 1. 实验目的 通过实验了解使用 ADS 1.2 编写 C 语言程序,并进行调试。 2. 实验设备 硬件:PC 机 一台 软件:Windows98/XP/2000 系统,ADS 1.2 集成开发环境 3. 实验内容 编写一个汇编程序文件和一个 C 程序文件。汇编程序的功能是初始化堆栈指针和初始 化 C 程序的运行环境,然后调跳转到 C 程序运行,这就是一个简单的启动程序。C 程序使 用加法运算来计算 1+2+3+...+(N-1)+N 的值(N>0)。 4. 实验预习要求 (1)仔细阅读参考文献[1]第 5 章 ARM 指令集的内容。 (2)仔细阅读产品配套光盘附带文档“ADS 集成开发环境及 JTAG 仿真器应用.pdf” 或其它 ADS 相关资料,了解 ADS 工程编辑和 AXD 调试的内容。(本实验使用软件仿真) 5. 实验步骤 (1)启动 ADS 1.2,使用 ARM Executable Image 工程模板建立一个工程 ProgramC。 (2)建立源文件 Startup.S 和 Test.c,编写实验程序,然后添加到工程中。 (3)设置工程链接地址 RO Base 为 0x40000000,RW Base 为 0x40003000。设置调试 入口地址 Image entry point 为 0x40000000。 (4)设置位于开始位置的起始代码段,如图 2.14 所示。 (5)编译链接工程,选择【Project】->【Debug】,启动 AXD 进行软件仿真调试。 (6)在 Startup.S 的“B Main”处设置断点,然后全速动行程序。 (7)程序在断点处停止。单步运行程序,判断程序是否跳转到 C 程序中运行。 (8)选择【Processor Views】->【Variables】)打开变量观察窗口,观察全局变量的值, 单步/全速运行程序,判断程序的运算结果是否正确。 - 72 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 图 2.14 起始代码段的设置 6. 实验参考程序 C 语言实验的参考程序见程序清单 2.6。汇编启动代码见程序清单 2.7。 程序清单 2.6 C 语言实验参考程序 #define uint8 #define uint32 #define N unsigned char unsigned int 100 uint32 sum; // 使用加法运算来计算 1+2+3+...+(N-1)+N 的值。(N>0) void Main(void) { uint32 i; sum = 0; for(i=0; i<=N; i++) { sum += i; } while(1); } 程序清单 2.7 简单的启动代码 ; 启动文件。初始化 C 程序的运行环境,然后进入 C 程序代码。 - 73 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com IMPORT IMPORT IMPORT IMPORT IMPORT |Image$$RO$$Limit| |Image$$RW$$Base| |Image$$ZI$$Base| |Image$$ZI$$Limit| Main ; 声明 C 程序中的 Main()函数 Reset AREA Start,CODE,READONLY ; 声明代码段 Start ENTRY CODE32 ; 标识程序入口 ; 声明 32 位 ARM 指令 LDR SP,=0x40003F00 ; 初始化 C 程序的运行环境 LDR R0,=|Image$$RO$$Limit| LDR R1,=|Image$$RW$$Base| LDR R3,=|Image$$ZI$$Base| LOOP0 CMP BEQ CMP LDRCC STRCC BCC R0,R1 LOOP1 R1,R3 R2,[R0],#4 R2,[R1],#4 LOOP0 LOOP1 LOOP2 LDR MOV CMP STRCC BCC R1,=|Image$$ZI$$Limit| R2,#0 R3,R1 R2,[R3],#4 LOOP2 B END Main ; 跳转到 C 程序代码 Main()函数 7. 思考 (1)在实验参考程序中,Startup.S 文件的作用是什么?如果没有 Startup.S 文件,C 程 序会运行出错吗? (2)实验程序中的 Main()函数名是否可以更改为其它名字?(提示:Main 只是一个标 号) 2.7 C 语言调用汇编程序实验 1. 实验目的 掌握在 C 语言程序中调用汇编程序,了解 ATPCS 基本规则。 - 74 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 2. 实验设备 硬件:PC 机 一台 软件:Windows98/XP/2000 系统,ADS 1.2 集成开发环境 3. 实验内容 在 C 程序调用汇编子程序,实现两个整数的加法运算。汇编子程序的原型为: uint32 Add(uint32 x, uint32 y),其中 uint32 已定义为 unsigned int。 4. 实验预习要求 (1)仔细阅读 ARM 公司的 ATPCS 的相关文档,比如 ATPCS.PDF(在产品配套光盘上 有此文件)。 (2)仔细阅读产品配套光盘附带文档“ADS 集成开发环境及 JTAG 仿真器应用.pdf” 或其它 ADS 相关资料,了解 ADS 工程编辑和 AXD 调试的内容。(本实验使用软件仿真) 5. 实验步骤 (1)启动 ADS 1.2,使用 ARM Executable Image 工程模板建立一个工程 ProgramC1。 (2)建立源文件 Startup.S、Add.S 和 Test.c,编写实验程序,然后添加到工程中。 (3)设置工程链接地址 RO Base 为 0x40000000,RW Base 为 0x40003000。设置调试 入口地址 Image entry point 为 0x40000000。 (4)设置工程链接选项,位于开始位置的起始代码段设置为 Startup.o 的 Start 段。 (5)编译链接工程,选择【Project】->【Debug】,启动 AXD 进行软件仿真调试。 (6)在 Test.c 文件中的调用 Add()的代码处设置断点,然后全速动行程序。 (7)程序在断点处停止。使用 Setp In 单步运行程序,观察程序是否转到汇编程序 Add.S。 (8)选择【Processor Views】->【Variables】)打开变量观察窗口,观察全局变量的值, 单步/全速运行程序,判断程序的运算结果是否正确。 6. 实验参考程序 C 语言调用汇编程序实验的参考程序见程序清单 2.8。汇编加法函数代码见程序清单 2.9。 程序清单 2.8 C 语言调用汇编程序实验参考程序 #define uint8 unsigned char #define uint32 unsigned int extern uint32 Add(uint32 x, uint32 y); uint32 sum; // 调用汇编程序 Add 实现加法运算 void Main(void) { sum = Add(555, 168); while(1); } - 75 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 程序清单 2.9 汇编加法函数代码 ; 加法函数,原型为 uint32 Add(uint32 x, uint32 y)。 EXPORT Add AREA AddC,CODE,READONLY ; 声明代码段 AddC ENTRY ; 标识程序入口 CODE32 ; 声明 32 位 ARM 指令 Add ADD R0,R0,R1 ; 输入参数 x 为 R0,y 为 R1 MOV PC,LR ; 返回值为 R0 END 7. 思考 在实验参考程序中,如何以指针形式传递参数?(即设计 uint32 Add(uint32 *x, uint32 *y) 函数) 2.8 GPIO 输出控制实验 1. 实验目的 (1)掌握 DeviceARM2410 专用工程模板的使用。 (2)掌握 EasyJTAG-H 仿真器的安装和使用。 (3)能够在 MagicARM2410 实验箱上运行第一个程序(无操作系统)。 (4)熟悉 S3C2410A 处理器的 I/O 配置方法及 GPIO 输出控制。 2. 实验设备 硬件:PC 机 一台 MagicARM2410 教学实验开发平台 一套 软件:Windows98/XP/2000 系统,ADS 1.2 集成开发环境 3. 实验内容 控制 MagicARM2410 实验箱上的 LED1~LED4 显示及蜂鸣器报警。先使用片外 SDRAM(HY57V561620 芯片)进行调试,调试通过后将程序固化到片外 NOR FLASH (SST39 VF1601 芯片),脱机运行程序。 4. 实验预习要求 (1)仔细阅读参考文献[2]第 9 节的 S3C2410A 的 GPIO 模块说明。 (2)仔细阅读本书第 1 章的内容,了解 MagicARM2410 实验箱的硬件结构,注意独立 LED 及蜂鸣器控制电路。 (3)仔细阅读产品配套光盘附带文档“ADS 集成开发环境及 JTAG 仿真器应用.pdf” 或其它 ADS 相关资料,了解 ADS 1.2 集成开发环境、DeviceARM2410 专用工程模板、 EasyJTAG-H 仿真器的应用。 - 76 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 5. 实验原理 S3C2410A 具有 117 个通用 I/O 口,分为 A~H 等 8 个端口,由于每个 I/O 都有第 2 功 能,甚至第 3 功能,所以需要通过设置 GPxCON 寄存器来选择 GPx 口 I/O 的功能,其中 x 可以为 A、B、C、D、E、F、G、H,表示相应的 I/O 端口。 当 I/O 设置为 GPIO 输出模式(Output 模式)时,可以通过写 GPxDAT 控制相应 I/O 口输 出高电平或低电平。GPxDAT 为 1 的位对应 I/O 输出高电平,为 0 的位对应 I/O 输出低电平。 如何在 MagicARM2410 实验箱上运行第一个程序?具体操作步骤如下: (1)添加 DeviceARM2410 专用工程模板。参考产品配套光盘附带文档“ADS 集成开 发环境及 JTAG 仿真器应用.pdf”的内容。 (2)连接 EasyJTAG-H 仿真器和 MagicARM2410 实验箱。将 EasyJTAG-H 仿真器的 25 针接口通过并口延长线与 PC 机的并口连接,将 EasyJTAG-H 仿真器的 20 针接口通过连接 电缆接到 MagicARM2410 实验箱的 J29 上,打开实验箱电源。 (3)EasyJTAG-H 仿真器的安装与应用。参考产品配套光盘附带文档“ADS 集成开发 环境及 JTAG 仿真器应用.pdf”的内容。 (4)用工程模板建立第一个工程。使用 DeviceARM2410 专用工程模板建立工程(比如 ARM Executable Image for DeviceARM2410 工程模板),然后在 src 组中的 main.c 中编写程序 代码。 (5)编译链接工程,若有错误,则修改程序,然后再次编译。 (6)仿真调试第一个工程正确设置 MagicARM2410 实验箱上的跳线。 (7)启动 AXD 进行仿真调试。 6. 实验步骤 (1)为 ADS1.2 增加 DeviceARM2410 专用工程模板(若已增加过,此步省略)。 (2)连接 EasyJTAG-H 仿真器和 MagicARM2410 实验箱,然后安装 EasyJTAG-H 仿真 器(若已经安装过,此步省略)。 (3)启动 ADS 1.2,使用 ARM Executable Image for DeviceARM2410 工程模板建立一 个工程 LEDCON。 (4)在 src 组中的 main.c 中编写实验代码。 (5)选用 DebugRel 生成目标,如图 2.15 所示,然后编译链接工程。 (6)将 MagicARM2410 实验箱上的蜂鸣器跳线 JP9 短接,将启动方式选择跳线 JP8 短 接,然后按 RST 键复位系统。 (7)选择【Project】->【Debug】,启动 AXD 进行 JTAG 仿真调试(需要正确设置仿真 器,参考产品配套光盘附带文档“ADS 集成开发环境及 JTAG 仿真器应用.pdf”的内容)。 (8)若 JTAG 连接出错,或 AXD 主窗口没有显示 Startup.S 源程序,按产品配套光盘 附带文档“ADS 集成开发环境及 JTAG 仿真器应用.pdf”介绍的方法进行处理。 (9)全速运行程序,程序将会在 main.c 的主函数中停止(因为 main 函数起始处默认设 置有断点)。 (10)单击 Context Variable 图标按钮(或者选择【Processor Views】->【Variables】)打 开变量观察窗口,通过此窗口可以观察局部变量和全局变量。 (11)可以单步运行程序,可以设置/取消断点,或者全速运行程序,停止程序运行, 观察变量的值,判断蜂鸣器及 LED1~LED4 的控制是否正确。 - 77 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 图 2.15 选择生成目标 (12)当仿真调试通过后,关闭 AXD。在 ADS 1.2 集成开发环境中选用 Release 生成目 标,并设置生成 LEDCON.hex 文件(或者 LEDCON.bin 文件),然后编译链接工程(参考产品 配套光盘附带文档“ADS 集成开发环境及 JTAG 仿真器应用.pdf”的内容)。 (13)将启动方式选择跳线 JP8 断开,然后按 RST 键复位系统。 (14)使用 Flash Programmer 软件将 LEDCON.hex 烧写到片外 NOR FLASH,或者使用 WR_NORFlash 工程将 LEDCON.bin 烧写到片外 NOR FLASH,操作方法请参考产品配套光 盘“\第 2 章_ADS 集成开发环境及 JTAG 仿真器应用\FlashDown”目录下的“操作说明.txt” 文件。 (15)将 EasyJTAG-H 仿真器拔出,断开与 MagicARM2410 实验箱的连接,然后给 MagicARM2410 实验箱下电,然后再重新上电,观察程序是否能脱机运行。 7. 实验参考程序 GPIO 输出控制实验 1 的参考程序见程序清单 2.10。 程序清单 2.10 GPIO 输出控制实验参考程序 /****************************************Copyright (c)*********************************** ** File Name: main.c ** Last modified Date: 2006-01-05 ** Last Version: v1.0 ** Description: MagicARM2410 实验箱的基础实验---GPIO 输出控制实验。 ** 使用 GPIO 控制 LED1~LED4 及蜂鸣器,先蜂鸣器响一声,全部闪烁 5 次, ** 然后指示 0~F 的 16 进制数值。 ************************************************************************************/ #include "config.h" // 定义 LED 控制口 (输出高电平时点亮 LED) #define LED1_CON (1<<11) /* GPE11 口 */ - 78 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com #define #define #define LED2_CON LED3_CON LED4_CON (1<<12) (1<<4) (1<<6) /* GPE12 口 */ /* GPH4 口 */ /* GPH6 口 */ // 定义蜂鸣器控制口 #define BEEP #define BEEP_MASK (1<<10) (~BEEP) /* GPH10 口 */ /************************************************************************************ ** Function name: DelayNS ** Descriptions: 长软件延时。 延时时间与系统时钟有关。 ** Input: dly 延时参数,值越大,延时越久 ** Output: 无 ************************************************************************************/ void DelayNS(uint32 dly) { uint32 i; for(; dly>0; dly--) for(i=0; i<50000; i++); } /************************************************************************************ ** Function name: RunBeep ** Descriptions: 控制蜂鸣器 Be 一声音。 ** Input: 无 ** Output: 无 ************************************************************************************/ void RunBeep(void) { rGPHDAT = rGPHDAT & BEEP_MASK; // BEEP = 0 DelayNS(5); rGPHDAT = rGPHDAT | BEEP; // BEEP = 1 DelayNS(5); } /************************************************************************************ ** Function name: LED_DispAllOn ** Descriptions: 控制 LED1~LED4 全部点亮。 ** Input: 无 ** Output: 无 ************************************************************************************/ void LED_DispAllOn(void) { - 79 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com rGPEDAT = rGPEDAT | (0x03<<11); rGPHDAT = rGPHDAT | (0x05<<4); } /************************************************************************************ ** Function name: LED_DispAllOff ** Descriptions: 控制 LED1~LED4 全部熄灭。 ** Input: 无 ** Output: 无 ************************************************************************************/ void LED_DispAllOff(void) { rGPEDAT = rGPEDAT & (~(0x03<<11)); rGPHDAT = rGPHDAT & (~(0x05<<4)); } /************************************************************************************ ** Function name: LED_DispNum ** Descriptions: 控制 LED1~LED4 显示指定 16 进制数值。LED4 为最高位, ** ** Input: dat LED1 为最低为,点亮表示该位为 1。 显示数值(低 4 位有效) ** Output: 无 ************************************************************************************/ void LED_DispNum(uint32 dat) { dat = dat & 0x0000000F; // 参数过滤 // 控制 LED4、LED3 显示(d3、d2 位) if(dat & 0x08) rGPHDAT = rGPHDAT | (0x01<<6); else rGPHDAT = rGPHDAT & (~(0x01<<6)); if(dat & 0x04) rGPHDAT = rGPHDAT | (0x01<<4); else rGPHDAT = rGPHDAT & (~(0x01<<4)); // 控制 LED2、LED1 显示(d1、d0 位) rGPEDAT = (rGPEDAT & (~(0x03<<11))) | ((dat&0x03) << 11); } /************************************************************************************ ** Function name: main ** Descriptions: 初始化 I/O,然后控制 LED 显示。 ** Input: 无 ** Output: 系统返回值 0 ************************************************************************************/ int main(void) - 80 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com { int i; // 初始化 I/O rGPECON = (rGPECON & (~(0x0F<<22))) | (0x05<<22); rGPHCON = (rGPHCON & (~(0x33<<8))) | (0x11<<8); rGPHCON = (rGPHCON & (~(0x03<<20))) | (0x01<<20); // LED 显示控制 while(1) { RunBeep(); // 蜂鸣器响一声 // rGPECON[25:22] = 0101b, // 设置 GPE11、GPE12 为 GPIO 输出模式 // rGPHCON[13:8] = 01xx01b, // 设置 GPH4、GPH6 为 GPIO 输出模式 // rGPHCON[21:20] = 01b, // 设置 GPH10 为 GPIO 输出模式 // LED 全闪烁 5 次 for(i=0; i<5; i++) { LED_DispAllOff(); DelayNS(5); LED_DispAllOn(); DelayNS(5); } // LED 全熄灭 // LED 全点亮 // 控制 LED 指示 0~F 的 16 进制数值 for(i=0; i<16; i++) { LED_DispNum(i); // 显示数值 i DelayNS(5); } } return(0); } 8. 思考 (1)为什么这个实验的工程不需要设置链接地址?(提示:DeviceARM2410 专用工程 模板已集成了启动代码、编译选项和链接地址设置等等) (2)在实验参考程序中,如何控制蜂鸣器报警的速度? (3)在 S3C2410A 处理器中,有哪些 I/O 只能设置为 GPIO 输出模式(Output 模式)? - 81 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 2.9 GPIO 输入实验 1. 实验目的 掌握 3C2410A 处理器的 I/O 配置方法,能够使用 GPIO 输入模式读取开关信号。 2. 实验设备 硬件:PC 机 一台 MagicARM2410 教学实验开发平台 一套 软件:Windows98/XP/2000 系统,ADS 1.2 集成开发环境 3. 实验内容 不断地读取 GPF4 口上的电平值,然后将读到的值输出控制蜂鸣器。 4. 实验预习要求 (1)仔细阅读参考文献[2]第 9 节的 S3C2410A 的 GPIO 模块说明。 (2)仔细阅读本书第 1 章的内容,了解 MagicARM2410 实验箱的硬件结构,注意蜂鸣 器控制电路。 (3)仔细阅读产品配套光盘附带文档“ADS 集成开发环境及 JTAG 仿真器应用.pdf” 或其它 ADS 相关资料,了解 ADS 1.2 集成开发环境、DeviceARM2410 专用工程模板、 EasyJTAG-H 仿真器的应用。 5. 实验原理 通过设置 GPxCON 寄存器来选择 GPx 口 I/O 的功能,当 I/O 设置为 GPIO 输入模式(Input 模式)时,读取 GPxDAT 寄存器即取得 I/O 口线上的电平状态。通常会使用 if(GPxDAT & (1<【Debug】,启动 AXD 进行 JTAG 仿真调试。 (6)单步运行程序,先按下 KEY1,观察 rGPFDAT 寄存器的值,然后释放 KEY1,观 察 rGPFDAT 寄存器的值。全速运行程序,按下按键,控制蜂鸣器的蜂鸣。 说明:可以通过 Watch 窗口观察寄存器的值。选择【Processor Views】->【Watch】打 开 Watch 窗口,在 Watch 窗口内点击鼠标右键,选择 Add Watch…项添加变量,如图 2.17 所示。 图 2.17 Watch 窗口 在 Add Watch 窗口中的 Expression 项输入*((unsigned long *) 0x56000054),然后回车, 如图 2.18 所示,然后选择 Add To View 按钮,即可在 Watch 窗口观察 rGPFDAT 寄存器 (rGPFDAT 寄存器的地址 0x56000054)。 图 2.18 Add Watch 对话框 在 Watch 窗口中选择一个观察变量,按 Del 键即可删除此观察变量。 7. 实验参考程序 GPIO 输入实验的参考程序见程序清单 2.11。 - 83 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 程序清单 2.11 GPIO 输入实验参考程序 /****************************************Copyright (c)*********************************** ** File Name: main.c ** Last modified Date: 2006-01-05 ** Last Version: v1.0 ** Description: MagicARM2410 实验箱的基础实验---GPIO 输入实验。 ** 使用 GPIO 输入模式对 GPF4 口进行扫描,对蜂鸣器控制。 ************************************************************************************/ #include "config.h" // 定义独立按键 KEY1 的输入口 #define KEY_CON (1<<4) /* GPF4 口 */ // 定义蜂鸣器控制口 #define BEEP #define BEEP_MASK (1<<10) (~BEEP) /* GPH10 口 */ /************************************************************************************ ** Function name: DelayNS ** Descriptions: 长软件延时。 延时时间与系统时钟有关。 ** Input: dly 延时参数,值越大,延时越久 ** Output: 无 ************************************************************************************/ void DelayNS(uint32 dly) { uint32 i; for(; dly>0; dly--) for(i=0; i<50000; i++); } /************************************************************************************ ** Function name: main ** Descriptions: 不断地读取 GPF4 口的值,并输出控制蜂鸣器 B1。 ** Input: 无 ** Output: 系统返回值 0 ************************************************************************************/ int main(void) { // 初始化 I/O rGPFCON = (rGPFCON & (~(0x03<<8))); // rGPFCON[9:8] = 00b, // 设置 GPF4 为 GPIO 输入模式 rGPHCON = (rGPHCON & (~(0x03<<20))) | (0x01<<20); // rGPHCON[21:20] = 01b, //设置 GPH10 为 GPIO 输出模式 - 84 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com while(1) { if(rGPFDAT & KEY_CON) // 读取 GPF 口线上的电平,判断 GPF4 是否为高电平 { rGPHDAT = rGPHDAT | BEEP; // GPF4 为高电平,则设置 GPH10=1 } else { rGPHDAT = rGPHDAT & BEEP_MASK; // GPF4 为低电平,则设置 GPH10=0 } DelayNS(1); } return(0); } 8. 思考 (1)如果将 GPF4 设置为 GPIO 输入模式,且管脚悬空,那么读取 GPF4 得到的值是 0 还是 1?或者是不确定?(提示:S3C2410A 的 I/O 内部上拉电阻可以通过设置 GPxUP 寄存 器使能或禁止) (2)请编写一个有去抖动功能的按键输入函数,然后在实验程序中使用,实现每按一 次 KEY1 键,蜂鸣器响两声的功能。 2.10 外部中断实验 1. 实验目的 (1)掌握 S3C2410A 处理器外部中断的引脚功能设置。 (2)掌握中断初始化以及中断服务函数的编写。 2. 实验设备 硬件:PC 机 一台 MagicARM2410 教学实验开发平台 一套 软件:Windows98/XP/2000 系统,ADS 1.2 集成开发环境 3. 实验内容 设置 GPF4 引脚为外部中断 EINT4 功能,下降沿触发模式。初始化 S3C2410A 中断控 制器,设置 EINT4 为 IRQ 中断,并使能中断允许。初始化完成后,等待外部中断产生。中 断服务程序里负责把 LED1 控制口输出信号取反,清除中断标志后退出中断。 - 85 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 4. 实验预习要求 (1)仔细阅读参考文献[2]第 9 节的 S3C2410A 的 GPIO 模块说明和第 14 节的中断控制 器说明。 (2)仔细阅读本书第 1 章的内容,了解 MagicARM2410 实验箱的硬件结构,注意独立 LED 控制电路。 5. 实验原理 独立按键 KEY1 电路原理如图 2.16 所示,设置 GPFCON 寄存器来选择 GPF4 引脚为外 部中断 EINT4 功能,此时通过按下 KEY1 键即可触发外部中断。 对于 S3C2410A 的众多中断源,通过设置 INTMOD 寄存器可将它们分为 IRQ 中断或 FIQ 中断,一般只设置一个中断源为 FIQ 中断。对于多个 IRQ 中断,通过 PRIORITY 寄存器可 以设置中断的优先级,一般将其设置为 0 使用默认固定的优先级即可。 设置 INTMSK 寄存器使能某个中断源的中断允许,有些中断源还需要设置 SUBMASK 寄存器使能(比如 UART 的发送中断和接收中断)。对于外部中断 EINT4~EINT23,由于它 们在 S3C2410A 的中断控制器中不是独立中断源(EINT4~EINT7 共用一个中断源,EINT8~ EINT23 共用另一个中断源),所以还需要设置 EINTMASK 寄存器来使能某一个外部中断。 由于 S3C2410A 的中断控制器不是向量中断控制器,即处理器硬件不能自动获取对应于 中断源的中断服务程序地址,所以在 IRQ 中断服务程序中要通过中断标志寄存器 INTPND 来获得对应的中断服务程序地址(参考 ARM Executable Image for DeviceARM2410 工程模板 的 Target.c 文件,其中的 IRQ_Exception 函数)。 在中断服务程序中,退出中断之前要清除中断标志,即对 SRCPND 和 INTPND 寄存器 相应位写 1,先清除 SRCPND 寄存器,再清除 INTPND 寄存器。对于外部中断 EINT4~EINT23 中断,要最先清除 EINTPEND 寄存器中的中断标志。 6. 实验步骤 (1)启动 ADS 1.2,使用 ARM Executable Image for DeviceARM2410 工程模板建立一 个工程 EINT。 (2)在 src 组中的 main.c 中编写主程序代码。 (3)选用 DebugRel 生成目标,然后编译链接工程。 (4)将 MagicARM2410 实验箱上的启动方式选择跳线 JP8 短接,然后按 RST 键复位 系统。 (5)选择【Project】->【Debug】,启动 AXD 进行 JTAG 仿真调试。 (6)在中断服务程序中设置断点,全速运行程序,按下/释放 KEY1 按键,使 EINT4 为低/高电平(产生中断)。 (7)取消中断服务程序中有断点,全速运行程序,按下/释放 KEY1 按键,观察 LED1 灯的变化。 7. 实验参考程序 外部中断实验的参考程序见程序清单 2.12。 程序清单 2.12 外部中断实验参考程序 /****************************************Copyright (c)*********************************** - 86 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com ** File Name: main.c ** Last modified Date: 2006-01-05 ** Last Version: v1.0 ** Description: MagicARM2410 实验箱的基础实验---外部中断实验。 ** 使用外部中断 EINT4 进行 LED1 的控制,每当有一次中断,就把 LED1 控制口输出信号取反一次。 ************************************************************************************/ #include "config.h" // 定义 LED 控制口 (输出高电平时点亮 LED) #define LED1_CON (1<<11) #define LED2_CON (1<<12) #define LED3_CON (1<<4) #define LED4_CON (1<<6) /* GPE11 口 */ /* GPE12 口 */ /* GPH4 口 */ /* GPH6 口 */ // 定义独立按键 KEY1 的输入口 #define KEY_CON (1<<4) /* GPF4 口 */ // 定义 LED1 控制值变量 uint8 ledcon = 0x00; /************************************************************************************ ** Function name: DelayNS ** Descriptions: 长软件延时。 延时时间与系统时钟有关。 ** Input: dly 延时参数,值越大,延时越久 ** Output: 无 ************************************************************************************/ void DelayNS(uint32 dly) { uint32 i; for(; dly>0; dly--) for(i=0; i<50000; i++); } /************************************************************************************ ** Function name: IRQ_Eint4 ** Descriptions: Eint4 中断服务程序。把 LED1 控制口输出信号取反。 ** Input: 无 ** Output: 无 ************************************************************************************/ void IRQ_Eint4(void) { int i; - 87 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com // 按键去抖动 rGPFCON = rGPFCON & (~(0x03<<8)); for(i=0; i<10000; i++); if(rGPFDAT&KEY_CON) { rGPFCON = rGPFCON | (0x02<<8); // 设置为 GPIO 输入方式 // 延时去抖动 // 若是假按键,则直接退出 // 设置回 EINT4 中断口 // 清除中断标志 rEINTPEND = (1<<4); rSRCPND = (1<<4); rINTPND = rINTPND; return; } rGPFCON = rGPFCON | (0x02<<8); // 设置回 EINT4 中断口 // 把 LED1 控制口输出信号取反 if(ledcon) { ledcon = 0; rGPEDAT = rGPEDAT & (~LED1_CON) ; } else { ledcon = 1; rGPEDAT = rGPEDAT | LED1_CON; } // 清除中断标志 rEINTPEND = (1<<4); rSRCPND = (1<<4); rINTPND = rINTPND; } /************************************************************************************ ** Function name: EINT_init ** Descriptions: 外部中断初始化。设置 GPF4 引脚为外部中断 EINT4 功能,下降沿触发模式, ** 并使能中断允许。 ** Input: 无 ** Output: 无 ************************************************************************************/ void EINT_init(void) { rGPFCON = (rGPFCON & 0xFFFFFCFF) | (0x02<<8); // 设置 GPF4 引脚为外部中断 EINT4 功能 rEXTINT0 = (0x2<<16); // 外部中断 EINT4 设置为下降沿触发 - 88 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com VICVectAddr[4] = (uint32) IRQ_Eint4; // 中断向量地址设置 rPRIORITY = 0x00000000; // 使用默认的固定的优先级 rINTMOD = 0x00000000; // 所有中断均为 IRQ 中断 rINTMSK = ~0x0000010; // 使能 EINT4 中断 rEINTMASK = ~0x0000010; } /************************************************************************************ ** Function name: LED_DispAllOff ** Descriptions: 控制 LED1~LED4 全部熄灭。 ** Input: 无 ** Output: 无 ************************************************************************************/ void LED_DispAllOff(void) { rGPEDAT = rGPEDAT & (~(0x03<<11)); rGPHDAT = rGPHDAT & (~(0x05<<4)); } /************************************************************************************ ** Function name: main ** Descriptions: 初始化外部中断 EINT4,然后循环等待中断。 ** Input: 无 ** Output: 系统返回值 0 ************************************************************************************/ int main(void) { // 初始化 I/O rGPECON = (rGPECON & (~(0x0F<<22))) | (0x05<<22); // rGPECON[25:22] = 0101b, // 设置 GPE11、GPE12 为 GPIO 输出模式 rGPHCON = (rGPHCON & (~(0x33<<8))) | (0x11<<8); // rGPHCON[13:8] = 01xx01b, // 设置 GPH4、GPH6 为 GPIO 输出模式 LED_DispAllOff(); // 熄灭 LED1--LED4 EINT_init(); IRQEnable(); // 外部中断初始化 // 使能 IRQ 中断 (清零 CPSR 寄存器的 I 位) while(1); return(0); } // 等待外部中断 8. 思考 (1)EINT4 与 EINT0 的中断设置和中断标志清除有什么异同? (2)为什么实验程序中的中断服务函数没有使用__irq 关键字修饰?(提示:在 Target.c - 89 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 文件中有一个 IRQ_Exception 函数,这是 IRQ 中断的总入口,此函数使用了__irq 修饰) (3)如果将实验程序中的中断服务函数的按键去抖动部分代码删除,会有什么结果? 请修改实验程序代码验证一下。 2.11 UART 通讯实验 1. 实验目的 (1)了解 S3C2410A 处理器的 UART 基本工作原理及配置操作。 (2)能够使用 S3C2410A 处理器的 UART 进行数据发送和接收。 2. 实验设备 硬件:PC 机 一台 MagicARM2410 教学实验开发平台 一套 软件:Windows98/XP/2000 系统,ADS 1.2 集成开发环境 超级终端程序(Windows 系统自带) 3. 实验内容 使用查询方式实现从 UART0 发送 10 次字符串“Hello World!”,然后不断地接收串口上 的字符再直接发送出去,要求能够处理回车键(Enter 键)实现换行。UART0 设置为通讯波特 率 115200,8 位数据位,1 位停止位,无奇偶校验。 4. 实验预习要求 (1)仔细阅读参考文献[2]第 11 节的 S3C2410A 的 UART 模块说明。 (2)仔细阅读本书第 1 章的内容,了解 MagicARM2410 实验箱的硬件结构,注意 RS2 32 接口电路。 5. 实验原理 工程模板中包含有串口软件包 UART.C,用户可以调用相应的接口函数进行串口 (UART0 或 UART1)数据发送和接收,串口的波特率需要在 config.h 文件中进行设置(设置 UART_BPS 宏),本实验使用默认的 115200 波特率。 对串口进行初始化时,首先要设置相应 I/O 为 TXD0、RXD0 功能引脚,然后通过 ULCON0 寄存器来设置串口数据格式,通过 UCON0 寄存器来设置串口工作模式,最后通过 UBRDIV0 来设置通讯波特率,初始化代码参考程序清单 2.13。 设置 UCON0 寄存器时,要注意设置串口工作模式为查询方式,即 UCON0[3:1]应为 0101b。 程序清单 2.13 串口初始化代码 void UART_Init(void) { // I/O 口设置 (GPH3,GPH2) - 90 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com rGPHUP = rGPHUP | (0x03<<2); rGPHCON = (rGPHCON & (~0x000000F0)) | (0x000000A0); // 串口模式设置 rUFCON0 = 0x00; rUMCON0 = 0x00; // 禁止 FIFO 功能 // AFC(流控制)禁能 rULCON0 = 0x03; // 禁止 IrDA,无奇偶校验,1 位停止位,8 位数据位 rUCON0 = 0x245; // 使用 PCLK 来生成波特率,发送中断为电平触发模式,接收中断为边 // 沿触发模式,禁止接收超时中断,使能接收错误中断,正常工作模式, // 中断或查询方式(非 DMA) // 串口波特率设置 rUBRDIV0=(int)(PCLK/16.0/UART_BPS + 0.5) -1; } 使用串口发送数据时,将待发送数据写入 UTXH0 寄存器,然后通过读取 UTRSTAT0 寄存器的值判断数据是否发送完成。当然,实际代码也可以先等待 UTXH0 寄存器为空(通 过读取 UTRSTAT0 寄存器的值判断),再将数据写入 UTXH0 寄存器,串口数据发送参考程 序清单 2.14。 程序清单 2.14 串口数据发送 void UART_SendByte(uint8 data) { int i; while(!(rUTRSTAT0 & 0x02)); // 等待发送器为空 for(i=0; i<10; i++); rUTXH0 = data; // 发送数据 } 进行串口数据接收时,通过读取 UTRSTAT0 寄存器的值判断是否接收到数据,如果接 收到数据,则可以从 URXH0 寄存器中读出数据,串口数据接收参考程序清单 2.15。 程序清单 2.15 串口数据接收 int UART_GetKey(void) { int i; while(!(rUTRSTAT0 & 0x1)); for(i=0; i<10; i++); return(rURXH0); } 6. 实验步骤 (1)启动 ADS 1.2,使用 ARM Executable Image for DeviceARM2410 工程模板建立一 - 91 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 个工程 UART。 (2)在 src 组中的 main.c 中编写主程序代码。 (3)选用 DebugRel 生成目标,然后编译链接工程。 (4)将 MagicARM2410 实验箱上的 UART0 连接跳线 JP1 短接,使用串口延长线把 MagicARM2410 实验箱的 CZ11 与 PC 机的 COM1 连接。 注意:CZ11 安装在 MagicARM2410 实验箱的机箱右侧。 (5)PC 机上运行“超级终端”程序(在 Windows 操作系统的【开始】->【程序】->【附 件】->【通讯】->【超级终端】),新建一个连接,设置串口波持率为 115200,如图 2.19 所 示,接着呼叫连接(“超级终端”主窗口的【呼叫】->【呼叫】)。 图 2.19 “超级终端”的端口设置 (6)选择【Project】->【Debug】,启动 AXD 进行 JTAG 仿真调试。 (7)全速运行程序,观察“超级终端”的主窗口显示内容,然后在“超级终端”的主 窗口中输入任意字符和回车键,观察“超级终端”的显示效果,参考如图 2.20 所示。 - 92 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 图 2.20 UART 通讯实验运行效果 (8)为了能够正确的调试 UART 通讯,检测 UART 发送和接收的数据,可以使用 LA1032 逻辑分析仪工具来帮助,LA1032 具有总线分析仪功能(目前支持 UART、I2C、SPI、SSI 和 1-Wire 总线)。使用 LA1032 的两路输入通道连接到 MagicARM2410 的 J2 连接器上,一路连 接到 TXD0,另一路连接到 RXD0,重新调试运行实验程序,捕获到 UART 发送的数据如图 2.21 所示。在图 2.21 中,TXD0 和 RXD0 信号中间的字符值和起始信号(BEGIN)、结束信 号(END)都是 LA1032 分析出来的。 说明:LA1032 逻辑分析仪的介绍请参考附录 B。 图 2.21 LA1032 捕获到 UART 发送的数据 7. 实验参考程序 UART 通讯实验的参考程序见程序清单 2.16。 程序清单 2.16 UART 通讯实验参考程序 /****************************************Copyright (c)*********************************** ** File Name: main.c ** Last modified Date: 2006-01-06 ** Last Version: v1.0 - 93 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com ** Description: MagicARM2410 实验箱的基础实验---UART 通讯实验。 ** 向 UART0 发送 10 次字符串"Hello World!",然后不断地接收串口上的字符再直接发送出去。 ************************************************************************************/ #include "config.h" /************************************************************************************ ** Function name: DelayNS ** Descriptions: 长软件延时。 延时时间与系统时钟有关。 ** Input: dly 延时参数,值越大,延时越久 ** Output: 无 ************************************************************************************/ void DelayNS(uint32 dly) { uint32 i; for(; dly>0; dly--) for(i=0; i<50000; i++); } // 串口接收字符临时变量 uint8 g_getch = 0; /************************************************************************************ ** Function name: main ** Descriptions: 向 UART0 发送 10 次字符串"Hello World!",然后不断地接收串口上的字符再直 ** ** Input: 无 接发送出去。 ** Output: 系统返回值 0 ************************************************************************************/ int main(void) { int i; UART_Select(0); UART_Init(); // 选择 UART0 // 初始化 UART0 for(i=0; i<10; i++) { UART_SendStr("Hello World!\n"); } while(1) { g_getch = UART_GetKey(); // 接收字符 - 94 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com if(g_getch == 0x0D) // 判断是否为回车键 { UART_SendByte('\r'); // 发送换行符 UART_SendByte('\n'); } else { UART_SendByte(g_getch); // 发送接收到的字符 } } return(0); } 8. 思考 (1)RS232 的电平与 S2C2410A 的 UART 电平有什么差别? (2)若要将实验参考程序的功能改为简单的菜单选择界面,应如何修改程序?(提示: 使用 UART_SendStr 函数显示菜单,然后调用 UART_GetKey 函数等待用户选择,通过 switch 开关语句判断用户的选择并执行相应操作) 2.12 I2C 接口实验 1. 实验目的 (1)熟悉 S3C2410A 处理器的硬件 I2C 接口的使用。 (2)了解 CAT1025 E2PROM 的操作方法及注意事项。 2. 实验设备 硬件:PC 机 一台 MagicARM2410 教学实验开发平台 一套 软件:Windows98/XP/2000 系统,ADS 1.2 集成开发环境 3. 实验内容 使用 I2C 接口主模式向 CAT1025 写入 10 字节数据,然后读出校验,若校验通过则蜂鸣 器响一声,否则不断地蜂鸣报警。I2C 接口操作采用查询方式。 4. 实验预习要求 (1)仔细阅读参考文献[2]第 20 节的 S3C2410A 的 I2C 接口模块说明。 (2)仔细阅读本书第 1 章的内容,了解 MagicARM2410 实验箱的硬件结构,注意 DeviceARM2410 核心板上的 E2PROM 存储器电路。 - 95 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 5. 实验原理 S3C2410A 具有 1 个硬件 I2C 接口,可以配置为主发送、主接收、从发送和从接收等 4 种操作模式。I2C 接口共包含 4 个寄存器,控制寄存器 IICCON 用于设置 I2C 总线时钟和中 断(标志)使能,还有 1 位中断标志位;状态寄存器 IICSTAT 除了指示当前 I2C 总线状态外, 还有 2 位 I2C 操作模式控制位和总线启动/结束控制位;数据寄存器 IICDS 用来发送数据或 接收数据;从机地址寄存器 IICADD 用来保存 S3C2410A 作 I2C 从机时的器件地址。 对 I2C 接口进行初始化时,首先要设置相应 I/O 为 IICSDA、IICSCL 功能引脚,然后通 过 IICCON 寄存器来设置 I2C 总线时钟,并使能 I2C 中断(标志),通过 IICSTAT 寄存器来设 置 I2C 接口为主发送模式,初始化代码参考程序清单 2.17。 程序清单 2.17 I2C 初始化代码 // I2C 总线设置宏定义 #define IICCON_DACK #define IICCON_DNACK ((1<<7) | (1<<6) | (1<<5) | (0<<0)) ((0<<7) | (1<<6) | (1<<5) | (0<<0)) /************************************************************************* ** Function name: InitI2C ** Descriptions: 初始化总线 (100KHz 总线速率) ** 设 FCLK=200MHz,HCLK=100MHz,PCLK=50MHz。 ** Input: 无 ** Output: 无 *************************************************************************************/ void InitI2C(void) { // 设置管脚连接 rGPECON = (rGPECON & 0x0FFFFFFF) | 0xA0000000; // 设置 I2C 口使能 rGPEUP = rGPEUP | 0xC000; // 禁止内部上拉电阻 // 设置 I2C 控制寄存器 (使能 ACK 位时才能接收从机的应答位) rIICCON = IICCON_DACK; // 设置 I2C 为主机模式 rIICSTAT = (3<<6)|(1<<4); // 从机地址 (作主机时没有用) rIICADD = 0x10; } 在进行每一次数据传送之前,都需要产生 I2C 总线启动信号。先把要访问的 I2C 器件的 地址写入 IICDS 寄存器当中 ,然后将 IICSTAT 寄存器的 d5 位置位,即可产生结束总线信号, 并且将从机地址发送出去,代码参考程序清单 2.18。通过读取 IICCON 寄存器的值来等待 总线启动和发送从机地址,通过读取 IICSTAT 寄存器的值判断是否有从机应答,如果没有 从机应答,则只能进行结束总线操作。 - 96 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 程序清单 2.18 产生 I2C 总线启动信号 /************************************************************************* ** Function name: START_I2C ** Descriptions: 启动总线,发送从机地址,并发送从机地址 ** Input: sla 从机动地址 ** Output: 操作成功返回 TRUE,仲载失败/无从机应答返回 FALSE ** Note: sla 位最低位为读写控制位 *************************************************************************************/ int StartI2C(uint8 sla) { uint32 i; rIICDS = sla; // 设置从机地址 if(sla&0x01) { rIICSTAT = (2<<6)|(1<<5)|(1<<4); rIICCON = IICCON_DACK; } else { rIICSTAT = (3<<6)|(1<<5)|(1<<4); } // 主接收模式,发送使能,启动总线 // 若是重启总线,则需要有此操作 // 主发送模式,发送使能,启动总线 // 等待操作完成 while((rIICCON&0x10) == 0); // 判断操作是否成功 (总线仲裁和从机应答) if((rIICSTAT&0x09) == 0) { return(TRUE); } else { // 发送结束信号 if(sla&0x01) rIICSTAT = (2<<6)|(0<<5)|(1<<4); else rIICSTAT = (3<<6)|(0<<5)|(1<<4); rIICCON = IICCON_DACK; for(i=0; i<5000; i++); // 等待结束信号产生完毕 return(FALSE); } // end of if((rIICSTAT&0x09) == 0)...else... } 启动总线后,就可以进行多个数据的发送或接收操作。进行 I2C 数据发送时,将待发送 数据写入 IICDS 寄存器,然后还要写 IICCON 寄存器清除 I2C 中断标志,总线才开始发送数 - 97 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 据。通过读取 IICCON、IICSTAT 寄存器的值判断数据是否发送完成,数据发送参考程序清 单 2.19。 程序清单 2.19 I2C 数据发送 /************************************************************************* ** Function name: I2C_SendByte ** Descriptions: 发送一字节数据,并接收应答位 ** Input: dat 要发送的数据 ** Output: 操作成功返回 TRUE,仲载失败/无从机应答返回 FALSE *************************************************************************************/ int I2C_SendByte(uint8 dat) { uint32 i; rIICDS = dat; rIICCON = IICCON_DACK; // 将数据写入 I2C 数据寄存器 // 清除中断标志,允许发送数据操作 // 等待操作完成 while((rIICCON&0x10) == 0); // 判断操作是否成功 (总线仲裁和从机应答) if((rIICSTAT&0x09) == 0) { return(TRUE); } else { // 发送结束信号 rIICSTAT = (3<<6)|(0<<5)|(1<<4); rIICCON = IICCON_DACK; for(i=0; i<5000; i++); // 等待结束信号产生完毕 return(FALSE); } } 进行 I2C 数据接收时,通过读取 IICCON、IICSTAT 寄存器的值判断是否接收到数据, 如果接收到数据,则可以从 IICDS 寄存器中读出数据,数据接收代码参考程序清单 2.20。 接收完一字节数据后,需要写 IICCON 寄存器清除 I2C 中断标志(同时,可以控制输出应答 或非应答信号),总线才允许接收下一字节数据。 程序清单 2.20 I2C 数据接收 /************************************************************************* ** Function name: I2C_RcvByteA ** Descriptions: 接上 I2C 总线上一字节数据,并发送应答位 - 98 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com ** Input: dat 用于接收数据的指针 ** Output: 操作成功返回 TRUE,仲载失败/无从机应答返回 FALSE *************************************************************************************/ int I2C_RcvByteA(uint8 *dat) { uint32 i; // 允许接收数据 rIICCON = IICCON_DACK; // 等待接收数据操作完成 while((rIICCON&0x10) == 0); // 判断操作是否成功 (总线仲裁) if((rIICSTAT&0x08) != 0) { // 发送结束信号 rIICSTAT = (2<<6)|(0<<5)|(1<<4); rIICCON = IICCON_DACK; for(i=0; i<5000; i++); // 等待结束信号产生完毕 return(FALSE); } *dat = rIICDS; // 读取数据 return(TRUE); } 当一次数据发送/接收完毕后,需要产生结束总线信号。将 IICSTAT 寄存器的 d5 位清零, 然后再清除 IICCON 寄存器的 d4 位(即中断标志位),即可产生结束总线信号,代码参考程 序清单 2.21。 程序清单 2.21 产生 I2C 总线结束信号 /************************************************************************* ** Function name: STOP_I2C ** Descriptions: 结束总线 ** Input: send I2C 当前模模式。主发送模式时为 1,否则为 0(主接收模式) ** Output: 无 *************************************************************************************/ void StopI2C(uint8 send) { uint32 i; if(send) { rIICSTAT = (3<<6)|(0<<5)|(1<<4); // 发送结束信号 } - 99 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com else { rIICSTAT = (2<<6)|(0<<5)|(1<<4); } rIICCON = IICCON_DACK; for(i=0; i<5000; i++); } // 发送结束信号 // 等待结束信号产生完毕 6. 实验步骤 (1)启动 ADS 1.2,使用 ARM Executable Image for DeviceARM2410 工程模板建立一 个工程 WR_EEPROM。 (2)在工程管理窗口中新建立一个 I2C 组,新建源文件 I2C.C 和 I2C.H,并将它们添 加到工程的 I2C 组中,编写 I2C 总线操作程序代码。 (3)在 head 组中的 config.h 文件中,加入 I2C.H 头文件的包含和 CAT1025 器件地址 的宏定义,如程序清单 2.22 所示。 程序清单 2.22 包含 I2C.H 头文件 …… /* 其它包含文件在这里 */ /* header files in here */ #include "i2c.h" // 定义 CAT1025 的器件地址 #define CAT1025 …… 0xA0 (4)在 src 组中的 main.c 中编写主程序代码。 (5)选用 DebugRel 生成目标,然后编译链接工程。 (6)将 MagicARM2410 实验箱上的蜂鸣器跳线 JP9 短接。 (7)选择【Project】->【Debug】,启动 AXD 进行 JTAG 仿真调试。 (8)全速运行程序,若蜂鸣器响一声,表明 E2PROM 读写操作成功。 (9)为了能够正确的调试 I2C 总线通讯,检测 I2C 总线上的数据流,可以使用 LA1032 逻辑分析仪工具来帮助,LA1032 具有总线分析仪功能(目前支持 UART、I2C、SPI、SSI 和 1-Wire 总线)。使用 LA1032 的两路输入通道连接到 MagicARM2410 的 J6 连接器上,一路连 接到 SDA,另一路连接到 SCL,重新调试运行实验程序,捕获到 I2C 总线上的数据如图 2.22 所示。在图 2.22 中,SDA 信号正上方的数据值和启动信号(START)、结束信号(STOP)都是 LA1032 分析出来的。 图 2.22 LA1032 捕获到 I2C 总线上的数据流 - 100 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 说明:LA1032 逻辑分析仪的介绍请参考附录 B。 7. 实验参考程序 I2C 实验的参考程序见程序清单 2.23。 程序清单 2.23 I2C 通讯实验参考程序 /****************************************Copyright (c)*********************************** ** File Name: main.c ** Last modified Date: 2006-01-11 ** Last Version: v1.0 ** Description: MagicARM2410 实验箱的基础实验---I2C 接口实验。 ** 使用 I2C 接口主模式向 CAT1025 写入 10 字节数据,然后读出校验,若校验通过则蜂鸣器 ** 响一声,否则不断地蜂鸣报警。 ************************************************************************************/ #include "config.h" // 读写 E2PROM 操作结果状态变量 int i2c_opsta = 0x00; // 读写 E2PROM 的数据缓冲区 uint8 dat_buf[50]; // 定义蜂鸣器控制口 #define BEEP #define BEEP_MASK (1<<10) (~BEEP) /* GPH10 口 */ /************************************************************************************ ** Function name: DelayNS ** Descriptions: 长软件延时。 延时时间与系统时钟有关。 ** Input: dly 延时参数,值越大,延时越久 ** Output: 无 ************************************************************************************/ void DelayNS(uint32 dly) { uint32 i; for(; dly>0; dly--) for(i=0; i<50000; i++); } /************************************************************************************ ** Function name: RunBeep ** Descriptions: 控制蜂鸣器 Be 一声音。 ** Input: 无 - 101 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com ** Output: 无 ************************************************************************************/ void RunBeep(void) { rGPHDAT = rGPHDAT & BEEP_MASK; // BEEP = 0 DelayNS(5); rGPHDAT = rGPHDAT | BEEP; // BEEP = 1 DelayNS(5); } /************************************************************************************ ** Function name: ErrorShow ** Descriptions: 不停地蜂鸣报警 ** Input: 无 ** Output: 无 ************************************************************************************/ void ErrorShow(void) { while(1) { rGPHDAT = rGPHDAT & BEEP_MASK; // BEEP = 0 DelayNS(2); rGPHDAT = rGPHDAT | BEEP; // BEEP = 1 DelayNS(2); } } /************************************************************************************ ** Function name: TestEEPROM ** Descriptions: 对 CAT1025 的 0--9 地址进行数据读/写操作,如果出错,则不停地蜂鸣报警。 ** Input: 无 ** Output: 无 ************************************************************************************/ void TestEEPROM(void) { uint8 suba[2]; int rw_err; int i; rw_err = 0; // 写数据测试 suba[0] = 1; suba[1] = 0x00; for(i=0; i<10; i++) // 1 位子地址 // 子地址 - 102 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com { dat_buf[i] = i+'0'; } i2c_opsta=ISendStr(CAT1025, suba, dat_buf, 10); for(i=0; i<10000; i++); // 等待写周期 // 读出校验 for(i=0; i<10; i++) dat_buf[i] = 0x00; i2c_opsta=IRcvStr(CAT1025, suba, dat_buf, 10); for(i=0; i<10; i++) { if(dat_buf[i] != (i+'0')) rw_err = 1; } // 判断操作是否出错,如果出错则蜂鸣报警 if(rw_err) ErrorShow(); } /************************************************************************************ ** Function name: main ** Descriptions: 初始化 I2C 总线,然后对 CAT1025 进行读写测试。 ** Input: 无 ** Output: 系统返回值 0 ************************************************************************************/ int main(void) { // 初始化 I/O rGPHCON = (rGPHCON & (~(0x03<<20))) | (0x01<<20); // rGPHCON[21:20] = 01b, rGPHDAT = rGPHDAT | BEEP; // 防止蜂鸣器响 // 设置 GPH10 为 GPIO 输出模式 // 初始化 I2C 接口 InitI2C(); // 测试 EEPROM(CAT1025) TestEEPROM(); // 测试通过 RunBeep(); while(1); return(0); } - 103 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 8. 思考 (1)I2C 从机地址最低位表示什么?I2C 总线的启动信号和结束信号有什么特点? (2)在实验参考程序中,若一次写入 20 字节数据,读出的数据是什么?(提示:E2PROM 的页写问题) 2.13 定时器实验 1. 实验目的 掌握 S3C2410A 的定时器基本设置及定时器中断应用。 2. 实验设备 硬件:PC 机 一台 MagicARM2410 教学实验开发平台 一套 软件:Windows98/XP/2000 系统,ADS 1.2 集成开发环境 3. 实验内容 使用 S3C2410A 的定时器 0 实现 0.5 秒的定时并产生中断,每产生一次中断即控制蜂鸣 器的控制 I/O 口状态取反,相当于每 1 秒钟蜂鸣器响一声。 4. 实验预习要求 (1)仔细阅读参考文献[2]第 10 节的 S3C2410A 的 PWM 定时器模块说明和第 14 节的 中断控制器说明。 (2)仔细阅读本书第 1 章的内容,了解 MagicARM2410 实验箱的硬件结构,注意蜂鸣 器控制电路。 5. 实验原理 S3C2410A 具有 5 个 16 位定时器,其中有 4 个可以来控制 PWM 信号输出,所以称它 们为 PWM 定时器。定时器的时钟源是 PCLK,5 个定时器共享 2 个 8 位预分频器,经过预 分频器之后,每个定时器还拥有 4 个不同分频信号(1/2,1/4,1/8 和 1/16)输出的时钟分割器, 这样就可以使定时器的时钟范围更大。预分频器的设置通过 TCFG0 寄存器实现,时钟分割 器的分频选择(即定时器时钟源选择)设置通过 TCFG1 寄存器实现。 定时器是减法计数的,当定时器 TCNTn 的值倒数到 0 时,TCNTBn 寄存器的值会被自 动的加载到定时器继续下一次定时操作。当定时器 TCNTn 的值倒数到 0 时,如果中断使能, 将会产生一次定时器中断请求。 设置好定时值 TCNTB 后,就可以通过操作 TCON 寄存器来启动定时器了。 6. 实验步骤 (1)启动 ADS 1.2,使用 ARM Executable Image for DeviceARM2410 工程模板建立一 - 104 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 个工程 TimeOut。 (2)在 src 组中的 main.c 中编写主程序代码。 (3)选用 DebugRel 生成目标,然后编译链接工程。 (4)将 MagicARM2410 实验箱上的蜂鸣器控制电路的跳线 JP9 短接,将启动方式选择 跳线 JP8 短接,然后按 RST 键复位系统。 (5)选择【Project】->【Debug】,启动 AXD 进行 JTAG 仿真调试。 (6)在中断服务函数中设置断点,全速运行程序观察是否能产生定时器中断。取消设 置断点,全速运行程序,蜂鸣器应每秒响一声。 7. 实验参考程序 定时器实验的参考程序见程序清单 2.24。 程序清单 2.24 定时器实验参考程序 /****************************************Copyright (c)*********************************** ** File Name: main.c ** Last modified Date: 2006-01-09 ** Last Version: v1.0 ** Description: MagicARM2410 实验箱的基础实验---定时器实验。 ** 使用 S3C2410A 的定时器 0 实现 0.5 秒的定时并产生中断,每产生一次中断即控制蜂 ** 鸣器的控制 I/O 口状态取反。 ************************************************************************************/ #include "config.h" // 定义蜂鸣器控制口 #define BEEP #define BEEP_MASK (1<<10) (~BEEP) /* GPH10 口 */ /************************************************************************************ ** Function name: DelayNS ** Descriptions: 长软件延时。 延时时间与系统时钟有关。 ** Input: dly 延时参数,值越大,延时越久 ** Output: 无 ************************************************************************************/ void DelayNS(uint32 dly) { uint32 i; for(; dly>0; dly--) for(i=0; i<50000; i++); } /************************************************************************************ ** Function name: IRQ_Time0 ** Descriptions: 定时器 0 中断服务程序。 - 105 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com ** Input: 无 ** Output: 无 ************************************************************************************/ void IRQ_Time0(void) { // 取反蜂鸣器控制 I/O 口的状态 if(rGPHDAT & BEEP) { rGPHDAT= rGPHDAT & BEEP_MASK; } else { rGPHDAT = rGPHDAT | BEEP; } // 清除中断标志 rSRCPND = 1<<10; rINTPND = rINTPND; } /************************************************************************************ ** Function name: main ** Descriptions: 初始化定时器 0,每 0.5 产生一次定时器中断。 ** Input: 无 ** Output: 系统返回值 0 ************************************************************************************/ int main(void) { // 初始化 I/O rGPHCON = (rGPHCON & (~(0x03<<20))) | (0x01<<20); // rGPHCON[21:20] = 01b, // 设置 GPH10 为 GPIO 输出模式 rGPHDAT = rGPHDAT | BEEP; // 防止蜂鸣器响 // 设置中断服务程序 VICVectAddr[10] = (uint32) IRQ_Time0; // 设置中断控制器 rPRIORITY = 0x00000000; rINTMOD = 0x00000000; rINTMSK = ~(1<<10); // 使用默认的固定的优先级 // 所有中断均为 IRQ 中断 // 打开 TIMER0 中断允许 // 定时器设置 // Fclk=200MHz,时钟分频配置为 1:2:4,即 Pclk=50MHz。 rTCFG0 = 250; // 预分频器 0 设置为 250,取得 200KHz - 106 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com rTCFG1 = 1; rTCMPB0 = 0x0000; rTCNTB0 = 25*1000; rTCON = (1<<1); rTCON = (1<<0)|(1<<3); // TIMER0 再取 1/4 分频,取得 50KHz // 设置定时器为 0 // 定时 0.5 秒 // 更新定时器数据 // 启动定时器 IRQEnable(); while(1); return(0); } // 使能 IRQ 中断(CPSR) 8. 思考 (1)如果需要实现 1S 定时,应如何修改实验程序? (2)使用定时器 0 来实现一个时钟,具有时、分、秒功能,要求每隔 1S 即通过串口 向 PC 机发送时间。(提示:使用 sprintf 函数将时间写入字符缓冲区,再使用 UART_SendStr 发送字符缓冲区的数据) 2.14 PWM DAC 实验 1. 实验目的 掌握使用 PWM 输出功能,实现数模转换。 2. 实验设备 硬件:PC 机 一台 MagicARM2410 教学实验开发平台 一套 软件:Windows98/XP/2000 系统,ADS 1.2 集成开发环境 3. 实验内容 使用 S3C2410A 的 TOUT0 口输出 PWM 信号,使用 RC 滤波电路实现 D/A 转换。通过 检测按键 KEY1 来改变 PWM 的占空比,改变 D/A 输出的电压值,输出电压分别为 0.0V、 0.5V、1.0V、1.5V、2.0V、2.5V 和 3.0V。 4. 实验预习要求 (1)仔细阅读参考文献[2]第 10 节的 S3C2410A 的 PWM 定时器模块说明。 (2)仔细阅读本书第 1 章的内容,了解 MagicARM2410 实验箱的硬件结构,注意 PWM DAC 电路。 5. 实验原理 S3C2410A 具有 4 路 PWM 输出,输出口分别为 TOUT0~TOUT3,其中两路带有死区 - 107 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 控制功能。为了能够正确输出 PWM 信号,需要正确设置 GPBCON 寄存器选择相应 I/O 的 为 TOUTx 功能。然后,通过 TCFG0 寄存器为 PWM 定时器时钟源设置预分频值,通过 TCFG1 寄存器选择 PWM 定时器时钟源。接着,通过 TCNTB0 寄存器设置 PWM 周期,通过 TCMPB0 设置 PWM 占空比。最后,通过 TCON 寄存器启动 PWM 定时器,即可输出 PWM 信号。 6. 实验步骤 (1)启动 ADS 1.2,使用 ARM Executable Image for DeviceARM2410 工程模板建立一 个工程 PWMDAC。 (2)在 src 组中的 main.c 中编写主程序代码。 (3)选用 DebugRel 生成目标,然后编译链接工程。 (4)将 MagicARM2410 实验箱上的 PWM DAC 电路的跳线 JP11 短接。 (5)选择【Project】->【Debug】,启动 AXD 进行 JTAG 仿真调试。 (6)全速运行程序,使用万用表测量 PWMDAC 测试点的输出电压值。按下独立按键 KEY1,观察电压值的改变是否正确。 7. 实验参考程序 PWM DAC 实验的参考程序见程序清单 2.25。 程序清单 2.25 PWM DAC 实验参考程序 /****************************************Copyright (c)*********************************** ** File Name: main.c ** Last modified Date: 2006-01-09 ** Last Version: v1.0 ** Description: MagicARM2410 实验箱的基础实验---PWM DAC 实验。 ** 使用 PWM 输出实现 DAC 功能,输出电压分别为为 0.0V、0.5V、1.0V、1.5V、 ** 2.0V、2.5V 和 3.0V。 ************************************************************************************/ #include "config.h" // 定义独立按键 KEY1 的输入口 #define KEY_CON (1<<4) /* GPF4 口 */ /************************************************************************************ ** Function name: DelayNS ** Descriptions: 长软件延时。 延时时间与系统时钟有关。 ** Input: dly 延时参数,值越大,延时越久 ** Output: 无 ************************************************************************************/ void DelayNS(uint32 dly) { uint32 i; for(; dly>0; dly--) - 108 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com for(i=0; i<50000; i++); } /************************************************************************************ ** Function name: WaitKey ** Descriptions: 等待一个有效按键。本函数有去抖功能。 ** Input: 无 ** Output: 无 ************************************************************************************/ void WaitKey(void) { uint32 i; while(1) { while((rGPFDAT&KEY_CON) == KEY_CON) ; // 等待 KEY 键按下 for(i=0; i<1000; i++); // 延时去抖 if( (rGPFDAT&KEY_CON) != KEY_CON) break; } while((rGPFDAT&KEY_CON) != KEY_CON); // 等待按键放开 } /************************************************************************************ ** Function name: PWM_Init ** Descriptions: 初始化 PWM 定时器 ** Input: cycle ** duty PWM 周期控制值(uint16 类型) PWM 占空比(uint16 类型) ** Output: 无 ************************************************************************************/ void PWM_Init(uint16 cycle, uint16 duty) { // 参数过滤 if(duty>cycle) duty = cycle; // 设置定时器 0,即 PWM 周期和占空比 // Fclk=200MHz,时钟分频配置为 1:2:4,即 Pclk=50MHz。 rTCFG0 = 97; // 预分频器 0 设置为 98,取得 510204Hz rTCFG1 = 0; rTCMPB0 = duty; // TIMER0 再取 1/2 分频,取得 255102Hz // 设置 PWM 占空比 rTCNTB0 = cycle; // 定时值(PWM 周期) if(rTCON&0x04) rTCON = (1<<1); // 更新定时器数据 (取反输出 inverter 位) else rTCON = (1<<2)|(1<<1); rTCON = (1<<0)|(1<<3); // 启动定时器 } - 109 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com /************************************************************************************ ** Function name: main ** Descriptions: 使用 PWM 输出实现 DAC 功能,输出电压分别为 0.0V、0.5V、 ** 1.0V、1.5V、2.0V、2.5V 和 3.0V。 ** Input: 无 ** Output: 系统返回值 0 ************************************************************************************/ int main(void) { uint16 pwm_dac; // 独立按键 KEY1 控制口设置 rGPFCON = (rGPFCON & (~(0x03<<8))); // rGPFCON[9:8] = 00b,设置 GPF4 为 GPIO 输入模式 // TOUT0 口设置 rGPBCON = (rGPBCON & (~(0x03<<0))) | (0x02<<0); // rGPBCON[1:0] = 10b,设置 TOUT0 功能 rGPBUP = rGPBUP | 0x0001; // 禁止 TOUT0 口的上拉电阻 // 初始化 PWM 输出。设 PWM 周期控制值为 255 (即 DAC 分辨率为 8 位) pwm_dac = 0; // 初始化占空比为 0,即输出 0V 电压 PWM_Init(255, pwm_dac); // 等待按键 KEY1,改变占空比 while(1) { WaitKey(); // 由于 PWM 周期控制值为 255,所以 0.5V 对应的 PWM 占空比的值为: 0.5/3.3 * 256 = 39 pwm_dac = pwm_dac + 39; // 改变 D/A 输出的电压值 if(pwm_dac>255) { pwm_dac = 0; } rTCMPB0 = pwm_dac; } return(0); } 8. 思考 (1)如何改变 PWM 输出的频率(即 PWM 周期)? (2)如果改变 PWM 输出频率很高或很低,D/A 输出的电压会有什么影响?请使用示 波器从 PWMDAC 测试点观察波形。 - 110 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 2.15 ADC 实验 1. 实验目的 掌握 S3C2410A 的模/数(A/D)转换器的应用设置,进行电压信号的测量。 2. 实验设备 硬件:PC 机 一台 MagicARM2410 教学实验开发平台 一套 软件:Windows98/XP/2000 系统,ADS 1.2 集成开发环境 超级终端程序(Windows 系统自带) 3. 实验内容 使用 AIN0 和 AIN1 测量两路直流电压,并将测量结果通过 UART0 向 PC 机发送。 4. 实验预习要求 (1)仔细阅读参考文献[2]第 16 节的 S3C2410A 的 ADC 模块说明。 (2)仔细阅读本书第 1 章的内容,了解 MagicARM2410 实验箱的硬件结构,注意 ADC 部分的电路。 5. 实验原理 S3C2410A 具有 1 个 8 通道的 10 位模数转换器(ADC),有采样保持功能,输入电压范围 是 0~3.3V,在 2.5MHz 的转换器时钟下,最大的转换速率可达 500KSPS。A/D 转换器的 AIN5、AIN7 还可以与控制脚 nYPON、YMON、nXPON 和 XMON 配合,实现触摸屏输入 功能。 为了正确使用 A/D 转换器,需要设置 A/D 转换器的时钟,还有 A/D 转换器的工作模式 设置和输入通道选择,这都是通过 ADCCON 寄存器来设置的。然后置位 ADCCON 寄存器 的 ENABLE_START 位来控制启动 A/D 转换,读 ADCCON 寄存器的 ECFLG 位来判断 A/D 转换是否已经结束。当一次 A/D 转换结束后,通过读 ADCDAT0 寄存器来取得 A/D 转换结 果,寄存器的低 10 位数据有效。 6. 实验步骤 (1)启动 ADS 1.2,使用 ARM Executable Image for DeviceARM2410 工程模板建立一 个工程 ADC01。 (2)在 src 组中的 main.c 中编写主程序代码。 (3)选用 DebugRel 生成目标,然后编译链接工程。 (4)将 MagicARM2410 实验箱上的 UART0 连接跳线 JP1 短接,使用串口延长线把 MagicARM2410 实验箱的 CZ11 与 PC 机的 COM1 连接。 注意:CZ11 安装在 MagicARM2410 实验箱的机箱右侧。 (5)PC 机上运行“超级终端”程序(在 Windows 操作系统的【开始】->【程序】->【附 件】->【通讯】->【超级终端】),新建一个连接,设置串口波持率为 115200,如图 2.19 所 示,接着呼叫连接(“超级终端”主窗口的【呼叫】->【呼叫】)。 - 111 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com (6)选择【Project】->【Debug】,启动 AXD 进行 JTAG 仿真调试。 (7)全速运行程序,调整 W1、W2 改变测量的电压,观察 PC 机上的“超级终端”主 窗口显示电压值是否正确,参考如图 2.23 所示。 图 2.23 ADC 实验结果参考图 7. 实验参考程序 ADC 实验的参考程序见程序清单 2.26。 程序清单 2.26 ADC 实验参考程序 /****************************************Copyright (c)*********************************** ** File Name: main.c ** Last modified Date: 2006-01-11 ** Last Version: v1.0 ** Description: MagicARM2410 实验箱的基础实验--- ADC 实验。 ** 使用 AIN0 和 AIN1 测量两路直流电压,并将测量结果通过 UART0 向 PC 机发送。 ************************************************************************************/ #include "config.h" // 定义用于保存 ADC 结果的变量 uint32 adc0, adc1; // 定义显示缓冲区 char disp_buf[50]; /************************************************************************************ ** Function name: DelayNS - 112 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com ** Descriptions: 长软件延时。 延时时间与系统时钟有关。 ** Input: dly 延时参数,值越大,延时越久 ** Output: 无 ************************************************************************************/ void DelayNS(uint32 dly) { uint32 i; for(; dly>0; dly--) for(i=0; i<50000; i++); } // 定义 ADC 转换时钟 (2MHz) #define ADC_FREQ (2*1000000) /************************************************************************************ ** Function name: ReadAdc ** Descriptions: ADC 转换函数 ** Input: ch 转换通道(0--7) ** Output: 返回转换结果 ************************************************************************************/ uint32 ReadAdc(uint32 ch) { int i; ch = ch & 0x07; // 参数过滤 // PRSCEN=1,使能分频器 // PRSCVL=(PCLK/ADC_FREQ - 1),即 ADC 转换时钟为 ADC_FREQ // SEL_MUX=ch,设置 ADC 通道 // STDBM=0,标准转换模式 // READ_START=0,禁止读(操作后)启动 ADC // ENABLE_START=0,不启动 ADC rADCCON = (1<<14)|((PCLK/ADC_FREQ - 1)<<6)|(ch<<3)|(0<<2)|(0<<1)|(0<<0); rADCTSC = rADCTSC & (~0x03); // 普通 ADC 模式(非触摸屏) for(i=0; i<100; i++); rADCCON = rADCCON | (1<<0); while(rADCCON & 0x01); while(!(rADCCON & 0x8000)); return (rADCDAT0 & 0x3ff); } // 启动 ADC // 等待 ADC 启动 // 等待 ADC 完成 // 返回转换结果 - 113 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com /************************************************************************************ ** Function name: main ** Descriptions: 使用 AIN0 和 AIN1 测量两路直流电压,并将测量结果通过 UART0 向 PC 机发送。 ** Input: 无 ** Output: 系统返回值 0 ************************************************************************************/ int main(void) { int vin0, vin1; UART_Select(0); UART_Init(); // 选择 UART0 // 初始化 UART0 while(1) { // 进行 A/D 转换 adc0 = ReadAdc(0); adc1 = ReadAdc(1); // 通过串口输出显示 vin0 = (adc0*3300) / 1024; // 读算实际电压值 (mV) vin1 = (adc1*3300) / 1024; sprintf(disp_buf, "AIN0 is %d mV, AIN1 is %d mV \n", vin0, vin1); UART_SendStr(disp_buf); // 延时 DelayNS(20); } return(0); } 8. 思考 若需要采用中断方式进行 A/D 转换,应如何修改实验参考程序? 2.16 RTC 实验 1. 实验目的 掌握 S3C2410A 的 RTC 基本设置及时间的读取操作。 2. 实验设备 硬件:PC 机 一台 - 114 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com MagicARM2410 教学实验开发平台 一套 软件:Windows98/XP/2000 系统,ADS 1.2 集成开发环境 超级终端程序(Windows 系统自带) 3. 实验内容 初始化 S3C2410A 内部的 RTC,然后每隔 1 秒钟读取一次 RTC 的时间,并通过串口发 送到 PC 机显示。 4. 实验预习要求 (1)仔细阅读参考文献[2]第 17 节的 S3C2410A 的 RTC 模块说明。 (2)仔细阅读本书第 1 章的内容,了解 MagicARM2410 实验箱的硬件结构,注意 RS2 32 接口电路。 5. 实验原理 S3C2410A 具有实时时钟(RTC)功能,能够提供时、分、秒,年、月、日的计时功能, 还具备定时报警功能。RTC 单元采用独立的后备电池供电,独立是时钟源(采用 32.768KHz 晶振),即使系统电源关闭,RTC 还可以正常工作。 要初始化 RTC 的时间值,首先要给 RTCCON 寄存器写为 0x01,使能 RTC 接口(即允许 写 RTC 操作),然后对年寄存器 BCDYEAR、月寄存器 BCDMON、日寄存器 BCDDATE、 时寄存器 BCDHOUR、分寄存器 BCDMIN、秒寄存器 BCDSEC、星期寄存器 BCDDAY 进 行初始化,时间值为 BCD 格式。初始化完成,将 RTCCON 寄存器写为 0x00,禁能 RTC 接 口(即禁止写 RTC 操作),接下来用户就可以直接读取 RTC 时间寄存器的值来使用了。 6. 实验步骤 (1)启动 ADS 1.2,使用 ARM Executable Image for DeviceARM2410 工程模板建立一 个工程 SendRTC。 (2)在 src 组中的 main.c 中编写主程序代码。 (3)选用 DebugRel 生成目标,然后编译链接工程。 (4)将 MagicARM2410 实验箱上的 UART0 连接跳线 JP1 短接,使用串口延长线把 MagicARM2410 实验箱的 CZ11 与 PC 机的 COM1 连接。 注意:CZ11 安装在 MagicARM2410 实验箱的机箱右侧。 (5)PC 机上运行“超级终端”程序(在 Windows 操作系统的【开始】->【程序】->【附 件】->【通讯】->【超级终端】),新建一个连接,设置串口波持率为 115200,如图 2.19 所 示,接着呼叫连接(“超级终端”主窗口的【呼叫】->【呼叫】)。 (6)选择【Project】->【Debug】,启动 AXD 进行 JTAG 仿真调试。 (7)全速运行程序,观察 PC 机上的“超级终端”主窗口显示时钟是否正确,参考如 图 2.24 所示。 - 115 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 图 2.24 RTC 实验结果参考图 7. 实验参考程序 RTC 实验的参考程序见程序清单 2.27。 程序清单 2.27 RTC 实验参考程序 /****************************************Copyright (c)*********************************** ** File Name: main.c ** Last modified Date: 2006-01-11 ** Last Version: v1.0 ** Description: MagicARM2410 实验箱的基础实验--- RTC 实验。 ** 初始化 S3C2410A 内部的 RTC,然后每隔 1 秒钟读取一次 RTC 的时间,并通过串 ** 口发送到 PC 机显示。 ************************************************************************************/ #include "config.h" // 定义显示缓冲区 char disp_buf[50]; // 定义当前时间变量 uint8 g_year = 0; uint8 g_month = 0; uint8 g_date = 0; uint8 g_day = 0; uint8 g_hour = 0; - 116 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com uint8 uint8 g_min = 0; g_sec = 0; // 定义星期字符串 char *str_day[8] = {" ","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday","Sunday"}; /************************************************************************************ ** Function name: DelayNS ** Descriptions: 长软件延时。 延时时间与系统时钟有关。 ** Input: dly 延时参数,值越大,延时越久 ** Output: 无 ************************************************************************************/ void DelayNS(uint32 dly) { uint32 i; for(; dly>0; dly--) for(i=0; i<50000; i++); } // 定义初始化时钟值 #define INIT_YEAR #define INIT_MONTH #define INIT_DATE #define INIT_DAY #define INIT_HOUR #define INIT_MIN #define INIT_SEC 0x06 /* 2006 年 */ 0x01 /* 1 月 */ 0x10 /* 10 日 */ 0x02 /* 星期二 */ 0x20 /* 20 时 */ 0x30 /* 30 分 */ 0x00 /* 0 秒 */ /************************************************************************************ ** Function name: RTC_Init ** Descriptions: RTC 初始化。使用的初始化值为 INIT_XXX(宏)来初始化。 ** 若 force 为 0,则先检查当前时钟是否正确(通过年月日、时分秒来判断),若正确 ** 则不再初始化。 ** Input: force ** Output: 无 是否强行初始化(非 0 值时表示强行) ************************************************************************************/ void RTC_Init(int force) { int err; uint32 bak; // 判断当前 RTC 是否正确运行 err = 0; - 117 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com if(force == 0) // 若 force 为 0,则判断当前时钟是否正确 { rRTCCON = 0x00; // 禁止 RTC 接口(只允许 RTC 计数和读数) bak = rBCDYEAR & 0xFF; if(bak>0x99) err++; // 年判断 bak = rBCDMON & 0x1F; if(bak>0x12) err++; // 月判断 bak = rBCDDATE & 0x3F; if(bak>0x31) err++; // 日判断 bak = rBCDHOUR & 0x3F; if(bak>0x24) err++; // 时判断 bak = rBCDMIN & 0x7F; if(bak>0x59) err++; // 分判断 bak = rBCDSEC & 0x7F; if(bak>0x59) err++; // 秒判断 if(err==0) return; // 若时钟正确,则直接返回 } rRTCCON = 0x01; // 标准模式,RTC 接口使能(允许写) rBCDYEAR = INIT_YEAR & 0xFF; rBCDMON = INIT_MONTH & 0x1F; rBCDDATE = INIT_DATE & 0x3F; rBCDDAY = INIT_DAY & 0x07; // 星期,MON:1 TUE:2 WED:3 THU:4 // FRI:5 SAT:6 SUN:7 rBCDHOUR = INIT_HOUR & 0x3F; rBCDMIN = INIT_MIN & 0x7F; rBCDSEC = INIT_SEC & 0x7F; rRTCCON = 0x00; // 禁止 RTC 接口(只允许 RTC 计数和读数) } /************************************************************************************ ** Function name: RTC_Read ** Descriptions: 读时间函数。可以指定时否读日期(年月日和星期) ** Input: date 是否读日期(非 0 值时表示读) ** Output: 无 ************************************************************************************/ void RTC_Read(uint32 date) { if(date) { g_year = rBCDYEAR; g_month = rBCDMON; g_date = rBCDDATE; g_day = rBCDDAY; - 118 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com } g_hour = rBCDHOUR; g_min = rBCDMIN; g_sec = rBCDSEC; } /************************************************************************************ ** Function name: DispRTC ** Descriptions: 显示时间(从串口发送显示数据),即显示 g_year、g_month、g_date 等变量的值。 ** Input: 无 ** Output: 无 ************************************************************************************/ void DispRTC(void) { sprintf(disp_buf, "%02x:%02x:%02x %10s, %2x/%2x/20%02x \n", g_hour, g_min, g_sec, str_day[g_day], g_month, g_date, g_year); UART_SendStr(disp_buf); } /************************************************************************************ ** Function name: main ** Descriptions: 初始化 RTC,然后不断地读取时间值,并输出串口。 ** Input: 无 ** Output: 系统返回值 0 ************************************************************************************/ int main(void) { int temp; UART_Select(0); UART_Init(); RTC_Init(0); RTC_Read(1); // 选择 UART0 // 初始化 UART0 // 初始化 RTC(非强行方式) // 读日期 temp = 0; while(1) { while(temp == rBCDSEC); temp = rBCDSEC; RTC_Read(0); // 读时间 DispRTC(); // 输出时间显示 } return(0); } - 119 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 8. 思考 (1)初始化 RTC 时间寄存器时,设置值要使用什么格式(如 21 秒怎样表示)? (2)如果想定时每天的 12:00:00 报警,需要如何设置 RTC 的相关寄存器? 2.17 步进电机控制实验 1. 实验目的 了解步进电机的控制原理,掌握电机转动控制和调速方法。 2. 实验设备 硬件:PC 机 一台 MagicARM2410 教学实验开发平台 一套 软件:Windows98/XP/2000 系统,ADS 1.2 集成开发环境 3. 实验内容 通过 4 个 GPIO 输出有序的矩形脉冲,控制 ULN2003 驱动四相步进电机实现正转,调 速的功能。 控制的方法采用双四拍(AB―BC―CD―DA―AB)。 4. 实验预习要求 (1)仔细阅读参考文献[2]第 9 节的 S3C2410A 的 GPIO 模块说明。 (2)仔细阅读本书第 1 章的内容,了解 MagicARM2410 实验箱的硬件结构,注意步进 电机控制电路。 5. 实验原理 步进电机是一种将电脉转换为角位移的数据控制电机,即给它一个脉冲信号,它就按设 定的方向转动一个固定的角度。用户可以通过控制脉冲的个数来控制角位移量,从而实现准 确的定位操作;另外,通过控制脉冲频率来控制电机转动的速度和加速度,从而达到调速的 目的。当然,对于步进电机各相绕组(即内部线圈)的控制脉冲要有一定的顺序,否则电机无 法正常旋转。 MagicARM2410 实验箱上的步进电机为四相步进电机,电机步距角为 18 度。S3C2410A 的 GPIO 驱动能力有限,必须通过 ULN2003 达林顿集成驱动芯片驱动步进电机,在步进电 机和驱动电路之间连接了电阻,防止控制紊乱造成电机的损坏,电路参考如图 1.44 所示。 6. 实验步骤 (1)启动 ADS 1.2,使用 ARM Executable Image for DeviceARM2410 工程模板建立一 个工程 StepMoto。 (2)在 src 组中的 main.c 中编写主程序代码。 (3)选用 DebugRel 生成目标,然后编译链接工程。 - 120 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com (4)将 MagicARM2410 实验箱上的步进电机控制电路的电源跳线 JP5 短接,将步进电 机控制口跳线 JP6 短接。 (5)选择【Project】->【Debug】,启动 AXD 进行 JTAG 仿真调试。 (6)全速运行程序,观察步进电机转动方向及速度。 (7)改变延时参数,如实验参考代码 MOTO_Mode2(3),观察步进电机转动的速度。 7. 实验参考程序 步进电机控制实验的参考程序见程序清单 2.28。 程序清单 2.28 步进电机控制实验参考程序 /****************************************Copyright (c)*********************************** ** File Name: main.c ** Last modified Date: 2006-01-09 ** Last Version: v1.0 ** Description: MagicARM2410 实验箱的基础实验---步进电机控制实验。 ** 使用 GPIO 控制步进电机转动,采用双四拍控制方式。 ************************************************************************************/ #include "config.h" // 步进电机控制口线及操作宏函数定义 #define MOTOA (1<<5) /* GPC5 */ #define MOTOB (1<<6) /* GPC6 */ #define MOTOC (1<<7) /* GPC7 */ #define MOTOD (1<<0) /* GPC0 */ #define GPIOSET(PIN) rGPCDAT = rGPCDAT | PIN #define GPIOCLR(PIN) rGPCDAT = rGPCDAT & (~PIN) /* 设置 PIN 输出 1 */ /* 设置 PIN 输出 0 */ /************************************************************************************ ** Function name: DelayNS ** Descriptions: 长软件延时。 延时时间与系统时钟有关。 ** Input: dly 延时参数,值越大,延时越久 ** Output: 无 ************************************************************************************/ void DelayNS(uint32 dly) { uint32 i; for(; dly>0; dly--) for(i=0; i<50000; i++); } /************************************************************************************ ** Function name: MOTO_Mode2() ** Descriptions: 步进电机双四拍程序。 - 121 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com ** 时序控制为 AB--BC--CD--DA--AB,共控制运转 4 圈(电机步距角为 18 度)。 ** Input: dly 每一步的延时控制。值越大,延时越久 ** Output: 无 ************************************************************************************/ void MOTO_Mode2(uint8 dly) { uint32 i; for(i=0; i<20; i++) { // AB 相有效 GPIOSET(MOTOA); GPIOSET(MOTOB); DelayNS(dly); GPIOCLR(MOTOA); GPIOCLR(MOTOB); // BC 相有效 GPIOSET(MOTOB); GPIOSET(MOTOC); DelayNS(dly); GPIOCLR(MOTOB); GPIOCLR(MOTOC); // CD 相有效 GPIOSET(MOTOC); GPIOSET(MOTOD); DelayNS(dly); GPIOCLR(MOTOC); GPIOCLR(MOTOD); // DA 相有效 GPIOSET(MOTOD); GPIOSET(MOTOA); DelayNS(dly); GPIOCLR(MOTOD); GPIOCLR(MOTOA); } } /************************************************************************************ ** Function name: main ** Descriptions: 使用 GPIO 控制步进电机转动,采用双四拍控制方式。 ** Input: 无 ** Output: 系统返回值 0 ************************************************************************************/ int main(void) - 122 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com { // 步进电机控制口设置 rGPCCON = (rGPCCON & (~0x0000FC03)) | (0x00005401); // GPC0、GPC5--7 口设置为输出 rGPCUP = rGPCUP | 0x00E1; // 禁止 GPC0、GPC5--7 口的上拉电阻 rGPCDAT = rGPCDAT & (~0x00E1); // 设置 GPC0、GPC5--7 口输出低电平 while(1) { MOTO_Mode2(1); DelayNS(50); // 控制步进电机正转 // 停止步进电机,延时 } return(0); } 8. 思考 (1)如何控制步进电机反转?(提示:时序控制为 BA—AD—DC—CB—BA 即可) (2)在参考实验程序中,怎么样修改才能提高步进电机的转速? 2.18 直流电机控制实验 1. 实验目的 掌握使用 PWM 方式控制直流电机的转动速度。 2. 实验设备 硬件:PC 机 一台 MagicARM2410 教学实验开发平台 一套 软件:Windows98/XP/2000 系统,ADS 1.2 集成开发环境 3. 实验内容 使用 S3C2410A 的 TOUT0 口输出 PWM 信号控制直流电机,实现四级调速控制。通过 检测按键 KEY1 来改变当前电机的速度级别。 4. 实验预习要求 (1)仔细阅读参考文献[2]第 10 节的 S3C2410A 的 PWM 定时器模块说明。 (2)仔细阅读本书第 1 章的内容,了解 MagicARM2410 实验箱的硬件结构,注意直流 电机控制电路。 5. 实验原理 S3C2410A 具有 4 路 PWM 输出,输出口分别为 TOUT0~TOUT3,其中两路带有死区 控制功能。为了能够正确输出 PWM 信号,需要正确设置 GPBCON 寄存器选择相应 I/O 的 为 TOUTx 功能。然后,通过 TCFG0 寄存器为 PWM 定时器时钟源设置预分频值,通过 TCFG1 - 123 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 寄存器选择 PWM 定时器时钟源。接着,通过 TCNTB0 寄存器设置 PWM 周期,通过 TCMPB0 设置 PWM 占空比。最后,通过 TCON 寄存器启动 PWM 定时器,即可输出 PWM 信号。 6. 实验步骤 (1)启动 ADS 1.2,使用 ARM Executable Image for DeviceARM2410 工程模板建立一 个工程 DCMoto。 (2)在 src 组中的 main.c 中编写主程序代码。 (3)选用 DebugRel 生成目标,然后编译链接工程。 (4)将 MagicARM2410 实验箱上的直流电机控制电路的电源跳线 JP4 短接,将直流电 机控制口跳线 JP3 短接。 (5)选择【Project】->【Debug】,启动 AXD 进行 JTAG 仿真调试。 (6)全速运行程序,观察直流电机转动的速度。按下独立按键 KEY1,观察直流电机 的转动速度是否改变。 7. 实验参考程序 直流电机控制实验的参考程序见程序清单 2.29。 程序清单 2.29 直流电机控制实验参考程序 /****************************************Copyright (c)*********************************** ** File Name: main.c ** Last modified Date: 2006-01-09 ** Last Version: v1.0 ** Description: MagicARM2410 实验箱的基础实验---直流电机控制实验。 ** 使用 TOUT0 口输出 PWM 信号控制直流电机,实现四级调速控制。 ************************************************************************************/ #include "config.h" // 定义独立按键 KEY1 的输入口 #define KEY_CON (1<<4) /* GPF4 口 */ /************************************************************************************ ** Function name: DelayNS ** Descriptions: 长软件延时。 延时时间与系统时钟有关。 ** Input: dly 延时参数,值越大,延时越久 ** Output: 无 ************************************************************************************/ void DelayNS(uint32 dly) { uint32 i; for(; dly>0; dly--) for(i=0; i<50000; i++); } - 124 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com /************************************************************************************ ** Function name: WaitKey ** Descriptions: 等待一个有效按键。本函数有去抖功能。 ** Input: 无 ** Output: 无 ************************************************************************************/ void WaitKey(void) { uint32 i; while(1) { while((rGPFDAT&KEY_CON) == KEY_CON) ; // 等待 KEY 键按下 for(i=0; i<1000; i++); // 延时去抖 if( (rGPFDAT&KEY_CON) != KEY_CON) break; } while((rGPFDAT&KEY_CON) != KEY_CON); // 等待按键放开 } /************************************************************************************ ** Function name: PWM_Init ** Descriptions: 初始化 PWM 定时器 ** Input: cycle PWM 周期控制值(uint16 类型) ** duty PWM 占空比(uint16 类型) ** Output: 无 ************************************************************************************/ void PWM_Init(uint16 cycle, uint16 duty) { // 参数过滤 if(duty>cycle) duty = cycle; // 设置定时器 0,即 PWM 周期和占空比 // Fclk=200MHz,时钟分频配置为 1:2:4,即 Pclk=50MHz。 rTCFG0 = 97; // 预分频器 0 设置为 98,取得 510204Hz rTCFG1 = 0; rTCMPB0 = duty; // TIMER0 再取 1/2 分频,取得 255102Hz // 设置 PWM 占空比 rTCNTB0 = cycle; // 定时值(PWM 周期) if(rTCON&0x04) rTCON = (1<<1); // 更新定时器数据 (取反输出 inverter 位) else rTCON = (1<<2)|(1<<1); rTCON = (1<<0)|(1<<3); // 启动定时器 } /************************************************************************************ ** Function name: main - 125 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com ** Descriptions: 初始化 PWM 输出,控制直流电机转动速度。 ** Input: 无 ** Output: 系统返回值 0 ************************************************************************************/ int main(void) { uint16 pwm_dac; // 独立按键 KEY1 控制口设置 rGPFCON = (rGPFCON & (~(0x03<<8))); // rGPFCON[9:8] = 00b,设置 GPF4 为 GPIO 输入模式 // TOUT0 口设置 rGPBCON = (rGPBCON & (~(0x03<<0))) | (0x02<<0); // rGPBCON[1:0] = 10b,设置 TOUT0 功能 rGPBUP = rGPBUP | 0x0001; // 禁止 TOUT0 口的上拉电阻 // 设置 GPH9 为 GPIO 输出模式 rGPHCON = (rGPHCON & (~(0x03<<18))) | (0x01<<18); // GPH9 口 rGPHDAT = rGPHDAT & (~(1<<9)); // 输出 0 电平 rGPHUP = rGPHUP | (1<<9); // 初始化 PWM 输出。设 PWM 周期控制值为 255 pwm_dac = 3*255/4; // 初始化占空比为 3/4 PWM_Init(255, pwm_dac); // 等待按键 KEY1,改变占空比 while(1) { WaitKey(); pwm_dac = pwm_dac + 255/4; if(pwm_dac>255) { pwm_dac = 255/4; } rTCMPB0 = pwm_dac; } return(0); } // 改变当前电机的速度级别 8. 思考 (1)如何控制直流电机正/反转?(提示:GPH9、GPB0 均要设置 GPIO 输出模式) (2)修改实验参考程序,加入停机控制功能(当电机在最高速度档转动时,再按一次按 键即控制电机停机)。 - 126 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 第3章 基于µC/OS-II 基础实验 3.1 μC/OS-II 移植实验 1. 实验目的 (1)掌握将μC/OS-II 操作系统移植到 ARM9 处理器的方法。 (2)了解μC/OS-II 操作系统的基本原理和移植条件。 2. 实验设备 硬件:PC 机 一台 MagicARM2410 教学实验开发平台 一套 软件:Windows98/XP/2000 系统,ADS 1.2 集成开发环境 3. 实验内容 学习移植μC/OS-II 操作系统到 ARM9 处理器,然后编写一个简单的多任务应用程序, 实现 LED 流水灯控制。 4. 实验预习要求 (1)仔细阅读参考文献[5],了解μC/OS-II 的组成和移植相关的文件内容。 (2)仔细阅读参考文献[2],了解 S3C2410A 微控制器的硬件结构(如向量中断控制器和 定时器等)。 (3)仔细阅读产品配套光盘附带文档“ADS 集成开发环境及 JTAG 仿真器应用.pdf” 或其它 ADS 相关资料,了解 ADS 1.2 集成开发环境、DeviceARM2410 专用工程模板、 EasyJTAG-H 仿真器的应用。 5. 实验原理 (1) μC/OS-II 概述 μC/OS-II 是一个完整的、可移植、可固化、可剪裁的占先式实时多任务内核。µC/OS-II 是用 ANSI C 语言编写,包含一小部分汇编代码,使之可以供不同架构的微处理器使用。 µC/OS-II 可以管理 64 个任务,具有信号量、互斥信号量、事件标志组、消息邮箱、消息队 列、任务管理、时间管理和内存块管理等系统功能。 μC/OS-II 软件体系结构如图 3.1 所示,由图可以看出,μC/OS-II 包括以下 3 个部分: μC/OS-II 核心代码:包括 10 个 C 程序文件和 1 个头文件,主要实现了系统调度、 任务管理、内存管理、信号量、消息邮箱和消息队列等系统功能。此部分的代码与 处理器无关。 μC/OS-II 配置代码:包括 2 个头文件,用于裁剪和配置μC/OS-II。此部分的代码 与用户实际应用相关。 μC/OS-II 移植代码:包括 1 个汇编文件、1 个 C 程序文件和 1 个头文件,这是移 植μC/OS-II 所需要的代码。此部分的代码与处理器相关。 说明:移植代码的文件名不是固定的,但为了保持μC/OS-II 系统的一致性,文件名一 般也不要改变(即 OS_CPU.H、OS_CPU_A.ASM 和 OS_CPU_C.C)。 - 127 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 用户应用软件 µC/OS-II 核心代码 (与处理器无关) OS_CORE.C OS_FLAG.C OS_MBOX.C OS_MEM.C OS_MUTEX.C OS_Q.C OS_SEM.C OS_TASK.C OS_TIME.C UCOS_II.C UCOS_II.H µC/OS-II 配置代码 (与应用相关) OS_CFG.H INCLUDES.H µC/OS-II 移植代码(与处理器相关) OS_CPU.H OS_CPU_A.ASM OS_CPU_C.C 图 3.1 μC/OS-II 软件体系结构 (2) μC/OS-II 移植条件 移植μC/OS-II 之前需要注意,目标处理器必须满足以下几点要求: 处理器的 C 编译器能产生可重入型代码; 处理器支持中断,并且能产生定时中断(通常为 10~100Hz); 用 C 语言就可以开/关中断; 处理器能够支持一定数量的数据存储硬件堆栈(可能是几千字节); 处理器有将堆栈指针以及其它 CPU 寄存器的内容读出,并保存到堆栈或内存中去 的指令。 S3C2410A 微控制器可以满足第 2、4 和 5 点要求,使用 ADS 1.2 的 C 编译器可以满足 第 1、3 点要求。 (3) μC/OS-II 移植步骤 1) OS_CPU.H 的移植 在 OS_CPU.H 文件中定义与处理器相关(实际上是与编译器相关)的数据类型,如 BOOLEAN、INT8U、INT8S 等等。根据 ADS 1.2 编译器的特性,定义代码可参考程序清单 3.1。 程序清单 3.1 OS_CPU.H—与编译器相关的数据类型 typedef typedef typedef unsigned char unsigned char signed char BOOLEAN; INT8U; INT8S; - 128 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com typedef typedef typedef typedef typedef typedef unsigned short INT16U; signed short INT16S; unsigned int INT32U; signed int INT32S; float FP32; double FP64; typedef INT32U OS_STK; 在 OS_CPU.H 文件中定义与处理器相关的宏,主要是进入临界区的 OS_ENTER_CRITI CAL 和退出临界区的 OS_EXIT_CRITICAL,定义代码可参考程序清单 3.2。如程序清单 3.2 所列,将 OS_ENTER_CRITICAL()和 OS_EXIT_CRITICAL()定义为软件中断函数,所以还 要编写相应的软件中断处理代码(可以在 OS_CPU_C.C 文件中编写)实现开/关中断。 同样定义 OS_TASK_SW()为软件中断函数,并编写有相应的软件中断处理代码(调用 OS IntCtxSw 函数)实现任务切换。 程序清单 3.2 OS_CPU.H—与处理器相关的宏 __swi(0x00) void OS_TASK_SW(void); /* 任务级任务切换函数 */ __swi(0x02) void OS_ENTER_CRITICAL(void); /* 关中断 */ __swi(0x03) void OS_EXIT_CRITICAL(void); /* 开中断 */ #define OS_STK_GROWTH 1 /* 堆栈是从上往下长的 */ 2) OS_CPU_C.C 的移植 在 OS_CPU_C.C 文件中,需要编写以下 10 个简单的 C 函数: OSTaskStkInit(); OSTaskCreateHook(); OSTaskDelHook(); OSTaskSwHook(); OSTaskIdleHook(); OSTaskStatHook(); OSTaskTickHook(); OSInitHookBegin(); OSInitHookEnd(); OSTCBInitHook()。 其中,9 个系统 Hook 函数可以为空函数,也可以根据用户自己的需要编写相应的操作 代码。任务栈结构初始化函数 OSTaskStkInit,必须根据移植时统一定义的任务堆栈结构进 行初始化,代码参考程序清单 3.3。 程序清单 3.3 OS_CPU_C.C—函数 OSTaskStkInit OS_STK *OSTaskStkInit (void (*task)(void *pd), void *pdata, OS_STK *ptos, INT16U opt) { OS_STK *stk; - 129 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com opt = opt; stk = ptos; /* 'opt' 没有使用。作用是避免编译器警告 */ /* 获取堆栈指针 */ /* 建立任务环境,ADS1.2 使用满递减堆栈 */ *stk = (OS_STK) task; /* pc */ *--stk = (OS_STK) task; /* lr */ *--stk = 0; /* r12 */ *--stk = 0; /* r11 */ *--stk = 0; /* r10 */ *--stk = 0; /* r9 */ *--stk = 0; /* r8 */ *--stk = 0; /* r7 */ *--stk = 0; /* r6 */ *--stk = 0; /* r5 */ *--stk = 0; /* r4 */ *--stk = 0; /* r3 */ *--stk = 0; /* r2 */ *--stk = 0; /* r1 */ *--stk = (unsigned int) pdata; /* r0,第一个参数使用 R0 传递 */ *--stk = (USER_USING_MODE|0x00); /* spsr,允许 IRQ, FIQ 中断 */ *--stk = 0; /* 关中断计数器 OsEnterSum; */ return (stk); } 3) OS_CPU_A.S 的移植 由于 ADS1.2 编译器默认汇编文件后缀名为“S”,所以移植代码 OS_CPU_A.ASM 改名 为 OS_CPU_A.S。 在 OS_CPU_A.S 文件中,需要编写以下 4 个简单的汇编语言函数: OSStartHighRdy(); OSCtxSw(); OSIntCtxSw(); OSTickISR()。 其中,函数 OSCtxSw 不是必须的,但必须要定义好函数 OS_TASK_SW(在 OS_CPU.H 中声明),以实现任务级任务切换。 在 ISR 中切换任务时会调用 OSIntCtxSw 函数,代码参考程序清单 3.4。 程序清单 3.4 OS_CPU_A.S—函数 OSIntCtxSw OSIntCtxSw ;下面为保存任务环境 LDR R2, [SP, #20] LDR R12, [SP, #16] MRS R0, CPSR MSR CPSR_c, #(NoInt | SYS32Mode) ;获取 PC ;获取 R12 - 130 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com MOV R1, LR STMFD SP!, {R1-R2} STMFD SP!, {R4-R12} MSR CPSR_c, R0 LDMFD SP!, {R4-R7} ADD SP, SP, #8 MSR CPSR_c, #(NoInt | SYS32Mode) STMFD SP!, {R4-R7} LDR R1, =OsEnterSum LDR R2, [R1] STMFD SP!, {R2, R3} ;保存 LR,PC ;保存 R4-R12 ;获取 R0-R3 ;出栈 R12,PC ;保存 R0-R3 ;获取 OsEnterSum ;保存 CPSR,OsEnterSum ;保存当前任务堆栈指针到当前任务的 TCB LDR R1, =OSTCBCur LDR R1, [R1] STR SP, [R1] BL OSTaskSwHook LDR LDR LDRB STRB R4, =OSPrioCur R5, =OSPrioHighRdy R6, [R5] R6, [R4] LDR LDR LDR STR R6, =OSTCBHighRdy R6, [R6] R4, =OSTCBCur R6, [R4] ;调用钩子函数 ;OSPrioCur <= OSPrioHighRdy ;OSTCBCur <= OSTCBHighRdy OSIntCtxSw_1 LDR R4, [R6] ADD SP, R4, #68 LDR LR, [SP, #-8] MSR CPSR_c, #(NoInt | SVC32Mode) MOV SP, R4 LDMFD SP!, {R4, R5} LDR R3, =OsEnterSum STR R4, [R3] MSR SPSR_cxsf, R5 LDMFD SP!, {R0-R12, LR, PC }^ ;获取新任务堆栈指针 ;17 寄存器 CPSR,OsEnterSum,R0-R12,LR,SP ;进入管理模式 ;设置堆栈指针 ;CPSR,OsEnterSum ;恢复新任务的 OsEnterSum ;恢复 CPSR ;运行新任务 启动µC/OS-II 是通过调用 OSStart()实现,OSStart()最终调用函数 OSStartHighRdy()运行 多任务启动前优先级最高的任务。OSStartHighRdy()函数的代码参考程序清单 3.5。 - 131 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 说明:在 OS_CPU_C.C 文件已定义 OSStartHighRdy(),此函数直接调用__OSStartHigh Rdy()。 程序清单 3.5 OS_CPU_A.S—函数 OSStartHighRdy __OSStartHighRdy MSR LDR MOV STRB BL LDR LDR B CPSR_c, #(NoInt | SYS32Mode) ;告诉 uC/OS-II 自身已经运行 R4, =OSRunning R5, #1 R5, [R4] OSTaskSwHook ;调用钩子函数 R6, =OSTCBHighRdy R6, [R6] OSIntCtxSw_1 函数 OSTickISR 为系统时钟节拍中断函数,这需要使用到处理器的定时器和定时中断。 为了达到集中地初始化硬件(定时器、中断和 I/O 等)的目的,此函数可以在用户工程的起动 代码文件中实现,参考程序清单 3.6。 说明:系统时钟节拍中断函数的名称并不是固定的,也并不一定要在 OS_CPU_A.S 文 件中实现。 程序清单 3.6 系统时钟节拍中断服务程序 void Timer0_Exception(void) { rSRCPND = 1 << 10; rINTPND = rINTPND; OSTimeTick(); } 6. 实验步骤 (1)为 ADS1.2 增加 DeviceARM2410 专用工程模板(若已增加过,此步省略)。 (2)连接 EasyJTAG-H 仿真器和 MagicARM2410 实验箱,然后安装 EasyJTAG-H 仿真 器(若已经安装过,此步省略),短接蜂鸣器跳线 JP9。 (3)启动 ADS 1.2,使用 ARM Executable Image for DeviceARM2410(uCOSII)工程模板 建立一个工程 Demo_uCOSII。(本范例在 ADS 文件夹中操作) (4)见图 3.2,在 ADS 文件夹中新建 arm、Arm_Pc、SOURCE 文件夹。将 µC/OS 2.52 源代码添加到 SOURCE 文件夹,将移植代码添加到 arm 文件夹,将移植的 PC 服务代码添 加到 Arm_Pc 文件夹。(移植代码可以在 DeviceARM2410 光盘上获得,µC/OS 2.52 源代码需 要从参考文献[5]的光盘上获得) (5)在 src 组中的 main.c 中编写主程序代码。 (6)根据程序设计来更改 Os_cfg.h 文件,配置 µC/OS-II 操作系统。(对于本实验,µC/OS-II 的配置使用模板默认设置即可) - 132 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 图 3.2 μC/OS-II 目录的结构 (7)选用 DebugRel 生成目标,如图 3.3 所示,然后编译链接工程。 图 3.3 选择生成目标 (8)将 MagicARM2410 实验箱上的蜂鸣器跳线 JP9 短接,将启动方式选择跳线 JP8 短 接,然后按 RST 键复位系统。 (9)选择【Project】->【Debug】,启动 AXD 进行 JTAG 仿真调试。 (10)全速运行程序,程序将会在 main.c 的主函数中停止(因为 main 函数起始处默认设 置有断点)。 (11)单击 Context Variable 图标按钮(或者选择【Processor Views】->【Variables】)打 开变量观察窗口,通过此窗口可以观察局部变量和全局变量。 (12)可以单步运行程序,可以设置/取消断点,或者全速运行程序,停止程序运行, 观察变量的值,判断蜂鸣器及 LED1~LED4 的控制是否正确。 - 133 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 7. 实验参考程序 μC/OS-II 移植实验的参考程序见程序清单 3.7。 程序清单 3.7 μC/OS-II 移植实验参考程序 #include "config.h" #define Task0StkLengh 64 #define Task1StkLengh 64 // Define the Task0 stack length 定义用户任务 0 的堆栈长度 // Define the Task1 stack length 定义用户任务 1 的堆栈长度 OS_STK Task0Stk [Task0StkLengh]; OS_STK Task1Stk [Task1StkLengh]; // Define the Task0 stack 定义用户任务 0 的堆栈 // Define the Task1 stack 定义用户任务 1 的堆栈 // 定义 LED 控制口 (输出高电平时点亮 LED) #define LED1_CON (1<<11) #define LED2_CON (1<<12) #define LED3_CON (1<<4) #define LED4_CON (1<<6) /* GPE11 口 */ /* GPE12 口 */ /* GPH4 口 */ /* GPH6 口 */ // 定义蜂鸣器控制口 #define BEEP #define BEEP_MASK (1<<10) (~BEEP) void Task0(void *pdata); void Task1(void *pdata); void RunBeep(void); void LED_DispNum(uint32 dat); /* GPH10 口 */ // Task0 任务 0 // Task1 任务 1 /******************************************************************************************* ** Function name: main ** Descriptions: 主函数,uCOS/II 移植实验范例 ** Input: ** Output: 无 系统返回值 0 ******************************************************************************************/ int main (void) { OSInit (); OSTaskCreate (Task0,(void *)0, &Task0Stk[Task0StkLengh - 1], 2); OSTaskCreate (Task1,(void *)0, &Task1Stk[Task1StkLengh - 1], 3); OSStart (); return 0; } - 134 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com /****************************************************************************************** ** Function name: Task0 ** Descriptions: 初始化 GPIO,并约 1 秒蜂鸣一次 ******************************************************************************************/ void Task0 (void *pdata) { pdata = pdata; TargetInit (); // 初始化 I/O rGPECON = (rGPECON & (~(0x0F<<22))) | (0x05<<22); rGPHCON = (rGPHCON & (~(0x33<<8))) | (0x11<<8); rGPHCON = (rGPHCON & (~(0x03<<20))) | (0x01<<20); while (1) { RunBeep(); OSTimeDly(OS_TICKS_PER_SEC); } } // rGPECON[25:22] = 0101b, // 设置 GPE11、GPE12 为 GPIO 输出模式 // rGPHCON[13:8] = 01xx01b, // 设置 GPH4、GPH6 为 GPIO 输出模式 // rGPHCON[21:20] = 01b, // 设置 GPH10 为 GPIO 输出模式 /******************************************************************************************* ** Function name: Task1 ** Descriptions: 控制 LED 显示加 1 *******************************************************************************************/ void Task1 (void *pdata) { uint8 i; pdata = pdata; while (1) { for(i=0; i<16; i++) { LED_DispNum(i); OSTimeDly(OS_TICKS_PER_SEC/2); } } } /************************************************************************************ ** Function name: RunBeep - 135 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com ** Descriptions: 控制蜂鸣器 Be 一声音。 ** Input: 无 ** Output: 无 ************************************************************************************/ void RunBeep(void) { rGPHDAT = rGPHDAT & BEEP_MASK; // BEEP = 0 OSTimeDly(OS_TICKS_PER_SEC/10); rGPHDAT = rGPHDAT | BEEP; // BEEP = 1 OSTimeDly(OS_TICKS_PER_SEC/10); } /************************************************************************************ ** Function name: LED_DispNum ** Descriptions: 控制 LED1~LED4 显示指定 16 进制数值。LED4 为最高位, ** LED1 为最低为,点亮表示该位为 1。 ** Input: ** Output: dat 显示数值(低 4 位有效) 无 ************************************************************************************/ void LED_DispNum(uint32 dat) { dat = dat & 0x0000000F; // 参数过滤 // 控制 LED4、LED3 显示(d3、d2 位) if(dat & 0x08) rGPHDAT = rGPHDAT | (0x01<<6); else rGPHDAT = rGPHDAT & (~(0x01<<6)); if(dat & 0x04) rGPHDAT = rGPHDAT | (0x01<<4); else rGPHDAT = rGPHDAT & (~(0x01<<4)); // 控制 LED2、LED1 显示(d1、d0 位) rGPEDAT = (rGPEDAT & (~(0x03<<11))) | ((dat&0x03) << 11); } 8. 思考 (1) 请简单描述μC/OS-II 操作系统的软件体系结构。 (2) 请简单描述μC/OS-II 应用程序的基本结构。 (3) μC/OS-II 任务的编写与前后台程序有何差别? 3.2 蜂鸣器实验 1. 实验目的 掌握在 MaigcARM2410 教学实验开发平台上运行μC/OS-II 程序。 - 136 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 2. 实验设备 硬件:PC 机 一台 MagicARM2410 教学实验开发平台 一套 软件:Windows98/XP/2000 系统,ADS 1.2 集成开发环境 3. 实验内容 不断地读取 GPF4 口上的电平值,然后控制蜂鸣器鸣响。 4. 实验预习要求 (1)仔细阅读参考文献[5],了解μC/OS-II 任务的概念。 (2)仔细阅读产品配套光盘附带文档“ADS 集成开发环境及 JTAG 仿真器应用.pdf” 或其它 ADS 相关资料,了解 ADS 1.2 集成开发环境、DeviceARM2410 专用工程模板、 EasyJTAG-H 仿真器的应用。 5. 实验原理 MagicARM2410 实验箱上使用了 S3C2410A 的 GPF4 口连接一个独立按键 KEY1,电路 原理如图 3.4 所示。本范例建立 2 个任务,任务 0 不断读取 KEY1 的状态,将状态写入状 态变量;任务 1 不断读取状态变量,如果发现 KEY1 按下则蜂鸣一次。 VDD33 KEY1 R181 22 R39 S3C2410A 10K EINT4/GPF4 图 3.4 独立按键电路 6. 实验步骤 (1)为 ADS1.2 增加 DeviceARM2410 专用工程模板(若已增加过,此步省略)。 (2)连接 EasyJTAG-H 仿真器和 MagicARM2410 实验箱,然后安装 EasyJTAG-H JTAG 仿真器(若已经安装过,此步省略),短接蜂鸣器跳线 JP9。 (3)启动 ADS 1.2,使用 ARM Executable Image for DeviceARM2410(uCOSII)工程模板 建立一个工程 GPIO_uCOSII。(本范例在 ADS 文件夹中操作) (4)见图 3.2,在 ADS 文件夹中新建 arm、Arm_Pc、SOURCE 文件夹。将 µC/OS 2.52 源代码添加到 SOURCE 文件夹,将移植代码添加到 arm 文件夹,将移植的 PC 服务代码添 加到 Arm_Pc 文件夹。(移植代码可以在 DeviceARM2410 光盘上获得,µC/OS 2.52 源代码需 要从参考文献[5]的光盘上获得) (5)在 src 组中的 main.c 中编写主程序代码。 (6)选用 DebugRel 生成目标,然后编译链接工程。 (7)将 MagicARM2410 实验箱上的蜂鸣器跳线 JP9 短接,将启动方式选择跳线 JP8 短 接,然后按 RST 键复位系统。 - 137 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com (8)选择【Project】->【Debug】,启动 AXD 进行 JTAG 仿真调试。 (9)全速运行程序,程序将会在 main.c 的主函数中停止(因为 main 函数起始处默认设 置有断点)。 (10)单击 Context Variable 图标按钮(或者选择【Processor Views】->【Variables】)打 开变量观察窗口,通过此窗口可以观察局部变量和全局变量。 (11)可以单步运行程序,可以设置/取消断点,或者全速运行程序,停止程序运行, 观察变量的值,按下 KEY1,观察蜂鸣器是否鸣响。 7. 实验参考程序 蜂鸣器实验的参考程序见程序清单 3.8。 程序清单 3.8 蜂鸣器实验参考程序 #include "config.h" #define Task0StkLengh 64 #define Task1StkLengh 64 // Define the Task0 stack length 定义用户任务 0 的堆栈长度 // Define the Task1 stack length 定义用户任务 1 的堆栈长度 OS_STK Task0Stk [Task0StkLengh]; OS_STK Task1Stk [Task1StkLengh]; // Define the Task0 stack 定义用户任务 0 的堆栈 // Define the Task1 stack 定义用户任务 1 的堆栈 // 定义独立按键 KEY1 的输入口 #define KEY_CON (1<<4) /* GPF4 口 */ // 定义蜂鸣器控制口 #define BEEP #define BEEP_MASK (1<<10) /* GPH10 口 */ (~BEEP) // 按键状态 uint8 KeyState = FALSE; void Task0(void *pdata); void Task1(void *pdata); void RunBeep(void); // Task0 任务 0 // Task1 任务 1 /************************************************************************************ ** Function name: main ** Descriptions: ** Input: 主函数 无 ** Output: 系统返回值 0 ************************************************************************************/ int main (void) { OSInit (); OSTaskCreate (Task0,(void *)0, &Task0Stk[Task0StkLengh - 1], 2); - 138 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com OSTaskCreate (Task1,(void *)0, &Task1Stk[Task1StkLengh - 1], 3); OSStart (); return 0; } /************************************************************************************ ** Function name: Task0 ** Descriptions: 读取按键 KEY1 状态 ************************************************************************************/ void Task0 (void *pdata) { pdata = pdata; TargetInit (); // 初始化 I/O rGPFCON = (rGPFCON & (~(0x03<<8))); // rGPFCON[9:8] = 00b, // 设置 GPF4 为 GPIO 输入模式 rGPHCON = (rGPHCON & (~(0x03<<20))) // rGPHCON[21:20] = 01b, | (0x01<<20); // 设置 GPH10 为 GPIO 输出模式 while (1) { if(rGPFDAT & KEY_CON) // 读取 GPF 口线上的电平,判断 GPF4 是否为高电平 { KeyState = FALSE; } else { OSTimeDly(OS_TICKS_PER_SEC/10); if(rGPFDAT & KEY_CON) // 防抖动 { KeyState = FALSE; } else { KeyState = TRUE; } } OSTimeDly(OS_TICKS_PER_SEC/10); } } /************************************************************************************ ** Function name: Task1 - 139 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com ** Descriptions: 等待按键,控制蜂鸣器响 ************************************************************************************/ void Task1 (void *pdata) { pdata = pdata; while (1) { if(TRUE == KeyState) // 如果有按键按下,则蜂鸣 { RunBeep(); } OSTimeDly(OS_TICKS_PER_SEC/10); } } /************************************************************************************ ** Function name: RunBeep ** Descriptions: 控制蜂鸣器 Be 一声音。 ** Input: 无 ** Output: 无 ************************************************************************************/ void RunBeep(void) { rGPHDAT = rGPHDAT & BEEP_MASK; // BEEP = 0 OSTimeDly(OS_TICKS_PER_SEC/10); rGPHDAT = rGPHDAT | BEEP; // BEEP = 1 OSTimeDly(OS_TICKS_PER_SEC/10); } 8. 思考 是否可以通过μC/OS-II 操作系统的事件标志组实现标志的信息传递? 3.3 串行通信实验 1. 实验目的 掌握μC/OS-II 操作系统的信号量的概念。 2. 实验设备 硬件:PC 机 一台 MagicARM2410 教学实验开发平台 一套 软件:Windows98/XP/2000 系统,ADS 1.2 集成开发环境 - 140 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 超级终端程序(Windows 系统自带) 3. 实验内容 实验通过信号量控制 2 个任务共享串口 0 打印字符串。为了使每个任务的字符串信息(句 子)不被打断,因此必须引入互斥信号量的概念,即每个任务输出时必须独占串口 0,直到 完整输出字符串信息才释放串口 0。 4. 实验预习要求 (1)仔细阅读参考文献[5],了解μC/OS-II 的信号量的概念。 (2)仔细阅读参考文献[2]关于 S3C2410A 的 UART 模块说明。 (3)仔细阅读产品配套光盘附带文档“ADS 集成开发环境及 JTAG 仿真器应用.pdf” 或其它 ADS 相关资料,了解 ADS 1.2 集成开发环境、DeviceARM2410 专用工程模板、 EasyJTAG-H 仿真器的应用。 5. 实验原理 在本范例中直接使用模板的 UART 通信驱动,关于 UART 的说明清参考 3.11 节的内容。 程序首先建立一个互斥信号量,对于任务 0,当需要控制串口时向操作系统申请串口 0 信号 量,如果申请不成功则一直等待;若获得串口 0 的信号量并操作完成后,应当释放串口 0 的信号量。对于任务 1 也遵照以上规则操作串口 0。 6. 实验步骤 (1)为 ADS1.2 增加 DeviceARM2410 专用工程模板(若已增加过,此步省略)。 (2)连接 EasyJTAG-H 仿真器和 MagicARM2410 实验箱,然后安装 EasyJTAG-H 仿真 器(若已经安装过,此步省略),短接蜂鸣器跳线 JP9。 (3)启动 ADS 1.2,使用 ARM Executable Image for DeviceARM2410(uCOSII)工程模板 建立一个工程 UART0_uCOSII。(本范例在 ADS 文件夹中操作) (4)见图 3.2,在 ADS 文件夹中新建 arm、Arm_Pc、SOURCE 文件夹。将 µC/OS 2.52 源代码添加到 SOURCE 文件夹,将移植代码添加到 arm 文件夹,将移植的 PC 服务代码添 加到 Arm_Pc 文件夹。(移植代码可以在 DeviceARM2410 光盘上获得,µC/OS 2.52 源代码需 要从参考文献[5]的光盘上获得) (5)在 src 组中的 main.c 中编写主程序代码。 (6)选用 DebugRel 生成目标,然后编译链接工程。 (7)将 MagicARM2410 实验箱上的 UART0 连接跳线 JP1 短接,使用串口延长线把 MagicARM2410 实验箱的 CZ11 与 PC 机的 COM1 连接。 注意:CZ11 安装在 MagicARM2410 实验箱的机箱右侧。 (8)PC 机上运行“超级终端”程序(在 Windows 操作系统的【开始】->【程序】->【附 件】->【通讯】->【超级终端】),新建一个连接,设置串口波持率为 115200,具体设置参 考图 3.5,确定后即进入通信状态。 - 141 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 图 3.5 “超级终端”的端口设置 (9)选择【Project】->【Debug】,启动 AXD 进行 JTAG 仿真调试。 (10)全速运行程序,程序将会在 main.c 的主函数中停止(因为 main 函数起始处默认设 置有断点)。 (11)可以单步运行程序,可以设置/取消断点,或者全速运行程序,停止程序运行, 在超级终端上观察任务 0 和任务 1 的打印结果。 7. 实验参考程序 串行通信实验的参考程序见程序清单 3.9。 程序清单 3.9 串行通信实验参考程序 #include "config.h" #define Task0StkLengh 64 #define Task1StkLengh 64 // Define the Task0 stack length 定义用户任务 0 的堆栈长度 // Define the Task1 stack length 定义用户任务 1 的堆栈长度 OS_STK Task0Stk [Task0StkLengh]; OS_STK Task1Stk [Task1StkLengh]; // Define the Task0 stack 定义用户任务 0 的堆栈 // Define the Task1 stack 定义用户任务 1 的堆栈 OS_EVENT *UART0_Sem; void Task0(void *pdata); void Task1(void *pdata); // Task0 任务 0 // Task1 任务 1 - 142 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com /************************************************************************************ ** Function name: main ** Descriptions: 主函数 ** Input: 无 ** Output: 系统返回值 0 ************************************************************************************/ int main (void) { OSInit (); OSTaskCreate (Task0,(void *)0, &Task0Stk[Task0StkLengh - 1], 2); OSTaskCreate (Task1,(void *)0, &Task1Stk[Task1StkLengh - 1], 3); UART0_Sem = OSSemCreate(1); OSStart (); return 0; } /************************************************************************************ ** Function name: Task0 ** Descriptions: 从 UART0 输出字符串"Task0 is running!" ************************************************************************************/ void Task0 (void *pdata) { uint8 err; pdata = pdata; TargetInit (); while (1) { OSSemPend(UART0_Sem, 0, &err); UART_SendStr("Task0 is running!\r\n"); OSTimeDly(OS_TICKS_PER_SEC); OSSemPost(UART0_Sem); } } /************************************************************************************ ** Function name: Task1 ** Descriptions: 从 UART0 输出字符串"Task1 is running!" ************************************************************************************/ void Task1 (void *pdata) { uint8 err; pdata = pdata; - 143 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com while (1) { OSSemPend(UART0_Sem, 0, &err); UART_SendStr("Task1 is running!\r\n"); OSTimeDly(OS_TICKS_PER_SEC); OSSemPost(UART0_Sem); } } 8. 思考 如果任务 0 注释(删除)语句“OSSemPost(UART0_Sem);”,那么程序还能完全正常无 误运行么?如果发生异常会出现什么现象? 3.4 图形液晶控制实验 1. 实验目的 (1)掌握图形液晶的绘点函数的使用。 (2)掌握μC/OS-II 操作系统的事件标志组的概念。 2. 实验设备 硬件:PC 机 一台 MagicARM2410 教学实验开发平台 一套 软件:Windows98/XP/2000 系统,ADS 1.2 集成开发环境 3. 实验内容 使用事件标志触发 LCD 的刷屏动作。1 个任务负责检测 KEY1 的状态,如果按键有效, 那么将键盘事件标志置位,否则清除;另一个任务一直等待键盘事件标志的置位触发,标志 置位后,用一个随机的颜色将整个液晶屏幕刷新。 4. 实验预习要求 (1)仔细阅读参考文献[5],了解μC/OS-II 的事件标志组的概念。 (2)仔细阅读产品配套光盘附带文档“ADS 集成开发环境及 JTAG 仿真器应用.pdf” 或其它 ADS 相关资料,了解 ADS 1.2 集成开发环境、DeviceARM2410 专用工程模板、 EasyJTAG-H 仿真器的应用。 5. 实验原理 实验通过键盘事件标志触发 LCD 的刷屏动作。任务 0 负责检测 KEY1 的状态,如果按 键有效,那么将键盘事件标志置位,否则清除;任务 1 一直等待键盘事件标志的置位触发, 标志置位后,任务 1 将一个随机的颜色将整个屏幕刷新。 - 144 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 6. 实验步骤 (1)为 ADS1.2 增加 DeviceARM2410 专用工程模板(若已增加过,此步省略)。 (2)连接 EasyJTAG-H 仿真器和 MagicARM2410 实验箱,然后安装 EasyJTAG-H 仿真 器(若已经安装过,此步省略),短接蜂鸣器跳线 JP9。 (3)启动 ADS 1.2,使用 ARM Executable Image for DeviceARM2410(uCOSII)工程模板 建立一个工程 LCD_uCOSII。(本范例在 ADS 文件夹中操作) (4)见图 3.2,在 ADS 文件夹中新建 arm、Arm_Pc、SOURCE 文件夹。将 µC/OS 2.52 源代码添加到 SOURCE 文件夹,将移植代码添加到 arm 文件夹,将移植的 PC 服务代码添 加到 Arm_Pc 文件夹。(移植代码可以在 DeviceARM2410 光盘上获得,µC/OS 2.52 源代码需 要从参考文献[5]的光盘上获得) (5)在 src 组中的 main.c 中编写主程序代码。 (6)选用 DebugRel 生成目标,然后编译链接工程。 (7)将 MagicARM2410 实验箱上的蜂鸣器跳线 JP9 短接,将启动方式选择跳线 JP8 短 接,然后按 RST 键复位系统。 (10)选择【Project】->【Debug】,启动 AXD 进行 JTAG 仿真调试。 (11)全速运行程序,程序将会在 main.c 的主函数中停止(因为 main 函数起始处默认设 置有断点)。 (12)单击 Context Variable 图标按钮(或者选择【Processor Views】->【Variables】)打 开变量观察窗口,通过此窗口可以观察局部变量和全局变量。 (13)可以单步运行程序,可以设置/取消断点,或者全速运行程序,停止程序运行, 观察变量的值,按下 KEY1,观察 LCD 是否出现刷屏。 7. 实验参考程序 图形液晶的参考程序见程序清单 3.10。 程序清单 3.10 图形液晶实验参考程序 #include "config.h" #define Task0StkLengh 64 #define Task1StkLengh 64 // Define the Task0 stack length 定义用户任务 0 的堆栈长度 // Define the Task1 stack length 定义用户任务 1 的堆栈长度 OS_STK Task0Stk [Task0StkLengh]; OS_STK Task1Stk [Task1StkLengh]; // Define the Task0 stack 定义用户任务 0 的堆栈 // Define the Task1 stack 定义用户任务 1 的堆栈 // 定义独立按键 KEY1 的输入口 #define KEY_CON (1<<4) // GPF4 口 // 定义按键状态事件组 OS_FLAG_GRP *KeyStatus; #define KEY_PRESS 0x01 void Task0(void *pdata); void Task1(void *pdata); // Task0 任务 0 // Task1 任务 1 - 145 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com /************************************************************************************ ** Function name: main ** Descriptions: 主函数,uCOS/II 移植实验范例 ** Input: ** Output: 无 系统返回值 0 ************************************************************************************/ int main (void) { uint8 err; OSInit (); OSTaskCreate (Task0,(void *)0, &Task0Stk[Task0StkLengh - 1], 2); OSTaskCreate (Task1,(void *)0, &Task1Stk[Task1StkLengh - 1], 3); KeyStatus = OSFlagCreate(0x00, &err); OSStart (); return 0; } /************************************************************************************ ** Function name: Task0 ** Descriptions: 读取按键 KEY1 状态 ************************************************************************************/ void Task0 (void *pdata) { uint8 err; pdata = pdata; TargetInit (); // 初始化 I/O rGPFCON = (rGPFCON & (~(0x03<<8))); // rGPFCON[9:8] = 00b,设置 GPF4 为 GPIO 输入模式 while (1) { if(rGPFDAT & KEY_CON) // 读取 GPF 口线上的电平,判断 GPF4 是否为高电平 { OSFlagPost(KeyStatus, KEY_PRESS, OS_FLAG_CLR, &err); } else { OSTimeDly(OS_TICKS_PER_SEC/10); if(rGPFDAT & KEY_CON) // 防抖动 { OSFlagPost(KeyStatus, KEY_PRESS, OS_FLAG_CLR, &err); } else - 146 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com { OSFlagPost(KeyStatus, KEY_PRESS, OS_FLAG_SET, &err); } } OSTimeDly(OS_TICKS_PER_SEC/10); } } /************************************************************************************ ** Function name: Task1 ** Descriptions: 填充液晶屏幕 ************************************************************************************/ void Task1 (void *pdata) { uint8 err; uint16 Color; uint32 i, j; pdata = pdata; while (1) { OSFlagPend( KeyStatus, // 等待按键的时间标志 KEY_PRESS, OS_FLAG_WAIT_SET_ANY, 0, // 一直等待 &err ); Color = rand(); for(i=0; iNetwork,打开网络配置 界面,如图 4.5 所示。 图 4.5 RedHat Linux 网络配置界面 双击 eth0,在弹出的界面进行具体的网络设置,如 IP 地址、子网掩码和网关等信息, 如图 4.6 所示。不同局域网的设置不一样,详细的网络设置请参考 RedHat Linux 操作系统 的使用教材。所示设定主机服务器 IP 地址为 192.168.0.94。 图 4.6 网络设置 (2)关闭防火墙 由于 RedHat Linux 默认安装时启动了防火墙,它将拒绝其它所有外来 IP 对它的访问。 - 163 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 要使用 NFS 服务,必须将防火墙关闭。从 RedHat Linux 的 Main Menu 菜单,选择 System Settings->Security Level,打开 RedHat Linux 安全级别设置界面,将其安全级别设置为 No Firewall,如图 4.7 所示。 图 4.7 关闭防火墙 (3)去掉 iptables 服务 从 RedHat Linux 的 Main Menu 菜单,选择 System Settings->Server Settings->Services, 在弹出的界面中,将 iptables、ip6tables 和 ipchains 前面的“√”去掉,如图 4.8 所示。 图 4.8 去掉 iptables 服务 (4)启动 NFS 服务 如果用户在安装 RedHat Linux 9.0 的时候选择了 Everything,则从 Linux 的 Main Menu 菜单,选择 System Settings->Server Settings,在其下一级将会有 NFS Server 的子菜单,如 图 4.9 所示。选择点击,将会弹出如图 4.10 所示的界面。 - 164 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 如果不是完全安装,则可能没有 NFS Server 子菜单,那样的话,请插入 RedHat Linux 的光盘,安装 NFS 服务器。 图 4.9 NFS 服务器菜单 图 4.10 NFS 服务器配置 点击 Add 按钮,将会弹出如图 4.11 所示的界面。在相应栏分别填入共享目录以及可以 访问该共享目录的主机的 IP。 图 4.11 设置 NFS 共享目录 - 165 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 示例中设置主机 IP 为“192.168.*.*”,表示处于网段 192.168.X.X 的主机均可对共享目 录/zylinux/root 进行访问。 至于一些权限,如“读/写”等,可以根据需要进行设置。设置后的文件保存在/etc/exports 文件中。用户亦可直接修改该文件进行共享设置。 /zylinux/root 192.168.*.*(rw, sync) 测试 NFS 是否设置成功。可以将主机上的共享目录 mount 到自己另外一个目录下,如 # mount 192.168.41.42:/zylinux/root /mnt 然后查看/mnt 目录下是否有/zylinux/root 目录下的文件,如果有的话,则 NFS 服务启动 成功。 提示:如果 NFS 启动不成功,在/etc/rc.local 文件末尾添加命令,让每次开机即启动 NFS 服务。 service portmap start service nfs start 至此,宿主机嵌入式开发环境已经建立完毕,环境设置如下: 交叉编译器路径: /usr/local/arm/2.95.3 嵌入式 Linux 安装路径: /zylinux/kernel NFS 根文件系统所在路径:/zylinux/root 宿主机 IP 地址: 192.168.0.94 4.3 构建嵌入式 Linux 目标平台 本节介绍以 ZLG/BOOT 作为 Bootloader、以 RAMDISK 作为根文件系统的嵌入式 Linux 系统目标平台的构建。 4.3.1 相关文件 ZLG/BOOT 是引导程序,在 SST39VF1601 中运行。Linux 内核和文件系统全部在 NAND FLASH 中,包含的文件较多,同时还有特定的目录结构,下面进行简要介绍。 ftp root 目录下包含 bin、boot、etc 和 root 等文件夹以及 zlg_ftp.ini、modules.tar 等文件, 所有文件都要下载到 NAND FLASH 中,在整个 Linux 系统中为/usr 目录。 表 4.1 相关文件 文件夹 bin boot 包含文件 zlg_ftp.ini modules.tar dm9000.ko init.img param.bin qtopia zImage zlg_boot.ini 说明 Ftp 下载设置 一些模块驱动 网卡芯片 DM9000E 驱动程序 RAMDISK 映象文件 Linux 启动参数 Qt 和 Qtopia 映象 Linux 内核映象 ZLG/BOOT 设置 - 166 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 文件夹 etc Rc root 包含文件 续表 4.1 说明 Linux 启动脚本(/usr/etc/rc) /root 链接的目标目录 zlg_ftp.ini 文件影响 ftp 更新系统时的设置,zlg_boot.ini 文件影响 ZLG/BOOT 的启动和 运行状况。这 2 个文件都是可编辑文件,下面对它们的内容进行简要介绍。 (1)zlg_ftp.ini zlg_ftp.ini 文件决定使用 ftp 对系统进行更新下载时实验箱的 IP 地址、网关、掩码地址 和 MAC 地址的设定。如果系统中有该文件,则 ZLG/BOOT 下载模式的选项 1:run ZLG/FTP-S V1.0 ( user ip)生效,该文件设定的 IP 就是 user ip。 IP=192.168.15.15 GateWay=192.168.0.1 用户 IP:user ip IPMark=255.255.255.0 MacID=0x00,0x14,0x97,0x0f,0x00,0x41 (2)zlg_boot.ini zlg_boot.ini 决定着 ZLG/BOOT 下载模式的选择菜单选项 3 的名称和 ZLG/BOOT 加载映 象文件的顺序和一些其它设置。 #run Linux for MagicARM2410 (1) load 0x30008000 a:\boot\zImage 下载模式选项 3 名称 (2) load 0x30000100 a:\boot\param.bin (3) load 0x33C00000 a:\boot\init.img (4) set R0=0x00 (5) #mach type, s3c2410 is 193 (6) set R1=0xC1 (7) set R2=0x30000100 (8) set PC=0x30008000 (9) run (10) 其中: (1)设置下载模式选择菜单选项 3 的名称为“run Linux For MagicARM2410”; (2)装载 Linux 内核文件 zImage 到 0x30008000 开始的空间; (3)装载 Linux 启动参数 param.bin 到 0x30000100 开始的空间; (4)装载文件系统映象 init.img 到 0x33C00000 开始的空间; (5)设置 R0 为 0,Linux Bootloader 所要求; (6)行(7)的注释; (7)传递机器型号(芯片)的代码,S3C2410 的代码为 193(0xC1); (8)传递 Linux 启动参数所在空间地址给 R2; (9)设置 PC 为 Linux 内核所在空间开始地址; (10)运行,从 PC 处开始运行,即开始运行 Linux 内核。 - 167 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 4.3.2 下载 Bootloader 使用 EasyJTAG-H 将 ZLG/BOOT 下载到 SST39VF1601 中。 需要 ADS1.2 软件、基于 ADS 的 WR_NORFLASH.mcp 工程、H-JTAG 软件和 EasyJTAG-H 下载器。 (1)下载 ZLG/BOOT 跳线设置:断开 BOOT-SEL 跳线 JP8,短接蜂鸣器跳线 JP9。 将 EasyJTAG-H 和实验箱相连,运行 H-JTAG,打开 WR_NORFLASH.mcp 工程,选择 DebugRel 生成目标,进入 AXD 调试环境。在语句 while(1)处设置断点,然后全速运行程序, 或者将光标放置在 while(1)处后运行到此处。程序停止后,如果蜂鸣器鸣叫一声则表示已经 正确将 ZLG/BOOT 下载到 SST39VF1601 中,然后后将实验箱断电即可;如果蜂鸣器连续鸣 叫则表示下载出错,需要重新下载。下载完毕,将 EasyJTAG-H 拔掉,以便启动系统。 (2)启动 ZLG/BOOT 设置串口终端(115200-8-N-1,无流控制)。将 PC 串口和实验箱右侧的 UART0 相连, 然后启动实验箱,将会得到如下输出信息。 ZLG/BOOT V1.0 for MagicARM2410 Guangzhou ZHIYUAN Electronics Co.,LTD. http://www.zyinside.com Press "Space" key to enter Boot Menu. ZLG/BOOT 包含两种模式:启动加载模式和下载模式。 根据提示,按空格键,将进入 ZLG/BOOT 的下载模式。在没有下载内核和文件系统的 情况下,下载模式输出如下信息: ZLG/BOOT V1.0 for MagicARM2410 Guangzhou ZHIYUAN Electronics Co.,LTD. http://www.zyinside.com Chiose Function: 1: run ZLG/FTP-S V1.0 ( user ip) 2: run ZLG/FTP-S V1.0 (ip = 192.168.15.115) F: Format Disk default choise is 3 有 3 个功能选择项:1――使用用户 IP 进行 ftp 下载;2――使用默认 IP(192.168.15.115) 进行 ftp 下载;F――格式化 NAND FLASH。从键盘输入相应的字符将选择相应的功能。 4.3.3 下载 Linux 内核和文件系统 使用 ftp 方式将 Linux 内核和映象文件下载到 NAND FLASH 中。 需要 FlashFXP 软件、Linux 内核和文件系统映象文件。 - 168 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com (1)相关准备工作 如果没有安装 FlashFXP 软件,请先安装。另外,由于进行 ftp 下载默认 IP 为 192.168.15.115,为了保证能正常下载,需要对 PC 的网络设置进行更改。打开“本地连接” 的属性,设置“Internet 协议(TCP/IP)”的属性,在界面点击“高级(V)”按钮,打开“高级 TCP/IP 设置”界面,如图 4.12 所示。 图 4.12 高级 TCP/IP 设置 点击“添加(A)…”按钮,在“IP 地址(R)”栏添加和默认 IP 192.168.15.115 在同一 IP 段的 IP 地址,如 192.168.15.41,掩码地址 255.255.255.0。 (2)下载内核和文件系统 将网线接到实验箱以太网接口 CZ8,启动 ZLG/BOOT,进入下载模式,选择 2,使用默 认 IP 192.168.15.115 进行 ftp 下载。如果需要对 NAND FLASH 进行格式化,则先格式化。 运行 FlashFXP 软件,选择“FTP”-->“快速连接(Q)”或者按 F8,打开快速连接界面, 在“服务器或 URL”栏输入 IP 地址 192.168.15.115,设置端口号为 21,如图 4.13 所示。 图 4.13 快速连接设置 - 169 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 点击“连接”后,将开始 ftp 连接,连接成功后,ftp root 文件夹下所有文件(Linux 内 核和文件系统以及其它文件)全部下载到实验箱的 NAND FLASH 中。 4.3.4 启动 Linux 操作系统 复位实验箱,ZLG/BOOT 默认进入启动加载模式,引导 Linux 系统启动。 ZLG/BOOT V1.0 for MagicARM2410 Guangzhou ZHIYUAN Electronics Co.,LTD. http://www.zyinside.com Press "Space" key to enter Boot Menu. Start run Linux for MagicARM2410 Uncompressing Linux................................................... done, booting the kernel. Linux version 2.4.18-rmk7-pxa1 (root@linuxserver) (gcc version 2.95.3 20010315 (release)) 如果在 ZLG/BOOT 界面按下空格键,将进入 ZLG/BOOT 的下载模式界面。 ZLG/BOOT V1.0 for MagicARM2410 Guangzhou ZHIYUAN Electronics Co.,LTD. http://www.zyinside.com Chiose Function: 1: run ZLG/FTP-S V1.0 ( user ip) 2: run ZLG/FTP-S V1.0 (ip = 192.168.15.115) 3: run Linux for MagicARM2410 F: Format Disk default choise is 3 可以看到,在选择菜单中出现了选项 3:run Linux for MagicARM2410。选择 3 或者按 回车键亦可引导 Linux 系统启动。在串口终端和实验箱液晶屏都可以看到 Linux 的启动信息。 启动完毕在串口终端可得到如图 4.14 所示的界面,在液晶屏上可看到预装的 Qtopia 界面。 - 170 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 图 4.14 Linux 文本界面 4.4 Linux 启动参数的设定方法 4.4.1 ZLG/BOOT 的运行过程 Linux 内核通常都在 RAM 中运行,这就需要 Linux 的 BootLoader 将整个内核复制到 RAM 中。在 MagicARM2410 实验箱上,ZLG/BOOT 就是 Linux 的 BootLoader,ZLG/BOOT 运行于 NorFlash 中,它的主要工作是:将 Linux 内核文件、根文件系统文件、Linux 启动参 数文件的内容复制到 SDRAM(以下简称 RAM)中,并跳至 RAM 中 Linux 内核的首地址, 开始运行 Linux。 以上各个文件在 RAM 中的存放空间示意图如图 4.15 所示。 启动参数 Linux内核 其它内存空间 根文件系统文件 图 4.15 Linux 内核及相关文件在 RAM 中的存放位置示意图 具体将哪个文件复制到 RAM 中的哪个地址中,是由在 zlg_boot.ini 文件指定的,该文 件的内容如程序清单 4.2 所示。 程序清单 4.2 zlg_boot.ini 文件内容 #run Linux for MagicARM2410 load 0x30008000 a:\boot\zImage (1) load 0x30000100 a:\boot\param.bin (2) load 0x33C00000 a:\boot\init.img (3) set R0=0x00 (4) #mach type, s3c2410 is 193 set R1=0xC1 (5) set R2=0x30000100 (6) - 171 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com set PC=0x30008000 (7) run 当 MagicARM2410 上电复位后,NorFlash 中的 ZLG/BOOT 开始运行,它首先读取 zlg_boot.ini 文件的内容,按照程序清单 4.2 (1) ~ 程序清单 4.2 (3),分别进行以下复制工作: (1) Linux 内核文件 zImage 复制到起始地址为 0x30008000 的 RAM 中; (2) 内核启动参数文件 param.bin 复制到起始地址为 0x30000100 的 RAM 中; (3) 根文件系统文件 init.img 复制到起始地址为 0x33C00000 的 RAM 中。 这样,各个文件在 RAM 中的分布状态就如图 4.15 所示了。 完成以上工作后,ZLG/BOOT 依据 zlg_boot.ini 内容的指示,将 S3C2410A 的寄存器 R0 置为 0、 将 R1 置为 S3C2410A 在 Linux 中的机器号,在 R2 存放 Linux 启动参数在 RAM 中 的首地址(如程序清单 4.2 (4) ~ 程序清单 4.2 (6)所示)。最后,置 PC 值为 Linux 内核在 RAM 中的首地址,也就是跳至 Linux 内核所在的地址,开始运行内核。这时,ZLG/BOOT 的工 作完成,将控制权完全交给 Linux 内核。 4.4.2 Linux 启动参数的含义 以上过程涉及到 Linux 的启动参数文件,那么该文件的内容是什么?又如何修改该文件 以满足我们的实际需要呢? 该启动参数文件用于设定 Linux 运行的一些参数,例如:设置 Linux 控制台为 ttyS0; 设置 RAMDisk 根文件系统的起始地址及大小等等。当然,Linux 的启动参数的格式是有规 范的,这样才能被 Linux 所识别。Linux 的启动参数为一个结构体,该结构体的定义在 Linux 内核源代码的 include\asm-arm\setup.h 文件中定义,如程序清单 4.3 所示。 程序清单 4.3 param_struct 结构体 struct param_struct { union { struct { unsigned long page_size; unsigned long nr_pages; unsigned long ramdisk_size; unsigned long flags; #define FLAG_READONLY 1 #define FLAG_RDLOAD 4 #define FLAG_RDPROMPT 8 unsigned long rootdev; unsigned long video_num_cols; unsigned long video_num_rows; unsigned long video_x; unsigned long video_y; unsigned long memc_control_reg; unsigned char sounddefault; unsigned char adfsdrives; unsigned char bytes_per_char_h; unsigned char bytes_per_char_v; unsigned long pages_in_bank[4]; /* 0 */ /* 4 */ /* 8 */ /* 12 */ /* 16 */ /* 20 */ /* 24 */ /* 28 */ /* 32 */ /* 36 */ /* 40 */ /* 41 */ /* 42 */ /* 43 */ /* 44 */ - 172 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com unsigned long pages_in_vram; /* 60 */ unsigned long initrd_start; /* 64 */ unsigned long initrd_size; /* 68 */ unsigned long rd_start; /* 72 */ unsigned long system_rev; /* 76 */ unsigned long system_serial_low; /* 80 */ unsigned long system_serial_high; /* 84 */ unsigned long mem_fclk_21285; /* 88 */ } s; char unused[256]; } u1; union { char paths[8][128]; struct { unsigned long magic; char n[1024 - sizeof(unsigned long)]; } s; } u2; char commandline[COMMAND_LINE_SIZE]; }; 该结构体各变量的含义请见 Linux 内核源代码中的 Documentation/arm/Setup 文件的详细 说明。 启动参数文件 param.bin,就是给该结构体各变量赋值后形成的一个文件,它的制作过 程如图 4.16 所示。Linux 内核运行后,Linux 内核就会自动到如图 4.15 中所示的“启动参 数”区读取这些启动参数,完成 Linux 的启动工作。这就达到了由 BootLoader 传递参数给 Linux 内核的目的。 struct param_struct{ } 形成 下载到RAM中 param.bin文件 RAM中的启动参数 图 4.16 启动参数的形成过程 4.4.3 Linux 启动参数文件的制作 param.bin 是一个二进制文件,用户无法编辑,为了方便用户设定启动参数,可以使用 广州致远电子有限公司提供的启动参数制作软件 LinuxParam.exe。在 Windows98/2000/XP 下,双击该文件即可运行(不要在光盘中运行本软件),其界面如图 4.17 所示。 - 173 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 图 4.17 制作 Linux 启动参数文件软件界面 如图 4.17 所示,只需在本软件的对话框中填入 struct param_struct 结构体各个成员变量 的值,然后按“生成 param.bin 文件”,即可在本软件所在的目录生成一个 param.bin 文件。 下面说明图 4.17 所示中一些常用成员变量的含义: (1) page_size:Linux 操作系统的内存页大小,通常为 4KB。 (2) nr_pages:物理内存的页数。在 MagicARM2410 上,外部 SDRAM 大小为 64MB, 所以,实际物理内存的页数为:16384 页,即存在这样的关系 4KB x 16384 = 64MB。 (3) initrd_start:RAM Disk(即根文件系统 init.img)在虚拟内存中的起始地址。由于在 S3C2410 上,Linux 内核所在的虚拟地址为 0xC000 0000,RAM Disk 的大小为 4MB, RAM Disk 一般存放在物理内存的末端。所以 RAM Disk 在虚拟内存中的地址为: 0xC000 0000 + 0x3C0 0000(即 60MB) = 0xC3C0 0000 = 3284140032。 (4) initrd_size:RAM Disk 的大小。这 MagicARM2410 上,RAM Disk 的大小为 4MB, 所以该成员变量的值为:4194304。用户也可以制作自己的 RAMDisk,具体方法见 第 6.2 小节。 (5) commandline:Linux 命令行。用于告诉 Linux 以下信息:根文件系统的的类型(此 处为 RAM Disk)、RAM Disk 的大小(此处为 4096KB)、控制台类型。在这里, console=tty0 表示控制台为液晶显示器,console=ttyS0,115200N8 表示控制台为串口 0,而且波特率为 115200,数据宽度为 8Bit。也就是使能了两个控制台:液晶和串 口 0。如果用户不需要在液晶屏上显示 Linux 启动信息及其它驱动程序打印出来的 信息,可将“console=tty0”去除。 struct param_struct 结构体中其它成员变量的值通常用户都无须设置,所以可不必理会, 如果用户确实需要设置这些值,在图 4.17 中按“设置其它参数”按键,在弹出的对话框中 进行其它参数的设置,这些参数的含义请用户自己阅读 struct param_struct 结构体的说明, 这里不再阐述。 - 174 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 第5章 Linux 应用程序编写 5.1 HelloWorld 程序实验 1. 实验目的 (1)熟悉 Linux 应用程序编程; (2)掌握 Makefile 文件编写; (3)掌握基于 NFS 的 Linux 应用程序调试方法。 2. 实验设备 (1)硬件:PC 机 MagicARM2410 教学实验开发平台 (2)软件:RedHat Linux 9.0 操作系统 嵌入式 Linux 开发环境 一台 一套 3. 实验内容 (1)编写一个简单的 HelloWorld 程序; (2)编写/修改相应的 Makefile 文件; (3)使用 NFS 方式调试 HelloWorld 程序。 4. 实验预习要求 (1)熟悉 Linux 基本操作; (2)熟悉嵌入式 Linux 开发环境。 5. 实验原理 通过网络文件系统(NFS)将宿主机(即 PC 机端的 Linux)的 NFS 共享目录 mount 到 ARM Linux 上后,可以当作本地存储器进行操作。 6. 实验步骤 (1)启动 PC 机端的 Linux 终端或者进入 Linux 虚拟控制台,在主机上为应用程序实验 建立工作目录/zylinux/armwork,并将该目录添加到主机 NFS 服务器中。 $ mkdir /zylinux/armwork 说明:/zylinux/armwork 目录是所有 Linux 实验的工作目录。 (2)在实验工作目录下,为 HelloWorld 实验建立工作目录 hello。 $ cd /zylinux/armwork $ mkdir hello (3)进入 hello 目录,使用自己熟悉的编辑器(如 vi)建立文件 hello.c,并编写如程序 清单 5.1 所示的程序代码。 - 175 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com (4)将光盘相应工程的 Makefile 文件复制到当前目录下,使用编辑器将其打开,并对 Makefile 文件进行如下修改保存,退出编辑器。 EXEC = hello OBJS = hello.o SRC = hello.c (5)输入 make 命令,对程序进行编译,编译完毕在当前目录下会生成可执行文件 hello。 $ make (6)启动 ARM Linux。将实验箱串口 0 和 PC 主机串口相连,同时将网线插入实验箱 网卡,将实验箱接入以太网。在 PC 端打开 minicom 或者超级终端,并进行正确设置 (115200-8-N-1,无流控制)。启动 ARM Linux,并根据实验指导老师的安排,修改实验箱 的 IP 地址(掉电后恢复默认值)。 # ifconfig eth0 192.168.x.x (示例) 注:后续的实验假定已经设定了 IP 地址和 MAC 地址,不存在 IP 冲突。 (7)进行 NFS 连接,将主机 NFS 共享目录的/zylinux/armwork 目录 mount 到 ARM Linux 的/mnt 目录下。 # mount –t nfs 192.168.0.94:/zylinux/armwork /mnt –o nolock (8)进入/mnt/hello 目录,执行 hello 程序,观察终端是否有 HelloWorld 字符串输出。 # ./hello 说明:“$”开始的命令为在 PC 主机输入的命令; “#”开始的命令为在实验箱端输入的命令。除非特殊说明,下同。 7. 实验程序 程序很简单,就是往终端输出“HelloWorld!”字符串。程序如程序清单 5.1 所示。 程序清单 5.1 HelloWorld 程序 #include /* ******************************************************************************************** ** Function name: main() ** Descriptions : printf "HelloWorld" on srceen. ******************************************************************************************** */ int main(int argc, char **argv) { int i; for (i=0; i<5; i++) { - 176 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com printf("HelloWorld!\n"); } return 0; } 8. Makefile 文件 Makefile 用于管理整个工程。HelloWorld 程序的 Makefile 文件如程序清单 5.2 所示。 程序清单 5.2 HelloWorld 的 Makefile 文件 EXEC = hello (1) OBJS = hello.o (2) SRC = hello.c (3) CC = arm-linux-gcc (4) CFLAGS += -O2 –Wall (5) LDFLAGS += (6) all:$(EXEC) (7) $(EXEC):$(OBJS) (8) $(CC) $(LDFLAGS) -o $@ $(OBJS) (9) %.o:%.c (10) $(CC) $(CFLAGS) -c $< -o $@ (11) clean: (12) @rm -vf $(EXEC) *.o *~ (13) 该 Makefile 中,定义了 3 个变量: (1) EXEC:最终生成的可执行文件,需要根据应用进行修改; (2) OBJS:生成的目标文件,需要根据应用进行修改(必须和源文件同名,不包括后缀); (3) SRC:源文件,需要根据应用进行修改。 使用了一些自动变量: (4) CC:指定了编译器为交叉编译器 arm-linux-gcc; (5) CFLAGS:指定编译参数为-O2 –Wall; (6) LDFLAGS:指定链接参数。 后续实验的 Makefile 文件都和这个文件类似,一般情况下仅需修改(1)~(3)行代码即可。 关于 Makefile 文件和编写的详细信息请参考相关资料。 9. 思考 (1)使用 NFS 进行 Linux 应用程序调试,需要哪些基本条件?需要注意哪些问题? (2)重新编写一个 Makefile 文件。 - 177 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 5.2 Linux 定时器实验 1. 实验目的 (1)熟悉 Linux 定时器的使用; (2)巩固基于 NFS 的 Linux 应用程序调试方法。 2. 实验设备 硬件: 软件: PC 机 MagicARM2410 教学实验开发平台 RedHat Linux 9.0 操作系统 嵌入式 Linux 开发环境 一台 一套 3. 实验内容 使用 Linux 定时器进行定时,定时值到后发出提示信息。 4. 实验预习要求 (1)熟悉 Makefile 文件编写; (2)熟悉 NFS 方式调试 Linux 应用程序; (3)熟悉 Linux 定时器。 5. 实验原理 Linux 为每个任务安排了 3 个内部定时器: ITIMER_REAL:实时定时器,不管进程在何种模式下运行(甚至在进程被挂起时), 它总在计数。定时到达,向进程发送 SIGALRM 信号。 ITIMER_VIRTUAL:这个不是实时定时器,当进程在用户模式(即程序执行时) 计算进程执行的时间。定时到达后向该进程发送 SIGVTALRM 信号。 ITIMER_PROF:进程在用户模式(即程序执行时)和核心模式(即进程调度用时) 均 计 数 。 定 时 到 达 产 生 SIGPROF 信 号 。 ITIMER_PROF 记 录 的 时 间 比 ITIMER_VIRTUAL 多了进程调度所花的时间。 定时器在初始化是,被赋予一个初始值,随时间递减,递减至 0 后发出信号,同时恢复 初始值。在任务中,我们可以一种或者全部三种定时器,但同一时刻同一类型的定时器只能 使用一个。 6. 实验步骤 (1)在实验工作目录下,为本实验建立工作目录 timer。 $ cd /zylinux/armwork $ mkdir timer (2)进入 timer 目录,使用自己熟悉的编辑器(如 vi)建立文件 hello.c,并编写如程 序清单 5.3 所示的程序代码。 (3)将光盘相应工程的 Makefile 文件复制到当前目录下,使用编辑器将其打开,并对 - 178 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com Makefile 文件进行如下修改保存,退出编辑器。 EXEC = timer OBJS = timer.o SRC = timer.c (4)输入 make 命令,对程序进行编译,编译完毕在当前目录下会生成可执行文件 timer。 $ make (5)启动 ARM Linux,进行 NFS 连接,进入/mnt/timer 目录,执行 timer 程序。 # ./timer 7. 实验程序 Linux 定时器实验参考程序如程序清单 5.3 所示。程序设置 10 秒的时限,每秒钟提示 剩余时间,当 10 秒的时限到后,发出警告,并停止运行。 程序清单 5.3 Linux 定时器实验参考程序 #include #include #include /* ******************************************************************************************** ** Function name: main() ** Descriptions : Demo for timer. ******************************************************************************************** */ int limit = 10; // 设置 10 秒的时限 /* signal process */ void timeout_info(int signo) { if(limit == 0) { printf("Sorry, time limit reached.\n"); exit(0); } printf("only %d senconds left.\n", limit--); } /* init sigaction */ void init_sigaction(void) { struct sigaction act; act.sa_handler = timeout_info; act.sa_flags = 0; - 179 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com sigemptyset(&act.sa_mask); sigaction(SIGPROF, &act, NULL); } /* init */ void init_time(void) { struct itimerval val; val.it_value.tv_sec = 1; val.it_value.tv_usec = 0; val.it_interval = val.it_value; setitimer(ITIMER_PROF, &val, NULL); } int main(void) { char *str; char c; init_sigaction(); init_time(); printf("You have only 10 seconds for thinking.\n"); while(1); exit(0); } 8. 思考 另外两个定时器如何使用? 5.3 多进程实验 1. 实验目的 掌握 Linux 多进程程序编写。 2. 实验设备 硬件: 软件: PC 机 MagicARM2410 教学实验开发平台 RedHat Linux 9.0 操作系统 嵌入式 Linux 开发环境 一台 一套 - 180 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 3. 实验内容 创建一个新进程后,打印各自的 PID 和 PPID。父进程须对子进程退出状态进行检测和 回收。 4. 实验预习要求 预习 Linux 进程相关知识。 5. 实验原理 进程是一个正在执行的程序实例,是 Linux 调度的基本单位。 进程 ID 仅介绍最常用的进程 ID(Process ID,PID)和父进程 ID(Parent Process ID,PPID)。 一个 PID 标识一个唯一的进程。一个进程创建的新进程称为子进程(child process),创建子 进程的进程称为父进程(parent process)。 相应的获取进程 ID 的函数: getpid(void) getppid(void) 进程的其它 ID 也都有相应的读取函数。 创建进程 在 Linux 中,使用 fork()函数创建子进程进程。函数原型: pid_t fork(void) 如果创建失败,返回-1;创建成功,则向父进程返回子进程的 PID,并向子进程返回 0。 等待进程 创建子进程后,为了出现避免出现僵死状态,父进程应该收集子进程的退出状态,等待 子进程终止。可使用 wait 系列函数实现。如果一个子进程已经死掉,但依然保留在进程表 中,则成为僵死进程,占用进程表。如果僵死进程过多,会严重影响系统性能。下面介绍 waitpid()函数。 pid_t waitpid(pid_t pid, int *status, int options) pid 是等待进程的 PID。 status 保存子进程的状态。 -1:等待任何 PGID 等于 PID 的绝对值的子进程; 1 :等待任何子进程; 0 :等待任何 PGID 等于调用进程的子进程; >0 :等待 PID 等于 pid 的子进程。 options 规定 wait 调用的行为(可复选)。 WHOHANG:没有子进程退出时立即返回; WUNTRACED:为没有存在报告状态的进程返回。 - 181 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 6. 实验步骤 (1)在实验工作目录下,为本实验建立工作目录 process。 $ cd /zylinux/armwork $ mkdir process (2)进入 process 目录,使用自己熟悉的编辑器(如 vi)建立文件 process.c,并编写如 程序清单 5.4 所示的程序代码。 (3)将光盘相应工程的 Makefile 文件复制到当前目录下,使用编辑器将其打开,并对 Makefile 文件进行如下修改保存,退出编辑器。 EXEC = process OBJS = process.o SRC = process.c (4)输入 make 命令,对程序进行编译,编译完毕在当前目录下会生成可执行文件 process。 $ make (5)启动 ARM Linux,进行 NFS 连接,进入/mnt/process 目录,执行 process 程序,观 察程序运行结果,注意各进程 PID 的关系。 # ./process 7. 实验程序 Linux 多进程实验程序参考程序清单 5.4。程序创建一个子进程,父进程等待子进程退 出后回收子进程的退出状态。 程序清单 5.4 Linux 多进程实验参考程序 #include #include #include #include #include #include /* ******************************************************************************************** ** Function name: mprocess() ** Descriptions : Demo for fork() usage. ******************************************************************************************** */ int main(int argc, char **argv) { int val, stat; pid_t child; - 182 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com printf("\nTry to create new process.\n"); child = fork(); switch(child) { case -1: // fault perror("fork.\n"); exit(EXIT_FAILURE); case 0: // child process printf("This is child.\n"); printf("\tchild pid is %d\n", getpid()); printf("\tchild ppid is %d\n", getppid()); exit(EXIT_SUCCESS); default: // father process waitpid(child, &stat, 0); printf("This is parent.\n"); printf("\tparent pid is %d\n", getpid()); printf("\tparent ppid is %d\n", getppid()); printf("\tchild exited with %d\n", stat); } exit(EXIT_SUCCESS); } 程序使用 waitpid()专门等待 child 指定的子进程返回,这样只有子进程退出后,父进程 才停止执行。 8. 思考 父进程为什么要等待并回收子进程的退出状态?不这样做会带来什么后果? 5.4 多线程实验 1. 实验目的 掌握 Linux 多线程程序编写。 2. 实验设备 硬件: 软件: PC 机 MagicARM2410 教学实验开发平台 RedHat Linux 9.0 操作系统 嵌入式 Linux 开发环境 一台 一套 - 183 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 3. 实验内容 创建两个线程,各自统计发生次数,主程序监测两个线程的返回值。 4. 实验预习要求 预习 Linux 线程相关知识。 5. 实验原理 线程是一种标准化模型,它用于把一个程序分成一组能够同时执行的任务。线程是一种 特殊的进程,常称之为轻量级进程(light-weight process)。一个进程的所有线程有独立的执行 线索和堆栈,但共享数据。 使用多线程的应用程序,必须包含 pthread.h 文件,同时在链接程序的时候加上-lpthread 参数。 线程的属性 joinable 具有 joinable 属性的线程在执行完毕后并不会立即被 Linux 清除,如果函数有返回值, 其返回值可通过 pthread_join()函数调用得到。 detatched 具有 detatched 属性的线程,执行完毕立即被 Linux 清除,无法通过 pthread_join()函数 调用获得其返回值。 建立线程的的时候如果没有指定属性,默认为 joinable 属性。 创建线程 创建线程使用 pthread_create()函数实现。函数原型: int pthread_create(pthread_t *thread, pthread_attr_t *attr, void *(*start_routine) (void *), void *arg) 包含 4 个参数: thread_id―― 指向新线程标识的指针。 attr―― 决定新线程的属性。设置为 PTHREAD_CREATE_JOINABLE 或者 NULL 表示线程具有 joinable 属性,设置为 PTHREAD_CREATE_DETATCHED 表示线程 具有 detatched 属性。 *start_routine―― 指向新线程中将要执行的函数的指针。 arg―― 传递给新线程函数的参数。 挂起线程 挂起线程使用 pthread_join()函数实现。函数原型: int pthread_join(pthread_t th, void **thread_return) pthread_join()调用挂起当前线程,直到 th 指定的线程终止运行为止。 如果线程有返回值,返回值保存在 thread_return 指向的地址中。一个线程所使用的内存 资源在对该线程应用 pthread_join()调用之前不会被重新分配。 - 184 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 6. 实验步骤 (1)在实验工作目录下,为本实验建立工作目录 thread。 $ cd /zylinux/armwork $ mkdir thread (2)进入 thread 目录,使用自己熟悉的编辑器(如 vi)建立文件 thread.c,并编写如程 序清单 5.5 所示的程序代码。 (3)将光盘相应工程的 Makefile 文件复制到当前目录下,使用编辑器将其打开,并对 Makefile 文件进行如下修改保存,退出编辑器。 EXEC = thread OBJS = thread.o SRC = thread.c 注意,本程序的 Makefile 必须修改,为链接选项加上-lpthread 参数。 LDFLAGS += -lpthread (4)输入 make 命令,对程序进行编译,编译完毕在当前目录下会生成可执行文件 thread。 $ make (5)启动 ARM Linux,进行 NFS 连接,进入/mnt/thread 目录,执行 thread 程序,观察 程序运行结果,注意两线程的运行顺序。多运行几次,比较各次运行结果。 # ./thread 7. 实验程序 创建两个具有 joined 属性的线程,每个线程都操作主程序传递的参数,统计线程运行的 次数,并将结果返回。参考程序如程序清单 5.5 所示。 程序清单 5.5 Linux 多线程实验参考程序 #include #include #include #include #include /* ******************************************************************************************** ** Function name: main() ** Descriptions : Demo for thread. ******************************************************************************************** */ int task1(int *cnt) { while(*cnt < 5) - 185 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com { sleep(1); (*cnt)++; printf("task1 cnt = %d.\n", *cnt); } return (*cnt); } int task2(int *cnt) { while(*cnt < 5) { sleep(2); (*cnt)++; printf("task2 cnt = %d.\n", *cnt); } return (*cnt); } int main(int argc, char **argv) { int result; int t1 = 0; int t2 = 0; int rt1, rt2; pthread_t thread1, thread2; /* create the first thread. */ result = pthread_create(&thread1, PTHREAD_CREATE_JOINABLE, (void *)task1, (void *)&t1); if(result) { perror("pthread_create: task1.\n"); exit(EXIT_FAILURE); } /* create the second thread. */ result = pthread_create(&thread2, PTHREAD_CREATE_JOINABLE, (void *)task2, (void *)&t2); if(result) { perror("pthread_create: task2.\n"); exit(EXIT_FAILURE); } pthread_join(thread1, (void *)&rt1); - 186 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com pthread_join(thread2, (void *)&rt2); printf("total %d times.\n", t1+t2); printf("return value of task1: %d.\n", rt1); printf("return value of task2: %d.\n", rt2); exit(EXIT_SUCCESS); } 8. 思考 Detached 线程和 Joinable 线程有何区别?如何正确使用 Thread_join 机制? 5.5 文件和目录操作实验 1. 实验目的 掌握 Linux 下文件和目录的基本操作。 2. 实验设备 硬件: 软件: PC 机 MagicARM2410 教学实验开发平台 RedHat Linux 9.0 操作系统 嵌入式 Linux 开发环境 一台 一套 3. 实验内容 在 ARM Linux 的/tmp 目录下,创建一个写有内容的文本文件和一个空文件夹。 4. 实验预习要求 预习 Linux 文件和目录相关知识。 5. 实验原理 文件是 Linux 中非常重要的一个概念,目录也是一种特殊的文件。 6. 实验步骤 (1)在实验工作目录下,为本实验建立工作目录 file。 $ cd /zylinux/armwork $ mkdir file (2)进入 file 目录,使用自己熟悉的编辑器(如 vi)建立文件 file.c,并编写如程序清 单 5.6 所示的程序代码。 - 187 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com (3)将光盘相应工程的 Makefile 文件复制到当前目录下,使用编辑器将其打开,并对 Makefile 文件进行如下修改保存,退出编辑器。 EXEC = file OBJS = file.o SRC = file.c (4)输入 make 命令,对程序进行编译,编译完毕在当前目录下会生成可执行文件 file。 $ make (5)启动 ARM Linux,进行 NFS 连接,进入/mnt/file 目录,执行 file 程序。程序执行 完毕,到/tmp 目录下查看是否有文件夹 linux 和文本文件 linux.txt。 # ./file # ls /tmp 7. 实验程序 程序在/tmp 目录下新建一个空文件夹 linux 和写有内容的文本文件 linux.txt。实验程序 如程序清单 5.6 所示。 程序清单 5.6 文件和目录实验参考程序 #include #include int main(void) { FILE *fp; int num; int folder; char a[] = "Hello ARM Linux!"; fp = fopen("/tmp/linux.txt","w+"); if(fp == NULL) { printf("\nFail to open linux.txt!\n"); exit(-1); } num = fwrite(a, sizeof(a), 1, fp); printf("%d byte data has written to linux.txt\n", num*sizeof(a)); folder = mkdir("/tmp/linux", 1); if(folder == -1) { printf("\n Fail to create folder linux!\nIt has existed or the path is error!\n"); - 188 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com exit(-1); } printf("Folder linux created success!\n"); close(fp); return 0; } 8. 思考 如果在实验箱上插上 CF 卡或者 SD 卡,对 CF 卡或者 SD 卡进行操作,该如何进行? 5.6 UDP 实验 1. 实验目的 掌握 Linux 下 UDP 通讯编程。 2. 实验设备 硬件: 软件: PC 机 MagicARM2410 教学实验开发平台 RedHat Linux 9.0 操作系统 嵌入式 Linux 开发环境 一台 一套 3. 实验内容 实现实验箱和宿主机 UDP 通讯,向主机发送一个字符串“MagicARM2410 UDP Experiment.”。 4. 实验预习要求 预习 Linux 网络相关知识,特别是 UDP 部分内容。 5. 实验原理 Linux 操作系统支持 TCP/IP 的网络体系结构,也称 Internet Protocol Suite(IPS)。见图 5.1,应用层的数据从传输层一直到数据链路层逐级打包,最后通过物理层与计算机网络通 讯。 在 TCP/IP 网络体系的分层中,传输层有两个协议传输数据:TCP(传输控制协议)、 UDP(用户数据报协议)。TCP 协议是面向连接的一个协议,可靠性高,对系统资源要求较 多;UDP 协议是提供最少服务的传输层协议,不提供可靠性,可靠性由用户程序保证,对 系统资源要求较少。 - 189 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com TCP/IP网络体系分层 应用层 传输层 TCP UDP 网络层 数据链路层 物理层 Telnet、FTP等 TCP、UDP IP、ICMP和IGMP 设备驱动程序和接口卡 铜缆、光缆等 图 5.1 TCP/IP 网络体系的分层 UDP 主要用于短应用和控制消息,具有如下优点: UDP 不要求保持一个连接; UDP 没有因接收方认可收到数据包而带来的开销; UDP 要求的网络带宽比 TCP 更小。 当然,UDP 也具有这样的缺点: 传输出错后,如果如果应用中需重传,必须由用户控制; 当数据包太大,需人为分包。 UDP 通讯流程图如图 5.2 所示。 监听端 取得UDP套接字 socket() 发话端 取得UDP套接字 socket() 填入本地IP和 PORT信息 填入远端IP和 PORT信息 本地IP和PORT 与套接字相连 bind() 等待并接收数据 recvfrom() 向远端发送数据 sendto() 打印接收信息 printf() 打印发送成功信息 printf() 删除套接字 close() 删除套接字 close() 结束 结束 图 5.2 UDP 通讯函数应用过程图 - 190 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 6. 实验步骤 (1)在实验工作目录下,为本实验建立工作目录 udp。 $ cd /zylinux/armwork $ mkdir udp (2)进入 udp 目录,在内创建文件夹 utalker,并在 utalker 目录下,使用自己熟悉的编 辑器(如 vi)建立发话端程序文件 talker.c,并编写如程序清单 5.7 所示的程序代码。 $ cd udp $ mkdir utalker (3)将光盘相应工程的 Makefile 文件复制到当前目录下,使用编辑器将其打开,并对 Makefile 文件进行如下修改保存,退出编辑器。 EXEC = talker OBJS = talker.o SRC = talker.c (4)输入 make 命令,对程序进行编译,编译完毕在当前目录下会生成可执行文件 talker。 $ make (5)在 udp 目录下创建目录 listener,并在 listener 目录下编写侦听端(监听端)程序文件 listener.c,编写或者使用光盘提供的 Makefile 文件编译,得到侦听端程序 listener,并运行。 $ mkdir listener $ cd listener $ make $ ./listener (6)启动 ARM Linux,进行 NFS 连接,进入/mnt/udp/utalker 目录,运行发话端 talker, 观察主机是否收到字符串“MagicARM2410 UDP Experiment.”。 # ./talker 192.168.0.94 7. 实验程序 实验程序分发话端程序和侦听端程序,发话端程序在 ARM Linux 上运行,侦听端程序 运行在宿主机上。 (1)发话端程序 talker.c 发话端程序运行于 ARM Linux 上,向主机的 5000 端口发送字符串“MagicARM2410 UDP Experiment.”。程序如程序清单 5.7 所示。 程序清单 5.7 UDP 实验发话端参考程序 #include #include #include #include - 191 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com #include #include #include #include #define PORT #define LENGTH 5000 512 // The port which is communicate with server // Buffer length int main(int argc, char *argv[]) { int sockfd; // Socket file descriptor int num; // Counter of received bytes char sdbuf[LENGTH]; // Receive buffer struct sockaddr_in addr_remote; // Host address information char sdstr[]= {"MagicARM2410 UDP Experiment."}; /* Check parameters number */ if (argc != 2) { printf ("Usage: talker HOST IP (ex: ./talker 192.168.0.94).\n"); return (0); } /* Get the Socket file descriptor */ if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) { printf("ERROR: Failed to obtain Socket Descriptor!\n"); return (0); } /* Fill the socket address struct */ addr_remote.sin_family = AF_INET; // Protocol Family addr_remote.sin_port = htons(PORT); // Port number inet_pton(AF_INET, argv[1], &addr_remote.sin_addr); // Net Address bzero(&(addr_remote.sin_zero), 8); // Flush the rest of struct /* Try to connect the server */ bzero(sdbuf,LENGTH); num = sendto(sockfd, sdstr, strlen(sdstr), 0, (struct sockaddr *)&addr_remote, sizeof(struct sockaddr_in)); if( num < 0 ) { printf ("ERROR: Failed to send your data!\n", argv[1], num); } else { printf ("OK: Sent to %s total %d bytes !\n", argv[1], num); } - 192 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com close (sockfd); return (0); } (2)侦听端程序 listener.c 侦听端程序运行于主机上,侦听 5000 端口,如果接收到发话端的信息,则将收到的信 息打印出来。程序如程序清单 5.8 所示。 程序清单 5.8 UDP 实验侦听端参考程序 #include #include #include #include #include #include #include #include #define PORT #define BACKLOG #define LENGTH 5000 10 512 // The port which is communicate with server // Buffer length int main () { int sockfd; int nsockfd; int num; int sin_size; char revbuf[LENGTH]; struct sockaddr_in addr_local; struct sockaddr_in addr_remote; // Socket file descriptor // New Socket file descriptor // to store struct size // Send buffer /* Get the Socket file descriptor */ if( (sockfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1 ) { printf ("ERROR: Failed to obtain Socket Despcritor.\n"); return (0); } else { printf ("OK: Obtain Socket Despcritor successfully.\n"); } /* Fill the local socket address struct */ addr_local.sin_family = AF_INET; addr_local.sin_port = htons(PORT); // Protocol Family // Port number - 193 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com addr_local.sin_addr.s_addr = INADDR_ANY; // AutoFill local address bzero(&(addr_local.sin_zero), 8); // Flush the rest of struct /* Blind a special Port */ if( bind(sockfd, (struct sockaddr*)&addr_local, sizeof(struct sockaddr)) == -1 ) { printf ("ERROR: Failed to bind Port %d\n",PORT); return (0); } else { printf("OK: Bind the Port %d successfully.\n",PORT); } sin_size = sizeof(struct sockaddr); if(num = recvfrom(sockfd, revbuf, LENGTH, 0, (struct sockaddr *)&addr_remote, &sin_size) == -1) { printf("ERROR!\n"); } else { printf("OK: %s\n", revbuf); } close(sockfd); return (0); } 8. 思考 如果不运行主机的侦听程序,仅运行发话端程序,会出现什么现象?请进一步分析 UDP 通信过程。 5.7 TCP 实验 1. 实验目的 掌握 Linux 下 TCP 通讯编程。 2. 实验设备 硬件: 软件: PC 机 MagicARM2410 教学实验开发平台 RedHat Linux 9.0 操作系统 嵌入式 Linux 开发环境 一台 一套 3. 实验内容 实现实验箱和宿主机 TCP 通讯。主机(服务器)向实验箱(客户端)发送字符信息, 客户端将收到的字符信息打印出来,并统计字符个数。 - 194 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 4. 实验预习要求 预习 Linux 网络相关知识,特别是 TCP 部分内容。 5. 实验原理 TCP(传输控制协议)是保证传输的面向连接的协议。 编写 TCP 通讯的任务时分为服务器方式和客户机方式两种。服务器方式是需要监听连 接,只有在与客户机建立连接后才能进行数据处理。客户机方式是主动连接服务器,它也是 在连接成功后才能进行数据处理。图 5.3 就是 TCP 通讯时服务器端和客户机端通讯的函数 应用过程图。 服务端 取得TCP套接字 socket() 客户端 取得TCP套接字 socket() 填入本地IP和 PORT信息 填入远端IP和 PORT信息 本地IP和PORT 与套接字相连 bind() 设置监听端口PORT 的连接最大数 listen() 等待远端的连接 成功后取得新套接字 accept() 尝试和远端连接 成功后取得新套接字 connect() N 子进程? Y 子进程 接收键盘输入 scanf() 向远端发送数据 sendto() 等待并接收数据 recvfrom() N “exit”? 父进程 删除套接字 Y close() 等待并清除 任意子进程 waitpid() 打印数据 printf() “exit”? N Y 删除套接字 close() 结束 图 5.3 TCP 通讯函数应用过程图 6. 实验步骤 (1)在实验工作目录下,为本实验建立工作目录 tcp。 $ cd /zylinux/armwork $ mkdir tcp - 195 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com (2)进入 tcp 目录,在内创建文件夹 uclient,并在 uclient 目录下,使用自己熟悉的编 辑器(如 vi)建立客户端程序文件 client.c,并编写如程序清单 5.9 所示的程序代码。 $ cd tcp $ mkdir uclient (3)将光盘相应工程的 Makefile 文件复制到当前目录下,使用编辑器将其打开,并对 Makefile 文件进行如下修改保存,退出编辑器。 EXEC = client OBJS = client.o SRC = client.c (4)输入 make 命令,对程序进行编译,编译完毕在当前目录下会生成可执行文件 client。 $ make (5)在 tcp 目录下创建目录 server,并在 server 目录下编写服务器端程序文件 server.c, 编写或者使用光盘提供的 Makefile 文件编译,得到服务器端程序 server,并运行。 $ mkdir server $ cd server $ make $ ./server (6)启动 ARM Linux,进行 NFS 连接,进入/mnt/tcp/uclient 目录,运行客户端 client。 连接成功后,在服务器端输入字符串并回车,在客户端观察是否收到。 # ./client 192.168.0.94 7. 实验程序 实验程序分客户端程序和服务器端程序。客户端程序在 ARM Linux 上运行,服务器端 程序在主机上运行。 (1)客户端程序 client.c 客户端程序在 ARM Linux 上运行,在远程连接完成之后,等待接收服务器端发送的信 息,并将收到的信息打印出来;如果收到的信息是字符串“exit”,则程序结束。参考程序如 程序清单 5.9 所示。 程序清单 5.9 TCP 实验客户端参考程序 #include #include #include #include #include #include #include #include - 196 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com #define PORT 5000 #define LENGTH 256 // The port which is communicate with server // Buffer length int main(int argc, char *argv[]) { int sockfd; int num; char revbuf[LENGTH]; struct sockaddr_in remote_addr; // Socket file descriptor // Counter of received bytes // Receive buffer // Host address information /* Check parameters number */ if (argc != 2) { printf ("Usage: client HOST IP (ex: ./client 192.168.0.94).\n"); return (0); } /* Get the Socket file descriptor */ if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) { printf("ERROR: Failed to obtain Socket Descriptor!\n"); return (0); } /* Fill the socket address struct */ remote_addr.sin_family = AF_INET; remote_addr.sin_port = htons(PORT); inet_pton(AF_INET, argv[1], &remote_addr.sin_addr); bzero(&(remote_addr.sin_zero), 8); // Protocol Family // Port number // Net Address // Flush the rest of struct /* Try to connect the remote */ if (connect(sockfd, (struct sockaddr *)&remote_addr, sizeof(struct sockaddr)) == -1) { printf ("ERROR: Failed to connect to the host!\n"); return (0); } else { printf ("OK: Have connected to the %s\n",argv[1]); } /* Try to connect the server */ while (strcmp(revbuf,"exit") != 0) // Check remoter command { bzero(revbuf,LENGTH); num = recv(sockfd, revbuf, LENGTH, 0); - 197 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com switch(num) { case -1: printf("ERROR: Receive string error!\n"); close(sockfd); return (0); case 0: close(sockfd); return(0); default: printf ("OK: Receviced numbytes = %d\n", num); break; } revbuf[num] = '\0'; printf ("OK: Receviced string is: %s\n", revbuf); } close (sockfd); return (0); } (2)服务器端程序 server.c 服务器端程序运行在主机上,在完成远程连接后,等待键盘输入信息,并将键盘的输入 信息发送到指定端口。参考程序如程序清单 5.10 所示。 程序清单 5.10 TCP 实验服务器端参考程序 #include #include #include #include #include #include #include #include #define PORT #define BACKLOG #define LENGTH int main () { int sockfd; int nsockfd; int num; 5000 10 512 // The port which is communicate with server // Buffer length // Socket file descriptor // New Socket file descriptor - 198 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com int sin_size; char sdbuf[LENGTH]; struct sockaddr_in addr_local; struct sockaddr_in addr_remote; char sendstr[16]= {"123456789 abcde"}; // to store struct size // Send buffer /* Get the Socket file descriptor */ if( (sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1 ) { printf ("ERROR: Failed to obtain Socket Despcritor.\n"); return (0); } else { printf ("OK: Obtain Socket Despcritor sucessfully.\n"); } /* Fill the local socket address struct */ addr_local.sin_family = AF_INET; addr_local.sin_port = htons(PORT); addr_local.sin_addr.s_addr = INADDR_ANY; bzero(&(addr_local.sin_zero), 8); // Protocol Family // Port number // AutoFill local address // Flush the rest of struct /* Blind a special Port */ if( bind(sockfd, (struct sockaddr*)&addr_local, sizeof(struct sockaddr)) == -1 ) { printf ("ERROR: Failed to bind Port %d.\n",PORT); return (0); } else { printf("OK: Bind the Port %d sucessfully.\n",PORT); } /* Listen remote connect/calling */ if(listen(sockfd,BACKLOG) == -1) { printf ("ERROR: Failed to listen Port %d.\n", PORT); return (0); } else{ printf ("OK: Listening the Port %d sucessfully.\n", PORT); } while(1) { sin_size = sizeof(struct sockaddr_in); - 199 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com /* Wait a connection, and obtain a new socket file despriptor for single connection */ if ((nsockfd = accept(sockfd, (struct sockaddr *)&addr_remote, &sin_size)) == -1) { printf ("ERROR: Obtain new Socket Despcritor error.\n"); continue; } else{ printf ("OK: Server has got connect from %s.\n", inet_ntoa(addr_remote.sin_addr)); } /* Child process */ if(!fork()) { printf("You can enter string, and press 'exit' to end the connect.\n"); while(strcmp(sdbuf,"exit") != 0) { scanf("%s", sdbuf); if((num = send(nsockfd, sdbuf, strlen(sdbuf), 0)) == -1) { printf("ERROR: Failed to sent string.\n"); close(nsockfd); exit(1); } printf("OK: Sent %d bytes sucessful, please enter again.\n", num); } } close(nsockfd); while(waitpid(-1, NULL, WNOHANG) > 0); } } 8. 思考 如果要建立两个 TCP 连接,该如何处理? 5.8 Webserver 实验 1. 实验目的 掌握 Linux 下 Webserver 编程方法。 2. 实验设备 硬件: PC 机 MagicARM2410 教学实验开发平台 一台 一套 - 200 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 软件: RedHat Linux 9.0 操作系统 嵌入式 Linux 开发环境 3. 实验内容 在 MagicARM2410 上构建一个静态 Web 服务器。 4. 实验预习要求 预习 Linux 网络相关知识,特别是 html 语言编程。 5. 实验步骤 (1)在实验工作目录下,为本实验建立工作目录 webserver。 $ cd /zylinux/armwork $ mkdir webserver (2)进入 webserver 目录,使用自己熟悉的编辑器(如 vi)建立文件 webserver.c,并 编写如程序清单 5.11 所示的程序代码。 (3)将光盘相应工程的 Makefile 文件复制到当前目录下,使用编辑器将其打开,并对 Makefile 文件进行如下修改保存,退出编辑器。 EXEC = webserver OBJS = webserver.o SRC = webserver.c (4)输入 make 命令,对程序进行编译,编译完毕在当前目录下会生成可执行文件 webserver。 $ make (5)启动 ARM Linux,进行 NFS 连接,进入/mnt/webserver 目录,执行 webserver 程序。 # ./webserver (6)在 PC 主机端打开 ie 浏览器,在地址栏输入实验箱的 IP 地址和端口号(81),访 问存在于实验箱里面的网页。 http://192.168.0.168:81 (假定实验箱的 IP 地址为 192.168.0.168) 6. 实验程序 使用 html 语言编写一个网页,存放在 ARM Linux 中。访问该网页的端口号为 81。实现 程序如程序清单 5.11 所示。 程序清单 5.11 webserver 实验参考程序 #include #include #include - 201 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com #include #include #include #include #include #define PORT #define BACKLOG #define LENGTH 81 10 1024 // The port which is communicate with server // Buffer length char httpweb[]={ "HTTP/1.0 200 OK\r\n" "Date: Mon, 24 Nov 2005 10:26:00 GMT\r\n" "Server: microHttp/1.0 ZHIYUAN Electronics CO.,LTD\r\n" "Accept-Ranges: bytes\r\n" "Connection: Keep-Close\r\n" "Content-Type: text/html\r\n" "\r\n"}; char web[]={ "\r\n" "\r\n" "MagicARM2410 演示网页(广州致远电子有限公司)\r\n" "\r\n" "

HELLO WELCOME TO MagicARM2410 WEBSERVER

\r\n" "
    \r\n" "
  • 广州致远电子 \r\n" "\r\n" "\r\n" }; char httpgif[]={ "HTTP/1.0 200 OK\r\n" "Date: Mon, 24 Nov 2005 10:26:00 GMT\r\n" "Server: microHttp/1.0 ZHIYUAN Electronics CO.,LTD\r\n" "Accept-Ranges: bytes\r\n" "Connection: Keep-Close\r\n" "Content-Type: image/bmp\r\n" "\r\n"}; int main () { int sockfd; int nsockfd; // Socket file descriptor // New Socket file descriptor - 202 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com int i,num; int flag = 1; int sin_size; char revbuf[LENGTH]; struct sockaddr_in addr_local; struct sockaddr_in addr_remote; // to store struct size /* Get the Socket file descriptor */ if( (sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1 ) { printf ("ERROR: Cannot obtain Socket Despcritor.\n"); return (0); } else{ printf ("OK: Obtain Socket Despcritor sucessfully.\n"); } /* Fill the local socket address struct */ addr_local.sin_family = AF_INET; addr_local.sin_port = htons(PORT); addr_local.sin_addr.s_addr = INADDR_ANY; bzero(&(addr_local.sin_zero), 8); // Protocol Family // Port number // AutoFill local address // Flush the rest of struct /* Blind a special Port */ if( bind(sockfd, (struct sockaddr*)&addr_local, sizeof(struct sockaddr)) == -1 ) { printf ("ERROR: Cannot bind Port %d\n.",PORT); return (0); } else{ printf("OK: Bind the Port %d sucessfully.\n",PORT); } /* Listen remote connect/calling */ if(listen(sockfd,BACKLOG) == -1) { printf ("ERROR: Cannot listen Port %d\n.", PORT); return (0); } else{ printf ("OK: Listening the Port %d sucessfully\n.", PORT); } while(1) { sin_size = sizeof(struct sockaddr_in); - 203 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com /* Wait a connection, and obtain a new socket file despriptor for single connection */ if ((nsockfd = accept(sockfd, (struct sockaddr *)&addr_remote, &sin_size)) == -1) { printf ("ERROR: Obtain new Socket Despcritor error\n"); continue; } else{ printf ("OK: Server has got connect from %s\n", inet_ntoa(addr_remote.sin_addr)); } num = recv(nsockfd, revbuf, LENGTH, 0); /* Child process */ if(!fork()) { printf("OK: Http web is servering.\n"); if(revbuf[5]==' ') { send(nsockfd, httpweb, sizeof(httpweb), 0); send(nsockfd, web, sizeof(web), 0); } else if(revbuf[5]=='1') send(nsockfd, httpgif, sizeof(httpgif), 0); } close(nsockfd); while(waitpid(-1, NULL, WNOHANG) > 0); } } 7. 思考 如何修改网页标题?请设计一个自己的网页,重新实验。 - 204 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 第6章 Linux 高级实验 6.1 Linux 内核编译实验 1. 实验目的 掌握 Linux 内核的编译下载操作。 2. 实验设备 硬件: 软件: PC 机 MagicARM2410 教学实验开发平台 RedHat Linux 9.0 操作系统 嵌入式 Linux 开发环境 一台 一套 3. 实验内容 更改 Linux 内核配置,重新编译 Linux 内核,将编译得到的 Linux 映象文件 zImage 重 新下载到实验箱进行测试。 4. 实验预习要求 预习 Linux 内核编译相关知识; 预习如何下载/更新 Linux 内核。 5. 实验步骤 编译内核可能需要 root 权限。 (1)进入/zylinux/kernel 目录,先清除以前编译产生的文件。 $ cd /zylinux/kernel $ make distclean (2)输入 make menuconfig 命令,进入 Linux 内核配置界面。 $ make menuconfig (3)使用出厂默认配置文件 ZY2410x,或者按照自己的需求重新配置内核,保存配置 后编译内核。 $ make dep $ make zImage (4)将 arch/arm/boot 目录下新得到的内核映象文件 zImage 下载到实验箱中,测试新 编译的内核。 6. 思考 尝试完全独立配置一个可运行的 Linux 内核。假如不需要 USB 功能,怎样配置以减小 - 205 - 广州致远电子有限公司 内核大小? Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 6.2 Linux 根文件系统实验 1. 实验目的 (1) 根据已提供的 RAM Disk 根文件系统定制自己的根文件系统; (2) 了解 Linux 下 RAM Disk 根文件系统的结构; (3) 掌握如何在根文件系统中添加文件或者应用程序。 2. 实验设备 硬件: 软件: PC 机 MagicARM2410 教学实验开发平台 RedHat Linux 9.0 操作系统 嵌入式 Linux 开发环境 一台 一套 3. 实验内容 通过修改 MagicARM2410 教学实验开发平台提供的 RAM Disk 根文件系统,定制自己 的根文件系统,并下载到实验箱进行验证。 4. 实验预习要求 预习并掌握使用 ZLG/BOOT 下载文件到 MagicARM2410 实验箱的方法。 5. 实验原理 Linux 内核启动完成以后,内核将寻找一个根文件系统,在 Linux 操作系统中,根文件 系统可以是 CRAMFS,也可以 RAM Disk。在 MagicARM2410 实验箱上,根文件系统是文 件格式为 Ext2 的 RAM Disk,该 RAM Disk 的制作方法如下: (1) 在 PC 机的 Linux 操作系统环境下,生成可以虚拟成块设备的文件,假设文件名为 init.img。 $ dd if=/dev/zero of=init.img bs=4096 count=1024 其中 bs*count 为块设备大小(单位:字节),生成 init.img 文件以后,还必须对该文件 进行格式化。 $ mke2fs –m0 –F init.img (2) 新建一个文件夹 ram,并将 init.img 挂接到 ram 目录。 $ mkdir ram $ mount init.img ram/ -o loop 这时,读写 ram 目录,等效于读写 init.img 文件。用户可以将根文系统所需的文件写入 到 ram 目录中。往 ram 目录写完文件以后,还需要使用 umount ram 命令卸载 init.img,才能 将已写入的文件保存到 init.img 中。 MagicARM2410 实验箱产品配套光盘中已经提供了制作好的 RAM Disk 根文件系统文 件 init.img,用户需要在根文件系统中添加自己的文件时,只须修改本文件即可。 - 206 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 6. 实验步骤 (1) 打开 PC 端 Linux 的终端或者进入虚拟控制台,进入实验目录/zylinux/armwork/,为 本实验新建工作目录 root。 $ cd /zylinux/armwork $ mkdir root (2) 请将产品配套光盘提供的根文件系统文件 init.img 复制到/zylinux/armwork/root/目录 下。 (3) 进入/zylinux/armwork/root 目录。 $ cd root (4) 建立文件夹 ram。 $ mkdir ram (5) 将 init.img 挂接到 ram 目录下。 $ mount init.img ram/ –o loop 这时,ram 目录中的内容就是 init.img 的内容。修改 ram 目录中的内容,等效于修改 init.img 的内容。 (6) 请根据实际情况,在 ram 目录中添加、删除或修改内容,也可以添加可执行的应用 程序。在本实验中,只是在 ram 目录中建立一个文件夹 tempusr。 $ cd ram $ mkdir tempusr (7) 退出 ram 目录,卸载 init.img,确保 init.img 的修改已保存。 $ cd .. $ umount ram (8) 将修改过的 init.img 下载到 MagicARM2410 实验箱上。 (9) 重新启动 MagicARM2410 的 Linux,验证本实验结果。 7. 思考 按照实验原理和实验步骤的提示,新建一个 Ext2 格式的 RAM Disk 文件,将产品配套 光盘提供的 init.img 文件中的内容复制到新建的 RAM Disk 文件中,并下载到实验箱上进行 验证。 6.3 CAT1025 读/写实验 1. 实验目的 (1)掌握 I2C 总线控制器驱动程序的使用方法; (2)掌握使用 I2C 总线控制器驱动程序访问 CAT1025 的方法。 - 207 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 2. 实验设备 硬件: 软件: PC 机 MagicARM2410 教学实验开发平台 RedHat Linux 9.0 操作系统 嵌入式 Linux 开发环境 一台 一套 3. 实验内容 使用 I2C 总线控制器驱动程序编写应用程序,往 CAT1025 内部写入 16 个字节,然后读 回并进行校验。 4. 实验预习要求 (1) 熟悉 Linux 应用程序调试方法。 (2) 熟悉如何修改工程管理文件 Makefile。 (3) 仔细阅读本书第 1 章的内容,了解 MagicARM2410 的硬件结构,注意 CAT1025 电 路。 (4) 仔细阅读 CAT1025 的数据手册,熟悉 CAT1025 的操作时序。 5. 实验原理 S3C2410A 微控制器内嵌了一个 I2C 总线控制器。在 Linux 操作系统中,该控制器的字 符型驱动包括以下四个模块,它们对应的源程序及简介如表 6.1 所示。 表 6.1 I2C 总线控制器驱动模块 模块 i2c-dev i2c-core i2c-algo-s3c2410 i2c-s3c2410 源程序 i2c-dev.c i2c-core.c i2c-algo-s3c2410.c i2c-s3c2410.c 简 介 I2C 总线字符型驱动,与具体使用的 I2C 控制器无关 I2C 总线操作核心函数,与具体使用的 I2C 控制器无关 S3C2410A I2C 总线控制器 I2C 驱动算法,与具体的控制器相关 S3C2410A I2C 总线控制器硬件抽象层,与具体的控制器相关 以上四个模块的关系是上层与下层的关系,它们之间的互相调用如图 6.1 所示。本 I2C 总线控制器驱动模块更详细的说明请见配套光盘本节目录下的《I2C 总线控制器驱动说明 书》。 上层 i2c-dev i2c-core i2c-algo-s3c2410 下层 i2c-s3c2410 图 6.1 I2C 总线控制器驱动各模块之间的关系 当需要使用 I2C 总线控制器驱动模块时,可以使用 I2C 总线控制器驱动的设备管理文件 loadi2c,其内容如程序清单 6.1 所示。本管理文件运行后,将自动在 Linux 的/dev/目录下创 - 208 - 广州致远电子有限公司 建设备节点 i2c。 #!/bin/sh Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 程序清单 6.1 loadi2c 文件内容 rmmod i2c-s3c2410.ko (1) rmmod i2c-algo-s3c2410.ko (2) rmmod i2c-dev.ko (3) rmmod i2c-core.ko (4) insmod i2c-core.ko (5) insmod i2c-dev.ko 延时 1 秒等待模块 (6) insmod i2c-algo-s3c2410.ko i2c-algo-s3c2410 (7) sleep 1 初始化完成 (8) insmod i2c-s3c2410.ko (9) 由图 6.1 可知,由于各个模块之间有上下层关系,所以,加载模块的顺序应该是从上到 下,如程序清单 6.1(5)~(9)所示,也就是最先加载 i2c-core,最后加载 i2c-s3c2410。而卸载 则顺序相反,如程序清单 6.1(1)~(4)所示。 当加载模块 i2c-algo-s3c2410 时,必须延时 1 秒,用于等待该模块初始化完成,否则将 无法加载下一个模块:i2c-s3c2410,如程序清单 6.1(8)所示。 如果应用程序要使用本驱动来访问外部 I2C 器件,首先要通过 open()来打开其驱动,使 用完毕后使用 close()将其关闭。 程序清单 6.2 打开与关闭 I2C 总线控制器驱动 int fd; fd = open("/dev/i2c/0", O_RDWR); …… close(fd); 注意:I2C 总线控制器驱动仅操作 I2C 总线控制器。因此,在利用本驱动编写应用程序 访问外部 I2C 器件(如 E2PROM 器件 CAT1025)时,应用程序的编写方法还与具体使用的器件 的特性相关,在本实验中将看到这一点。 I2C 总线控制器驱动(字符型)提供的 API 函数除了 read()与 write()以外,还提供了 ioctl() 函数用于设定 I2C 总线控制器的一些参数,该函数常用的命令列表如表 6.2 所示,该函数可 以使用的全部命令请见驱动源码中的 i2c.h 文件的具体说明。 表 6.2 iotcl()函数命令列表 命令 I2C_SLAVE I2C_SLAVE_FORCE I2C_TENBIT I2C_S3C2410_SET_SPEED I2C_S3C2410_GET_SPEED 第二参数取值 I2C 从机地址 I2C 从机地址 0:从机地址为 7bit;1:从机地址为 10bit S3C2410A I2C 总线控制器分频值 32 位变量指针,用于保存读取得的频率值 作用 设定 I2C 从机地址 修改 I2C 从机地址 指定 I2C 从机地址的位数 设置 I2C 总线控制器时钟频率 获取 I2C 总线控制器时钟频率 - 209 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 例 1 设置 I2C 从机地址为 0xA0。 ret = ioctl(fd, I2C_SLAVE, 0xA0 >> 1); ret = ioctl(fd, I2C_TENBIT, 0); /* 由于是 7bit 地址, 所以要右移 1 位 */ /* 指定从机地址为 7bit */ 例 2 向 I2C 总线发送 1 字节数据 data。 write(fd, &data, 1); 读/写 I2C 总线则通过 read()与 write()函数来实现。 例 3 向有子地址的 I2C 器件写入 8 个字节,假设子地址为 0。 unsigned char sendbuf[9] = {0,1,2,3,4,5,6,7,8}; /* 第 1 个字节 0 为子地址 */ write(fd, sendbuf, 9); /* 写入 8 个字节,第 1 个字节为子地址 */ 例 4 从有子地址的 I2C 器件读取 8 个字节,假设子地址为 0。 unsigned char suba = 0; recbuf[8]; write(fd, &suba, 1); /* 发送子地址 0 */ read(fd, recbuf, 8); /* 从子地址 0 开始读取 8 个字节 */ 在 MagicARM2410 实验箱上,CAT1025 的 I2C 地址为 0xA0。利用 I2C 总线控制器驱动 程序提供的 API 函数,就可以直接读写 CAT1025 了。 6. 实验步骤 (1) 在 PC 端,打开终端或者进入虚拟控制台,进入 arm 实验目录/zylinux/armwork/,为 本实验新建工作目录 cat1025。 $ cd /zylinux/armwork $ mkdir cat1025 (2) 使用自己熟悉的编辑器(例如 vi)建立文件 cat1025.c,编写实验代码并保存。 $ vi cat1025.c (3) 编写 Makefile 或修改 5.1 小节的 Makefile,使其适合于本实验。 EXEC = cat1025 OBJS = cat1025.o SRC = cat1025.c (4) 将配套光盘本节目录下提供的 i2c.h 文件拷贝到当前目录下,在 cat1025.c 中包含该 头文件。 #include "i2c.h" (5) 编译程序,生成可执行代码 cat1025。 $ make (6) 启动 MagicARM2410 实验箱的 Linux,进行 NFS 连接,进入 I2C 总线控制器驱动程 序所在目录,先加载 I2C 驱动,然后进入 cat1025 目录,运行程序,查看运行结果。 #./loadi2c - 210 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com # ./cat1025 这时,在终端打印出实验结果: Write CAT1025: 12345678 Read CAT1025: 12345678 Read and Write CAT1025 sucessfully! 7. 实验参考程序 应用程序通过 I2C 总线控制器驱动对 CAT1025 进行读/写操作,首先程序必须先打开该 驱动,如程序清单 6.3(1)所示。然后设置从机地址为 7bit(程序清单 6.3(2))以及从机地址 为 0xA0,由于从机地址为 7bit,所以从机地址值要左移 1 位(程序清单 6.3(3))。 程序清单 6.3 CAT1025 读写实验参考程序 #include #include #include #include "i2c.h" /* 文件操作 */ /* I2C 总线控制器驱动命令 */ #define I2C_ADDR 0xA0 /* CAT1025 从机地址 */ int main() { int fd,ret,i; unsigned char suba; char buf[9] = {0,1,2,3,4,5,6,7,8}; fd = open("/dev/i2c/0", O_RDWR); /* 打开设备 */ (1) if(fd == -1) { printf("\Can't open I2C device!\n"); exit(-1); } ret = ioctl(fd, I2C_TENBIT, 0); /* 指定从机地址为 7bit */ (2) if (ret != 0) { printf("\Can't set I2C address bit number.\n"); close(fd); exit(-1); } ret = ioctl(fd, I2C_SLAVE, I2C_ADDR >> 1); /* 设置从机地址,7 位地址,须右移 1 位*/ (3) - 211 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com if (ret != 0) { printf("\Can't set I2C slave device address.\n"); close(fd); exit(-1); } printf("Write CAT1025:\n"); for(i = 1; i < 9; i++) printf("%d ", buf[i]); ret = write(fd, buf, 9); if (ret != 9) { printf("Write CAT1025 failed.\n"); close(fd); exit(-1); } 必须延时 10ms /* 写 8 个字节到 CAT1025,第 1 字节为子地址*/ (4) usleep(10000); /* 等待 10ms 写入完成 */ printf("\nRead CAT1025:\n"); 读有子地址的从机时,要先发送子地址 suba = 0; ret = write(fd, &suba, 1); /* 发送从机子地址 */ (5) if (ret != 1) { printf("send slave address fail.\n"); close(fd); exit(-1); } ret = read(fd, buf, 8); if (ret == 8) { for (i = 0; i < 8; i++) printf("%d ", buf[i]); } else { printf("Read CAT1025 failed.\n"); close(fd); exit(-1); } /* 从 CAT1025 读 8 个字节 */ - 212 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com printf("\nRead and Write CAT1025 sucessfully!\n"); return 0; } 完成从机地址的设置后,就可以往 CAT1025 写数据了,注意发送的第 1 个字节为从机 地址(程序清单 6.3(4)),而且写完后要延时 10ms,确保数据完全写入 CAT1025,也保证 CAT1025 退出“忙”状态。 而读 CAT1025 时,必须先用“写”操作来设定从机子地址,然后才能执行读操作,如 程序清单 6.3(5)所示。 8. 思考 如果写入 CAT1025 的数据大于 16 字节,应该如何编写程序实现? 6.4 ZLG7290 键盘读取 1. 实验目的 (1)掌握 I2C 总线控制器驱动程序的使用; (2)掌握 ZLG7290 在键盘管理和显示控制上的应用。 2. 实验设备 硬件: 软件: PC 机 MagicARM2410 教学实验开发平台 RedHat Linux 9.0 操作系统 嵌入式 Linux 开发环境 一台 一套 3. 实验内容 (1) 使用 I2C 总线控制器驱动程序编写应用程序,驱动 MagicARM2410 实验箱上的 8 个 七段数码管,在数码管上显示字样“S3C2410A”; (2) 读取按键的值,控制对应数码管闪烁。 4. 实验预习要求 (1) 熟悉 Linux 应用程序调试方法。 (2) 熟悉如何修改工程管理文件 Makefile。 (3) 仔细阅读本书第 1 章的内容,了解 MagicARM2410 的硬件结构,注意 ZLG7290 电 路。 (4) 仔细阅读 ZLG7290 的数据手册,熟悉 ZLG7290 的操作时序。 (5) 仔细阅读 6.3 小节(CAT1025 读/写实验),理解 S3C2410A 微控制器 I2C 总线驱动 程序的使用方法。 5. 实验原理 (1) ZLG7290 键盘按键的读取和识别。ZLG7290 的 I2C 总线地址为 0x70,键值寄存器 - 213 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 地址为 0x01,连击计数器地址为 0x02。 (2) ZLG7290 数码管显示。使用按位下载且译码的指令进行显示。将命令和将要显示的 数据送到命令缓冲区 0x07 和 0x08 两个单元。 (3) 闪烁控制使用“0x70+数码管控制字”命令。 6. 实验步骤 (1) 在 PC 端,打开终端或者进入虚拟控制台,进入 arm 实验目录/zylinux/armwork/,为 本实验新建工作目录 zlg7290。 $ cd /zylinux/armwork $ mkdir zlg7290 (2) 使用自己熟悉的编辑器(例如 vi)建立文件 zlg7290.c,编写实验代码并保存。 $ vi zlg7290.c (3) 编写 Makefile 或修改 5.1 小节的 Makefile,使其适合于本实验。 EXEC = zlg7290 OBJS = zlg7290.o SRC = zlg7290.c (4) 将配套光盘本节目录下提供的 i2c.h 文件拷贝到 zlg7290 目录下,在 cat1025.c 中包 含该头文件。 #include "i2c.h" (5) 编译程序,生成可执行代码 zlg7290。 $ make (6) 启动 MagicARM2410 实验箱的 Linux,进行 NFS 连接,进入 I2C 总线控制器驱动程 序所在目录,先加载 I2C 驱动,然后进入 zlg7290 目录,运行程序,查看运行结果。 # ./loadi2c # ./zlg7290 7. 实验参考程序 本实验所有代码都在 zlg7290.c 文件中。程序先打开 I2C 总线控制器驱动程序,如果打 开失败则报错退出。打开成功后,首先需要设置 I2C 总线的速率(ZLG7290 在外接 6MHz 晶振的情况下,I2C 总线最高速度建议不要超过 30KHz),然后才能对 ZLG7290 进行访问。 注:进行该实验时,需要熟悉 ZLG7290 的操作时序,请参考其数据手册。 (1) 在 zlg7290.c 文件中,先包含相关的头文件及定义 I2C 从机 zlg7290 的 I2C 总线地址。 程序清单 6.4 包含相关头文件及定义相关宏定义 #include #include #include #include "i2c.h" /* 文件操作 */ /* I2C 命令 */ - 214 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com #define int fd; I2C_ADDR 0x70 /* zlg7290 从机地址 */ (2) 编写 main()函数,如程序清单 6.5 所示。 程序清单 6.5 ZLG7290 键盘读取实验参考程序 int main() { int ret,i; unsigned char suba,buf[9]; unsigned short key; fd = open("/dev/i2c/0", O_RDWR); /* 打开设备 */ (1) if(fd == -1) { printf("Can't open I2C device!\n"); exit(-1); } ret = ioctl(fd, I2C_TENBIT, 0); /* 指定从机地址为 7bit */ (2) if (ret != 0) { printf("Can't set I2C address bit number.\n"); close(fd); exit(-1); } ret = ioctl(fd, I2C_SLAVE, I2C_ADDR >> 1); /* 设置从机地址,7 位地址,须右移 1 位*/ (3) if (ret != 0) { printf("Can't set I2C slave device address.\n"); close(fd); exit(-1); } /* 设置 I2C 总线频率小于 30KHz */ ret = ioctl(fd, I2C_S3C2410_SET_SPEED, 3); /* 3 为 I2C 总线频率分频值 */ (4) if (ret != 0) { printf("Can't set I2C speed.\n"); close(fd); exit(-1); } - 215 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com /* 读取 I2C 总线频率 */ ret = ioctl(fd, I2C_S3C2410_GET_SPEED, &i); if (ret != 0) { printf("Can't read I2C speed.\n"); close(fd); exit(-1); } printf("I2C Speed is:%dKHz\n", i); // S3C2410A // buf[7] = 0x05; buf[6] = 0x03; buf[5] = 0x0C; buf[4] = 0x02; buf[3] = 0x04; buf[2] = 0x01; buf[1] = 0x00; buf[0] = 0x0A; /* 显示 S3C2410A */ zlg7290_disp(buf, 8); for (;;) { if (zlg7290_getkey(&key) != 0) { printf("Read key value fail\n"); exit(-1); } /* 读取按键键值 */ (5) if (zlg7290_sndcmd(0x70, 1<<(key - 1)) != 0) /* 闪烁 */ (6) { printf("Display fail\n"); exit(-1); } usleep(1000); } close(fd); return 0; } 程序清单 6.5(1) ~ (3)打开设备并设置 I2C 从机 ZLG7290 的从机地址。程序清单 6.5(4) 设置 I2C 总线频率小于 30KHz,这样才能正确对 ZLG7290 进行操作。 - 216 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 程序清单 6.5(5)则读取键盘按键值,程序清单 6.5(6)根据按键值使对应的按键闪烁。程 序清单 6.5 中调用的一些函数分析如下。 程序清单 6.6 为读取 zlg7290 按键键值函数,读取正确时函数返回 0,否则返回-1。 程序清单 6.6 读取 zlg7290 按键键值函数 int zlg7290_getkey(unsigned short *key) { unsigned char temp[2]; temp[0] = 1; temp[1] = 0; if (write(fd, temp, 1) != 1) return -1; /* 发送子地址 */ if (read(fd, temp, 2) != 2) return -1; /* 读取键值 */ *key = temp[0] + (temp[1] * 256); return 0; } 程序清单 6.7 则为向 zlg7290 发送命令函数,如果该函数的入口参数 dat1 取值为 0x70, 就可用该函数进行数码管闪烁控制,dat2 为要控制闪烁显示的数码管编号。 程序清单 6.7 向 zlg7290 发送命令函数 int zlg7290_sndcmd(unsigned char dat1, unsigned char dat2) { unsigned char temp[3]; temp[0] = 0x07; temp[1] = dat1; temp[2] = dat2; if (write(fd, temp, 3) != 3) return -1; usleep(1000); return 0; } 程序清单 6.8 用于控制 MagicARM2410 实验箱上数据管的显示,其中 buf 为显示缓冲 区,num 为要显示的字符个数。 程序清单 6.8 数码管显示函数 void zlg7290_disp(unsigned char *buf, unsigned char num) - 217 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com { unsigned char i; unsigned char temp[3]; for(i=0; i #include #include "i2c.h" #include "usbdev.h" /* 文件操作 */ #define I2C_ADDR 0xA0 #define PAGE_SIZE_CAT1025 16 #define CMD_READ_CAT1025 0x01 #define CMD_WRITE_CAT1025 0x02 /* CAT1025 的 I2C 地址 */ /* CAT1025 的页面大小:16 字节 */ /* 读 CAT1025 命令 */ /* 写 CAT1025 命令 */ (2) 根据实验原理的分析,编写 main()函数,如程序清单 6.11 所示。程序清单 6.11(1) 调用的函数用于打开 I2C 总线控制器驱动程序、设置从机地址。程序清单 6.11(2)打开 USB 设备控制器驱动的从设备 1(端点 1 和 2,本实验只用到 USB 设备控制器的端点 1 和 2)。 程序清单 6.11(3)设置写端点 1 的超时时间。 - 225 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 程序清单 6.11 中的标注,清晰地反映了实验原理中读/写 CAT1025 的方法,与图 6.3 与图 6.4 一一对应。 程序清单 6.11 main()函数 int main() { unsigned char buff[259]; int i2cfd, usbfd; int len, ret; /* 初始化 I2C: 打开 I2C 驱动, 设置从机地址 */ i2cfd = initialize_i2cdev(0xA0); (1) if (i2cfd < 0) exit(-1); usbfd = open("/dev/usbdev1", O_RDWR); if(usbfd == -1) { printf("\nCan't open usb device!\n"); exit(-1); } /* 打开 usb 驱动程序的从设备 1 */ (2) ret = ioctl(usbfd, USBDEV_SET_WRITE_TIMEOUT, 1000); /* 设置写端点 1 超时时间 */ (3) if (ret < 0) { printf("\nSet write endpoint timeout fail!\n"); exit(-1); } while(1) 等待接收命令帧 { ret = read(usbfd, buff, sizeof(buff)); if (ret < 0) { close(i2cfd); close(usbfd); exit(-1); } /* 等待接收 USB 总线数据 */ if (ret == sizeof(buff)) 收到读命令帧 { if (buff[0] == CMD_READ_CAT1025) { 读 CAT1025 len = (buff[1] << 8) + buff[2]; ret = readcat1025(i2cfd, 0, len, &buff[3]); /* 读 CAT1025 */ - 226 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com if (ret >= 0) { buff[1] = ret / 256; buff[2] = ret % 256; ret = write(usbfd, buff, sizeof(buff)); /* 发送响应帧到 PC */ if (ret < 0) { 发送读响应帧到 PC printf("usb write endpoint fail!\n"); close(i2cfd); close(usbfd); exit(-1); } } else { printf("Read CAT1025 fail!\n"); close(i2cfd); close(usbfd); exit(-1); } }//end of if (buff[0] == CMD_READ_CAT1025) if (buff[0] == CMD_WRITE_CAT1025) { len = (buff[1] << 8) + buff[2]; 收到写命令帧 ret = writecat1025(i2cfd, 0, len, &buff[3]); /* 写 CAT1025 */ if (ret >= 0) { 写 CAT1025 buff[1] = ret / 256; buff[2] = ret % 256; 发送写响应帧到 PC ret = write(usbfd, buff, sizeof(buff)); /* 发送响应帧到 PC */ if (ret < 0) { printf("usb write endpoint fail!\n"); close(i2cfd); close(usbfd); exit(-1); } } else { printf("Write CAT1025 fail!\n"); close(i2cfd); close(usbfd); - 227 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com exit(-1); } }//end of if (buff[0] == CMD_WRITE_CAT1025) }//end of if (ret == sizeof(buff)) }//end of while(1) close(i2cfd); close(usbfd); return 0; } 对于 main()函数中调用的几个函数,说明如下。例如初始化 I2C 总线控制器函数如程序 清单 6.12 所示。 程序清单 6.12 初始化 I2C 总线控制器 int initialize_i2cdev(unsigned char slaveaddr) { int fd, ret; fd = open("/dev/i2c/0", O_RDWR); if (fd == -1) { printf("Can't open i2c device!\n"); return -1; } ret = ioctl(fd, I2C_TENBIT, 0); if (ret != 0) { printf("Can't set slave address bit number!\n"); close(fd); return -1; } ret = ioctl(fd, I2C_SLAVE, slaveaddr >> 1); if (ret != 0) { printf("Can't set slave address!\n"); close(fd); return -1; } return fd; } /* 打开 I2C 总线控制器驱动 */ (1) /* 设置 I2C 从机地址为 7bit */ (2) /* 设置 I2C 从机地址 */ (3) 程序清单 6.12(1) ~ (3)完成了打开 I2C 总线控制器驱动,设置 CAT1025 从机地址为 7bit 及从机地址等工作。而读 CAT1025 函数则如程序清单 6.13 所示。 - 228 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 程序清单 6.13 读 CAT1025 函数 int readcat1025(int fd, unsigned char offset, int len, unsigned char *recbuff) { int actlen; if (len > 256) return -1; actlen = write(fd, &offset, 1); /* 发送从机地址 */ (1) if (actlen != 1) return -1; actlen = read(fd, recbuff, len); if (actlen < 0) return -1; return actlen; } /* 读取数据 */ (2) /* 返回实际读到的字节数 */ 程序清单 6.13 比较简单,只是在读 CAT1025 之前,必须用写函数发送 1 个字节的子地 址,如程序清单 6.13(1)所示。发送成功后,就可以将数据读取出来了,如程序清单 6.13(2) 所示。函数最后返回读取到的字节数,如果失败则返回-1。 但写 CAT1025 则比较复杂,这是因为每次写 CAT1025 只能写一页(16 字节),写 CAT1025 的函数如程序清单 6.14 所示。该函数根据要求写入的字节数来决定写多少页以及写不够一 页的数据。程序清单 6.14 已有详细的注释,这里不再分析。 程序清单 6.14 写 CAT1025 函数 int writecat1025(int fd, unsigned char offset, int len, unsigned char *sendbuff) { unsigned char pages, nums, i; unsigned char buff[PAGE_SIZE_CAT1025 + 1]; /* 写缓冲区 */ int ret = 0, actlen = 0; if (len > 256) return -1; pages = len / PAGE_SIZE_CAT1025; nums = len % PAGE_SIZE_CAT1025; buff[0] = offset; /* CAT1025 一次只能写一页,一页为 16 字节 */ /* 不够整数页的字节数 */ /* buff[0]为写偏移地址 */ for (i = 0; i < pages; i++) { memcpy(&buff[1], sendbuff, PAGE_SIZE_CAT1025); /* 将要写入的数据复制到写缓冲区 */ actlen = write(fd, buff, PAGE_SIZE_CAT1025 + 1); if (actlen < 0) - 229 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com return -1; ret += actlen - 1; usleep(10000); sendbuff += PAGE_SIZE_CAT1025; buff[0] += PAGE_SIZE_CAT1025; } /* 记录已写入的字节数 */ /* 延时 10ms 的时间让 CAT1025 */ /* 内部执行写操作 */ if (nums > 0) { memcpy(&buff[1], sendbuff, nums); actlen = write(fd, buff, nums + 1); if (actlen < 0) return -1; /* 下面写不够整数页的字节 */ ret += actlen - 1; usleep(10000); } return actlen; } /* 返回实际写入的字节数 */ 8. 思考题 请用户思考,如何利用 S3C2410A I2C 总线控制器驱动程序和 USB 设备控制器驱动程序, 操作 MagicARM2410 实验箱上的 I2C 器件 ZLG7290,实现用 PC 来控制七段码显示器的显 示。 6.6 SD/MMC 卡实验 1. 实验目的 (1)根据提供的相关资料及原理图,理解 SD/MMC 卡相关规范及访问时序。 (2)理解 Linux 下 SD/MMC 卡块驱动的软件结构。 (3)掌握 SD/MMC 卡块驱动的使用方法。 2. 实验设备 硬件: 软件: PC 机 MagicARM2410 教学实验开发平台 RedHat Linux 9.0 操作系统 嵌入式 Linux 开发环境 一台 一套 - 230 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 3. 实验内容 根据提供的相关资料及原理图,理解 SD/MMC 卡相关规范及访问时序、SD/MMC 卡块 驱动程序的软件结构,并使用该块驱动,在 SD/MMC 卡上创建文件夹及文件。 4. 实验预习要求 (1) 仔细阅读本书第 1 章的内容,了解 MagicARM2410 的硬件结构,注意 SD/MMC 卡 电路。 (2) 仔细阅读 S3C2410A 用户手册中的 MMC/SD/SDIO 主机控制器一节,理解该控制器 的相关寄存器的使用方法及特点。 (3) 仔细阅读《S3C2410A SD/MMC 卡块驱动使用手册》(见产品配套光盘),该使用手 册详细描述了 SD/MMC 卡的相关知识及驱动的使用方法。 5. 实验原理 SD/MMC 卡是一种大容量(最大可达 4GB)、性价比高、体积小、访问接口简单的存储 卡。SD/MMC 卡大量应用于数码相机、MP3、手机、大容量存储设备,做为这些便携式设 备的存储载体,它还具有低功耗、非易失性、保存数据无需消耗能量等特点。 SD 卡接口向下兼容 MMC(MutliMediaCard 多媒体卡)卡,访问 SD 卡的 SD 协议或 SPI 协议及部分命令也适用于 MMC 卡。 S3C2410A 微控制器内嵌了 MMC/SD/SDIO 主机控制器,只需要在微控制器外部外接少 量器件就可以读写 SD/MMC 卡。在 MagicARM2410 实验箱上,S3C2410A 与 SD/MMC 卡座 的电路原理图请见第 1 章。 关于 SD/MMC 卡相关规范、读写时序、块驱动的更加详细的说明请见光盘《S3C2410A SD/MMC 卡块驱动使用手册》。 在 Linux 操作系统下,SD/MMC 卡块驱动的软件包括两个模块,如表 6.6 所示。 表 6.6 SD/MMC 卡驱动模块 模块 zlg_fs.ko mmc2410.ko 简 介 块设备通用驱动(支持分区)模块,是 SD 卡、NandFlash 等其它块设备驱动的基础。 S3C2410A SD/MMC 卡底层读写模块,不是驱动程序,不能被 Linux 直接识别,使用时必 须先加载 zlg_fs。 这两个模块是上层与下层的关系,它们之间的调用关系如图 6.8 所示。Linux 内核只与 zlg_fs 打交道,zlg_fs 则调用 mmc2410 在底层完成 SD/MMC 卡的访问操作。 Linux内核 zlg_fs.ko mmc2410.ko 图 6.8 SD/MMC 卡块驱动各模块之间的关系 zlg_fs 模块对应的源文件及简单介绍如表 6.7 所示,mmc2410 模块对应的源文件及简单 介绍如表 6.8 所示。 - 231 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 源文件 zlg_fs.c 源文件 sd.c zlg_fs_sd.c sddriver.c sdcmd.c sdhal.c 表 6.7 zlg_fs 模块对应的源文件 简 介 块设备通用驱动(支持分区)接口,是 SD 卡、NandFlash 等其它块设备驱动的基础。 表 6.8 mmc2410 模块对应的源文件 简 介 zlg_fs.ko 模块与 mmc2410.ko 模块之间的接口。 zlg_fs.ko 模块与 mmc2410.ko 模块之间的接口。 为 sd.c 提供初始化 SD/MMC 卡、读写 SD/MMC 卡扇区的函数。 SD/MMC 卡命令层,实现卡的各种命令以及主机与卡之间的数据流控制。 硬件抽象层,包括相关硬件、寄存器初始化,设置读写 SD/MMC 卡时钟等函数。 如果将图 6.8 细化到源文件,就可以清晰地看到各个源文件之间的关系了,如图 6.9 所示。从该图可见,sd.c 和 zlg_fs_sd.c 在 zlg_fs.c 与 sdriver.c 之间起到桥梁作用,这种结构 使能 zlg_fs.c 与设备无关。 zlg_fs.c sd.c, zlg_fs_sd.c zlg_fs.c与sddriver.c接口 sddriver.c sdcmd.c sdhal.c 图 6.9 SD/MMC 卡驱动对应各源文件之间的关系 在使用 SD/MMC 卡块驱动时,必须先加载 zlg_fs 模块,然后再加载 mmc2410 模块。而 卸载顺序则相反,先卸载 mmc2410 模块,再卸载 zlg_fs 模块。 zlg_fs 支持 4 个块设备,分别为 zlg_fsa、zlg_fsb、zlg_fsc 和 zlg_fsd。每个块设备最多 支持 16 个分区,设备分区由其后的数字来区分,例如:zlg_fsa 的第 1 个分区为 zlg_fsa1, 第 2 个分区为 zlg_fsa2,以此类推,第 15 个分区为 zlg_fsa15。 在使用任何一个设备分区之前,必须为整个设备创建节点,然后再为分区创建节点。例 如使用 zlg_fsa1,必须进行如程序清单 6.15 所示的操作。 程序清单 6.15 为块设备创建节点 mknod /dev/zlg_fsa b 252 0 mknod /dev/zlg_fsa1 b 252 1 (1) 程序清单 6.15 中的 b 表示块设备,252 为主设备号,0 和 1 和从设备号。 节点创建完毕后,还需要将使用的块设备或者分区 mount 到文件系统的某个目录,才 能对该块设备(如 SD 卡)进行操作。例如,将程序清单 6.15(1)对应的分区 mount 到/tmp/sd 目录下的指令为: mount /dev/zlg_fsa1 /tmp/sd 这样,操作目录/tmp/sd 就是对 zlg_fsa1 进行操作。如果设备没有分区,则直接操作整 个设备即可。例如挂载到系统上的第 1 个块设备没有分区,则使用: mount /dev/zlg_fs /tmp/sd - 232 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 命令将整个设备 mount 到/tmp/sd 目录下。 以上操作步骤比较多,为了方便,使用一个 loadsd 文件进行管理。用于加载 SD/MMC 卡块驱动程序和建立相关节点,如程序清单 6.16 所示。 程序清单 6.16 loadsd 文件内容 #!/bin/sh rm -f /dev/zlg_fsb rm -f /dev/zlg_fsb1 rmmod mmc2410.ko #rmmod zlg_fs.ko // 该模块在 Linux 启动时已加载 mknod /dev/zlg_fsb b 125 16 mknod /dev/zlg_fsb1 b 125 17 #insmod zlg_fs.ko insmod mmc2410.ko 该文件使用的前提条件是:zlg_fs、mmc2410 和 loadsd 都在同一目录下。 进行本实验时,只须将 SD 或 MMC 卡插入到卡座中,然后加载 SD/MMC 卡块驱动程 序,驱动程序将自动完成 SD/MMC 卡的初始化工作。用户只须将卡 mount 到文件系统的一 个文件夹中,再利用 Linux 操作系统中的读/写文件函数,就可以在 SD 或 MMC 卡上创建文 件及文件夹了。 6. 实验步骤 (1)在 PC 端,打开终端或者进入虚拟控制台,进入 arm 实验目录/zylinux/armwork/, 为本实验新建工作目录 sdtest。 $ cd /zylinux/armwork $ mkdir sdtest (2)使用自己熟悉的编辑器(例如 vi)建立文件 sdtest.c,编写实验代码并保存。 $ vi sdtest.c (3)编写 Makefile 或修改 5.1 小节的 Makefile,使其适合于本实验。 EXEC = sdtest OBJS = sdtest.o SRC = sdtest.c (4)编译程序,生成可执行代码 sdtest。 $ make (5)将 SD 或 MMC 卡插入到 MagicARM2410 实验箱上的 SD/MMC 卡卡座中。 (6)启动 MagicARM2410 实验箱上的 Linux,进行 NFS 连接,进入 SD/MMC 卡块驱 动所在目录,先加载 SD/MMC 卡块驱动。再进入到/tmp 目录下,将 SD/MMC 卡的第 1 个分 区 mount 到/tmp/sd 目录下。 - 233 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com # ./loadsd # cd /tmp # mkdir sd # mount –t vfat /dev/zlg_fsb1 /tmp/sd/ 如果 SD/MMC 卡没有分区,则使用命令 mount –t vfat /dev/zlg_fsb /tmp/sd/ 即可将整个设备 mount 到/tmp/sd/目录下。 (7)进入 sdtest 目录,运行程序。 # ./sdtest (8)切换到/tmp/sd 目录,查看实验结果。 # cd /tmp/sd # ls 这时,在终端列出了/tmp/sd 目录下的文件。 linux linux.txt (9)查看 linux.txt 文件的内容。 # cat linux.txt 这时,终端打印出了 linux.txt 文件的内容。 Hello Linux! (10)umount sd 目录。 # cd .. # umount sd (11)拔出 SD 卡或 MMC 卡,可用 SD/MMC 卡读卡器验证创建的文件和文件夹是否 正确。 7. 实验参考程序 本实验对应的程序都在 sdtest.c 文件中,该文件的内容如程序清单 6.17 所示。创建文件、 往文件里添加数据、创建文件夹等操作请见程序清单 6.17 中的标注。 程序清单 6.17 SD/MMC 卡实验参考程序 #include "config.h" #include int main(void) { FILE *fp; int num; int folder; char a[14] = "Hello Linux!\n"; - 234 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com fp = fopen("/tmp/sd/linux.txt","w+"); if(fp == NULL) { 创建 linux.txt 文件 printf("\nCan't open linux.txt!\n"); exit(-1); } 往 linux.txt 文件中写入数据 num = fwrite(a, sizeof(a), 1, fp); printf("%d byte data has written to linux.txt\n", num*sizeof(a)); folder = mkdir("/tmp/sd/linux", 1); if(folder == -1) { 创建文件夹 linux printf("\n Cann't create folder linux!\nIt has existed or the path is error!\n"); exit(-1); } printf("Folder linux created success!\n"); close(fp); return 0; } 8. 思考 如果要对 CF 卡进行操作,应如何进行? 6.7 触摸屏实验 1. 实验目的 学会 Linux 下 S3C2410A 触摸屏驱动的使用方法。 2. 实验设备 (1)硬件: PC 机 MagicARM2410 教学实验开发平台 (2)软件: RedHat Linux 9.0 操作系统 嵌入式 Linux 开发环境 一台 一套 3. 实验内容 使用 S3C2410A 触摸屏驱动编写应用程序,读取触摸屏的触点座标值及动作信息,并在 串口终端中打印出来。 - 235 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 4. 实验预习要求 (1) 仔细阅读本书第 1 章的内容,了解 MagicARM2410 实验箱的硬件结构,注意触摸屏 电路。 (2) 仔细阅读S3C2410A用户手册中的《ADC& TOUCH SCREEN INTERFACE》一节, 理解该控制器的相关寄存器的使用方法及特点。 5. 实验原理 S3C2410A 微控制器内嵌了一个 ADC 和触摸屏接口,只需要在微控制器外部外接少量 器件,就可以与触摸屏相连,实现触摸功能。在 MagicARM2410 实验箱上,触摸屏电路原 理及分析请见第 1 章。 在 Linux 操作系统中,该控制器对应的字符型驱动源文件为:s3c2410-ts.c,将该驱动编 译为模块后,生成驱动模块:s3c2410ts.ko。使用该驱动模块时,只须将该模块用 insmod 命 令插入到内核中即可。 该模块插入内核后,自动在 Linux 的/dev/目录下创建节点 touchscreen。 对触摸屏设备的操作除了打开设备、关闭设备操作以外,一般只有读操作。读操作读取 触摸屏的触点座标值及动作信息,读取结果保存在一个结构体变量中,该结构体的定义如程 序清单 6.18 所示。 该结构体的定义见配套光盘提供的 Linux 源码中的 include/asm-arm/linuette_ioctl.h 文件。 程序清单 6.18 触摸屏触点座标值及动作信息 typedef struct { unsigned short pressure; unsigned short x; unsigned short y; unsigned short pad; } TS_RET; //触摸笔动作 //触点 x 座标值 //触点 y 座标值 其中,触摸笔动作取值如下: #define PEN_UP 0 //触摸笔抬笔,即触摸屏不被压下 #define PEN_DOWN 1 //触摸笔下笔,即触摸屏被压下 #define PEN_FLEETING 2 //触摸笔拖动 编写应用程序读取触摸屏的触点座标值及动作信息时,只须利用触摸屏驱动程序便可实 现,先打开触摸屏设备,然后调用读函数即可。 6. 实验步骤 (1)在 PC 端,打开终端或者进入虚拟控制台,进入 arm 实验目录/zylinux/armwork/, 为本实验新建工作目录 touchscreen。 $ cd /zylinux/armwork $ mkdir touchscreen (2)使用自己熟悉的编辑器(例如 vi)建立文件 ts.c,根据触摸屏驱动的介绍,编写 实验代码并保存。 - 236 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com $ vi ts.c (3)编写 Makefile 或修改 5.1 节的 Makefile,使其适合于本实验。 EXEC = ts OBJS = ts.o SRC = ts.c (5)编译程序,生成可执行代码 ts。 $ make (6)启动 MagicARM2410 实验箱上的 Linux,进行 NFS 连接,进入触摸屏驱动所在目 录,先插入触摸屏驱动模块,然后进入 touchscreen 目录,运行应用程序,查看运行结果。 # insmod s3c2410ts.ko # ./ts 用触摸笔点击触摸屏上的任意一点,可在实验箱 Linux 的终端上看到打印出来的信息。 pressure is: 1 x is: 305 y is: 526 如果触摸笔离开触摸屏,则可看到以下打印信息。 pressure is: 0 x is: 0 y is: 0 7. 实验参考程序 本实验的函数在 ts.c 文件中。 (1)包含相关头文件及定义结构体,如程序清单 6.19 所示。 程序清单 6.19 包含相关头文件及定义结构体 #include #include #include /* 文件操作 */ #define PEN_UP 0 #define PEN_DOWN 1 #define PEN_FLEETING 2 /* 触摸笔抬笔,即触摸屏不被压下 */ /* 触摸笔下笔,即触摸屏被压下 */ /* 触摸笔拖动 */ typedef struct { unsigned short pressure; unsigned short x; unsigned short y; unsigned short pad; }TS_RET; /* 触摸笔动作 */ /* 触点 x 座标值 */ /* 触点 y 座标值 */ - 237 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com (2)编写 main()函数,打开驱动,读取触摸屏的触点座标值及动作信息。如程序清单 6.20 所示。程序很简单,只须调用用 read()函数(如程序清单 6.20(1)所示)就可读取触触点 座标值及动作信息了。 程序清单 6.20 main()函数 int main() { int fd,ret,i; unsigned char suba; TS_RET tsret; fd = open("/dev/touchscreen/0", O_RDWR); if(fd == -1) { printf("\nCan't open I2C device!\n"); exit(-1); } /* 打开设备 */ while(1) { ret = read(fd, (char *)&tsret, sizeof(TS_RET)); if (ret != sizeof(TS_RET)) { printf("read touch screen error!"); close(fd); exit(-1); } else { printf("pressure is: %d\n", tsret.pressure); printf("x is: %d\n", tsret.x); printf("y is: %d\n", tsret.y); } } /*读取触摸屏的触点座标值及动作信息*/ (1) close(fd); return 0; } 8. 思考 在本实验中,触摸屏的零点在左上角,请修改 main()函数,使得触摸屏的零点变为右下 角(也就是点击触摸屏右下角时,打印出来的 x 和 y 座标值都为 0)。 - 238 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 6.8 PCMCIA 接口 CF 卡实验 1. 实验目的 (1) 掌握 Linux 系统下 PCMCIA 设备驱动的配置与编译; (2) 掌握 Linux 系统 IDE 驱动模块的编译与配置; (3) 掌握 PCMCIA 设备在 Linux 系统下的使用,如挂载、操作及卸载。 2. 实验设备 硬件: 软件: PC 机 MagicARM2410 教学实验开发平台 CF 卡 CF 卡读卡器 RedHat Linux 9.0 操作系统 Windows 98/2000/XP 操作系统(可选) 嵌入式 Linux 开发环境 一台 一套 一张 一个 3. 实验内容 (1) 配置及编译 PCMCIA 驱动模块; (2) 编译 PCMCIA 控制芯片 PD6710 驱动; (3) 配置及编译 ATA 设备驱动模块; (4) 在目标系统上使用 CF 卡(PCMCIA 设备的一种),在 CF 卡上创建文件夹及验证。 4. 实验预习要求 (1) 复习 Linux 开发环境的使用方法; (2) 复习内核编译实验的相关内容。 5. 实验原理 Linux 系统对 PCMCIA 设备提供了一套完善的管理机制(软件包),通过这些机制可以 管理 PCMCIA 接口的所有设备,如:PCMCIA 存储卡、无线上网卡、CF 卡、无线网卡等等, 同时也支持 PCMCIA 设备的“热拔插”。对于不同的 PCMCIA 接口设备需要编写不同的软 件驱动(通用的设备 PCMCIA 软件包都已提供驱动),Linux 系统对 PCMCIA 设备管理机制 提供了相关的接口函数。 PCMCIA 设备管理机制提供了对 PCMCIA 控制器的支持接口,用户需根据系统选用的 PCMCIA 控制器编写硬件驱动程序。MagicARM2410 教学实验开发平台使用的控制器为 PD6710,产品光盘中已提供了该芯片的驱动源程序。 由于 PCMCIA 驱动是支持“热拔插”的,所以在编译内核时必须使内核支持“热拔插” 功能。使内核支持“热拔插”是在“General setup ”里设置的如图 6.10 和图 6.11 所示。 如果现有的内核中不支持“Support hot-pluggable devices”,需重新编译内核。 - 239 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 图 6.10 进入一般设置 图 6.11 配置支持热拔插 编译 PCMCIA 设备管理模块 前面已提过 Linux 提供了管理 PCMCIA 设备的机制,在使用这些机制前,需要将相关 的软件编译链接成模块。当然这些软件可以直接编译链接到内核中,出于考虑精简内核,我 们将其编译成模块,在需要使用 PCMCIA 设备时才加载相关模块。在图 6.11 中进入到 “PCMCIA/CardBus support”选项中设置,如图 6.12 所示。 - 240 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 图 6.12 配置生成 PCMCIA 模块 配置 CF 卡驱动 CF 卡其实是一个 IDE 设备,它与 IDE 硬盘一样需要 ATA 模块的支持。 在 Main Menu 下进入“ATA/IDE/MFM/RLL support --->”如图 6.13 所示。再选择 “ATA/IDE/MFM/RLL support”如图 6.14 所示。 图 6.13 进入 ATA 配置 - 241 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 图 6.14 配置 ATA 驱动为模块 进入到“IDE, ATA and ATAPI Block devices --->”配置选项,设置“Enhanced IDE/MFM/ RLL disk/cdrom/tape/floppy support”为模块,并设置“Include IDE/ATA-2 DISK support”和 “Include IDE/ATA-2 DISK support”为模块,如图 6.15 所示。 图 6.15 配置 ATA 选项 编译 PCMCIA 及 ATA 模块 以上配置完成后,退出并保存配置,然后执行以下命令: # make clean # make dep # make modules 将在/zylinux/kernel/drivers/ide 文件夹中生成 ide-mod.o、ide-probe-mod.o、ide-disk.o 和 ide-cs.o 文件,/zylinux/kerel/drivers/pcmcia/文件夹中生成 pcmcia_core.o、ds.o 文件。 - 242 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 编译 PD7610 驱动 从产品光盘本实验文件夹中复制 pd6700.c、pd6700.h 和 Makefile 文件到 Linux 开发环境, 并根据 Linux 开发环境修改 Makefile 文件。执行 make 命令编译连接,生成 pd6700.o 文件。 编写 config 文件 当执行了 cardmgr 命令后,内核中将创建一个进程对 PCMCIA 设备的插入与拔出进行 管理。当设备插入后进程将根据/etc/pcmcia 文件夹中的 config 文件,自动加载相关模块,所 以我们必须编写该文件。该文件内容如程序清单 6.21 所示。 程序清单 6.21 PCMCIA 配置文件 config device "ide-cs" class "ide" module "/tmp/ide-cs" # # ATA/IDE fixed disk devices # card "ATA/IDE Fixed Disk" function fixed_disk bind "ide-cs" 6. 实验步骤 (1) 配置并编译连接 PCMCIA 设备管理模块和 ATA 设备模块,见实验原理。 (2) 从产品光盘本实验文件夹中复制 pd6700.c、pd6700.h 和 Makefile 文件到 Linux 开发 环境,并根据 Linux 开发环境修改 Makefile 文件。执行 make 命令编译链接,生成 pd6700.o 文件。 (3) 将 ide-mod.o、ide-probe-mod.o、ide-disk.o、ide-cs.o、pcmcia_core.o、ds.o 和 pd6700.o 文件下载到目标板的/tmp 文件夹中。 (4) 编写 PCMCIA 设备配置文件 config,并将其下载到目标板/etc/pcmcia 文件夹中。 (5) 执行以下命令加载 ATA 模块: # cd /tmp # insmod ide-mod.o # insmod ide-probe-mod.o # insmod ide-disk.o 这里不需要加载 ide-cs.o 模块,其在 CF 卡接入时将被自动加载。这时执行 lsmod 命令 将看到以下已加载模块: # lsmod Module Size Used by ide-disk 8128 0 ide-probe-mod 7888 0 ide-mod 41392 0 [ide-disk ide-probe-mod] (6) 执行以下命令加载 PCMCIA 模块: # cd /tmp # insmod pcmcia_core.o.o - 243 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com # insmod pd6700.o # insmod ds.o 这时执行 lsmod 命令将看到以下已加载模块: # lsmod Module Size Used by ds 9168 0 (unused) pd6700 11088 1 pcmcia_core 42880 0 [ds pd6700] ide-disk 8128 0 ide-probe-mod 7888 0 ide-mod 41392 0 [ide-disk ide-probe-mod] (7) 执行 PCMCIA 服务命令 cardmgr,启动 PCMCIA 驱动服务程序。将返回以下信息: # cardmgr # cardmgr[54]: starting, version is 3.1.22 ds_open(socket 0) ds_open(socket 1) ds_open(socket 1) cardmgr[54]: watdhing 1 sockets s_ioctl(socket 0, 0x80146401, 0xbffffc28) ds_poll(socket 0) ds_poll(socket 0) 表示 PCMCIA 驱动服务程序已起动,正在等待 PCMCIA 卡的插入。 (8) 插入 CF 卡(CF 卡支持 PCMCIA 模式,可以将 CF 卡看作 PCMCIA 卡的一种)。插 入 CF 卡后,超级终端会打印出许多配置信息,最后将出现以下信息: hda: Hitachi Flash Card, ATA DISK drive ide0 at 0xd2000000-0xd2000007,0xd200000e on irq 36 hda: 125184 sectors (64 MB) w/1KiB Cache, CHS=978/4/32 Partition check: /dev/ide/host0/bus0/target0/lun0: p1 p2 p3 p4 ide_cs: hda: Vcc = 5.0, Vpp = 0.0 ds_ioctl(socket 0, 0xc050643d, 0x20125a0) DS: start get_dev_info DS: end get_dev_info ds_ioctl(socket 0, 0xc050643e, 0x20125f8) DS: start get_dev_info cardmgr[54]: executing: './ide start hda' cardmgr[54]: + ./ide: No such file or directory cardmgr[54]: start cmd exited with status 127 ds_poll(socket 0) 从以上信息可以看出,该 CF 卡是 Hitachi 公司的一 FLASH 卡,其总扇区数为 125184 - 244 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com (每扇区大小为 512 字节),每一块的大小为 1K 字节,并有 4 个分区。在非 Linux 系统下 对设备进行分区,其分区信息在 Linux 系统下不一定正确,可以通过“cat /proc/partitions” 命令判断,执行该命令后将返回以下信息: # cat /proc/partitions major minor #blocks name 30 62592 ide/host0/bus0/target0/lun0/disc 3 1 570754815 ide/host0/bus0/target0/lun0/part1 3 2 968014120 ide/host0/bus0/target0/lun0/part2 3 3 968014096 ide/host0/bus0/target0/lun0/part3 34 27749 ide/host0/bus0/target0/lun0/part4 很明显 part1、part2 、part3 和 part1 的分区信息都不对的,其实该 CF 卡并没有分区, 也即只有一个区 disc。 (9) CF 卡虽然已被初始化,但是现在还不能访问 CF 卡中的文件。需要挂载到指定的文 件夹才可以访问。执行以下命令可以挂载 CF 卡: # mkdir /mnt/cf # mount /dev/ide/host0/bus0/target0/lun0/disc /mnt/cf (10) 进入/mnt/cf 目录,创建 zhiyuan 文件夹: # cd /mnt/cf # mkdir zhiyuan (11) 执行以下命令卸载 CF 卡: # umount /mnt/cf 然后将 CF 卡拔出,并插入到 CF 卡读卡器,再将读卡器插入到 PC 机检验文件夹是否 正确创建。注意:如果不先执行 umount 命令就拔出 CF 卡,有可能数据未被写入到 CF 卡。 7. 实验参考程序 见 MagicARM2410 产品光盘本实验文件夹。 8. 思考 如何在 Linux 系统下操作 PCMCIA 接口的以太网网卡? 6.9 IDE 硬盘实验 1. 实验目的 (1) 掌握 Linux 系统下 IDE 硬盘驱动的编写与使用; (2) 掌握 Linux 系统 IDE 驱动模块的编译与配置; (3) 了解 PD6710 芯片的 ATA 模式的设置及使用。 2. 实验设备 硬件: PC 机 MagicARM2410 教学实验开发平台 一台 一套 - 245 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 软件: IDE 硬盘 RedHat Linux 9.0 操作系统 Windows 98/2000/XP 操作系统(可选) 嵌入式 Linux 开发环境 一块 3. 实验内容 (1) 编写及编译 PD6710 芯片 ATA 模式下的驱动程序; (2) 配置及编译 ATA 设备驱动模块; (3) 加载 ATA 驱动模块和 PD6710 驱动,在 IDE 硬盘上创建文件夹,并验证。 4. 实验预习要求 (1) 了解 PD6710 芯片 ATA 模式的使用。 (2) 复习内核编译实验的相关内容。 (3) 复习 6.8 小节实验中的 ATA 驱动模块的编译。 5. 实验原理 IDE 设备是 Linux 系统下常用的数据存储设备,其容量大而且价格便宜的特点是其它存 储设备不可比拟的。所以在数据量特大的嵌入式系统应用中,IDE 设备是不可以缺少的。 PD6710 是一个 PCMCIA 接口的桥接芯片,它可以完成实现 PCMCIA 接口的所有功能。它 还有一种工作模式,那就 ATA 模式。 Linxu 系统中带有了完整的 ATA 设备驱动,并且提供了简易接口。只需要用户提供两个 基地址及 1 个中断号,就可以由内核接管 ATA 设备。注册及注销 IDE 设备的接口函数如程 序清单 6.22 所示。 程序清单 6.22 ATA 设备驱动接口函数 int ide_register (int arg1, int arg2, int irq); void ide_unregister (unsigned int index); ide_register()函数为注册 ATA 设备,其有三个输入参数:arg1、arg2 和 irq。arg1 为一般 寄存器的起始地址,其地址为:vCF_IO_BASE + 0x1f0,vCF_IO_BASE 为 PD6710 芯片所 在系统中 IO 地址的虚拟地址;arg2 为控制寄存器的起始地址,其地址为:vCF_IO_BASE + 0x3f6;irq 则为 ATA 设备分配的中断号,这与硬件系统分配的中断引脚相关。使用该函数 注册 ATA 设备成功将返回一个设备索引号,该索引号在 IDE 设备注销时使用。 ide_unregister()函数注销 ATA 设备,其只有 1 个参数 index,该参数为注册 ATA 设备时 返回的值。 配置 PD6710 为 ATA 模式 MagicARM2410产品光盘中已提供了PD6710在ATA模式的驱动,将光盘本实验文件夹中 复制pd6700_ide.c、pd6700.h和Makefile文件到Linux开发环境,并根据Linux开发环境修改 Makefile文件。执行make命令编译连接,生成pd6700_ide.ko文件。 关于PD6710的ATA模式设置请参阅Intel公司的PD67XX — Configuring PCMCIA Sockets for ATA Drive Interface文档。 - 246 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 配置 ATA 驱动模块 在 Main Menu 下进入“ATA/IDE/MFM/RLL support --->”如图 6.16 所示。再选择 “ATA/IDE/MFM/RLL support”如图 6.17 所示。 图 6.16 进入 ATA 配置 图 6.17 配置 ATA 驱动为模块 进入到“IDE, ATA and ATAPI Block devices --->”配置选项,设置“Enhanced IDE/MFM/ RLL disk/cdrom/tape/floppy support”为模块,并设置“Include IDE/ATA-2 DISK support”和 “Include IDE/ATA-2 DISK support”为模块,如图 6.18 所示。 - 247 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 图 6.18 配置 ATA 选项 编译 ATA 模块 以前配置完成后,退出并保存配置,然后执行以下命令: $ make clean $ make dep $ make modules 将在/zylinux/kernel/drivers/ide 文件夹中生成 ide-mod.o、ide-probe-mod.o 和 ide-disk.o 文 件。 注意事项 IDE 硬盘不支持热插拔,所以在系统起动前应将 IDE 硬盘连接到系统并上电。在系统运 行过程中不允许拔出硬盘。 6. 实验步骤 (1) 配置并编译连接 ATA 设备模块,参考实验原理。 (2) 从产品光盘将本实验文件夹中复制 pd6700_ide.c、pd6700.h 和 Makefile 文件到 Linux 开发环境,并根据 Linux 开发环境修改 Makefile 文件。执行 make 命令编译链接, 生成 pd6700_ide.ko 文件。 (3) 将 MagcARM2410 上的 PCMCIA 接口或 CF 卡接口的设备拔出,将硬盘连接到 MagcARM2410 的 IDE 接口,然后给硬盘上电(电源需要另外提供),并将 IDE 接 口旁边的 JP13 路线帽短接。 (4) 启动 MagcARM2410 的 Linux 系统,并将 ide-mod.o、ide-probe-mod.o、ide-disk.o 和 pd6700_ide.ko 文件下载到目标板的/tmp 文件夹中。 (5) 执行以下命令加载 ATA 模块: # cd /tmp # insmod ide-mod.o # insmod ide-probe-mod.o # insmod ide-disk.o - 248 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 这时执行 lsmod 命令将看到以下已加载模块: # lsmod Module Size Used by ide-disk 8128 0 ide-probe-mod 7888 0 ide-mod 41392 0 [ide-disk ide-probe-mod] (6) 执行以下命令,加载 PD6710 的 ATA 驱动模块: # insmod pd6700_ide.ko 执行以上命令后终端将会打印出许多配置信息,最后将出现以下信息: hda: QUANTUM FIREBALLlct08 04, ATA DISK drive ide0 at 0xd20001f0-0xd20001f7,0xd20003f6 on irq 36 hda: 8421840 sectors (4312 MB) w/418KiB Cache, CHS=8912/15/63 Partition check: /dev/ide/host0/bus0/target0/lun0: p1 p2 < p5 p6 p7 > PD6710 IDE: ide_register() at 0xd20001f0 & 0xd20003f6, irq 36 从以上信息可以看出,该 IDE 硬盘是 QUANTUM 公司的 ATA 硬盘,其总扇区数为 8421840(每扇区大小为 512 字节),也即 40G。执行 cat /proc/partitions 命令浏览分区信息, 执行该命令后将返回以下信息: # cat /proc/partitions major minor #blocks name 3 0 4210920 ide/host0/bus0/target0/lun0/disc 3 1 1028128 ide/host0/bus0/target0/lun0/part1 32 1 ide/host0/bus0/target0/lun0/part2 3 5 1028128 ide/host0/bus0/target0/lun0/part5 3 6 1028128 ide/host0/bus0/target0/lun0/part6 3 7 1124518 ide/host0/bus0/target0/lun0/part7 (7) IDE 硬盘虽然已被初始化,但是现在还不能访问硬盘中的文件。需要挂载到指定的 文件夹才可以访问。执行以下命令挂载 IDE 硬盘的第一个分区: # mount /dev/ide/host0/bus0/target0/lun0/part1 /mnt (8) 进入/mnt 目录,创建 zhiyuan 文件夹: # cd /mnt/cf # mkdir zhiyuan (9) 使用 vi 命令在硬盘中创建一个文本文件 test.txt,并向文本文件中写入任意字符。 (10) 执行以下命令卸载 IDE 硬盘,将数据写入硬盘: # cd / # umount /mnt 注意:如果不执行 umount 命令,有可能数据未被写入到硬盘。 - 249 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com (11) 重新启动 Linux 系统,检查之前在硬盘中创建的文件夹及文件是否正确,参考本 实验的 4~7 步。 7. 实验参考程序 见 MagicARM2410 产品光盘的工程文件。 8. 思考 如何在 Linux 系统下操作 IDE 接口的 CDROM? 6.10 USB 主机驱动编译与加载实验 1. 实验目的 (1) 掌握 Linux 系统下 USB 内核及 USB 主控制器驱动模块的配置及编译; (2) 了解 Linux 系统下 USB 主机的软件结构。 2. 实验设备 硬件: 软件: PC 机 MagicARM2410 教学实验开发平台 U盘 Red Hat Linux 9.0 操作系统 Windows 98/2000/XP 操作系统(可选) 嵌入式 Linux 开发环境 一台 一套 一个 3. 实验内容 (1) 配置及编译链接 USB 内核相关模块; (2) 编译链接 USB 主机控制器驱动模块; (3) 在目标系统中加载 USB 内核模块及 USB 主机控制器驱动模块,然后插入 U 盘,观 察终端的打印信息。 4. 实验预习要求 (1) 复习 Linux 系统开发环境的使用; (2) 复习内核模块的编译相关内容。 5. 实验原理 Linux 系统 2.4.18 版本内核中包含了功能全面的 USB 主机内核软件,通过该内核将 USB 的软件与硬件隔离开。对于不同的 USB 主机控制器只需要编写与硬件相关的驱动程序就可 以在 Linux 系统下使用。USB 内核提供了两套 API,分别为高层 API 和低层 API,如图 6.19 所示。高层 API 是与硬件无关的,由应用程序使用的函数集;低层 API 也就是与硬件底层 USB 主机控制器相关的函数集。不同的 USB 主机控制器使用低层 API 编写其驱动程序。 - 250 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 高API层 低API层 USB 设备驱动程序 USB 设备驱动程序 USB 设备驱动程序 USB 内核 USB HC 驱动程序 USB HC 驱动程序 图 6.19 USB 主机驱动软件结构 编译 USB 内核及其文件系统模块: 在/zylinux/kernel 目录下输入 make menuconfig 命令配置内核,在打开的 Main Menu 菜单 窗口中进入“USB support ---> ”选项,如图 6.20 所示。 图 6.20 进入 USB suport 选项 进入到 USB suport 选项菜单后,配置“Support for USB”为模块,并选上 “Preliminary USB device filesystem (NEW) ”选项,如图 6.21 所示。 - 251 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 图 6.21 USB support 配置 退出并保存配置,并使用 make dep 命令建立依赖文件,然后使用 make modules 命令编 译并链接模块。最后将在/zylinux/kernel/drivers/usb/文件夹下生成 usbcore.o 文件,该文件就 是我们需要的 USB 内核文件。 编译链接 S3C2410A 芯片 USB 主机控制器驱动模块: 开发套件的光盘中提供了 USB 主机控制器驱动程序,将光盘本实验文件夹中的驱动文 件复制到 Linux 开发环境中的任意文件夹,然后修 Makefile 文件,如程序清单 6.23 所示。 只需要修改程序清单 6.23 (1)那行代码,将其改为在 Linux 开发环境中内核头文件的路径。 程序清单 6.23 USB 主机控制器驱动 Makefile EXEC = usb-ohci-s3c2410.ko OBJS = usb-ohci-s3c2410.o usb-ohci.o SRC = usb-ohci-s3c2410.c usb-ohci.c INCLUDE = /zylinux/kernel/include (1) USEINC =. CC = arm-linux-gcc LD = arm-linux-ld MODCFLAGS = -O2 -I$(INCLUDE) -I$(USEINC) -march=armv4t -c -o LDFLAGS = -r all: $(EXEC) $(EXEC): $(OBJS) $(LD) $(LDFLAGS) -o $@ $(OBJS) %.o:%.c $(CC) $(MODCFLAGS) -mapcs -c $< -o $@ clean: -rm -f $(EXEC) *.o *~ core 执行 make 命令编译链接驱动,最后将生成 usb-ohci-s3c2410.ko 模块文件。 USB 内核模块和主机控制器驱动模块在目标系统中成功加载后,当有 USB 设备插入到 - 252 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com USB 下行口时,内核将检测到设备插入并查找适合的驱动初始化设备。由于 USB 的设备驱 动没有加载,当插入一个 USB 设备(USB 集线器除外)终端将打印出以下信息: # hub.c: USB new device connect on bus1/1/4, assigned device number 3 usb.c: USB device 3 (vend/prod 0x9a6/0x8001) is not claimed by any active driver. 6. 实验步骤 (1) 使用 make menuconfig 命令配置 USB 内核模块,参见实验原理; (2) 编译连接 S3C2410 芯片的 USB 主机控制器驱动,参见实验原理; (3) 运行目标板 Linux 系统,并将 usbcore.o 模块和 usb-ohci-s3c2410.ko 模块下载到目标 板; (4) 在目标板系统中使用 insmod 命令先加载 usbcore.o 模块,这时终端将打印出以下信 息: # insmod usbcore.o usb.c: registered new driver usbdevfs usb.c: registered new driver hub (5) 在目标板系统中使用 insmod 命令先加载 usb-ohci-s3c2410.ko 模块,这时终端将打 印出以下信息: # insmod usb-ohci-s3c2410.ko usb-ohci.c: USB OHCI at membase 0xe9000000, IRQ 26 usb.c: new USB bus registered, assigned bus number 1 Product: USB OHCI Root Hub SerialNumber: e9000000 hub.c: USB hub found port #1 suspened! port #0 alived! hub.c: 1 port detected (6) 将 U 盘插入目标板的 USB 下行口,这时将打印出以下信息: # hub.c: USB new device connect on bus1/1, assigned device number 2 usb.c: USB device 2 (vend/prod 0x9a6/0x8001) is not claimed by any active driver. 0x9a6 是该 U 盘的厂家 ID,0x8001 为该产品 ID。由于大容量驱动未加载所以出现以上 信息。 7. 实验参考程序 参考程序见光盘本实验文件夹 usb-ohci.c 和 usb-ohci-s3c2410.c 文件。 8. 思考 请思考,如何加载 USB 大容量设备类驱动,使系统中可以使用 U 盘? 6.11 U 盘驱动程序编译与使用实验 1. 实验目的 (1) 掌握 USB 大容量类设备驱动 Linux 模块的配置与编译; - 253 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com (2) 掌握 Linux 系统下 U 盘等大容量设备的使用。 2. 实验设备 硬件: 软件: PC 机 MagicARM2410 教学实验开发平台 U盘 RedHat Linux 9.0 操作系统 Windows 98/2000/XP 操作系统(可选) 嵌入式 Linux 开发环境 一台 一套 一个 3. 实验内容 (1) 编译及连接 USB 大容量类设备驱动模块; (2) 下载大容量类设备驱动模块到目标板,并加载模块; (3) 挂载 U 盘到 Linux 系统,然后往 U 盘里创建文件与文件夹。 4. 实验预习要求 (1) 复习 USB 主机驱动编译与加载实验内容; (2) 复习 Linux 系统下文件的操作与 VI 的使用。 5. 实验原理 U 盘、移动硬盘、MP3 和数码相机等都是大容量类设备。大容量设备底层是基于 USB 接口,上层由大容量类驱动映射成 SCSI 磁盘设备。所以,实现对 U 盘的操作主要包含三个 模块:USB 主机驱动、大容量类设备驱动和 SCSI 磁盘设备驱动模块。 USB 主机驱动在 6.10 小节已介绍,这里主要介绍大容量类设备驱动和 SCSI 磁盘设备驱 动模块的编译及链接。 在终端使用 make menuconfig 命令打开 S3C2410Linux 内核编译的 Main Menu 窗口,并 进入“SCSI support --->”菜单选项,然后将 SCSI disk support 配置为模块,再将 SCSI disk support 也配置为模块如图 6.22 所示。 图 6.22 配置 SCSI 磁盘设备 - 254 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 返回主菜单(Main Menu),再进入“USB support --->” 菜单选项,然后将 Support for USB 设置为模块,再将 USB Mass Storage support 配置为模块,如图 6.23 所示。 图 6.23 配置 USB 大容量驱动 以上配置已完成了 USB 大容量驱动的配置及 SCSI 磁盘设备驱动模块的配置。退出并 保存配置,使用 make dep 命令建立文件依赖关系,然后使用 make modules 命令编译链接模 块。编译链接完成后,在/zylinux/kernel/drivers/scsi/文件夹中生成 scsi_mod.o 和 sd.o 模块,在 /zylinux/ kernel/drivers/usb/storage /文件夹中生成 usb-storage.o 模块。 在目标系统中加载以下模块就可以实现 USB 大容量设备的支持: USB 主机: usbcore.o usb-ohci-s3c2410.ko SCSI 磁盘驱动: scsi_mod.o sd.o 大容量类驱动: usb-storage.o 6. 实验步骤 (1) 配置及编译链接大容量类驱动、SCSI 磁盘驱动,参考实验原理。 (2) 将 usbcore.o、usb-ohci-s3c2410.ko、scsi_mod.o、sd.o 和 usb-storage.o 文件下载到 目标板的/tmp 文件夹中。 (3) 加载 USB 主机驱动模块,在终端输入以下命令: # insmod usbcore.o # insmod usb-ohci-s3c2410.ko (4) 加载 SCSI 磁盘驱动模块,在终端输入以下命令: # insmod scsi_mod.o # insmod sd.o (5) 加载 USB 大容量类驱动模块,在终端输入以下命令: # insmod usb-storage.o (6) 插入 U 盘后,终端将打印出以下信息: - 255 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com # hub.c: USB new device connect on bus1/1, assigned device number 2 scsi0 : SCSI emulation for USB Mass Storage devices Vendor: Aigo Model: 2.0 Rev: 1.06 Type: Direct-Access ANSI SCSI revision: 02 Attached scsi removable disk sda at scsi0, channel 0, id 0, lun 0 SCSI device sda: 260384 512-byte hdwr sectors (133 MB) sda: Write Protect is off Partition check: /dev/scsi/host0/bus0/target0/lun0: p1 p2 p3 p4 (7) 挂载 U 盘到/mnt 目录,在终端输入以下命令: # mount -t vfat /dev/scsi/host0/bus0/target0/lun0/disc /mnt (8) 在 U 盘里创建 1 个文件夹与 1 个文本文件。使用以下命令进入/mnt 目录,并创建 一个文件夹 zhiyuan 和文件 test.txt。 # cd /mnt # mkdir zhiyuan # vi test.txt (9) 卸载 U 盘,然后拔出 U 盘,将 U 盘插入到电脑,验证之前创建的文件夹与文件 是否成功。输入以下命令卸载 U 盘: # cd / # umount /mnt 7. 实验参考程序 本实验不需要编写程序。 8. 思考 请思考,如何编写应用程序来操作 U 盘? 6.12 USB 键盘与鼠标应程序实验 1. 实验目的 (1) 掌握如何在 Linux 就应程序中使用 USB 键盘鼠标设备; (2) 掌握如何配置及编译 Linux 输入设备模块及模块的加载; (3) 掌握如何配置及编译 USB 键盘鼠标驱动模块及模块的加载。 2. 实验设备 硬件: 软件: PC 机 MagicARM2410 教学实验开发平台 USB 接口键盘 USB 接口鼠标 RedHat Linux 9.0 操作系统 Windows 98/2000/XP 操作系统(可选) 一台 一套 一个 一个 - 256 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 嵌入式 Linux 开发环境 3. 实验内容 (1) 配置及编译链接输入设备驱动模块; (2) 配置及编译链接 USB 接口键盘和鼠标驱动模块; (3) 编写应用程序,将 USB 接口键盘或 USB 接口鼠标事件信息打印到终端。 4. 实验预习要求 (1) 熟悉嵌入式 Linux 应用程序的编写及其编译调试的方法。 (2) 熟悉 nfs 文件系统的使用。 (3) 复习 USB 主机驱动编译与加载实验内容; (4) 了解 Linux 输入设备模块的配置及 HID 设备模块配置相关内容。 5. 实验原理 Linux 系统中集成了输入内核,通过输入内核管理各种各样的输入设备,如 GPIO 输入 按键、PS2 接口的键盘和鼠标、USB 接口的键盘、鼠标和操纵杆等。不同类型的输入设备, 输入内核都为上层软件提供了统一的接口,该接口称为事件接口。 输入内核中的事件接口对于不同的输入设备,输入内核根据检测到设备的先后顺序分配 一个事件的节点,这些节点都是以设备的形式在/dev/input/文件夹下出现,设备的名称为 event0~event31。应用程序通过 open()函数打开事件设备,然后通过 read()可以读出事件的 数据。每个事件的数据固定为 16 字节,以 struct input_event 数据结构格式存储,该数据结 构如程序清单 6.24 所示。 程序清单 6.24 输入事件数据结构 struct input_event { struct timeval time; unsigned short type; unsigned short code; unsigned int value; }; time,为事件产生的时间,该时间以 struct timeval 结构体格式表示。 type,为事件的类型。EV_KEY(代码为 0x01)为按键事件,如键盘按键和鼠标上的按 键等;EV_REL(代码为 0x02)为轨迹事件,如鼠标移动的轨迹等。 code,事件的代码。如果事件的类型代码是 EV_KEY,该代码 code 为设备键盘代码。 代码植 0~127 为键盘上的按键代码,0x110~0x116 为鼠标上按键代码,其中 0x110(BTN_ LEFT)为鼠标左键,0x111(BTN_RIGHT)为鼠标右键,0x112(BTN_ MIDDLE)为鼠标 中键。其它代码含义请参看/zylinux/kernel/include/linux/input.h 文件。 如果事件的类型代码是 EV_REL,code 值表示轨迹的类型。如指示鼠标的 X 轴方向 REL_X(代码为 0x00),指示鼠标的 Y 轴方向 REL_Y(代码为 0x01),指示鼠标中轮子方 向 REL_WHEEL(代码为 0x08)。 value,事件的值。如果事件的类型代码是 EV_KEY,当按键按下时值为 1,松开时值为 0;如果事件的类型代码是 EV_ REL,value 的正数值和负数值分别代表两个不同方向的值。 - 257 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 配置输入内核模块 在/zylinux/kernel 目录下输入 make menuconfig 命令配置内核,并进入“Input core support --->”菜单选项,然后将 Input core support、Keyboard support、Mouse support 和 Event interface support 配置为模块,如图 6.24 所示。 图 6.24 配置输入内核 配置 USB 键盘鼠模块 返回主菜单(Main Menu),再进入“USB support --->” 菜单选项,然后将 Support for USB、USB HIDBP Keyboard (basic) support 和 USB HIDBP Mouse (basic) support 设置为模块, 如图 6.25 所示。 图 6.25 配置 USB HID 驱动 编译连接模块 退出并保存配置,使用 make dep 命令建立文件依联关系,然后使用 make modules 命令 编译链接模块。编译链接完成后,在/zylinux/kernel/drivers/input/文件夹中生成 input.o、evdev.o、 keybdev.o 和 mousedev.o 模 块 , 在 /zylinux/kernel/drivers/usb/ 文 件 夹 中 生 成 usbkbd.o 和 usbmouse.o 模块。 - 258 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 模块安装 执行以下命令安装输入模块: # insmod input.o # insmod evdev.o # insmod keybdev.o # insmod mousedev.o 执行以下命令安装输入设备驱动模块: # insmod usbcore.o # insmod usb-ohci-s3c2410.ko # insmod usbkbd.o # insmod usbmouse.o 由于使用的设备是 USB 接口的键盘和鼠标,所以在加载键盘鼠标驱动模块前,需要加 载 USB 内核驱动和主机控制器驱动。 6. 实验步骤 (1) 打开终端或进入虚拟控制台,进入嵌入式 Linux 开发环境中内核文件夹,配置及编 译链接输入内核模块和 USB 键盘鼠标驱动模块,参考实验原理。 (2) 使用自己熟悉的编辑器如 vi 建立文件 main.c,编写实验代码并保存。 (3) 将光盘提供的 Makefile 文件复制到当前目录下进行修改,使之适合本实验,如果编 译器路径和光盘提供的不一致,还需修改编译器路径。 EXEC = inputdevice.ko OBJS = main.o SRC = main.c (4) 编译程序,生成 inputdevice.ko 文件,然后修改文件属性为可执行。 # make # chmod 777 inputdevice.ko (5) 启动目标板 Linux 系统,进行 NFS 连接,分别进入输入内核模块文件夹和 USB 键 盘鼠标驱动模块文件夹,并加载各模块。 (6) 插入 USB 键盘到目标板的 USB 接口,然进入 inputdevice.ko 所在的文件夹,并运行 该程序。 # ./inputdevice.ko (7) 敲击键盘按键,观察终端打印的信息。如敲击键盘 A 键,终端打印信息如下: Watting event ... Keyboard key, the code is : 30 Press down. Exit , please press : Ctrl + C Watting event ... Keyboard key, the code is : 30 - 259 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com Press up. Exit , please press : Ctrl + C Watting event ... (8) 拔出 USB 键盘(inputdevice.ko 自动退出),然后插入 USB 鼠标,再次运行 inputdevice.ko 程序。 (9) 移动鼠标或敲击鼠标按键,观察终端打印的信息。 7. 实验参考程序 本实验应用程序代码如程序清单 6.25 所示。 程序清单 6.25 输入事件应用程序 #include #include #include typedef struct input_event Myinputevent; #define DEVICENAME "/dev/input/event0" int main(int argc, char **argv) { int i, n; int fd; unsigned char data[8]; Myinputevent event; fd = open( DEVICENAME , O_RDONLY, 0); // 打开设备 if (fd < 0) { perror("Can't open device...\n"); exit(1); } while(1) { printf("Watting event ...\n\n\n"); n = read(fd, &event, sizeof(Myinputevent) ); // 读数事件数据 if ( n != 16 ) { perror(" Read data error! "); exit(1); } if(event.type == EV_KEY) { if((event.code >= BTN_MOUSE)&&(event.code <= BTN_BACK)) printf(" Mouse key, the code is : %x \n",event.code); if((event.code >= KEY_ESC)&&(event.code <= KEY_UNKNOWN)) printf(" Keyboard key, the code is : %d \n",event.code); - 260 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com // 如果是按键事件,该值为 1 表示按下,为 0 表示松开,如果为 2 表示键盘按键长按。 if(event.value) printf(" Press down.\n"); else printf(" Press up.\n"); } if(event.type == EV_REL) // 轨迹事件类型 { if(event.code == REL_X) // X 轴移动 printf(" X track moving : %d\n\n",event.value); if(event.code == REL_Y) // Y 轴移动 printf(" Y track moving : %d\n\n",event.value); if(event.code == REL_WHEEL) // 中轮移动 printf(" WHEEL track moving : %d\n\n",event.value); } printf("Exit , please press : Ctrl + C \n"); } return 0; } 8. 思考 请思考,如何在应用程序判别输入设备的类型? 6.13 FrameBuffer 模块应用实验 1. 实验目的 (1) 掌握 Linux 系统下 FrameBuffer 驱动的基本使用方法; (2) 掌握 FrameBuffer 常用 API 函数的使用方法。 2. 实验设备 硬件: 软件: PC 机 MagicARM2410 教学实验开发平台 RedHat Linux 9.0 操作系统 Windows 98/2000/XP 操作系统(可选) 嵌入式 Linux 开发环境 一台 一套 3. 实验内容 使用 Linux 系统 FrameBuffer 驱动提供的 API 函数编写应用程序,实现在 MagicARM2410 实验开发平台的液晶中间填充一块颜色。 4. 实验预习要求 (1) 熟悉嵌入式 Linux 应用程序的编写及其编译调试的方法。 (2) 熟悉 nfs 文件系统的使用。 - 261 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 5. 实验原理 FrameBuffer 中文译名帧缓冲,该设备提供了 LCD 控制器的抽象描述。它同时代表了 LCD 控制器上的显存,应用程序通过定义好的接口可以访问 LCD 控制器,而不需要知道底层的 任何操作。 该设备使用特殊的设备节点,通常位于/dev 目录,如/dev/fb*。他是一个字符设备,其主 设备号是 29,次设备号定义帧缓冲的个数。从用户的角度看,帧缓冲设备和其他位于/dev 下面的设备类似。通常,使用如下方式(前面的数字代码次设备号): 0 = /dev/fb0 First frame buffer 1 = /dev/fb1 Second frame buffer ... 31 = /dev/fb31 32nd frame buffer 帧缓冲设备也是一种普通的内存设备,可以读写其内容,例如,对屏幕抓屏 cp /dev/fb0 myfile。系统也可以同时有多个显示设备,例如主板上有内置的 LCD 控制器还有另一独立的 LCD 控制器。对应的帧缓冲设备(/dev/fb0 和 /dev/fb1 等)可以独立工作。 正如刚才所说,一个帧缓冲设备和内存设备类似/dev/mem,并且有许多共性。可以使用 read()、write()、seek()以及 mmap()函数。不同仅仅是帧缓冲的内存不是所有的内存区,而是 LCD 控制器专用的那部分内存。/dev/fb*也允许使用 ioctl 操作,通过 ioctl 可以读取或设定设 备参数。颜色映射表也是通过 ioctl 设定。查看就知道有多少 ioctl 应用以及相关 数据结构。这里给出摘要: 可以获取设备一些不变的信息,如设备名,屏幕的组织(平面,象素,...)对应内存 区的长度和起始地址。 也可以获取可以发生变化的信息,例如位深,颜色格式,时序等。如果你改变这些 值,驱动程序将对值进行优化,以满足设备特性(如果你的设定,设备不支持,返 回 EINVAL)。 也可以获取或设定部分颜色表。 所有这些特性让应用程序十分容易地使用设备。MiniGUI 和 QT 等 GUI 软件可以使用 /dev/fb*而不需知道硬件的寄存器是如何组织的。 使用 read、write 函数在读或写之前持续的寻址将会导致很多的开销。这就是为什么要 映射屏幕内存。当你将屏幕内存映射到你的应用程序时,你将得到一个直接指向屏幕内存的 指针。 在我们可以映射屏幕内存之前,我们需要知道我们能够映射多少,以及我们需要映射多 少。第一件要做的事情就是从我们新得到的 framebuffer 设备取回信息,有两个结构包含着 我们需要的信息,第一个包含固定的屏幕信息,这部分是由硬件和驱动的能力决定的;第二 个包含着可变的屏幕信息,这部分是由硬件的当前状态决定的,可以由用户空间的程序调用 ioctl()来改变。 固定的屏幕信息可以使用 FBIOGET_FSCREENINFO 通过 ioctl()函数获得,得到的数据 结构如程序清单 6.26 所示。 程序清单 6.26 固定的屏幕信息数据结构 struct fb_fix_screeninfo { char id[16]; unsigned long smem_start; /* identification string eg "TT Builtin" */ /* Start of frame buffer mem */ /* (physical address) */ - 262 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com __u32 smem_len; __u32 type; __u32 type_aux; __u32 visual; __u16 xpanstep; __u16 ypanstep; __u16 ywrapstep; __u32 line_length; unsigned long mmio_start; __u32 mmio_len; __u32 accel; __u16 reserved[3]; }; /* Length of frame buffer mem */ /* see FB_TYPE_* */ /* Interleave for interleaved Planes */ /* see FB_VISUAL_* */ /* zero if no hardware panning */ /* zero if no hardware panning */ /* zero if no hardware ywrap */ /* length of a line in bytes */ /* Start of Memory Mapped I/O */ /* (physical address) */ /* Length of Memory Mapped I/O */ /* Type of acceleration available */ /* Reserved for future compatibility */ 程序清单 6.26 中非常重要的域是 smem_len 和 line-length。smem-len 告诉我们 framebuffer 设备的大小,第二个域告诉我们指针应该前进多少字节去得到下一行的数据。 可变的屏幕信息使用 FBIOGET_VSCREENINFO 通过 ioctl()函数获得,该数据结构则有 更多的意思,它给了我们可以改变的信息,如程序清单 6.27 所示。 程序清单 6.27 可变的屏幕信息数据结构 struct fb_var_screeninfo { __u32 xres; __u32 yres; __u32 xres_virtual; __u32 yres_virtual; __u32 xoffset; __u32 yoffset; /* visible resolution */ /* virtual resolution */ /* offset from virtual to visible */ /* resolution */ __u32 bits_per_pixel; __u32 grayscale; /* guess what */ /* != 0 Graylevels instead of colors */ struct fb_bitfield red; struct fb_bitfield green; struct fb_bitfield blue; struct fb_bitfield transp; /* bitfield in fb mem if true color, */ /* else only length is significant */ /* transparency */ __u32 nonstd; __u32 activate; __u32 height; __u32 width; /* != 0 Non standard pixel format */ /* see FB_ACTIVATE_* */ /* height of picture in mm */ /* width of picture in mm */ __u32 accel_flags; /* acceleration flags (hints) */ - 263 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com /* Timing: All values in pixclocks, except pixclock (of course) */ __u32 pixclock; /* pixel clock in ps (pico seconds) */ __u32 left_margin; /* time from sync to picture */ __u32 right_margin; /* time from picture to sync */ __u32 upper_margin; /* time from sync to picture */ __u32 lower_margin; __u32 hsync_len; /* length of horizontal sync */ __u32 vsync_len; /* length of vertical sync */ __u32 sync; /* see FB_SYNC_* */ __u32 vmode; /* see FB_VMODE_* */ __u32 reserved[6]; /* Reserved for future compatibility */ }; 前几个成员决定了分辨率。xres 和 yres 是在屏幕上可见的实际分辨率,在通常的 vga 模 式将为 640 和 400(也许是 480)。*res-virtual 决定了构建屏幕时视频卡读取屏幕内存的方式。 当实际的垂直分辨率为 400,虚拟分辨率可以是 800。这意味着 800 行的数据被保存在了屏 幕内存区中。因为只有 400 行可以被显示,决定从那一行开始显示就是你的事了。这个可以 通过设置*offset 来实现。给 yoffset 赋 0 将显示前 400 行,赋 35 将显示第 36 行到第 435 行, 如此重复。这个功能在许多情形下非常方便实用。它可以用来做双缓冲。双缓冲就是程序分 配了可以填充两个屏幕的内存。将 offset 设为 0,将显示前 400 行(假设是标准的 vga),同 时可以秘密的在 400 行到 799 行构建另一个屏幕,当构建结束时,将 yoffset 设为 400,新的 屏幕将立刻显示出来。现在将开始在第一块内存区中构建下一个屏幕的数据,如此继续。这 在动画中十分有用。 将 bits_per_pixel 设为 1,2,4,8,16,24 或 32 来改变颜色深度(color depth)。不是 所有的视频卡和驱动都支持全部颜色深度。当颜色深度改变,驱动将自动改变 fb-bitfields。 现在我们知道了结构的细节了,但还不清楚如何去获得或设置它们。这里有一些 ioctl 的命令可以参考,见程序清单 6.28。 程序清单 6.28 ioctl 的命令使用参考 int main () { int framebuffer_handler; struct fb_fix_screeninfo fixed_info; struct fb_var_screeninfo variable_info; framebuffer_handler = open ("/dev/fb0", O_RDWR); ioctl (framebuffer_handler,FBIOGET_VSCREENINFO, &variable_info); variable_info.bits_per_pixel = 32; ioctl(framebuffer_handler, FBIOPUT_VSCREENINFO, &variable_info); ioctl (framebuffer_handler,FBIOGET_FSCREENINFO, &fixed_info); variable_info.yoffset = 513; ioctl (framebuffer_handler,FBIOPAN_DISPLAY, &variable_info); } - 264 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 这些 FBIOGET_*的 ioctl 命令将请求的信息写入最后一个变量所指向的结构体中。 FBIOPUT_VSCREENINFO 将所有提供的信息复制回内核。如果内核不能激活新的设置,将 返回-1。 FrameBuffer 的一般使用步骤如下: 计算出需要映射多少 ; 映射内存; 决定如何构建屏幕; 向屏幕中写入数据。 使用例程如程序清单 6.29 所示。 程序清单 6.29 FrameBuffer 使用例程 int main() { int framebuffer_device; int line_size,buffer_size, *i; int *screen_memory; struct fb_var_screeninfo var_info; framebuffer_device = open ( "/dev/fb0" , O_RDWR); ioctl (framebuffer_device, FBIOGET_VSCREENINFO, &var_info); line_size = var_info.xres * var_info.bits_per_pixel / 8; // 计算一行字节数 buffer_size = line_size * var_info.yres; // 计算显存缓冲区大小 var_info.xoffset = 0; var_info.yoffset = 0; ioctl (framebuffer_device, FBIOPAN_DISPLAY,&var_info) == -1); screen_memory = (char *) mmap (513, buffer_size, PROT_READ | PROT_WRITE, MAP_SHARED, framebuffer_device, 0); for (i=0;i < buffer_size ; i++ ) { *(screen_memory+i) = i%236; } sleep(2); return 0; } 程序清单 6.29 中新用到的是 mmap 函数。第一个变量在这种情形下可以忽略,第二个 是映射的内存大小,第三个变量声明我们将共享内存进行读和写。第四个变量表示这段内存 将和其他进程共享。在 framebuffer 上面建一个 MAP_PRIVATE 是不可能的。 通常这意味着 你需要中断控制台的切换去备份和恢复屏幕内容,而且不在自己没有权利的时候向屏幕内存 写东西。 系统中第 1 个 FrameBuffer 设备的节点为/dev/fb0,如果文件系统中没有该节点则应先创 建该节点。执行该命令:mknod /dev/fb0 c 29 0。 - 265 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 6. 实验步骤 (1) 使用自己熟悉的编辑器如 vi 建立文件 main.c,编写实验代码并保存。 (2) 将光盘提供的 Makefile 文件复制到当前目录下进行修改,使之适合本实验,如果编 译器路径和光盘提供的不一致,还需修改编译器路径。 EXEC = framebuff.ko OBJS = framebuff.o SRC = framebuff.c (3) 编译程序,生成 framebuff.ko 文件,然后修改文件属性为可执行。 # make # chmod 777 framebuff.ko (4) 使用短路器短接目标板的 JP7,然后启动目标板 Linux 系统进行 NFS 连接,并进入 framebuff.ko 文件所在的目录。 (5) 运行 framebuff.ko 程序,观察液晶屏显示的状态。 7. 实验参考程序 本实验完整的参考程序如程序清单 6.30 所示。 程序清单 6.30 Frame Buffer 应用程序 #include #include #include #include #include int main() { int fbfd = 0; struct fb_var_screeninfo vinfo; struct fb_fix_screeninfo finfo; struct fb_cmap cmapinfo; long int screensize = 0; char *fbp = 0; int x = 0, y = 0; long int location = 0; int b,g,r; // Open the file for reading and writing fbfd = open("/dev/fb0", O_RDWR); // 打开 Frame Buffer 设备 if (fbfd < 0) { printf("Error: cannot open framebuffer device.%x\n",fbfd);exit(1); } printf("The framebuffer device was opened successfully.\n"); - 266 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com // Get fixed screen information if (ioctl(fbfd, FBIOGET_FSCREENINFO, &finfo)) { // 获取设备固有信息 printf("Error reading fixed information.\n");exit(2); } printf(finfo.id); printf("\ntype:0x%x\n", finfo.typel ); // FrameBuffer 类型,如 0 为象素 printf("visual:%d\n", finfo.visual ); // 视觉类型:如真彩 2,伪彩 3 printf("line_length:%d\n", finfo.line_length ); // 每行长度 printf("\smem_start:0x%x,smem_len:%d\n", finfo.smem_start, finfo.smem_len ); // 映象 RAM 的参数 printf("mmio_start:0x%x ,mmio_len:%d\n", finfo.mmio_start, finfo.mmio_len ); // Get variable screen information if (ioctl(fbfd, FBIOGET_VSCREENINFO, &vinfo)) { // 获取设备可变信息 printf("Error reading variable information.\n");exit(3); } printf("%dx%d, %dbpp\n", vinfo.xres, vinfo.yres, vinfo.bits_per_pixel ); // Figure out the size of the screen in bytes screensize = vinfo.xres * vinfo.yres * vinfo.bits_per_pixel / 8; // Map the device to memory fbp = (char *)mmap(0, screensize, PROT_READ | PROT_WRITE, MAP_SHARED, fbfd, 0); if ((int)fbp == -1) { printf("Error: failed to map framebuffer device to memory.\n"); exit(4); } printf("The framebuffer device was mapped to memory successfully.\n"); vinfo.xoffset = (640-420)/2; // 计算图像在屏中间显示 vinfo.yoffset = (480-340)/2; b = 10; g = 100; r = 100; // 设置显示颜色 // Figure out where in memory to put the pixel for ( y = 0; y < 340; y++ ) // 行扫描 for ( x = 0; x < 420; x++ ) { // 列扫描 location = (x+vinfo.xoffset) * (vinfo.bits_per_pixel/8) +(y+vinfo.yoffset) * finfo.line_length; if ( vinfo.bits_per_pixel == 32 ) { *(fbp + location) = b; // Some blue *(fbp + location + 1) = g; // A little green *(fbp + location + 2) = r; // A lot of red *(fbp + location + 3) = 0; // No transparency } else { //assume 16bpp - 267 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com unsigned short int t = r<<11 | g << 5 | b; *((unsigned short int*)(fbp + location)) = t; } } munmap(fbp, screensize); close(fbfd); return 0; } 8. 思考 请思考,如何使用 FrameBuffer 在液晶屏上显示圆形等几何图形? 6.14 video4linux 模块应用实验 1. 实验目的 (1) 掌握配置和编译链接 Linxu 系统的视频内核 video4linux 的方法。 (2) 掌握 video4linux 常用 API 函数的使用方法。 2. 实验设备 硬件:MagicARM2410 实验开发平台 USB 摄像头(OV511 芯片组) 软件:RedHat Linux 9.0 操作系统 Windows 98/2000/XP 操作系统(可选) 嵌入式 Linux 开发环境 一套 一个 3. 实验内容 (1) 配置和编译链接 Linxu 系统的视频内核 video4linux。 (2) 配置和编译链接 OV511 芯片组 USB 摄像头驱动。 (3) 使用 video4linux 的 API 函数获取 USB 摄像头的基本信息,并打印到终端。 4. 实验预习要求 (1) 熟悉嵌入式 Linux 应用程序的编写及其编译调试的方法。 (2) 熟悉 nfs 文件系统的使用。 (3) Linux 系统内核自带的 USB 设备驱动模块的配置及编译链接。 5. 实验原理 video4linux(V4L)是 Linux 的影像串流系统与嵌入式影像系统的基础。Linux 在 TV、多 媒体上的应用是目前相当热门的研究领域,而其中最关键的技术则是 Linux 的 video4linux。 video4linux 是 Linux kernel 里支持影像设备的一组 APIs,配合适当的视频采集卡与视频 采集卡驱动程序,video4linux 可以让我们实现影像采集、AM/FM 无线广播、影像 CODEC、 频道切换等功能;而目前最主要则是应用在影像串流系统与嵌入式影像系统里,其应用范围 相当广泛,例如:远距离教学系统、远距离诊断系统、视频会议等。 video4linux 分为 2 层式架构,最上层为 video4linux 驱动程序本身,最下层架构则是影像 - 268 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 设备的驱动程序。本实验中则是使用 V4L 的最上层驱动程序,即 V4L 本般所提供给程序开 发人员的 APIs。 Video4Linux 下的图像采集编程: 在图像采集设备驱动安装后,只需要再编写一个对视频流采集的应用程序就可以了采集 视频图像。Video4Linux 应用程序中常用的数据结构如下: struct voide_capability grab_cap; video_capability 包含摄像头的基本信息,例如设备名称、支持的最大最小分辨率、信号 源信息等,分别对应着结构体中成员变量 name[32]、maxwidth、maxheight、minwidth、 minheight、channels(信号源个数)、type 等; struct video_picture grab_pic; voide_picture 包含设备采集图像的各种属性,如 brightness(亮度)、hue(色调)、contrast(对 比度)、whiteness(色度)、depth(深度)等; struct video_mmap grab_buf; video_mmap 用于内存映射; struct video_mbuf grab_vm; video_mbuf 利用 mmap 进行映射的帧信息,实际上是输入到摄像头存储器缓冲中的帧信息, 包括 size(帧的大小)、frames(最多支持的帧数)、offsets(每帧相对基址的偏移)。 程序中用到的主要系统调用函数有:open( "/dev/video0", int flags )、close( fd )、 mmap( void *start , size_t length, int prot, int flags, int fd, off_t offset )、munmap( void *start, size_tlength ) 和 ioctl( int fd, int cmd, … )。 前面提到 Linux 系统中把设备看成设备文件,在用户空间可以通过标准的 I/O 系统调用 函数操作设备文件,从而达到与设备通信交互的目的。当然,在设备驱动中要提供对这些函 数的相应支持。这里说明一下 ioctl(int fd,int cmd,…)函数,它在用户程序中用来控制 I/O 通 道,其中,fd 代表设备文件描述符,cmd 代表用户程序对设备的控制命令,省略号一般是 一个表示类型长度的参数,也可以缺省。 视频设备在 Linux 系统下为一个字符型设备,分配给视频设备使用的主设备号固定为 81, 次设备号为 0~31。在 Linux 系统中通常使用设备名为 video0~ video31,使用以下命令在设 备文件夹/dev/下创建 1 名称为 video0 的节点: # mknod /dev/video0 c 81 0 配置 video4linux 内核 在终端使用 make menuconfig 命令打开 S3C2410Linux 内核编译的 Main Menu 窗口,并 进入“Multimedia devices --->”菜单选项,然后将 Video For Linux 配置为模块,如图 6.26 所示。 - 269 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 图 6.26 配置多媒体设备模块 配置 OV511 驱动 返回主菜单(Main Menu),再进入“USB support --->” 菜单选项,然后将 USB OV511 Camera support 设置为模块,如图 6.27 所示。 图 6.27 配置 OV511 驱动模块 编译连接模块 退出并保存配置,使用 make dep 命令建立文件依联关系,然后使用 make modules 命令 编 译 链 接 模 块 。 编 译 链 接 完 成 后 , 在 /zylinyx/kernel/drivers/media/video 文 件 夹 中 生 成 videodev.o 模块,在/zylinux/kernel/drivers/usb/文件夹中生成 ov511.o 模块。 模块安装 执行以下命令安装输入模块: # insmod videodev.o 执行以下命令安装输入设备驱动模块: # insmod usbcore.o # insmod usb-ohci-s3c2410.ko - 270 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com # insmod ov511.o 由于使用的设备是 USB 接口的摄头,所以在加载 ov511.o 模块前,需要加载 USB 内核 驱动和主机控制器驱动。 6. 实验步骤 (1) 打开终端或进入虚拟控制台,进入嵌入式 Linux 开发环境中内核文件夹,配置及编 译链接输入内核模块和 USB 键盘鼠标驱动模块,参考实验原理。 (2) 使用自己熟悉的编辑器如 vi 建立文件 video.c,编写实验代码并保存。 (3) 从终端输入以下命令及参数编译 video.c 文件: # arm-linux-gcc -s -Wall -I/zls/2410/kernel2.4.18/include -Wstrict-prototypes video.c -o video.ko 其中/zls/2410/kernel2.4.18/include 为 Linux 内核的包含头文件所在的文件夹,需要根据 实际的开发环境修改。 (4) 编译链接后生成 video.ko 文件,将该文件属性修改为可执行。 # chmod 777 video.ko (5) 启动目标板 Linux 系统,进行 NFS 连接,进入多媒体设备模块文件夹和 USB 摄像 头驱动模块文件夹,并加载各模块。 (6) 加载模块后插入 USB 摄像头,终端将打印出以下信息: hub.c: USB new device connect on bus1/1/4, assigned device number 3 ov511.c: USB OV511+ camera found ov511.c: Camera type (108) not recognized ov511.c: Please notify mmcclell@bigfoot.com of the name, ov511.c: manufacturer, model, and this number of your camera. ov511.c: Also include the output of the detection process. ov511.c: Sensor is an OV7620 ov511.c: Device registered on minor 0 (7) 通过目标板的终端进入 video.ko 所在的文件夹,运行 video.ko 程序终端将打印出 USB 摄像头的基本信息,如下所示: ==================Get struct video_capability======================= OV511+ USB Camera, Type:513 Maxwidth:640,Maxheight:480 Minwidth:64,Minheight:48 Channels:1,Audios:0 ====================Get struct video_mbuf========================== Memery buffer size:1843216 Memery buffer frames:2 ===================Get struct video_picture========================= Brightness:18176,Hue:32768,Colour:49152 Contrast:22016,Whiteness:26880(Black and white only) Capture depth:24,Palette:4 Set vpic.palette to VIDEO_PALETTE_RGB565,and vpic.depth to 16. - 271 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com ===================Get struct video_picture========================= Brightness:17664,Hue:32768,Colour:49152 Contrast:13312,Whiteness:26880(Black and white only) Capture depth:16,Palette:3 7. 实验参考程序 本程序完整的参考程序,如程序清单 6.31 所示。应用程序中打印出设备性能描述信息、 图象特性信息和设备缓冲区信息,并且修改图象特性参数。 程序清单 6.31 video4linux 实验程序 #include #include #include #include #include #include #include #include #define FILE "/dev/video0" int main(void) { struct video_capability cap; struct video_picture vpic; struct video_mbuf mbuf; int fd = open(FILE, O_RDONLY); if (fd < 0) { perror(FILE); exit(1); } // 定义打开文件的名称 // 设备的性能 // 设备的图片特性 // 设备缓冲区信息 // 打开设备 printf("\n==================Get struct video_capability=======================\n"); if (ioctl(fd, VIDIOCGCAP, &cap) < 0) // 获取设备性能描述数据结构 { perror("VIDIOGCAP"); fprintf(stderr, "(" FILE " not a video4linux device?)\n"); close(fd); exit(1); } printf(cap.name);printf(", Type:%d\n",cap.type); printf("Maxwidth:%d,Maxheight:%d\n",cap.maxwidth ,cap.maxheight); printf("Minwidth:%d,Minheight:%d\n",cap.minwidth,cap.minheight); printf("Channels:%d,Audios:%d\n",cap.channels,cap.audios); printf("\n====================Get struct video_mbuf==========================\n"); if (ioctl(fd, VIDIOCGMBUF, &mbuf) < 0) // 获取设备缓冲区信息 - 272 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com { perror("VIDIOCGMBUF"); fprintf(stderr, "(" FILE " not a video4linux device?)\n"); close(fd); exit(1); } printf("Memery buffer size:%d\n",mbuf.size); printf("Memery buffer frames:%d\n",mbuf.frames ); printf("\n===================Get struct video_picture=========================\n"); if (ioctl(fd, VIDIOCGPICT, &vpic) < 0) // 获取图象特性数据结构 { perror("VIDIOCGPICT"); close(fd); exit(1); } printf("Brightness:%d,Hue:%d,Colour:%d\n",vpic.brightness,vpic.hue,vpic.colour); printf("Contrast:%d,Whiteness:%d(Black and white only)\n",vpic.contrast,vpic.whiteness); printf("Capture depth:%d,Palette:%d\n",vpic.depth,vpic.palette); printf("\nSet vpic.palette to VIDEO_PALETTE_RGB565,and vpic.depth to 16.\n"); vpic.palette=VIDEO_PALETTE_RGB565; // 设置调色板 vpic.depth=16; // 设置象素深度 if(ioctl(fd, VIDIOCSPICT, &vpic)==-1) // 设置图像特性 { fprintf(stderr, "Unable to find a supported capture format.\n"); close(fd); exit(1); } printf("\n===================Get struct video_picture=========================\n"); if (ioctl(fd, VIDIOCGPICT, &vpic) < 0) // 获取图象特性数据结构 { perror("VIDIOCGPICT"); close(fd); exit(1); } printf("Brightness:%d,Hue:%d,Colour:%d\n",vpic.brightness,vpic.hue,vpic.colour); printf("Contrast:%d,Whiteness:%d(Black and white only)\n",vpic.contrast,vpic.whiteness); printf("Capture depth:%d,Palette:%d\n",vpic.depth,vpic.palette); close(fd); return 0; } - 273 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 8. 思考 请思考,如何使用 video4linxu 驱动捕捉图象,然后在液晶屏上显示? 6.15 USB 摄像头实验 1. 实验目的 (1) 掌握 video4linux 常用 API 函数的使用方法。 (2) 掌握 Frame Buffer 驱动程常用 API 函数的使用方法。 (3) 了解视频应用与开发的过程。 2. 实验设备 硬件:MagicARM2410 实验开发平台 USB 摄像头(OV511 芯片组) 软件:RedHat Linux 9.0 操作系统 Windows 98/2000/XP 操作系统(可选) 嵌入式 Linux 开发环境 一套 一个 3. 实验内容 通过使用 video4linux 的 API 函数从视频设备(OV511 摄像头)中读取图像数据,然后 将这些数据写入 Frame Buffer,使摄像头采集到的图像在液晶屏中显示出来。 4. 实验预习要求 (1) 熟悉嵌入式 Linux 应用程序的编写及其编译调试的方法。 (2) 熟悉 nfs 文件系统的使用。 (3) 复习 6.13 小节 FrameBuffer 模块应用实验和 6.14 小节的 video4linux 模块应用实验。 5. 实验原理 采集程序实现过程: 首先打开视频设备,视频采集设备在系统中对应的设备文件为/dev/video0,采用系统调 用函数 fd = open ( "/dev/video0", O_RDWR ),fd 是设备打开后返回的文件描述符(打开错误 返回-1),以后的系统调用函数就可使用它来对设备文件进行操作了。接着,利用 ioct1(fd, VIDIOCGCAP, &grab_cap)函数读取 struct video_capability 中有关图像捕捉设备的信息。该 函数成功返回后,这些信息从内核空间拷贝到用户程序空间 grab_cap 各成员分量中,使用 printf 函数就可得到各成员分量信息,例如 printf("maxheight=%d", grab_fd.maxheight)获得最 大垂直分辨率的大小。还可以使用 ioct1( fd, VIDIOCGPICT, &grab_pic)函数读取视频采集设 备缓冲 voideo_picture 信息。在用户空间程序中可以改变这些信息,具体方法为先给变量赋 新值,再调用 VIDIOCSPICT ioct1 函数,如程序清单 6.32 所示: 程序清单 6.32 改变图像捕捉设备缓冲信息 grab_fd.depth = 3; if ( ioct1( fd, VIDIOCSPICT, &grab_pic ) < 0 ) { perror("VIDIOCSPICT"); - 274 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com return -1; } 完成以上初始化设备工作后,就可以对视频图像截取了,有两种方法:一种是 read()直 接读取;另外一种 mmap()内存映射。Read()通过内核缓冲区来读取数据;而 mmap()通过把 设备文件映射到内存中,绕过了内核缓冲区,最快的磁盘访问往往还是慢于最慢的内存访问, 所以 mmap()方式加速了 I/O 访问。另外,mmap()系统调用使得进程之间通过映射同一文件 实现共享内存,各进程可以像访问普通内存一样对文件进行访问,访问时只需要使用指针而 不用调用文件操作函数。因为 mmap()的以上优点,所以在程序实现中采用了内存映射方式, 即 mmap()方式。 利用 mmap()方式视频裁取具体进行操作如下: ①先使用 ioct1( fd, VIDIOCGMBUF, &grab_vm)函数获得摄像头存储缓冲区的帧信息,之 后修改 voideo_mmap 中的设置,例如重新设置图像帧的垂直及水平分辨率、彩色显示格式。 可利用如下语句: grab_buf.height = 240; grab_buf.width = 320; grab_buf.format = VIDEO_PALETTE_RGB24; ②接着把摄像头对应的设备文件映射到内存区,具体使用 grab_data = (unsigned char*) mmap( 0, grab_vm.size, PROT_READ|PROT_WRITE, MAP_SHARED, grad_fd, 0 )操作。这样 设备文件的内容就映射到内存区,该映射内容区可读可写并且不同进程间可共享。该函数成 功时返回映像内存区的指针,出错时返回值为-1。 下面对单帧采集和连续帧采集进行说明: 单帧采集 在上面获取的摄像头存储缓冲区帧信息中,最多可支持的帧数(frames 的值)一般为两 帧。对于单帧采集只需设置 grab_buf.frame=0,即采集其中的第一帧,使用 ioctl( fd, VIDIOCMCAPTURE, &grab_buf )函数,若调用成功,则激活设备真正开始一帧图像的截取, 是非阻塞的。接着使用 ioct1( fd, VIDIOCSYNC, &frame )函数判断该帧图像是否截取完毕, 成功返回表示截取完毕,之后就可把图像数据写入到 Frame Buffer。 连续帧采集 在单帧的基础上,利用 grab_fd.frames 值确定采集完毕摄像头帧缓冲区帧数据进行循环 的次数。在循环语句中,也是使用 VIDIOCMCCAPTURE ioct1 和 VIDIOCSYNC ioctl 函数 完成每帧截取,但要给采集到的每帧图像赋地址,利用语句 buf = grab_data + grab_vm.offsets [ frame ],然后保存文件的形式。若要继续采集可再加一个外循环,在外循环语句只要给原 来的内循环再赋 frame=0 即可。 本实验中使用单帧采集的方式。 6. 实验步骤 (1) 在 PC 端,打开终端或进入虚拟控制台,进入 ARM 实验目录/zylinux/armwork/,为 本实验新建工作目录 video4linux。 $ cd /zylinux/armwork $ mkdir video4linux (2) 使用自己熟悉的编辑器(例如 vi)建立文件 videodemo.c,编写实验代码并保存。 $ vi videodemo.c - 275 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com (3) 编译程序,生成可执行代码 videodemo.o。 $ arm-linux-gcc -s -Wall -I/zylinux/kernel/include -Wstrict-prototypes videodemo.c -o videodemo (4) 短接 JP7,起动 MagicARM2410 实验箱的 Linux,进行 NFS 连接。 (5) 分别加载 USB 内核模块和 video4linx 视频模块:usbcore.o、usb-ohci-s3c2410.ko 和 videodev.o。 # insmod usbcore.o # insmod usb-ohci-s3c2410.ko # insmod videodev.o (6) 进入 USB 摄像头 VO511 驱动所在的文件夹,加载 VO511 的驱动程序:ov511.o。 # insmod ov511.o (7) 插入 USB 摄像头到 USB 主机下行口,这时在终端上将打印以下信息: ov511.c: USB OV511+ camera found ov511.c: Camera type (108) not recognized ov511.c: Please notify mmcclell@bigfoot.com of the name, ov511.c: manufacturer, model, and this number of your camera. ov511.c: Also include the output of the detection process. ov511.c: Sensor is an OV7620 ov511.c: Device registered on minor 0 (8) 进入到本实验程序所在文件夹,运行本实验程序,观察液晶屏的图像效果: # ./ videodemo 7. 实验参考程序 实验程序的主函数如程序清单 6.33 所示。 程序清单 6.33 实验程序的主函数 int main( void ) { fb_v41 vd; int ret,i; unsigned short *imageptr; unsigned short tempbuf[640*480]; ret = open_framebuffer(FB_FILE,&vd); // 打开 FrameBuffer 设备 if( 0!= ret ) { goto err; } for(i=0;i<640*480;i++) tempbuf[i] = 0xffff; rgb_to_framebuffer(&vd,640,480,0,0,tempbuf); // 填充 FrameBuffer 颜色 - 276 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com ret = open_video( V4L_FILE, &vd , 16 // 像素深度 VIDEO_PALETTE_RGB565, // 设置调色板 320,240 ); // 图像的开小 if( 0!= ret ) // 打开视频设备失败 { goto err; } // 打印设备信息 printf(vd.capability.name);printf(", Type:%d\n",vd.capability.type); printf("Maxwidth:%d,Maxheight:%d\n",vd.capability.maxwidth ,vd.capability.maxheight); printf("Minwidth:%d,Minheight:%d\n",vd.capability.minwidth,vd.capability.minheight); printf("Channels:%d,Audios:%d\n",vd.capability.channels,vd.capability.audios); while(1) { imageptr = (unsigned short *) get_frame_address( &vd ); rgb_to_framebuffer(&vd,vd.mmap.width,vd.mmap.height, 160,120,imageptr); if(get_next_frame( &vd ) !=0 ) { // 获取图像数据出错 goto err; } } err: if(vd.fbfd) close(vd.fbfd); // 关闭 FrameBuffer 设备 if(vd.fd) close(vd.fd); exit(0); return 0; } 打开 FrameBuffer 设备函数如程序清单 6.34 所示。 程序清单 6.34 打开 FrameBuffer 设备函数 int open_framebuffer(char *ptr,fb_v41 *vd) { int fbfd,screensize; // Open the file for reading and writing fbfd = open( ptr, O_RDWR); if (fbfd < 0) { printf("Error: cannot open framebuffer device.%x\n",fbfd); return ERR_FRAME_BUFFER; - 277 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com } printf("The framebuffer device was opened successfully.\n"); vd->fbfd = fbfd; // 保存打开 FrameBuffer 设备的句柄 // Get fixed screen information 获取 FrameBuffer 固定不变的信息 if (ioctl(fbfd, FBIOGET_FSCREENINFO, &vd->finfo)) { printf("Error reading fixed information.\n"); return ERR_FRAME_BUFFER; } // Get variable screen information 获取 FrameBuffer 屏幕可变的信息 if (ioctl(fbfd, FBIOGET_VSCREENINFO, &vd->vinfo)) { printf("Error reading variable information.\n"); return ERR_FRAME_BUFFER; } printf("%dx%d, %dbpp, xoffset=%d ,yoffset=%d \n", vd->vinfo.xres, vd->vinfo.yres, vd->vinfo.bits_per_pixel,vd->vinfo.xoffset,vd->vinfo.yoffset ); // Figure out the size of the screen in bytes screensize = vd->vinfo.xres * vd->vinfo.yres * vd->vinfo.bits_per_pixel / 8; // Map the device to memory 影射 Framebuffer 设备到内存 vd->fbp = (char *)mmap(0,screensize,PROT_READ|PROT_WRITE,MAP_SHARED,fbfd,0); if ((int)vd->fbp == -1) { printf("Error: failed to map framebuffer device to memory.\n"); return ERR_FRAME_BUFFER; } printf("The framebuffer device was mapped to memory successfully.\n"); return 0; } 打开视频设备函数如程序清单 6.35 所示。 程序清单 6.35 打开视频设备 int open_video( char *fileptr,fb_v41 *vd ,int dep,int pal,int width,int height) { // 打开视频设备 if ((vd->fd = open(fileptr, O_RDWR)) < 0) { perror("v4l_open:"); - 278 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com return ERR_VIDEO_OPEN; } // 获取设备 if (ioctl(vd->fd, VIDIOCGCAP, &(vd->capability)) < 0) { perror("v4l_get_capability:"); return ERR_VIDEO_GCAP; } // 获取图象 if (ioctl(vd->fd, VIDIOCGPICT, &(vd->picture)) < 0) { perror("v4l_get_picture"); return ERR_VIDEO_GPIC; } // 设置图象 vd->picture.palette = pal; // 调色板 vd->picture.depth = dep; // 像素深度 vd->mmap.format =pal; if (ioctl(vd->fd, VIDIOCSPICT, &(vd->picture)) < 0) { perror("v4l_set_palette"); return ERR_VIDEO_SPIC; } vd->mmap.width = width; // width; vd->mmap.height = height; // height; vd->mmap.format = vd->picture.palette; vd->frame_current = 0; vd->frame_using[0] = 0; vd->frame_using[1] = 0; // 获取缓冲影射信息 if (ioctl(vd->fd, VIDIOCGMBUF, &(vd->mbuf)) < 0) { perror("v4l_get_mbuf"); return -1; } // 建立设备内存影射 vd->map = mmap(0, vd->mbuf.size, PROT_READ|PROT_WRITE, MAP_SHARED, vd->fd, 0); if ( vd->map < 0) - 279 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com { perror("v4l_mmap_init:mmap"); return -1; } printf("The video device was opened successfully.\n"); return 0; } 详细的参考程序见 MagicARM2410 配套实验光盘的相应文件夹。 8. 思考 请思考,如果将采集到的图像数据保存为 JPEG 文件格式。 6.16 无线网络实验 1. 实验目的 (1) 掌握 Linux 系统下 wireless 无线网络模块的应用。 (2) 掌握 Linux 系统下无线网卡驱动 linux-wlan-ng 驱动的使用。 2. 实验设备 硬件: 软件: MagicARM2410 实验开发平台 WL-110 CF 接口无线网卡 CF 转 PCMCIA 接口适配器 带 AP 功能的路由器 D-Link DI-624 RedHat Linux 9.0 操作系统 Windows 98/2000/XP 操作系统(可选) 嵌入式 Linux 开发环境 linux-wlan-ng-0.2.0.tar.gz 一套 一个 一个 一个 3. 实验内容 (1) 交叉编译 linux-wlan-ng-0.2.0.tar.gz 软件包中的 USB 接口和 PCMCIA 卡接口的无线 网卡驱动模块。 (2) 配置使用的无线网卡工作在 AP 模式,并使用 ping 命令检测网络状态。 4. 实验预习要求 (1) 熟悉嵌入式 Linux 应用程序的编写及其编译调试的方法。 (2) 阅读 linux-wlan-ng-0.2.0.tar.gz 解压后的 README 文件。 5. 实验原理 Wireless LAN 通信系统作为有线 LAN 以外的另一种选择一般用在同一座建筑内。 Wireless LAN 使用 ISM (Industrial、Scientific、Medical) 无线电广播频段通信。Wireless LAN 的 802.11a 标准使用 5 GHz 频段,支持的最大速度为 54 Mbps,而 802.11b 和 802.11g 标 准使用 2.4 GHz 频段,分别支持最大 11 Mbps 和 54 Mbps 的速度。 Wireless LAN 类似于有线以太网,它们都是从同一地址池分配 MAC (Media Access - 280 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com Control) 地址,并且都是作为以太网设备出现在操作系统的网络设备层。例如,ARP(Address Resolution Protocol) 表是用 Wireless LAN MAC 地址和以太网 MAC 地址填充的。 然而 Wireless LAN 与有线以太网在链路层有很大的区别。例如,802.11 标准使用冲突 避免(CSMA/CA)代替有线以太网的冲突检测(CSMA/CD)。而且,与以太网帧不同的是, Wireless LAN 帧是被确认的。 由于 Wireless LAN 工作站之间的模糊边界,Wireless LAN 链路层拥有在传送前清除一 个区域的协议。出于安全性考虑,Wireless LAN 的 Wired Equivalent Privacy (WEP) 加密机 制提供与有线网络相同的安全级别。WEP 将 40 比特或 104 比特密钥与随机的 24 比特 初始向量组合用以加解密数据。Wireless LAN 支持两种通信模式:Ad Hoc 模式,用于小群 组工作站之间不必使用访问点的短时间内通信;而 AP 模式的所有通信必须通过访问点。访 问点周期性地广播一个服务集标识符(SSID),SSID 用于将一个 Wireless LAN 网络与其他 网络区别开来。 大多数可用的 Wireless LAN 卡是基于 Intersil Prism 或 Lucent Hermes 芯片组的。 Compaq、Nokia、Linksys 和 D-Link 卡使用 Prism 芯片组,而 Lucent Orinoco 卡和 Apple Airport 使用 Hermes 芯片组。 linux-wlan 项目的 linux-wlan-ng 驱动程序:支持多种基于 Prism 芯片组的卡。这个驱 动程序支持 linux-wlan API 并部分支持 Wireless Extensions。 Linux PCMCIA/CF 层由 PCMCIA 主机控制器的设备驱动程序、不同卡的客户机驱动 程序、用户模式程序、有助于热拔的后台进程和与以上各部分交互并为它们提供服务的内核 卡服务中枢组成。PCMCIA 控制器将卡连接到系统总线,将卡内存映射到主机 I/O 和内存 窗口,并将卡产生的中断路由到自由处理器中断线。CF 卡较小,但与 PCMCIA 兼容,并 且经常应用于手持设备。PCMCIA/CF 卡拥有两个存储空间:属性内存(attribute memory) 和 公共内存(common memory)。属性内存类似于 Card Information Structure (CIS),用来保 存配置注册和描述符信息。Linux 卡服务核心与主机控制器设备驱动程序、卡设备驱动程序 及用户模式 cardmgr 后台进程交互。它在一些事件(比如卡插入、卡移出以及低电量)发 生时调用卡驱动程序的事件处理程序例程。尽管卡服务从卡的 CIS 向上传送信息到 cardmgr,但是 cardmgr 将为分配内存窗口和中断级别而在用户空间(/etc/pcmcia/config)中 定义的资源分配策略向下传送到卡服务。查看 drivers/pcmcia/ds.c 可以了解与 cardmgr 交 互的内核代码,查阅/etc/pcmcia/config 可以了解用户空间资源分配策略。 插入 Intersil WLAN CF 卡时,卡服务调用 prism2_cs.o 模块的 PCMCIA 事件处理程 序。卡服务解析卡属性内存中的 CIS 元组(tuples)并向上传送信息到 cardmgr,这将从 /etc/pcmcia/config 文件(如程序清单 6.36 所示)加载适当的设备驱动程序。由于卡的 CIS 中 的 manfid 元组匹配 /etc/pcmcia/config 中的条目,所以 cardmgr 绑定带有 prism2_cs.o 驱 动程序的卡。 程序清单 6.36 PCMCIA 卡 config 文件 device "prism2_cs" module "prism2_cs" card "ASUS WL-100 802.11b WLAN PC Card" version "ASUS", "802_11b_PC_CARD_25" bind "prism2_cs" card "ASUS WL-110 802.11b WLAN CF Card" version "ASUS", "802_11B_CF_CARD_25" - 281 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com bind "prism2_cs" 通过以下脚本文件使能无线网卡,并将其配置为 AP 模式,同时禁止默认的以太网卡和 设置无线网卡的 IP 地址,如程序清单 6.37 所示。 程序清单 6.37 配置无线网卡脚本文件 wland_ap #!/bin/sh wlanctl wlan0 lnxreq_ifstate ifstate=enable wlanctl wlan0 lnxreq_autojoin ssid=linux-wlan authtype=opensystem ifconfig eth0 down ifconfig wlan0 192.168.0.236 netmask 255.255.255.0 broadcast 192.168.0.255 注意:“ssid=linux-wlan”中 linux-wlan 需要与 AP 的 ssid 字段一致。 6. 实验步骤 (1) 在 PC 端,打开终端或者进入虚拟控制台,进入 ARM 实验目录/zylinux/armwork/, 将 linux-wlan-ng-0.2.0.tar.gz 文件解压在当前目录: $ tar xvzf linux-wlan-ng-0.2.0.tar.gz (2) 解压后将在当前目录生成文件夹 linux-wlan-ng-0.2.0/,进入该文件夹配置并编译驱 动: $ cd linux-wlan-ng-0.2.0 $ ./Configure 主要配置以下几项: Build Prism2.x PCMCIA Card Services (_cs) driver? (y/n) [y]: y Build Prism2 PLX9052 based PCI (_plx) adapter driver? (y/n) [n]: n Build Prism2.5 native PCI (_pci) driver? (y/n) [n]: n Build Prism2.5 USB (_usb) driver? (y/n) [n]: y Linux source directory [/usr/src/linux]: /zylinux/kernel 其它选项直接按回车键即可。 (3) 编译 linux-wlan-ng: $ make all 最后在 linux-wlan-ng-0.2.0/src/p80211/文件夹下生成 p80211.o,在 linux-wlan-ng-0.2.0/ src/prism2/driver 文 件 夹 下 生 成 prism2_usb.o 和 prism2_cs.o 文 件 , linux-wlan-ng-0.2.0/ src/wlanctl/文件夹下生成 wlanctl 文件。 (4) 在 MagicARM2410 文件系统/lib/modules/下创建文件夹 wireless/,然后将 p80211.o、 prism2_usb.o(在使用 USB 接口的无线网卡使用该模块)和 prism2_cs.o 文件复制到 wireless/文件夹;将并 wlanctl 文件复制到/sbin/文件夹。 (5) 修改/lib/modules/2.4.18-rmk7-pxa1/文件夹下的 modules.dep 文件,添加以下内容: /lib/modules/wireless/prism2_cs.o: 这是由于当 PCMCIA 卡插入时 cardmgr 应用程序通过 modules.dep 文件加载 prism2_cs.o 模块。 (6) 启动 MagicARM2410 的 Linux 系统,然后分别加载以下模块:pcmcia_core.o、 pd6700.ko、ds.o 和 p80211.o 模块,并运行 cardmgr 程序。 - 282 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com # insmod pcmcia_core.o # insmod pd6700.ko # insmod p80211.o (7) 将 CF 无线网卡插入 PCMCIA 适配器,并插入到 MagicARM2410 的 PCMCIA 接口。 最后终端将打印出以下信息: prism2_cs: index 0x01: Vcc 3.3, irq 36, io 0xd2000000-0xd200003f cs: read_cis_mem(1, 0x1f0, 1) cs: 0x41 0x60 0xa9 0xbb ... cs: write_cis_mem(1, 0x1f0, 1) cs: write_cis_mem(1, 0x1f0, 1) cs: write_cis_mem(1, 0x1f0, 1) ds_ioctl(socket 0, 0xc050643d, 0x20123e0) DS: start get_dev_info DS: end get_dev_info ds_ioctl(socket 0, 0xc050643e, 0x2012438) DS: start get_dev_info ds_poll(socket 0) (8) 配置 AP 路由器,使其 IP 地址为 192.168.0.235,设置 SSID 名称为 linux-wlan,并 为广播方式不加密。 (9) 运行 wland_ap 脚本文件,端终将打印出以下信息: ident: nic h/w: id=0x800c 1.0.0 ident: pri f/w: id=0x15 1.1.0 ident: sta f/w: id=0x1f 1.4.2 MFI:SUP:role=0x00:id=0x01:var=0x01:b/t=1/1 CFI:SUP:role=0x00:id=0x02:var=0x02:b/t=1/1 PRI:SUP:role=0x00:id=0x03:var=0x01:b/t=4/4 STA:SUP:role=0x00:id=0x04:var=0x01:b/t=1/9 PRI-CFI:ACT:role=0x01:id=0x02:var=0x02:b/t=1/1 STA-CFI:ACT:role=0x01:id=0x02:var=0x02:b/t=1/1 STA-MFI:ACT:role=0x01:id=0x01:var=0x01:b/t=1/1 Prism2 card SN: 42430101\x00\x00\x00\x00 message=lnxreq_ifstate ifstate=enable resultcode=success message=lnxreq_autojoin ssid='linux-wlan' authtype=opensystem resultcode=success [root@zylinux /usr]# linkstatus=CONNECTED 从 linkstatus 可以看到无线网卡已与 AP 路由器连接成功。 (10) 从终端上输入以下命令,检测网络状态,终端将打印出以下信息。 - 283 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com [root@zylinux /usr]# ping -c 5 192.168.0.235 PING 192.168.0.235 (192.168.0.235): 56 data bytes 64 bytes from 192.168.0.235: icmp_seq=0 ttl=127 time=6.8 ms 64 bytes from 192.168.0.235: icmp_seq=1 ttl=127 time=2.4 ms 64 bytes from 192.168.0.235: icmp_seq=2 ttl=127 time=2.6 ms 64 bytes from 192.168.0.235: icmp_seq=3 ttl=127 time=2.4 ms 64 bytes from 192.168.0.235: icmp_seq=4 ttl=127 time=2.8 ms --- 192.168.0.235 ping statistics --5 packets transmitted, 5 packets received, 0% packet loss round-trip min/avg/max = 2.4/3.4/6.8 ms 7. 实验参考程序 本实验中无需编写应用程序,只需编写脚本文件 wland_ap 如程序清单 6.37 所示。 8. 思考 请思考,如果配置无线网卡工作在 AD HOC 模式,实现点对点的通讯。 6.17 CAN 接收实验 1. 实验目的 (1) 掌握基于 Linux 下 SJA1000 独立 CAN 控制器的操作方法。 (2) 掌握 Linux 系统 SJA1000 CAN 驱动模块的编译与配置。 (3) 掌握 SJA1000 控制器接收的操作过程。 2. 实验设备 硬件: 软件: PC 机 USBCAN-II CAN 接口卡 CAN-bus 通信电缆 MagicARM2410 教学实验开发平台 RedHat Linux9.0 操作系统 嵌入式 Linux 开发环境 ZLGCANTest 通用测试软件 一台 一台 一条 一套 3. 实验内容 (1) 编译 SJA1000 CAN 控制器驱动模块; (2) 编译 SJA10000 CAN 控制器接收程序示例; (3) 加载 SJA1000 CAN 控制器驱动模块; (4) 学会使用 USBCAN-II CAN 接口卡和 ZLGCANTest 软件; (5) 观察接收数据。 4. 实验预习要求 (1) 阅读《CAN-bus 通用测试软件及接口函数库使用手册》中的软件使用说明部分,掌 握 ZLGCANtest 软件的使用方法; - 284 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com (2) 初步掌握 CAN 网络的物理连接,了解 CAN 报文的结构以及阅读 SJA1000 CAN 控 制器器件手册; (3) 复习 Linux 开发环境的使用方法。 5. 实验原理 SJA1000 CAN 控制器是目前使用的最普遍的一种独立 CAN 控制器,前面的硬件介绍中 已经介绍过。ARM 的结构是采用数据、地址总线分开的结构,不能直接和 SJA1000 连接, 因此通过硬件逻辑扩展的方法把 SJA1000 划分出两个地址:“锁存器地址”和“数据地址”。 在驱动程序的实现中,我们可以看到读写函数实现都进行了先写锁存器,然后读/写数据的 操作,如程序清单 6.38 所示。 程序清单 6.38 SJA1000 的读写实现 void Write_SJA1000(INT8U Val, INT8U OffSet) { writeb(OffSet,sja1000_ale); writeb(Val,sja1000_dat); } INT8U Read_SJA1000(INT8U OffSet) { writeb(OffSet,sja1000_ale); return readb(sja1000_dat); } //写 SJA1000 寄存器函数 //读 SJA1000 寄存器函数 SJA1000 CAN 控制器的底层操作都封装到了驱动程序中,初始化函数 can_init 为 CAN 分配了访问地址,检测 SJA1000 的硬件连接并并注册驱动模块;can_open 完成初始化,中 断申请;can_read,can_write 充当接收和发送的角色;can_ioctl 可以设置通信参数。在接收 实验中,我们主要熟悉 CAN 驱动库的使用,CAN 工具的使用。 CAN 的初始化流程如图 6.28 所示。 - 285 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 开始 进入软件复位 设置工作模式 配置波特率 配置验收过滤器 设置输出方式 退出软件复位模式 结束 图 6.28 SJA1000 初始化流程 对应的程序段在 SJA1000.c 文件的 SJA1000Init 函数中,部分程序如程序清单 6.39 所示。 程序清单 6.39 SJA1000Init 主要代码 if(TRUE != SJA_SoftRst(TRUE)) … if(TRUE != SetModeReg(MOD_AFM_SIG,TRUE)) … if(TRUE != SetInterrupt(IER_RC,TRUE)) … if(TRUE != SetClkDiv(CanMode,FALSE,TRUE,0)) … if(TRUE != SetFliter(ACRCode,AMRCode)) … if(TRUE != SetBaudRate(BaudRate)) … if(TRUE != SetOutPutMod(0x1A)) … if(TRUE != SJA_SoftRst(FALSE)) //进入复位模式 //设置验收过滤方式 //设置中断,只开放接收中断 //设置工作模式 //设置验收过滤值 //设置波特率 //设置驱动输出模式 //退出软件复位模式 - 286 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 调用 can_open 函数时会调用 SJA1000Init 函数,默认设置 CAN 通信波特率 1M/bits,设 置验收过滤方式为但滤波方式,设置过滤值为全部接收。验收过滤设置在后面的实验中会做 进一步介绍。如用户不作额外配置,在整个通信过程中将使用这些参数。调用 can_open 函 数成功后,即可进行正常通信实验。 6. 实验步骤 (1) 编译链接 SJA1000 驱动模块。在 linux 开发环境中新建一个文件夹,将产品光盘中 的“CAN/SJA1000_LinuxV0.1”文件夹中的所有文件复制到该文件夹中。假设用户新建的文 件路径为“/zylinux/root/CAN”。 (2) 进入“root/CAN”文件夹,编译生成 can_sja1000_dev.ko 驱动模块。在终端执行的 命令如下: $cd /zylinux/root/CAN $make clean $make (3) 编译生成测试程序 main。测试程序放在“CAN/SJA1000_LinuxV0.1/app”中,app 整个(连文件夹一起)复制“root/CAN”中。在终端执行命令如下: $cd /zylinux/root/CAN/app $make clean $make app 目录包含 main.c、autoload 和 Makefile 文件。其中 autoload 为 shell 脚本文件,主要 是完成自动创建设备节点的功能,相当于代替手工完成 mknod 命令。autoload 文件代码如程 序清单 6.40 所示。 程序清单 6.40 autoload 文件内容 #!/bin/sh rm -f /dev/SJA1000_CAN mknod /dev/SJA1000_CAN c 251 0 #强行删除/dev 目录下 SJA1000_CAN 设备文件 #创建 SJA1000 设备节点,类型为字符型,主设备号为 251,次 #设备号为 0 autoload 文件在 main.c 文件中调用系统函数 system 自动加载。为方便起见,main.c 文 件中包含了 CAN 的三个实验,使用条件编译的形式给出,如程序清单 6.41 所示。在实验 的时候根据要求把相应宏的值改成‘y’即可,注意只能允许其中一项为‘y’。程序清单 6.41 中的 READ_TEST 为‘y’,故只编译 CAN 接收实验代码。 程序清单 6.41 main.c 文件的主要结构 //main.c … #define WRITE_TEST 'n' #define READ_TEST 'y' #define SET_TEST 'n' … int main() - 287 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com { … system("sh autoload"); #if('y' == READ_TEST) … #elif('y' == WRITE_TEST) … #elif('y' == SET_TEST) … #endif … } //加载 autoload 文件 //CAN 接收实验代码 //CAN 发送实验代码 //CAN 参数配制实验代码 (4) 加 载 驱 动 模 块 , 运 行 测 试 程 序 。 启 动 ARM Linux , 进 行 NFS 连 接 , 进 入 zylinux/root/CAN 目录使用 insmod 命令加载驱动模块,命令如下: #insmod can_sja1000_dev.ko 出现如图 6.29 所示的提示表示加载已经成功,此时不但表明软件已经成功加载,而且 还正确检测到了 SJA1000 的正确连接。 图 6.29 CAN 驱动模块加载 进入 app 目录,在终端键入命令./main&,得到如图 6.30 所示画面。 图 6.30 运行 main 程序画面 - 288 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com (5) 用 ZLGCANTest 发送数据,并观察接收情况。 打开 ZLGCANTest 软件,在设备类型中选择“UABCAN2”,即选中 USBCAN-II 接口卡 如所示。 选择USBCAN2 图 6.31 选择设备类型 点击打开设备,如图 6.32 所示。 点击这里打开设备 选择所有 的CAN通道 默认通信频率是 1M, 不必改动 图 6.32 设置 USBCAN 设备参数 选择 USBCAN-II 接口卡的 0 通道,发送格式选择“自收自发”,点击“启动 CAN”,如 图 6.33 所示。这时,接口卡上的 CAN1 指示灯由绿色闪烁变成绿色常亮。 - 289 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 选择0通道 点击这里启动 选择的CAN通道 发送格式选择 图 6.33 启动 0 通道、设置发送格式 点击“发送”按钮,如果 USBCAN-II 接口卡工作正常,就会收到刚才发出去的数据, 如图 6.34 所示。 图 6.34 测试 USBCAN-II CAN 卡测试正常之后把发送格式切换到“正常发送”模式,连接好 MagicARM 和 USBCAN-II 之间的通信电缆并启动发送。超级终端收到的数据显示如图 6.35 所示, ZLGCANTest 发送数据如图 6.36 所示。 - 290 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 图 6.35 超级终端收到的数据 图 6.36 ZLGCANTest 发送数据界面 7. 实验程序 程序清单 6.42 给出的是接收部分程序,其余部分请自己阅读 main.c 文件。 程序清单 6.42 接收实验程序关键代码 count = read(fd,(void*)(&Buf), sizeof(Buf)); if(count < 0) { printf("read err!.\n"); } else { printf("CAN Recive %d Bytes.\n", count); printf("CAN ID = 0x%08X.\n", Buf.FrID); printf("CAN FramID = 0x%08X.\n", Buf.FrIf.Byte); for(i=0; i<(Buf.FrIf.Bits.DLC); i++) { printf("CAN Data[0x%02X] = 0x%02X.\n",i,Buf.DA[i]); } } - 291 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 8. 思考 在驱动的 read 函数的返回值中,并不能反映实际接收到的 CAN 报文的数据长度,试改 进驱动程序,使之真正能够反映真实的接收数据长度。 6.18 CAN 发送实验 1. 实验目的 (1) 掌握基于 Linux 下 SJA1000 独立 CAN 控制器驱动操作方法。 (2) 掌握 Linux 系统 SJA1000 CAN 驱动模块的编译与配置。 (3) 掌握 SJA1000 控制器发送的操作过程。 2. 实验设备 硬件: 软件: PC 机 USBCAN-II CAN 接口卡 CAN-bus 通信电缆 MagicARM2410 教学实验开发平台 RedHat Linux9.0 操作系统 嵌入式 Linux 开发环境 ZLGCANTest 通用测试软件 一台 一台 一条 一套 3. 实验内容 (1) 编译 SJA1000 CAN 控制器驱动模块; (2) 编译 SJA10000 CAN 控制器发送程序示例; (3) 加载 SJA1000 CAN 控制器驱动模块; (4) 用 ZLGCANTest 观察发送的数据。 4. 实验预习要求 (1) 阅读《CAN-bus 通用测试软件及接口函数库使用手册》中的软件使用说明部分,掌 握 ZLGCANtest 软件的使用; (2) 了解 CAN 有哪几种发送方式,各有什么特点和作用。认真阅读 SJA1000 的器件手 册,掌握 SJA1000 器件的发送操作; (3) 复习 Linux 开发环境的使用方法。 5. 实验原理 SJA1000 控制器有 3 种发送方式:正常发送,单次发送,自发自收。本驱动没有实 现给用户的太多选择,仅仅保留了正常发送的方式,这种模式也是 CAN 在正常情况下 的使用方式。读者可进一步修改驱动源码,使其支持另外两种发送模式。发送程序中使 用了 sleep 函数,使其每两秒发送一次数据,发送数据的起始帧 ID 为 0x12345678,每 发送一次,帧 ID 向右循环移位一个字节。 6. 实验步骤 实验步骤(1),(2),(4)和 CAN 接收实验相同,步骤(3)需要修改 main.c 文件 的宏定义,如程序清单 6.43 所示。 - 292 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com #define WRITE_TEST'y' #define READ_TEST 'n' #define SET_TEST 'n' 程序清单 6.43 发送实验的 main.c 文件配置 观察 ZLGCANTest 接收到的数据,看看是否和发送的数据相同,该实验的终端显示如 图 6.37 所示,ZLGCANTest 显示如图 6.38 所示。 图 6.37 发送实验的终端显示 图 6.38 发送实验的 ZLGCANTest 显示 7. 实验程序 发送实验部分程序如程序清单 6.44 所示。 - 293 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 程序清单 6.44 发送程序关键代码 … stcSJA1000_BufInfo Buf; Buf.FrID = 0x12345678; //初始化帧 ID=0x12345678 Buf.FrIf.Byte = 0; Buf.FrIf.Bits.DLC = 8; //发送数据为 8 个字节 Buf.FrIf.Bits.FF = 1; for(i=0; i>24; //帧 ID 循环右移 Buf.FrID = ((Buf.FrID<<8)|i)&0x1fffffff; 8. 思考 结合接收和发送两个实验,可以实现数据的接收处理和发送,完成一个可处理数据的完 整的 CAN 功能节点。试把两个实验相结合,实现接收并且发送的功能。 6.19 CAN 通信参数设置实验 1. 实验目的 (1) 掌握基于 Linux 下 SJA1000 独立 CAN 控制器驱动操作方法。 (2) 掌握 Linux 系统 SJA1000 CAN 驱动模块的编译与配置。 (3) 掌握 SJA1000 控制器通信参数的设置。 2. 实验设备 硬件: 软件: PC 机 USBCAN-II CAN 接口卡 CAN-bus 通信电缆 MagicARM2410 教学实验开发平台 RedHat Linux9.0 操作系统 嵌入式 Linux 开发环境 ZLGCANTest 通用测试软件 一台 一台 一条 一套 - 294 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 3. 实验内容 (1) 编译 SJA1000 CAN 控制器驱动模块; (2) 编译 SJA10000 CAN 控制器参数配置程序示例; (3) 加载 SJA1000 CAN 控制器驱动模块; (4) 学会使用 USBCAN-II CAN 接口卡和 ZLGCANTest 软件; (5) 设置通信参数后,比较这些参数的功能区别。 4. 实验预习要求 (1) 阅读《CAN-bus 通用测试软件及接口函数库使用手册》中的软件使用说明部分,掌 握 ZLGCANtest 软件的使用; (2) 了解 CAN 验收过滤器的功能; (3) 了解 SJA1000 波特率的计算。 5. 实验原理 CAN 的通信波特率范围在 5Kbps~1Mbps 之间,通信距离从 40m~10Km,可适应不同 的应用场合。通常,CAN 的波特率在通信过程中能够在一定范围内进行自我调整,所以各 个厂商的 CAN 设备一般来说都能很好的兼容,但是仍然会出现个别厂商由于使用的波特率 偏差太大而导致设备间通信故障的问题。所以我们推荐用户使用 CIA 推荐的标准波特率, 在我们的 CAN 驱动中,已经使用 CIA 推荐的波特率值,在 SJA1000.h 文件中定义,如程序 清单 6.45 所示。 程序清单 6.45 标准波特率定义 /* ***************************** 标准波特率值(16MHz) ***************************** */ #define BTR_1000K 0x0014U #define BTR_800K 0x0016U #define BTR_500K 0x001CU #define BTR_250K 0x011CU #define BTR_125K 0x031CU #define BTR_100K 0x041CU #define BTR_50K 0x091CU #define BTR_20K 0x181CU #define BTR_10K 0x311CU 验收过滤是 CAN 中一种选择性接收机制,类似于以太网的子网掩码的作用,有了这个 功能,CAN 节点的应用程序就可以不用过多的判断是否应该处理接收到的数据。因为不符 合验收过滤器验收要求的帧是不会被 SJA1000 接收的。我们这里简略介绍 SJA1000 单滤波 模式下的验收过滤器设置。 图 6.39 画出了标准帧和扩展帧的滤波的标识符及数据。对于标准帧而言,11 位标识符 和 RTR 位对应 ACR0、 ACR1、AMR0、AMR1,其中 ACR1 和 AMR1 的低四位未使用。 标准帧只有 11 位标识符,数据场的前两个字节也参与滤波,Data1 对应 ACR2 、AMR2, - 295 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com Data2 对应 ACR3 、AMR3。参与滤波的数据字节不能作为一般用户数据使用。若接收的标 准帧为一个远程帧(RTR 位为 1),则只要标识符参与滤波即可。若接收的标准帧是数据帧, 且数据场长度少于 2 字节,则缺少的那部分数据可以不用参与滤波。对扩展帧而言,29 位 标识符和 RTR 位分别对应 4 个 ACR 和 4 个 AMR,只是 ACR3 和 AMR3 的低 2 位未使用, 实际上扩展帧的情况比标准帧要更简单一些。无论是标准帧还是扩展帧,只有在符合上述条 件的验收滤波通过以后,滤波器才将该帧数据存入接收 FIFO 且置位 RBS(接收标志)标志。 图 6.39 SJA1000 但滤波模式示意图 要想深入了解这部分类容,请参考《现场总线 CAN 原理与应用技术》一书。 6. 实验步骤 步骤(1)~(3)同 CAN 发送实验,步骤(4)中,需要将 USBCAN-II 接口卡的波特 率设置成 500K,如图 6.40 中定时器 0 和定时器 1 的值。在编译 main.c 之前记得把宏 SET_TEST 的值设置成‘y’,WRITE_TEST 和 READ_TEST 设置成‘n’,其他步骤不再獒 诉。 图 6.40 500K 波特率设置 在运行 main.程序时,设置波特率成功在超级终端会出现“BTR Set OK!”字样。这时, 使用 ZLGCANTest 发送数据的情况和接收实验中的完全一样。 设定验收过滤的方法和设置波特率类似,这里就把验收过滤的设置留给读者。在 - 296 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com SJA1000.h 头文件中,已经定义好了 ioctl 函数的命令字,如程序清单 6.46 所示。 程序清单 6.46 ioctl 的命令字定义 /* *********************************** 该行命令码为 linux ioctl 函数定义 *********************************** */ #define CAN_BUS_TYPE 0x40 #define BAUD_SIZE INT16U #define ARC_SIZE INT32U #define AMR_SIZE INT32U #define IOCTL_BAUD _IOWR(CAN_BUS_TYPE,0x01,sizeof(BAUD_SIZE)) //波特设置率命令 #define IOCTL_ACR _IOWR(CAN_BUS_TYPE,0x02,sizeof(ARC_SIZE)) //验收代码设置命令 #define IOCTL_AMR _IOWR(CAN_BUS_TYPE,0x03,sizeof(AMR_SIZE)) //验收屏蔽码设置命令 7. 实验程序 参数设置实验的程序如程序清单 6.47 所示。 程序清单 6.47 CAN 参数设置关键代码 … i = ioctl(fd, IOCTL_BAUD, BTR_500K); if(i<0) { printf("BTR Set Err!.\n"); } else { printf("BTR Set OK!.\n"); } … count = read(fd,(void*)(&Buf), sizeof(Buf)); if(count < 0) { printf("read err!.\n"); } else { printf("CAN Recive %d Bytes.\n", count); printf("CAN ID = 0x%08X.\n", Buf.FrID); printf("CAN FramID = 0x%08X.\n", Buf.FrIf.Byte); for(i=0; i<(Buf.FrIf.Bits.DLC); i++) { printf("CAN Data[0x%02X] = 0x%02X.\n",i,Buf.DA[i]); } } … 8. 思考 如果仅仅希望 ID 为 0x00~0xFF 的标准帧能够通过验收过滤器,那么验收屏蔽码和验 - 297 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 收代码的值应该如何设置。 6.20 busybox 移植实验 1. 实验目的 掌握 busybox 在 ARM Linux 上的移植。 2. 实验设备 硬件: 软件: PC 机 MagicARM2410 教学实验开发平台 RedHat Linux 9.0 操作系统 嵌入式 Linux 开发环境 一台 一套 3. 实验内容 将 busybox 移植到 ARM Linux 上。先在 PC 机的 Linux 环境下移植、编译好 busybox, 然后将其加入到根文件系统系统中,并下载到 MagicARM2410 实验箱上运行。 4. 实验预习要求 (1) 预习 busybox 相关知识。 (2) 复习第 4.3.3 小节,理解如何将 Linux 内核文件、根文件系统下载到 MagicARM2410 实验箱上。 5. 实验原理 busybox 是一个 UNIX 系统工具集,它将很多普通的 UNIX 工具集成到一个很小的可执 行文件中(在 Linux 下该可执行文件的文件名为 busybox),为普通用户提供大多数常用的命 令。用命令链接 busybox 就可运行相应的服务。 busybox 享有“嵌入式 Linux 的瑞士军刀”美誉,由 Erik Andersen 先生维护,busybox 包括的命令非常多。用户在启动 MagicARM2410 实验箱上的 Linux 后,进入到/bin 或/sbin, 就可以看到很多命令,如 mkdir、cp 等等,这些都是 busybox 文件的链接命令。 6. 实验步骤 (1) 准备源代码 请到 http://www.busybox.net/网站下载 busybox 的发布源码压缩包 busybox-0.60.5.tar.bz2 文件(也可以从产品光盘中取得)。 (2) 在 PC 机的 Linux 环境下,新建目录 busybox,将 busybox-0.60.5.tar.bz2 放到该目录 下。 $ mkdir busybox (3) 在 busybox 目录中解压 busybox-0.60.5.tar.bz2,那么 busybox-0.60.5 目录就是 busybox 源码所在路径了,进入到 busybox-0.60.5 目录。 $ cd busybox $ tar -jxvf busybox-0.60.5.tar.bz2 $ cd busybox-0.60.5 - 298 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com (4) 用 vi 等编辑器编辑 Config.h 文件,使能你所需要的命令,例如,现在需要用到 adjtimex 命令,那么找到 Config.h 中使能 adjtimex 命令的语句: //#define BB_ADJTIMEX 将注释符号“//”去除即可使能编译器编译该命令了。 (5) 先退出对 Config.h 文件的编辑,然后用 make CROSS=arm-linux-命令编译 busybox。 $ make CROSS=arm-linux- 这里 CROSS=arm-linux-用于指明使用的交叉编译工具。当然,用户也可以用 vi 等编辑 文本的工具编辑本目录下的 Makefile,找到其中的 CROSS = 将这一行改为: CROSS=arm-linux- 然后再运行 make 命令,也能够达到 make CROSS=arm-linux-一样的效果。 (6) 执行 make install 命令,生成最终的 busybox 应用程序。 $ make install 这时,在当前目录的_install 目录中,生成了三个文件夹 bin、sbin、usr。其中,只有 bin 目录下的 busybox 为实际的文件,其它目录下的命令全部为 busybox 文件的符号链接。 将 bin、sbin(其中 usr/bin 和 usr/sbin 中的文件全部为符号链接文件,请将它们分别复 制到 bin 和 sbin 文件夹中,并重新制作它们的链接)中的全部文件复制到 MagicARM2410 的 Linux 根文件系统相应的文件夹中,然后将根文件系统下载到 MagicARM2410 实验箱, 即可实现 busybox 在 Linux 下的运行了。修改 Linux 根文件系统的方法见 6.2 小节。 将一个符号链接文件链接到一个实际的文件的方法是使用 ln 命令,例如将 cd 命令链接 到 busybox 文件的方法是(假设 busybox 在当前目录下,而且当前目录没有 cd 文件): $ ln –s busybox cd 7. 思考题 根据本实验提供的方法,使能更多的 busybox 指令,并编译下载到 MagicARM2410 实 验箱上运行。 6.21 boa 移植实验 1. 实验目的 掌握 boa 在 ARM Linux 上的移植。 2. 实验设备 硬件: 软件: PC 机 MagicARM2410 教学实验开发平台 RedHat Linux 9.0 操作系统 嵌入式 Linux 开发环境 boa-0.94.13.tar.gz 软件包 - 299 - 一台 一套 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 3. 实验内容 将 boa 移植到 ARM Linux 上,并构建一个小型的网页服务器。先使用 NFS 方式调试, 然后将移植后的 boa 添加/安装到文件系统中,并重新下载文件系统。 4. 实验预习要求 (1) 预习 boa 相关知识,可查阅 boa 网站 www.boa.org。 (2) 预习交叉编译相关知识,预习如何下载文件系统。 5. 实验步骤 (1)准备源代码 到 boa 网 站 http://www.boa.org 下 载 boa-0.94.13.tar.gz 源 代 码 , 或 者 使 用 光 盘 的 boa-0.94.13.tar.gz 软件包。 解压软件包,安装源代码。 $ tar xzvf boa-0.94-13.tar.gz (2)编译源代码 进入 src 目录,编译源代码。 解压后 src 目录下有 Makefile.in 文件,但没有 Makefile 文件,为了编译源代码,需要先 生成 Makefile 文件,在 src 目录下运行 configure 命令即可。 $ ./configure 生成的 Makefile 文件是针对 X86 平台的,为了生成能够在 ARM 上运行的 boa,需要修 改 Makefile 文件。 将 Makefile 的 31~32 行内容: CC = gcc CPP = gcc –E 改为: CC = arm-linux-gcc CPP = arm-linux-gcc –E 然后输入 make 命令进行编译,在 src 目录下就会生成 boa 文件。 $ make 然后将该文件添加到文件系统中,重新下载文件系统。如果不幸出现“icky Linux kernel bug!”的错误,请将 src 下 boa.c 的第 226 行注释掉,重新编译下载即可。 225 if(setuid(0) != -1) { 226 // DIE(“icky Linux kernel bug!”); 227 } (3)安装 boa 服务器 主要是配置 boa 服务器。boa 启动时需要一个配置文件 boa.conf,该文件的缺省目录由 - 300 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com src/defines.h 文件的 SERVER_ROOT 定义,或者在启动 boa 的时候通过参数“-c”指定。其 中指定的默认目录是: /etc/boa/ 如果用户不希望放在别的目录,而又不想在启动的时候指定,则需要修改 defines.h 文 件后重新编译。 在 boa 源代码目录下有一个 boa.conf 文件,用户可以对其按照自己的要求进行修改后, 添加到文件系统中。其中设定了 boa 运行时的一些参数,部分介绍如下。 服务器端口,默认为 80: Port 80 服务器名称,没有默认值。 #ServerName www.your.org.here HTML 文档根目录,默认为/var/www。将服务器的网页放在该目录下。 DocumentRoot /var/www CGI 程序所在目录,默认为/cgi-bin/ /usr/lib/cgi-bin/。 ScriptAlias /cgi-bin/ /usr/lib/cgi-bin/ 另外还有其它一些参数,请参考该文档说明。配置完毕,将 boa.conf 文件添加到文件系 统指定目录,然后启动 boa 服务器。 # ./boa (4)登录 boa 服务器 在 PC 机浏览器地址栏输入目标系统的 IP 地址,访问存在于目标系统中的网页。 http://192.168.0.168 (使用实验箱的 IP 地址) 6. 思考 移植/安装 boa,需要注意哪些问题? 6.22 Madplay 移植实验 1. 实验目的 掌握 Madplay 在 ARM Linux 上的移植。 2. 实验设备 硬件: 软件: PC 机 MagicARM2410 教学实验开发平台 RedHat Linux 9.0 操作系统 嵌入式 Linux 开发环境 一台 一套 - 301 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com madplay-0.15.2b.tar.gz libid3tag-0.15.1b.tar.gz libmad-0.15.1b.tar.gz zlib-1.2.3.tar.gz 3. 实验内容 将 Madplay 移植到 ARM Linux 上,并使用 Madplay 播放 mp3。先使用 NFS 方式调试, 然后将移植后的 Madplay 添加到文件系统中,并重新下载文件系统。 4. 实验预习要求 (1) 预习 Madplay 相关知识。 (2) 预习交叉编译相关知识,预习如何下载文件系统。 5. 实验步骤 (1)准备源代码 可以到 http://sourceforge.net/project/showfiles.php?group_id=12349 下载 madplay-0.15.2b. tar.gz 源代码和相关依赖包: madplay-0.15.2b.tar.gz libid3tag-0.15.1b.tar.gz libmad-0.15.1b.tar.gz 另外,还需要 zlib 库,请到 http://www.gzip.org/zlib/上下载。目前最新版本是 zlib-1.2.3, 下载软件包 zlib-1.2.3.tar.gz。 (2)安装 zlib-1.2.3 新建目录 install,作为库文件的安装路径。解压 zlib-1.2.3.tar.gz,在当前目录下生成的 zlib-1.2.3 目录就是 zlib-1.2.3 源代码所在路径。 $ mkdir install $ tar xzvf zlib-1.2.3.tar.gz 编译 zlib-1.2.3。进入 zlib-1.2.3 目录,修改 Makefile 文件的 CC=arm-linux-gcc 修改前缀为安装路径,安装完毕会生成 include、lib 和 share 3 个文件夹,默认生成在 /usr/local 目录下。由于这里使用交叉编译,为了不改变系统的库,现在为其指定生成路径, 在编译 libid3tag 的时候需要寻找这个路径。我们将其放在当前目录下上一级目录的 install 目录下: prefix=$(PWD)/../install 然后编译并安装: $ make $ make install - 302 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 我们在上一级目录的 install 文件夹下将会看到,里面多了 3 个文件夹 include、lib 和 share。include 文件夹内有 zconf.h、zlib.h 两个文件;在 lib 目录下有 libz.a 文件,share 里面 也有一个文件。 (3)编译安装 libid3tag-0.15.1b 解压 libid3tag-0.15.1b.tar.gz,在当前目录下生成的 libid3tag-0.15.1b 目录就是安装目录。 $ tar xzvf libid3tag-0.15.1b.tar.gz 使用 configure 命令配置库编译选项,包括 C 编译器、编译选项、链接选项和安装路径 等。 $ ./configure --host=arm-linux --enable-static --disable-shared --disable-debugging --prefix=$INSTALLPATH 编译并安装库,将编译好的库安装到指定目录下。 $ make $ make install (4)编译安装 libmad-0.15.1b 解压 libmad-0.15.1b.tar.gz,在当前目录下生成的 libmad-0.15.1b 就是安装路径。 $ tar xzvf libmad-0.15.1b.tar.gz 使用 configure 命令配置库编译选项,包括 C 编译器、编译选项、链接选项和安装路径 等。 $ ./configure --host=arm-linux --enable-static --disable-shared -disable-debugging --prefix=$INSTALLPATH 编译并安装库,将编译好的库安装到指定目录下。 $ make $ make install (5)编译安装 madplay-0.15.2b 解压 madplay-0.15.2b.tar.gz,在当前目录下生成的 madplay-0.15.2b 就是安装路径。 $ tar xzvf madplay-0.15.2b.tar.gz 使用 configure 命令配置库编译选项,包括 C 编译器、编译选项和链接选项等。 $ ./configure --host=arm-linux --enable-static --disable-shared --with-pic --disable-debugging 编译 madplay,当前目录下会生成 madplay 文件。 $ make (6)播放 mp3 使用 NFS 方式调试或者将生成的 madplay 添加到文件系统中,重新下载文件系统。使 用 madplay 播放 mp3 文件。 # ./madplay music.mp3 - 303 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 提示: 安装 madplay 的步骤以及所依赖的库比较多,使用命令很容易出错,我们为此编写了一 个脚本文件 build,只需要执行脚本文件即可完成所有操作。 $ ./build 6. 思考 尝试在主机上编译 Madplay,并和为 ARM 编译相比较。 - 304 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 第7章 嵌入式 Linux 驱动开发 7.1 Linux 驱动编写概述 本节以字符驱动为例对 Linux 传统驱动编写方法进行简单分析。下一节对基于设备文件 系统(DEVFS)的驱动编写进行介绍。对于块设备和网络设备以及 MTD 等驱动编写暂时不 做介绍。 7.1.1 设备号 主设备号对应于驱动程序。 从设备号对应于使用驱动的设备。 主设备号的使用情况请参考/Documentation/Devices.txt。参看该文件, 可得到如下信息: 231~239:UNSSIGNED 240~254:LOCAL/EXPERIMENTAL USE 255: RESERVED 其余设备号已经被分配了,我们从以上设备号中选择使用即可。 7.1.2 文件层接口 1. file_operations Linux 把所有设备当成文件。为了操作文件,Linux 提供了统一的文件操作函数接口, 以字符型设备/文件为例,其文件操作函数接口是 file_operations 结构,如程序清单 7.1 所示, 定义在中。 程序清单 7.1 file_operations /* * NOTE: * read, write, poll, fsync, readv, writev can be called * without the big kernel lock held in all filesystems. */ struct file_operations { struct module *owner; loff_t (*llseek) (struct file *, loff_t, int); ssize_t (*read) (struct file *, char *, size_t, loff_t *); ssize_t (*write) (struct file *, const char *, size_t, loff_t *); int (*readdir) (struct file *, void *, filldir_t); unsigned int (*poll) (struct file *, struct poll_table_struct *); int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long); int (*mmap) (struct file *, struct vm_area_struct *); int (*open) (struct inode *, struct file *); int (*flush) (struct file *); int (*release) (struct inode *, struct file *); int (*fsync) (struct file *, struct dentry *, int datasync); - 305 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com int (*fasync) (int, struct file *, int); int (*lock) (struct file *, int, struct file_lock *); ssize_t (*readv) (struct file *, const struct iovec *, unsigned long, loff_t *); ssize_t (*writev) (struct file *, const struct iovec *, unsigned long, loff_t *); ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int); unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long); #ifdef MAGIC_ROM_PTR int (*romptr) (struct file *, struct vm_area_struct *); #endif /* MAGIC_ROM_PTR */ }; 在 fs.h 文件中还定义了其它如节点操作、块设备操作的结构体。 该结构体实际上是一个函数指针表。在驱动程序中常说的“方法”,就是 file_operations 结构提供的函数指针,是一系列的接口函数,如用于读写的 read/write 函数,用于 IO 控制 的 ioctl 函数等。打开一个文件就是调用这个文件 file_operations 中的 open 操作。一般情况 下,返回 0 表示访问成功,返回负数表示发生了错误。 不同类型的文件有不同的 file_operations 成员函数。如普通的磁盘数据文件,接口函数 完成磁盘数据块读写操作;而对于各种设备文件,则最终调用各自驱动程序中的 I/O 函数进 行具体设备的操作。这样,应用程序根本不用考虑操作的是设备还是普通文件,可一律当作 文件处理,具有非常清晰统一的 I/O 接口。所以 file_operations 是文件层次的 I/O 接口。 2. modulename _fops 通常,不同驱动文件层接口又不同。并不是所有驱动模块都需要 file_operations 所提供 的所有方法,不需要的方法以设为 NULL 指针即可(设为 NULL 指针的可以不写出来),定 义一个文件层的接口结构 modulename_fops。假定一个设备的操作接口如程序清单 7.2 所 示。 程序清单 7.2 modulename _fops struct file_operations modulename_fops = { owner: THIS_MODULE, read: modulename _read, write: modulename _write, ioctl: modulename _ioctl, open: modulename _open, release: modulename _release, }; 当注册设备的时候,register_chrdev()函数将会把设备操作函数接口登记进内核。 以典型的声音设备为例,其文件层的 file_operations 定义如程序清单 7.3 所示。 程序清单 7.3 oss_sound_fops struct file_operations oss_sound_fops = { owner: THIS_MODULE, - 306 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com llseek: sound_lseek, read: sound_read, write: sound_write, poll: sound_poll, ioctl: sound_ioctl, mmap: sound_mmap, open: sound_open, release: sound_release, }; 其中的 sound_read,sound_write 等函数 Linux 都已提供,处理了与声音设备相关的许多 细节,如 DMA 的申请,释放和操作等。 而文件层到驱动程序的接口为 audio_driver 结构,其中包含底层操作函数。文件层的 sound_read,sound_write 会在需要时调用 audio_driver 中的函数。开发人员只要编写 audio_driver 中的函数就可以了,最大程度地减小了工作量。 7.1.3 驱动层接口 但是,由于外设的种类繁多,操作方式也各不相同。如声音设备驱动要使用 DMA 通道, 显示设备驱动要提供对显存的操作,硬盘驱动要处理复杂的缓冲区结构,网络设备驱动和 socket 联系紧密。如果 file_operations 中的函数都让驱动程序的开发人员来写,则就要处理 大量的细节,几乎是不可能的。为了解决设备多样性的问题,Linux 采用了特殊情况特殊处 理的办法,为不同设备定义好了文件层次 file_operations 结构中的接口函数,其中处理了大 多数设备相关的操作,如各种缓冲区的申请和释放等等,而具体操作底层硬件的一小部分则 留给开发人员。所以 Linux 另外提供一个文件层到底层驱动程序的接口,通常为一个结构 体,其中包含成员变量和函数指针。不同的设备驱动有不同的结构体。这样,一方面保证 了文件层 I/O 接口 file_operations 的一致性,另一方面驱动程序的开发人员也不用了解太多 细节,只专著于硬件相关的 I/O 操作就可以了。 在 Linux 中为设备定义了一个设备信息结构体 device_struct,有时也称为设备开关表。 一般情况下,该结构体定义在中,如程序清单 7.4 所示。 程序清单 7.4 device_struct struct device_struct { const char * name; struct file_operations * fops; }; 其中的成员结构 struct file_operations fops 是设备的标准操作函数集,其中的操作函数由 驱动程序实现,完成指定的设备操作。该结构让设备和文件操作联系起来。 为 设 备 定 义 了 一 个 保 存 信 息 的 结 构 数 组 , 如 字 符 设 备 的 chrdevs[MAX_CHRDEV],该数组元素为 device_struct 结构。 static struct device_struct chrdevs[MAX_CHRDEV]; 当设备注册到内核后,设备的名称和相关的操作被添加到设备信息结构的全局数组中, - 307 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 如 chrdevs[]。 当然,也可以直接将 file_oprations 结构中的部分成员放在设备信息结构中,如声音设 备,其文件层到驱动程序的接口为 audio_driver 结构,其中包含底层操作函数,如程序清单 7.5 所示。文件层的 sound_read,sound_write 会在需要时调用 audio_driver 中的函数。开发 人员只要编写 audio_driver 中的函数就可以了,最大程度地减小了工作量。 程序清单 7.5 audio_driver struct audio_driver { struct module *owner; int (*open) (int dev, int mode); void (*close) (int dev); void (*output_block) (int dev, unsigned long buf, int count, int intrflag); void (*start_input) (int dev, unsigned long buf, int count, int intrflag); int (*ioctl) (int dev, unsigned int cmd, caddr_t arg); int (*prepare_for_input) (int dev, int bufsize, int nbufs); int (*prepare_for_output) (int dev, int bufsize, int nbufs); void (*halt_io) (int dev); int (*local_qlen)(int dev); void (*copy_user) (int dev, char *localbuf, int localoffs, const char *userbuf, int useroffs, int max_in, int max_out, int *used, int *returned, int len); void (*halt_input) (int dev); void (*halt_output) (int dev); void (*trigger) (int dev, int bits); int (*set_speed)(int dev, int speed); unsigned int (*set_bits)(int dev, unsigned int bits); short (*set_channels)(int dev, short channels); void (*postprocess_write)(int dev); /* Device spesific postprocessing for written data */ void (*preprocess_read)(int dev); /* Device spesific preprocessing for read data */ void (*mmap)(int dev); }; 7.1.4 中断 如果驱动程序需要使用中断,则需申请中断,卸载模块的时候需要释放中断。 1. 申请中断 request_irq() 在 include/linux/sched.h 里声明。request_irq()函数原型如程序清单 7.6 所示。 程序清单 7.6 request_irq()函数原型 int request_irq( unsigned int irq, void (*handler)(int irq, void *dev_id, struct pt_regs *regs), unsigned long flags, const char * dev_name, void *dev_id ); - 308 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 通常情况下,返回值为 0 表示申请成功,负值表示出错。其中的参数简单介绍一下: irq 是要申请的硬件中断号。 handler 是指实际中断处理程序的函数指针。只要系统接收到中断,系统调用这个函数。handler 的函数原型是特定的――接受 3 个参数,包括硬件中断号,device id,寄存器值。dev_id 就 是下面的 request_irq 时传递给系统的参数 dev_id。 flags 是中断处理的一些属性。比较重要的有 SA_INTERRUPT,标明中断处理程序是快速处 理程序(设置 SA_INTERRUPT)还是慢速处理程序(不设置 SA_INTERRUPT)。快速处理程序 被调用时屏蔽所有中断。慢速处理程序不屏蔽。还有一个 SA_SHIRQ 属性,设置了以后运 行多个设备共享中断,处理程序之间通过 dev_id 来进行区分。如果中断由某个处理程序独 占,则 dev_id 可以设置为 NULL。 dev_name 传递给 request_irq 的字符串,用来在/proc/interrupts 显示中断的拥有者。使用 cat 命令 查看。 dev_id 在中断共享时会用到。一般设置为这个设备的 device 结构本身或者 NULL。中断处理程 序可以用 dev_id 找到相应的控制这个中断的设备,或者用 rq2dev_map 找到中断对应的设 备。 在没有强制使用共享方式时,dev_id 可以被设置为 NULL,不过,将它指向设备的数 据结构是比较好的方法。函数会将 dev_id 原封不动的传递给中断处理程序,因而可以很方 便的用于向中断传递额外数据。 2. 中断处理 现在着重介绍中断处理函数。在申请中断的时候,将中断处理函数的函数指针传递给内 核,一旦发生相应中断,则执行中断处理程序。函数原型如程序清单 7.7 所示。 程序清单 7.7 irq 中断处理函数原型 void (int irq, void *dev_id, struct pt_regs *regs), irq 中断号。在 Linux2.0 之前使用,现在后续版本可通过 dev_id 实现。 dev_id 属于 ClientData 类型,即驱动程序可用的私有数据。将传递给 request_irq 的 dev_id 参数, 发生中断时候,会被传回给处理程序。它与注册中断的 request_irq()函数中的 dev_id 必须一 致。 regs 指向一个结构的指针,该参数很少使用。它保存着处理器进入中断代码之前处理器的的 寄存器和状态。常用于调试,一般驱动程序不必使用。 中断处理程序通常被声明为 static,因为它不会被其它文件中的代码直接调用。 3. 释放中断 free_irq() void free_irq(unsigned int irq, void *dev_id); - 309 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 第一个参数是将要释放的 irq 中断号。 第二个参数标志设备。如果中断是该设备独占的,这里设置为 NULL;如果是共享中断, 需要设置为中断处理程序指针。 7.1.5 I/O 操作 1. ioctl 方法 ioctl 方法 当设备不能通过标准 UNIX 接口函数进行操作的时候使用该方法。 2. 阻塞型 I/O 当进行 read 操作时,如果没有数据可读,而又没有到达文件末尾,此时有两种处理办 法:阻塞型操作和非阻塞型操作。 如果采用阻塞型操作,应该实现这样的操作: 如果进程调用 read,而又没有数据可读,进程必须阻塞,当数据到达的时候,进程被唤 醒,并将数据返回调用者。支持这种处理方法需要一个基本的数据类型――等待队列。 wait_queue_head_t 在/include/linux/wait.h 中定义。其结构体如程序清单 7.8 所示。 程序清单 7.8 等待队列数据结构 struct __wait_queue_head { wq_lock_t lock; struct list_head task_list; #if WAITQUEUE_DEBUG long __magic; long __creator; #endif }; typedef struct __wait_queue_head wait_queue_head_t; 让进程进入睡眠状态可调用下面的函数实现: interruptible_sleep_on(wait_queue_head_t *queue); sleep_on(wait_queue_head_t *queue); interruptiable_sleep_on()能被信号取消,适用于可中断进程;sleep_on()则不能被信号取 消,适用于不可中断的进程。 相应的,唤醒进程可调用如下函数: wake_up_interruptible(wait_queue_head_t *queue); wake_up(wait_queue_head_t *queue); wake_up_interruptiable ()能被信号取消,适用于可中断进程;wake_up()则不能被信号取 消,适用于不可中断的进程。一般驱动程序中,进程仅在 read 或者 write 操作期间才会睡眠, 所以应该使用适用于可中断的进程睡眠和唤醒函数。 进入睡眠,就是进入等待队列。需要声明一个 decleare_wait_queue_head 变量,然后将 - 310 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 该变量的指针传递给 sleep_on 和 wake_up 函数。方法如下: DECLARE_WAIT_QUEUE_HEAD(wait)声明一个叫 wait 的等待队列。 DECLARE_WAIT_QUEUE_HEAD()是一个宏,在/include/linux/wait.h 中定义。经过宏展开后就是定义了一个等待队列头变量。 #define DECLARE_WAIT_QUEUE_HEAD(name) \ wait_queue_head_t name = __WAIT_QUEUE_HEAD_INITIALIZER(name) 唤醒进程使用的队列和进程睡眠使用相同的队列,必须为每一个可阻塞 I/O 的事件建立 一个等待队列。 在 Linux 2.4 的内核中,等待操作引入了新的函数簇――wait_event*(),位于/include/linux/sched.h 文件中。 int wait_event_interruptible (wait_queue_head_t queue, int condtion); void wait_event (wait_queue_t queue, int condtion); 这两个函数分别和 sleep_on()两个函数对应。 3. poll 和 select 方法 包含头文件。 poll 和 select 方法通常用来实现对一个或者多个打开的文件进行非阻塞型操作。常用于 要使用多个输入/输出设备,而又不会阻塞其它设备的应用中。poll 由 System V 提供,select 由 BSD UNIX 提供。在 Linux 2.0 中,仅使用 select,而从 Linux 2.1.23 开始,两种方法都实 现了。 poll 可用来实现 poll 和 select 系统调用。函数原型: unsigned int(*poll) (struct file *, poll_table *); 第一个参数是设备文件描述符。对设备操作分两步处理: (1)在一个或者多个指明了 poll 状态变化的等待队列上调用 poll_wait; (2)描述符操作是否可以立即进行无阻塞执行位掩码。 第二个参数是 poll_table 结构,用在内核中实现 poll 和 select 系统调用。调用 poll_wait 函数可将可唤醒进程和可修改 poll 操作状态的事件加入 poll_table。 void poll_wait (struct file *, wait_queue_head_t *, poll_table *); poll 方法还描述哪个操作可以立即执行能够位掩码。例如,如果设备数据已经就绪,则 read 操作立即执行,不用睡眠。 select 系统调用使用 select_table 结构,当 select 发现无需阻塞时,select_table 结构返回 1;当进程需要等待,select-table 结构替代 read 或者 write,并使其进入睡眠状态,此时, select_table 结构加入等待队列,并且返回 0。 select 在进程要求的资源之间进行选择时,只有当没有一个可以接收或者返回数据时, 进程在真正进入睡眠状态。它可以说是对 read 和 write 的补充,更重要的用途是让应用程序 可以同时等待多个数据流。 7.1.6 设备注册和注销 1. 设备注册 设备驱动程序提供的入口点在设备驱动程序初始化时向内核登记,以供系统调用。注册 - 311 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 设备驱动程序就是将它与对应的设备文件连接起来。 对于字符设备,Linux 系统通过调用 register_chrdev()向系统注册。 register_chrdev()在中定义,在中声明,函数 原型如程序清单 7.9 所示。 程序清单 7.9 register_chrdev()函数原型 int register_chrdev(unsigned int major, const char * name, struct file_operations *fops) 其中,major 是设备驱动向内核注册的主设备号,name 是设备名称,fops 则为设备操作 函数的入口点。 返回值为 0 表示注册成功,返回-EINVAL 表示所申请的主设备号非法,一般为大于系 统所允许的最大设备号;返回-EBUSY 为表示所申请的主设备号正在被其它设备驱动使用。 注册成功后,设备名称就会出现在/proc/devics 文件中。 2. 设备注销 当卸载驱动的时候,系统将会删除设备驱动,并释放主设备号,对于字符型设备,注销 函 数 为 unregister_chrdev() , unregister_chrdev() 在 中 定 义 , 在 中声明,函数原型如程序清单 7.10 所示。 程序清单 7.10 unregister_chrdev()函数原型 int unregister_chrdev(unsigned int major, const char * name) 其中,major 为要释放的主设备号,name 为相应的设备名称。系统将 name 与内核中和 该主设备号参数对应的已经注册设备名称进行比较,如果不同,则返回-EINVAL,如果主设 备号超出了允许的范围,同样返回-EINVAL。 7.1.7 模块化 用于注册/注销设备驱动。 1. init_module 和 cleanup_module init_module 负责注册模块所提供的任何设备。cleanup_module 撤销由 init_module 所注 册的所有设备。习惯上,以和注册相反的顺序进行撤销。但是,当同时编译多个模块的时候, 将会出现几个模块重名的情况。 2. module_init 和 module_exit 从 Linux2.3.13 开 始 , 增 加 了 显 式 的 模 块 初 始 化 和 清 除 宏 函 数 : module_init 和 module_exit。 需要将模块初始化函数命名为 your_init(),将模块清除函数命名为 your_cleanup(),然后 使用 module_init 和 module_exit 来进行标记(通常在文件末尾),如程序清单 7.11 所示。 程序清单 7.11 显式标记模块化 module_init(your_init); module_exit(your_cleanup); 注意,使用 module_init 和 module_exit 必须包含头文件。这两个标记就是 - 312 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 将 init_module 和 cleanup_module 定义为所给定函数的名字。这样就保证内核重每个初始化 和清除函数都有一个唯一的名字,给调试带来方便。 Linux2.2 以后的版本,模块初始化和清除函数有所改变,参考程序清单 7.12。 程序清单 7.12 模块初始化和清除属性 static int __init your_init(void) { …… } static int __exit your_cleanup(void) { …… } __init 关键字是 Linux2.2 版本及其以后版本新加的特性。它会在初始化工作完成以后, 丢弃初始化函数并且回收它所占的内存。但是,它仅对直接链接入内核的驱动程序有效,对 于驱动模块则没有作用。 但是,__exit 用在直接链接入内核的驱动程序时,将忽略所标记的函数,而用在模块中 则没有任何作用。 另外,使用__init(如果是数据项,则是__initdata)能够减少内核使用的内存。 7.1.8 初始化 初始化和注册是两码事。设备驱动程序应当尽早被注册,以供用户应用程序通过相应的 设备文件使用它。但是,设备驱动的初始化应当尽可能晚才进行。因为初始化驱动程序意味 着分配系统资源。资源一旦分配,在没有释放之前,其它驱动程序将不能再使用。 初始化在驱动中,对应有两种操作,open 方法和 release 方法。 open 方法在使用驱动程序之前进行,为应用驱动程序申请所需的资源,如申请中断和 硬件初始化等。另外,增加模块使用次数计数器的使用次数。 release 方法在使用完驱动后进行,完成 open 方法为驱动申请的资源的释放,以供其它 程序使用。另外,将模块使用次数计数器次数减少。 对硬件的初始化和资源分配可在注册时进行,亦可在初始化时进行,但是为了充分利用 系统资源,如果驱动程序要对某些硬件资源进行初始化,请将这些操作放在 open 方法中。 7.1.9 编译 编译分静态编译和模块化编译两种情况,两者的编译是不一样的。 静态编译需要修改 Linux 内核原有的 Makefile 文件和配置文件,程序每经过修改,都要 重新编译内核,调试不太方便;而模块化编译则只需要编译模块代码,不需要编译内核,因 而比较灵活,方便调试,只是需要重新编写 Makefile 文件。静态编译方法请参考 Linux 内核 自带驱动的源码,本节重点介绍模块化编译。 模块化编译需要编写单独的 Makefile 文件。Makefile 文件编写在这里不再介绍,给出一 个完整的实例,参考程序清单 7.13。 程序清单 7.13 一个完整的 Makefile 文件 EXEC = driver.ko OBJS = driver.o - 313 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com SRC = driver.c INCLUDE = /zylinux/kernel/include USEINC =. CC = arm-linux-gcc LD = arm-linux-ld MODCFLAGS = -O2 -Wall -D__KERNEL__ -DMODULE -I$(INCLUDE) -I$(USEINC) -march=armv4t -c -o LDFLAGS = -r all: $(EXEC) $(EXEC): $(OBJS) $(LD) $(LDFLAGS) -o $@ $(OBJS) %.o:%.c $(CC) $(MODCFLAGS) -mapcs -c $< -o $@ clean: -rm -f $(EXEC) *.o *~ core 说明一下第 1 行代码。在 Linux 2.4 中,驱动模块文件并没有扩展名,在 Linux 2.6 中为 了将驱动模块和其它文件区别开来,就给驱动模块加上了.ko 的扩展名。在这里我们也出于 这个原因,为驱动模块加上了.ko 的扩展名。 7.2 Devfs 驱动程序编写 Devfs,是设备文件系统(Device FileSystem)的简写。它是 Linux 2.4 中的一种新型文 件管理系统,用于管理/dev 下的所有字符设备和块设备。Devfs 较传统 Linux 驱动管理方式 相比,有很多优越性,在驱动程序编写和使用上都有一些差别。 传统驱动采用主设备号和次设备号,由此带来一些局限性: (1)在/dev 目录下的大多数设备是不存在的;没有用到的设备文件是为了方便在添加 新设备的时候不用再创建设备文件,但是由此带了第一次引用索引节点时查找所花费的事 件。 (2)主设备号和次设备号都是 8 位长度。在现代操作系统中,成了某些硬件的限制因 素。 Devfs 系统允许设备驱动程序通过名字而不是主次设备号注册设备,和传统驱动的优势: (1)设备初始化的时候在/dev 目录下创建设备入口节点,移除设备时自动将它删除; (2)设备驱动程序可以指定设备名称、所有者和权限位,而用户空间程序仍可以修改所 有者和权限位; (3)不再需要人为为设备驱动程序分配主设备号以及处理次设备号。 基于 Devfs 的 Linux 驱动程序,在使用的时候,和传统 Linux 驱动程序相比,也简单很 多。不再需要单独编写和运行一个创建设备文件的脚本了。 使用 Devfs 必须在内核的文件系统支持中支持 devfs。 - 314 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 7.2.1 设备的注册和注销 (1)为驱动创建目录 在默认情况下,设备文件直接存放在/dev 目录下。如果需要为自己的设备在/dev 目录下 单独创建一个文件夹,可使用 devfs_mk_dir()函数进行。函数原型如程序清单 7.14 所示。 程序清单 7.14 devfs_mk_dir()函数原型 devfs_handle_t devfs_mk_dir ( devfs_handle_t dir, const char *name, void *info ); (2)注册设备 使用 devfs_register()函数将设备向 devfs 系统注册,函数原型如程序清单 7.15 所示。 程序清单 7.15 devfs_register()函数原型 devfs_handle_t devfs_register ( devfs_handle_t dir, const char *name, unsigned int flags, unsigned int major, unsigned int minor, umode_t mode, void *ops, void *info ); 该函数参数比较多,简要说明如下: dir 创建的设备文件的父目录。如果设置为 NULL 则将设备文件创建在/dev 目录下。 如果需要为自己的设备单独创建目录则需要调用 devfs_mk_dir()进行。 name 设备名称。前面无须加上/dev/。如果希望设备存放于子目录下,则名称中需要包含 /,子目录在注册过程中被创建。另外,也可以指定一个指向目标子目录的合法指 针。 flags devfs 标志的位掩码,各掩码定义和使用参考 devfs_fs_kernel.h。一般情况下选择 DEVFS_FL_DEFAULT,如果设定为 DEVFS_FL_AUTO_DEVNUM,则 devfs 会自 动分配主次设备号。 major 主设备号,如果 flags 设置为 DEVFS_FL_AUTO_DEVNUM,则此位不再有效。 minor 次设备号,如果 flags 设置为 DEVFS_FL_AUTO_DEVNUM,则此位不再有效。 mode 设备的访问模式。 ops 指向设备文件操作数据结构的指针。 info - 315 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com filp->private_data 的默认值。当打开设备时,文件系统将使用 info 的值初始化 filp->private_data 指针。 de 调用 devfs_register()后得到的 devfs 入口。 (3)注销设备 使用 devfs_unregister()即可将设备从 devfs 系统中注销,函数原型如程序清单 7.16 所示: 程序清单 7.16 devfs_unregister()函数原型 void devfs_unregister (devfs_handle_t de); 和 devfs 相关的函数还有很多,请参考/include/linux/devfs_fs_kernel.h 文件。各函数的具体实现请参考/kernel/fs/devfs 目录下的文件。 7.2.2 加载驱动 使用 devfs 编写的驱动,在使用的时候并不需要为设备建立节点文件,只需简单使用 insmod 模块名,将驱动加载到系统中,如: insmod driver.ko 7.3 LED 驱动程序 7.3.1 LED 驱动程序编写 说明:该驱动同时包含了蜂鸣器的驱动。 1. 编译方式宏定义 驱动程序可以和内核一起编译,也可以作为一个模块单独编译。为了方便调试驱动程序, 我们将以模块化的方式对 LED 驱动进行编译。要使用模块化的方法编译驱动,必须用如程 序清单 7.17 所示的宏定义进行控制。如果源程序中没有这样的宏定义,则在 Makefile 文件 中必须设定__KERNEL__和 MODULE 的编译选项。 程序清单 7.17 指定模块化编译 #ifndef __KERNEL__ #define __KERNEL__ #endif #ifndef MODULE #define MODULE #endif 2. 包含头文件 不同驱动使用到的 Linux 机制和资源不一样,因而头文件包含根据具体情况而不同,程 序清单 7.18 所示为该驱动所需要的头文件。 程序清单 7.18 包含头文件 #include #include // 模块编程必须的头文件 - 316 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com #include #include #include // printk()函数 // 显式模块化标记函数所需 // 内核 API 定义和变量声明 //#include //#include //#include //#include //#include #include 3. 设备名称和设备号 为编写的驱动定义设备名称和设备号。这里为 LED 设备命名为“magic-leds”,参考程 序清单 7.19。至于设备号,可以根据自行需要进行分配,如果使用动态分配设备号,则无 须再定义设备号。该 LED 驱动具体实现采用 devfs 自动分配设备号。 程序清单 7.19 设备名称和设备号 #define DEVICE_NAME "magic-leds" //#define LED_MAJOR 231 // 可以是 231~239 或者 240~254 4. 模块声明 添加该模块的相关声明,包括版权、描述和作者等信息,如程序清单 7.20 所示。如果 该模块还需要输入某些参数,也可以通过这种方式声明。 程序清单 7.20 模块声明 MODULE_LICENSE("Proprietary"); MODULE_DESCRIPTION("Guangzhou Zhiyuan Electronic Co.,LTD.\n http://www.zyinside.com"); MODULE_SUPPORTED_DEVICE("Linux2.4.18 & MagicARM2410"); MODULE_AUTHOR("Chenxibing"); graduate school\n 5. LED 基本信息 LED 驱动的具体实现。 MagicARM2410 有 4 个独立 LED 和一个蜂鸣器,而且并不是连续的 GPIO 端口,为了 驱动编写的方便,我们将占用的 5 个端口安排成一个一维表格,如程序清单 7.21 所示。 程序清单 7.21 LED 基本信息 static unsigned long leds_table [] = { GPIO_E11, GPIO_E12, GPIO_H4, GPIO_H6, GPIO_H10, }; - 317 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 6. ioctl 方法 操作 LED(蜂鸣器)很简单,无非就是控制 LED 的亮灭(或者蜂鸣器是否鸣叫),这 样的程序不宜使用标准文件操作如 read()、write()方法实现,使用 ioctl()方法更方便。根据用 户传递的参数,控制某一个 LED 点亮还是熄灭(或者蜂鸣器鸣叫还是停止),参考程序清单 7.22。 程序清单 7.22 LED 驱动的 ioctl 方法 static int magic_leds_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) { if (arg > 4) return -EINVAL; switch(cmd) { case 0: case 1: write_gpio_bit(leds_table[arg], cmd); default: return -EINVAL; } } arg-将要操作控制 LED(包括蜂鸣器)的序号(0~4); cmd-被操作的 LED(或者蜂鸣器)的状态:1-LED 点亮(蜂鸣器停止),0-LED 熄 灭(蜂鸣器鸣叫),其它-非法。 程序先判断传递的参数 arg 是否大于 4,大于 4 则退出。如果 arg 合法,则根据 cmd 的 参数控制 LED(或者蜂鸣器)。这里调用了操作 S3C2410 GPIO 端口的 write_gpio_bit()函数, 该函数其实是一个宏定义,具体参见/include/asm/arch-s3c2410/S3C2410.h 文件。 7. open 方法 用户的应用程序开始使用设备之前会调用该方法。完成对 LED(和蜂鸣器)使用的端 口进行初始化和对模块使用计数器加 1 操作,然后打印提示信息,如程序清单 7.23 所示。 程序清单 7.23 LED 驱动的 open 方法 static int magic_leds_open(struct inode *inode, struct file *filp) { int i; for (i = 0; i < 5; i++) { set_gpio_ctrl (leds_table[i] | GPIO_PULLUP_EN | GPIO_MODE_OUT); write_gpio_bit(leds_table[i], 1); } MOD_INC_USE_COUNT; - 318 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com printk(KERN_INFO DEVICE_NAME ": opened.\n"); return 0; } 程序使能 GPIO 端口内部的上拉电阻,并设置为输出模式,同时将 5 个 IO 端口输出高 电平。 8. release 方法 用户的应用程序使用完设备后会调用该方法。完成对模块使用计数器的减 1 操作,然后 打印提示信息,如程序清单 7.24 所示。 程序清单 7.24 LED 驱动的 release 方法 static int magic_leds_release(struct inode *inode, struct file *filp) { MOD_DEC_USE_COUNT; printk(KERN_INFO DEVICE_NAME ": released.\n"); return 0; } 9. 操作接口 声明 LED 驱动文件层操作接口,将驱动程序用到的方法添加到这里,如程序清单 7.25 所示。 程序清单 7.25 LED 驱动操作接口 static struct file_operations magic_leds_fops = { owner: THIS_MODULE, ioctl: magic_leds_ioctl, open: magic_leds_open, release: magic_leds_release, }; 10. 注册设备 在初始化部分,主要完成 LED 设备的注册。将 LED 设备向 devfs 系统注册,如程序清 单 7.26 所示。 程序清单 7.26 注册 LED 设备 static devfs_handle_t devfs_handle; static int __init magic_leds_init(void) { devfs_handle = devfs_register(NULL, DEVICE_NAME, DEVFS_FL_AUTO_DEVNUM, 0, 0, S_IFCHR | S_IRUSR | S_IWUSR, &magic_leds_fops, NULL); printk(KERN_INFO DEVICE_NAME ": Initialize OK.\n"); return 0; } - 319 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 程序通过 devfs_register()向 devfs 系统注册,设置为系统自动分配设备号。 同时对控制 LED(包括蜂鸣器)的 5 个 GPIO 端口进行初始化,使能 GPIO 端口的内部 上拉电阻,同时设置为输出模式。GPIO_PULLUP_EN 等宏定义参见/include/asm/arch-s3c2410/S3C2410.h 文件。 如果使用传统方法,则需按照如程序清单 7.27 所示的程序进行注册。程序通过 register_chrdev()向内核注册设备,主设备号设置为 0,表示由系统自动分配设备号。 程序清单 7.27 使用传统方法注册 int result; result = register_chrdev(0, DEVICE_NAME, &magic_leds_fops); if (result < 0) { printk(KERN_ERR DEVICE_NAME ": Failed to register major.\n"); return result; } 11. 注销设备 主要完成设备的注销工作。通过 devfs_unregister()从 devfs 系统中将设备注销,程序参 考程序清单 7.28。 程序清单 7.28 注销 LED 设备 static void __exit magic_leds_exit(void) { devfs_unregister(devfs_handle); } 如果使用传统方法,则需使用如程序清单 7.29 所示的方法进行设备注销。通过 unregister_chrdev ()将设备从内核中注销。 程序清单 7.29 使用传统方法注销设备 unregister_chrdev(0, DEVICE_NAME); 12. 模块化 从 Linux 2.3.13 开始,编写任何一个驱动模块都需要这样显式的进行模块化,LED 设备 模块化程序如程序清单 7.30 所示。 程序清单 7.30 LED 设备模块化 module_init(magic_leds_init); module_exit(magic_leds_exit); - 320 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 13. Makefile 文件编写 为驱动程序编写工程管理文件 Makefile,设定工程源文件、目标文件、可执行文件、包 含文件路径、交叉编译器、链接器、编译选项等。下面给出一个完整的 Makefile 文件,如 程序清单 7.31 所示。 程序清单 7.31 模块化编译内核驱动的 Makefile 文件 EXEC = leds.ko OBJS = magic-leds.o SRC = magic-leds.c INCLUDE = /zylinux/kernel/include USEINC =. CC = arm-linux-gcc LD = arm-linux-ld MODCFLAGS = -O2 -Wall -D__KERNEL__ -DMODULE -I$(INCLUDE) -I$(USEINC) -march=armv4t -c -o LDFLAGS = -r all: $(EXEC) $(EXEC): $(OBJS) $(LD) $(LDFLAGS) -o $@ $(OBJS) %.o:%.c $(CC) $(MODCFLAGS) -mapcs -c $< -o $@ clean: -rm -f $(EXEC) *.o *~ core 7.3.2 LED 驱动测试程序 1. 测试程序源代码 驱动程序编写完毕,编译后加载到内核中后,我们就可以使用驱动程序来操作 LED 或 者蜂鸣器了。下面编写一个简单的 LED 驱动测试程序,控制其中一个 LED 闪烁。 程序很简单,先打开设备 magic-leds,然后控制 LED1 闪烁,实现程序参考程序清单 7.32。 程序清单 7.32 LED 驱动测试程序 #include #include #include #include #define LED1 0 #define ON 1 //LED1 的编号是 0 //LED 是 1 点亮,0 熄灭 - 321 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com #define OFF 0 int main(int argc, char **argv) { int i; int fd; fd = open("/dev/magic-leds", 0); if (fd < 0) { perror("Failed to open magic-leds"); exit(1); } for (i=0; i<5; i++) { ioctl(fd, ON, LED1); usleep(500000); ioctl(fd, OFF, LED1); usleep(500000); } close(fd); return 0; } usleep()是让进程睡眠一段事件,以微秒为单位,可用于延时。usleep(500000)表示延时 500 毫秒,程序运行效果是 LED1 每 1 秒钟闪烁一次。 2. Makefile 文件 参考前面的文件(应用程序编写部分)。 3. LED 测试实验 先加载驱动程序模块,然后运行程序。 # insmod leds.ko # ./led 行程序开始会有提示信息,接着 LED1 开始闪烁。 magic-leds: opend 蜂鸣器停止后,提示: magic-leds: released 可以使用 ls 命令查看/dev 下的设备 magic-leds 的设备号。 # ls –l /dev - 322 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 7.4 按键驱动程序 7.4.1 按键驱动程序编写 按键是一个输入设备,用于向系统输入外部输入信号。但是外部信号的输入并不是程序 可预见的。系统接收外部信号可以主动读取,这样只能采取查询方式实现,亦可采取被动接 收方式,当外部信号到达,系统产生一个事件。 采用后者实现的设备常成为阻塞型 I/O。当没有外部事件(按键)的时候,进程进入睡 眠状态并等待事件发生。 本驱动程序采用人为分配主设备号的方式实现。注意与自动分配主设备号的区别。 1. 编译方式宏定义 与 LED 驱动的一样。告知编译器,该驱动编译成一个模块,声明如程序清单 7.33 所示。 程序清单 7.33 指定模块化编译 #ifndef __KERNEL__ #define __KERNEL__ #endif #ifndef MODULE #define MODULE #endif 2. 包含头文件 包含该驱动模块所必须的头文件,参考程序清单 7.34。 程序清单 7.34 KEY 驱动所需头文件 #include #include #include #include #include #include #include #include #include #include 3. 设备名称和设备号 为按键命名为 magic-key,设备号可以人为分配,亦可由系统自动分配。该驱动为 KEY1 分配主设备号为 231,参考程序清单 7.35。 程序清单 7.35 KEY 设备名称和设备号 #define DEVICE_NAME "magic-key" - 323 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com #define KEY_MAJOR 231 // can be 231~239 or 240~254 4. 模块声明 添加该模块的相关声明,包括版权、描述和作者等信息,如程序清单 7.36 所示。如果 该模块还需要输入某些参数,也可以通过这种方式声明。 程序清单 7.36 模块声明 MODULE_LICENSE("Proprietary"); MODULE_DESCRIPTION("Guangzhou Zhiyuan Electronic \nhttp://www.zyinside.com"); MODULE_SUPPORTED_DEVICE("Linux 2.4.18 & MagicARM2410"); MODULE_AUTHOR("Chenxibing"); Co.,LTD.\ngraduate school 5. 按键基本信息 按键 KEY1 连接到系统外部中断 4,本驱动以中断方式驱动按键。把按键所占用的资源 包括外部中断号、GPIO 端口(GPIO_F4)和按键编号(也是键值)存放到一个数据结构中, 便于编程,若按键资源有所改变,也方便修改。按键基本信息参考程序清单 7.37。 程序清单 7.37 KEY 基本信息 static struct key_info { int irq_num; unsigned int gpio_port; int key_num; } key1[1] = { { IRQ_EINT4, GPIO_F4, 1 }, }; static int key_value = 0; static int ready = 0; 全局变量 key_value 用来保存键值,驱动中安排和按键编号一致,ready 是按键键值就 绪标志。 6. 中断处理 按键中断处理程序。当按键被按下,程序将被执行,具体程序参考程序清单 7.38。 程序清单 7.38 KEY 中断处理程序 static DECLARE_WAIT_QUEUE_HEAD(key_wait); static void key_irq_handle(int irq, void *dev_id, struct pt_regs *reg) { struct key_info *key; key = key1; - 324 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com key_value = key->key_num; ready = 1; wake_up_interruptible(&key_wait); } 进入中断后,先将键值传送给全局变量,然后设置键值就绪标志为 1,最后唤醒正睡眠 在等待队列 key_wait 上的进程。 DECLARE_WAIT_QUEUE_HEAD(key_wait) 声 明 一 个 叫 key_wait 的 等 待 队 列 。 DECLARE_WAIT_QUEUE_HEAD()是一个宏,在/include/linux/wait.h 中定义。经过宏展开后就是定义了一个等待队列头变量。 #define DECLARE_WAIT_QUEUE_HEAD(name) \ wait_queue_head_t name = __WAIT_QUEUE_HEAD_INITIALIZER(name) wake_up_interruptible()只能唤醒可中断的进程。 7. read 方法 read()方法,若有按键,则读取按键键值,并将键值传递到用户空间,同时复位按键标 志,实现程序如程序清单 7.39 所示。 程序清单 7.39 KEY 驱动的 read 方法 static ssize_t magic_key_read(struct file *filp, char * buf, size_t count, loff_t *f_pos) { static int value; wait_event_interruptible(key_wait, ready == 1); //interruptible_sleep_on(&key_wait); if(count != sizeof(key_value)) return -EINVAL; value = key_value; copy_to_user(buf, &value, sizeof(value)); ready = 0; return sizeof(value); } copy_to_user()将数据从内核空间复制到用户空间。 如果键植就绪标志 ready 不为 1(即没有按键),wait_event_interruptible()将读取进程进 入睡眠状态,加入等待队列;若 read=1,则读取进程被唤醒。唤醒后,读取键值并通过 copy_to_user()将键值传递到用户空间,供给用户程序使用,同时复位 ready 标志。 也可以使用 interruptible_sleep_on()将读取进程进入睡眠状态,加入等待队列,等待被(中 断程序)唤醒。如果发生中断,进程将被唤醒,则读取键值,并通过 copy_to_user()将键值 传递到用户空间,供给用户程序使用。此时进程的唤醒不依赖于 ready 标志。 - 325 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 8. open 方法 open 方法会实际分配和占用资源。 应用程序打开设备的时候调用。完成 irq 中断申请,同时对 KEY1 对应管脚初始化,并 实现模块使用计数器加 1 和打印提示信息,具体程序参考程序清单 7.40。 程序清单 7.40 KEY 驱动的 open 方法 static int magic_key_open(struct inode *inode, struct file *filp) { int result; struct key_info *key; ready = 0; key = key1; set_external_irq(key->irq_num, EXT_FALLING_EDGE, GPIO_PULLUP_DIS); result = request_irq(key->irq_num, key_irq_handle, SA_INTERRUPT, DEVICE_NAME, NULL); if(result) { printk(KERN_INFO DEVICE_NAME " Failed to request irq.\n"); return result; } MOD_INC_USE_COUNT; printk(KERN_INFO DEVICE_NAME ": opened.\n"); return 0; } set_gpio_mode_usr()是一个宏,用于设置某个端口的模式。该宏在/include/asm/arch-s3c2410/S3C2410.h 中定义。 set_extenal_irq()函数设置 irq 中断的触发模式和是否使能内部上拉。该文件在/include/asm/arch-s3c2410/irq.h 文 件 中 声 明 , 在 /arch/arm/mach-s3c2410/irq.c 中实现。 9. release 方法 release 方法将释放 open 方法所占用的资源。 应用程序使用完设备后调用,完成 irq 中断的释放,并实现模块使用计数器减 1 和打印 提示信息,具体程序参考程序清单 7.41。 程序清单 7.41 KEY 驱动的 release 方法 static int magic_key_release(struct inode *inode, struct file *filp) { struct key_info *key; key = key1; - 326 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com free_irq(key->irq_num, NULL); MOD_DEC_USE_COUNT; printk(KERN_INFO DEVICE_NAME ": released.\n"); return 0; } free_irq()释放中断;该中断为独占中断,因而传递参数 NULL。 10. 操作接口 定义该驱动所实现的操作方法,如程序清单 7.42 所示。 程序清单 7.42 KEY 驱动的操组接口 static struct file_operations magic_key_fops = { owner: THIS_MODULE, read: magic_key_read, open: magic_key_open, release: magic_key_release, }; 11. 注册设备 加载模块的时候调用。实现向 devfs 系统注册设备,程序如程序清单 7.43 所示。 程序清单 7.43 注册 KEY 设备 static devfs_handle_t devfs_handle; static int __init magic_key_init(void) { devfs_handle = devfs_register(NULL, DEVICE_NAME, DEVFS_FL_DEFAULT, KEY_MAJOR, 0, S_IFCHR | S_IRUSR | S_IWUSR, &magic_key_fops, NULL); return 0; } 用 devfs_handle_t 声明一个句柄。 通过 devfs_register()向 devfs 系统注册设备。设置为:使用默认路径,注册主设备号为 KEY_MAJOR。 如果要想兼容传统驱动编写方法,可使用如程序清单 7.44 的方法,通过 register_chrdev() 向内核注册设备。如果要想同时使用两种类型的驱动,则必须将设备注册两次。 程序清单 7.44 使用传统方法注册 KEY 设备 int result; result = register_chrdev(KEY_MAJOR, DEVICE_NAME, &magic_key_fops); - 327 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com if(result<0) { printk(KERN_INFO "Failed to register major: " DEVICE_NAME ".\n"); return result; } 12. 注销设备 模块卸载的时候调用。将设备从 devfs 系统中注销,程序参考程序清单 7.45。 程序清单 7.45 注销 KEY 设备 static void __exit magic_key_exit(void) { devfs_unregister(devfs_handle); } 如果使用传统方法注销 KEY 设备,需要使用如所示程序清单 7.46 的方法,使用 unregister_chrdev()将设备从内核中注销。 程序清单 7.46 使用传统方法注销 KEY 设备 unregister_chrdev(KEY_MAJOR, DEVICE_NAME); 13. 模块化 明确指定模块化,如程序清单 7.47 所示。 程序清单 7.47 KEY 设备驱动模块化 module_init(magic_key_init); module_exit(magic_key_exit); 14. Makefile 文件 参考 LED 驱动的 Makefile 文件。 7.4.2 按键驱动测试程序 1. 测试程序 按键 KEY1 连接了中断,驱动程序也是基于中断实现。读取按键非阻塞方式实现,亦 可以采用阻塞方式读取。为了提高 CPU 运行效率,按键驱动测试实验采用中断方式。程序 读取键值,并将按键被按的次数打印出来,如果按键次数超过 9 次,程序将停止运行。实验 程序参考程序清单 7.48。 程序清单 7.48 KEY 驱动测试程序 #include #include #include #include - 328 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com #include #include #include /* ******************************************************************************************** ** Function name: main() ** Descriptions : Read KEY's value and Pressed times. ** Created by : Chenxibing ** Created Date : 2005-12-27 ******************************************************************************************** */ int main(int argc, char **argv) { int fd; int result; int key_value; int times = 1; fd = open("/dev/magic-key", 0); if (fd < 0) { perror("Failed to open magic-key\n"); exit(1); } while(times < 10) { result = read(fd, &key_value, sizeof(key_value)) == sizeof(key_value); if (!result) { if (errno == EINVAL) printf("Wrong size!\n"); goto exit; } printf("KEY1's value is %d ;", key_value); printf(" Be pressed %d times\n", times++); } exit: close(fd); return 0; } 2. Makefile 文件 参考 LED 驱动测试程序的 Makefile 文件。 - 329 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 3. 按键测试实验 采用 NFS 方式或者将驱动和测试程序下载到目标系统中。在执行测试程序之前先加载 按键驱动。 # ./insmod key.ko 然后运行测试程序。 # ./key& 不按键则有如下提示: magic-key: opened. 按下 KEY1,将会出现提示信息: KEY1's value is 1 ; Be pressed 1 times 按 9 次之后,程序退出并有提示信息: KEY1's value is 1 ; Be pressed 9 times magic-key: released. 可以使用 ls 命令查看/dev 下的设备 magic-key 的设备号。 # ls –l /dev 在程序尚未退出之前,使用 cat 命令查看/proc/interrupts 中正在使用的中断号。 # cat /proc/interrupts - 330 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 第8章 嵌入式图形用户界面-Qt/Embedded 本章主要介绍基于 Qt/Embedded 和 Qtopia 的图形用户界面开发环境的构建。 建立 Qt/Embedded 和 Qtopia 开发环境需要以下软件包,可以到 Trolltech 网站服务器 ftp://ftp.trolltech.com 进行下载。 Tmake 工具包: tmake-1.11.tar.gz Qt/Embedded 安装包: qt-embedded-2.3.7.tar.gz Qt/X11 本安装包: qt-x11-2.3.2.tar.gz Qtopia 安装包: qtopia-free-1.7.0.tar.gz 以下的介绍摘自 Trolltech 公司网站 www.trolltech.com 和其中文网站 www.trolltech.cn,如 果想进一步了解,请登录网站。 8.1 Qt 介绍 Qt 是一个跨平台的 C++图形用户界面库,是挪威 Trolltech 公司的产品。 Qt 是一个全面的 C++应用程序开发框架。它包含一个类库,和用于跨平台开发及国际 化的工具。 8.1.1 全面的 Qt Qt 是一个全面的开发框架,它包括广泛的特征,性能与工具,可以开发高性能,跨平 台客户端,以及服务器端的应用程序。 Qt 类库是一个拥有超过 400 C++个类,同时不断扩展的库。它封装了用于端到端 应用程序开发所需要的所有基础结构。优秀的 Qt 应用程序接口包括成熟的对象模 型,内容丰富的集合类,图形有户界面编程与布局设计功能,数据库编程,网络, XML,国际化,OpenGL 集成等等。 Qt 设计者是一个功能强大的 GUI 布局与窗体构造器,能够在所有支持平台上, 以本地化的视图外观与认知,快速开发高性能的用户界面。 Qt 语言家是一套用来消除国际化工作流程中所带来障碍的工具。使用 Qt 语言家, 开发小组可把应用程序的翻译转换外包给非技术性翻译人员,从而可增加精确度, 大大加快本地化处理过程。. Qt 助手一个完全可自定义,重新分配的帮助文件或文档浏览器,它可与基于 Qt 的 应用程序运行。使用 Qt 助手,开发小组同样能够很大程度上加快文档的处理过程。 8.1.2 跨平台的 Qt Qt 是用于本地化跨平台应用开发的领先性框架。Qt 应用程序接口与工具兼容于所有支 持平台,让开发员们掌握一个应用程序接口,便可执行与平台非相关的应用开发与配置。通 过使用 Qt,开发小组们从主要的开发平台,可为主要操作系统创建本地化的应用程序。 Qt 可提供于下列平台: Qt/Windows (Microsoft Windows XP, 2000, NT 4, Me/98) Qt/Mac (Mac OS X) Qt/X11 (Linux, Solaris, HP-UX, IRIX, AIX, 与其它许多 Unix 变式) Qt 对不同平台(Unix, Windows, and Mac)的专门 API 进行了封装,如文件处理、网络 - 331 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com (操作,协议),进程处理、线程、数据库访问等。 Qt 应用程序本地化运行-类似于本地化 应用程序,在所有主要平台上,从单一源代码中 汇编而成: Qt 在 Windows 上本地化运行 Qt 在 Mac OS X 上本地化运行 Qt 在 Linux/X11 上本地化运行 使用 Qt 进行精确的平台非相关运行-编 程后可在任何地方配置。确立新的平台,仅需重 新汇编一个单一源代码库而已。 8.1.3 深入了解 Qt Qt 类库 众多的 Qt 类库构成 Qt 的基础。该库可以利用大约 400 个面向对象的类,这些类带有 大多数构建跨平台服务器与富客户端应用程序的底层基础构造函数. 这些库包括用于 GUI、布局、数据库、国际化、网络与 XML 等的类。要获得更多信息, 请参阅 Qt 库,模块清单,或请参考范围广泛的 Qt 在线支持文档。 信号与槽 在开发用户图形界面中,一个常见并重复发生的系统崩溃与问题源,即如何在不同组件 之间进行通信。对于该问题,Qt 的解决方案为信号与槽机制。信号与槽是 Qt 的主要特征, 它对促进对象通信提供一个类型安全的方法,并可能是区别于其它多数框架所提供特征的一 个部分。 使用 Qt Designer(设计者)的 GUI 设计 Qt 设计者是一个可见即所得的全方位 GUI 构造器。利用 Qt Designer,开发者可以拖放 各种 Qt 控件构造图形用户界面并可预览效果。 使用 Qt Linguist(语言家)进行国际化 国际市场的应用程序必须应支持全球各种语言与写入系统。无需修改源代码,Qt 应用即可 支持全球各种语言。Qt Linguist 工具帮助用户实现应用国际化。 使用 Qt Assistant(助手)进行在线文档与帮助 对于大多数复杂的程序来说,在线文档和帮助是必不可少的。 Qt 通过 Qt 助手-一个 帮助文件和文档的在线阅读器,来满足这一需求。它可定制,并且可随用户自己的应用程序 一起发布,从而形成用户自己的帮助系统。 Cross-Platform Builds 跨平台构建 编写用于多平台的软件是单调乏味的,且可能出现错误。维护编制文件更是如此,尤其 是当不同的编译器和平台组合需要若干个编制文件时。通过 qmake 工具,Qt 能够很好地面 对这一挑战。这个工具可以为目标平台生成准确无误的编制文件。 8.2 Qt/Embedded 介绍 Qt/Embedded 是一个完整的自包含 GUI 和基于 Linux 的嵌入式平台开发工具,是 Qt 在 - 332 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 嵌入式平台的版本。 Qt/Embedded 以原始 Qt 为基础,并做了许多出色的调整以适用于嵌入式环境。 Qt/Embedded 通过 Qt API 与 Linux I/O 设施直接交互,成为嵌入式 Linux 端口。同 Qt/X11 相比,Qt/Embedded 很省内存,因为它不需要一个 X 服务器或是 Xlib 库,它在底层 摒弃了 X lib,采用 framebuffer(帧缓冲)作为底层图形接口。同时,将外部输入设备抽象 为 keyboard 和 mouse 输入事件。Qt/Embedde 的应用程序可以直接写内核缓冲帧,这避免开 发者使用繁琐的 Xlib/Server 系统。 图 8.1 Qt/Embedded 与 Qt/X11 的比较 Qt/Embedded 的底层图形引擎基于 Framebuffer。Framebuffer 是 Linux 2.2.x 以上本版内 核中的一种驱动程序接口。这种接口采用 mmap 系统调用,将显示设备抽象为帧缓冲区。用 户可以将它看成是显示内存的一个映象,将其映射到进程地址空间之后,就可以直接进行读 写操作了,而写操作可以立即反映在屏幕上。framebuffer 驱动程序是最重要的驱动程序之一, 正是这个驱动程序才能使系统屏幕显示内容。其实现分为两个方面:一是对 LCD 及其相关 部件的初始化,包括画面缓冲区的创建和对 DMA 通道的设置;二是对画面缓冲区的读写, 具体到代码为 read、write 等系统调用接口。 8.3 Qtopia 介绍 8.3.1 简介 Qtopia 是一种全方位的应用程序开发平台,它可用于基于嵌入式 Linux 的 PDA(个人 数字助理),移动电话,web pads,以及其他移动计算设备。 Qtopia 构建于 Qt/Embedded 之上,是专为基于 Linux 的消费电子 设备提供和创建图形用户界面而设计的。 常见的有 2 种版本:Qtopia Phone 版和 Qtopia PDA 版。Qtopia Phone 版必须付费才能得到,而 Qtopia PDA 版有免费版本。 Qtopia Phone 版 Qtopia Phone 版专为基于 Linux 的智能电话和多功能电话设计。 Qtopia PDA 版 Qtopia PDA 版专为基于 Linux 的 PDA (个人数字助理)设计。 Qtopia 特色: Qtopia Phone 版 - 333 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 视窗操作系统 同步框架 开发环境 本地化支持 游戏和多媒体 PIM 应用程序 输入法 个性化选项 生产力(Productivity)程序 Internet 应用程序 Java 集成 无线支持 Qtopia PDA 版 8.3.2 Qtopia 平台的核心特征 输入法 Qtopia 支持两种基本类型的输入法。 Qtopia 可由带有少量按键的键盘驱动,也可由用于触摸屏设备的手写笔驱动。 Qtopia 支持众多的文本输入方式,包括基于键盘的预测键入,可定制的手写识别,以及 屏幕键盘输入。此外,还支持数种可用于亚洲书写系统的第三方输入方式。 屏幕尺寸/布局 Qtopia 强大的设计引擎支持各种屏幕尺寸以及横向和纵向布局,包括 176×208,176× 220,240×320 和 480×640 (像素)。 程序发布器 Qtopia 含有一个程序发布器。根据使用版本的不同(PDA 或 Phone),程序发布器也会 有所不同,但它始终包含一个默认的基于图标的应用程序导航布局方案。 资料处理 Qtopia 允许存储,查看和转移资料。它还有一个应用程序业务框架,允许开发者和用户 选择打开每种资料的程序。 程序安装 程序可以通过桌面型电脑,插入式媒体卡(如 CF 或 SD 卡)或者网络连接安装, 甚至 可以安装在外部存储媒介上。一旦将这个存储媒介插入到基于 Qtopia 的设备,程序可以立 即运行。 插件管理器 Qtopia 自带的插件框架使得向设备添加新特性无缝化且便捷。用户可以添加新字体,插 入新的多媒体格式,添加或移除输入方式,插入新的媒体播放器外观,新的主项,以及许多 其他特性。 国际化支持 Qtopia 内部使用统一的代码,因此可以很方便地针对不同的市场进行本地化。此外,程 序的设计引擎能自动调整比原始文本长或短的翻译文本的按钮和标签。目前,Qtopia 支持多 种语言。 Java 集成 Otopia 上可以运行数种 Java 虚拟器(JVM),包括 Esmertec's Jeode 和 IBM VisualAge Micro Edition。Java 应用程序可以无缝集成到 Qtopia 中,提供同原程序相同的效果。 无线支持 蓝牙和 IrDA 红外线的实现确保了 Qtopia 能和其他移动设备进行通信,包括便携型电脑。 - 334 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 无线支持性能基于 OBEX 标准。 终端用户个性化支持 终端用户可以个性化设置背景,色彩方案,字体,多媒体外观,还可以更改窗口和按钮的颜 色及外观。 同步框架 Qtopia 含有同步框架,可确保方便地备份所有的设备侧数据,并能与桌面型计算机共享。 利用 Qtopia Desktop 和 Microsoft Outlook,Qtopia 可以同步其 PIM 数据。 8.3.3 Qtopia PDA 版本简介 Qtopia PDA 版(Trolltech)是第一个用于嵌入式 Linux PDA 的全方位应用程序开发平台。 Qtopia PDA 版(Qtopia PDA),名副其实基于 Linux 的 PDA 的标准,可为新一代的高级移 动计算设备提供稳定的软件平台。Qtopia PDA 运行于 Linux 之上,只需占用少量内存就能 提供强大的功能。 Qtopia PDA 包括: 核心平台 Qtopia PDA 具备平台级的特色,可提供一个健全且具有许多后台特征的计算环境,从 而为终端用户提供完整的软件开发体验。通过简化增加特别功能的工作,程序制作者将会更 轻松。这些特性包括:输入法,可调的屏幕尺寸和布局,插件管理器,程序安装以及无线支 持。 程序发布器 Qtopia PDA 含有一个基于图标的应用程序导航布局方案。它完全可定制,专为移动计 算设备而设计。用户界面功能强大而直观。 程序 Qtopia PDA 含有一套强大的 PDA 程序集,包括 PIM(包括联系人、事件、任务、地址 簿和计划事项),电子邮件、游戏、多媒体框架以及其他设置。 同步框架 用户可以把他们的 PDA 与 Qtopia Desktop、Trolltech 的跨平台桌面 PIM 集或 Microsoft (R) Outlook 同步。Qtopia PDA 还可以同步联系人、日志、计划事项、多媒体文件和文档等。 开发环境 为了正确地定制 PDA,制造商需要强大的开发工具。Trolltech 提供了一整套工具集来 定制和扩展 Qtopia PDA。强大的开发环境简化了在桌面系统进行开发,进而交互编译到目 标设备的过程。 Qtopia PDA 版的技术特性: 源代码 所有 Qtopia PDA 客户都能获得全部源代码。客户可以创建与现有程序紧密结合的定制 程序,并能在他们想使用的处理器上进行编译。 国际化支持 Qtopia PDA 内部使用统一的代码,因此可以很方便地针对不同的市场进行本地化。此 外,程序的设计引擎能自动调整比原始文本长或短的翻译文本的按钮和标签。 定制 Qtopia PDA 提供一个强大的主题开发引擎,允许程序制作者定制全新的用户界面和程 序发布工具。 Java 集成 Otopia PDA 上可以运行数种 Esmertec,IBM 和 Sun 的 Java 虚拟器(JVM)。Java 应用 - 335 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 程序可以无缝集成到 Qtopia PDA 中,提供同原程序相同的效果。 程序安装 程序可以通过桌面型电脑,插入式媒体卡(如 CF 或 SD 卡)或者网络连接安装, 甚至 可以安装在外部存储媒介上。一旦将这个存储媒介插入到基于 Qtopia PDA 的设备,程序可 以立即运行。 无线支持 红外线的实现确保了 Qtopia PDA 能和其他移动设备进行通信,包括膝上型电脑。无线 支持性能基于 OBEX 标准。 输入法 Qtopia PDA 支持众多的文本输入方式,包括基于键盘的预测键入,可定制的全屏手写 识别,以及屏幕键盘输入。此外,还支持数种可用于非西方书写系统的第三方输入模式。 屏幕尺寸/布局 Qtopia PDA 强大的设计引擎支持各种屏幕尺寸以及横向和纵向布局,包括 240×320 和 480×640 (像素)。 插件管理器 Qtopia PDA 自带的插件框架使得向设备添加新特性无缝化且便捷。用户可以添加新字 体,插入新的多媒体格式,添加或移除输入法,插入新的媒体播放器外观,新的主项,以及 许多其他特性。 终端用户个性化支持 终端用户可以个性化设置背景,色彩方案,字体,多媒体外观,还可以更改窗口和按钮 的颜色及外观。 8.4 Qt/Embedded 和 Qtopia 开发模式 嵌入式软件开发通常都采用交叉编译的方式进行,基于 Qt/Embedded 与 Qtopia 的 GUI 应用开发也采取这样的模式。先在宿主机上调试应用程序,调试通过通过后,经过交叉编译 移植到目标板上。 前 面 介 绍 过 Qt/Embedded 直 接 写 入 帧 缓 冲 , 在 宿 主 机 上 则 是 通 过 qvfb ( vitural framebuffer)来模拟帧缓冲。qvfb 是 X 窗口用来运行和测试 Qtopia 应用程序的系统程序, 允许我们在桌面及其上开发 Qt 嵌入式程序,而不需要在命令台和 X11 之间来回切换。qvfb 使用了共享存储区域(虚拟的帧缓冲)来模拟帧缓冲并且在一个窗口中(qvfb)模拟一个应 用来显示帧缓冲,显示的区域被周期性的改变和更新。通过指定显示设备的宽度和颜色深度, 虚拟出来的缓冲帧和物理的显示设备在每个像素上保持一致。 表 8.1 宿主机移植所需工具及环境变量声明 工具软件 Tmake-1.11 Qt-x11-2.3.2 Qt-embedded-2.3.7 Qtopia-free-1.7.0 描述 生成 Makefile 文件 Qvfb-虚拟帧缓冲工具 Uic 用户界面编译器 Designer Qt 图形设计器 Qt 库支持 libqte.so 应用程序开发包 桌面环境 变量声明 TMAKEDIR / TMAKEPATH / PATH LD_LIBRARY_PATH / PATH QTEDIR / LD_LIBRARY_PATH / PATH QPEDIR / LD_LIBRARY_PATH / PATH 因此在最初编译配置嵌入式 Linux 内核时必须使其支持帧缓冲。宿主机上的移植需要的 工 具 及 环 境 变 量 见 表 8.1 。 其 中 环 境 变 量 可 以 直 接 用 export 来 声 明 , 也 可 以 在 - 336 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com ~/.bash_profile 脚本文件中进行设置。 特别指出,在配置 qt-embedded-2.3.7 时,“./configure -qconfig -qvfb -depths 4,8,16,32” 就是指定 Qt/Embedded 开发包生成虚拟缓冲帧工具 qvfb,并支持 4/8/16/32 位的显示颜色深 度。运行 Qt 的虚拟缓冲帧工具的方法是:在 Linux 图形模式下运行命令:./qvfb &。如果要 把 Qt 嵌入式应用程序的显示结果输出到虚拟缓冲帧时,运行时需在程序名后加上“-qws” 选项。如“./canvas-qws”。 8.5 建立宿主机 Qt/Embedded 与 Qtopia 开发环境 在/zylinux 目录下为基于 PC 的 Qt/Embedded 与 Qtopia 开发建立工作目录 x86-qtopia,将 下 载 的 软 件 包 tmake1.11.tar.gz 、 qt-embedded-2.3.7.tar.gz 、 qt-x11-2.3.2.tar.gz 和 qtopia-free-1.7.0.tar.gz 复制到该目录下,并进入该目录。 提示:最好不要手动输入命令安装,请使用光盘的脚本文件 build 进行安装。 8.5.1 安装 tmake 可以参考 doc 目录下的文档 tmake.html。 使用 tar 命令对 tmake-1.11.tar.gz 进行解压,解压完毕,在当前目录下将会多出文件夹 tmake-1.11,这是 tmake 的安装目录。 $ tar xzvf tmake-1.11.tar.gz $ export TMAKEDIR=$PWD/tmake-1.11 $ export TMAKEPATH=$TMAKEDIR/lib/qws/linux-x86-g++ $ export PATH=$TMAKEDIR/bin:$PATH tmake 的详细使用方法请参考 doc 目录下的文档。 Tmake 中有 3 个模板: app.t-用于创建生成应用程序的 Makefile lib.t-用于创建生成库文件的 Makefile subdirs.t-用于创建编译子目录中的程序的 Makefie Tmake 的配置文件 Tmake.conf 包含了各种编译选项和各种资源。如果生成的 Makefile 文件没有达到相应的要求,可以人为修改。例如增加-QDT_THREAD_SUPPORT,修改链接 库-lqte-mt 可以增加多线程支持。 8.5.2 安装 Qt/X11 参考 qt-x11 目录下的安装说明文件 INSTALL。 使用 tar 命令对 qt-x11-2.3.2.tar.gz 进行解压,解压完毕,在当前目录下会多出文件夹 qt-2.3.2,这就是 Qt/X11 的安装目录。 $ tar xzvf qt-x11-2.3.2.tar.gz $ cd qt-2.3.2 $ export QTDIR=$PWD $ export PATH=$QTDIR/bin:$PATH $ export LD_LIBRARY_PATH=$QTDIR/lib:$LD_LIBRARY_PATH $ ./configure –static –no-xft –no-opengl $ make $ make -C tools/qvfb - 337 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com $ mv tools/qvfb/qvfb bin $ cp bin/uic $QTEDIR/bin $ cd .. Qt 的配置比较复杂,根据配置的不同,需要的编译参数也不尽相同。配置信息请使用 “./configure --help”来查看。 make 加上不同的参数,可以进行不同形式的编译。如果需要编译图形设计器 designer, 可以这样进行“make –C tools/designer”,类似还可以编译其它需要的工具。 make 完毕,如果有“Enjoy! -The Trolltech team”的提示,则编译成功,然后可进行其 它编译和移动/复制工作。 程序清单 8.1 qt configure 选项清单 Usage: ./configure [-debug] [-release] [-shared] [-static] [-gif] [-no-gif] \ [-sm] [-no-sm] [-thread] [-no-thread] [-qt-zlib] [-system-zlib] \ [-qt-libpng] [-system-libpng] [-no-jpeg] [-system-jpeg] \ [-no-] [-kde] [-Istring] [-Lstring] [-Rstring] [-lstring] The defaults (*) are usually acceptable. Here is a short explanation of each option: * -release ........... Compile and link Qt with debugging turned off. -debug ............. Compile and link Qt with debugging turned on. * -shared ............ Create and use a shared Qt library (libqt.so) -static ............ Create and use a static Qt library (libqt.a) * -no-gif ............ Do not compile in GIF reading support. -gif ............... Compile in GIF reading support. See src/kernel/qgif.h * -no-sm ............. Do not support X Session Management. -sm ................ Support X Session Management, links in -lSM -lICE. * -no-thread ......... Do not compile with Threading Support -thread ............ Compile with Threading Support * -qt-zlib ........... Use the zlib bundled with Qt. -system-zlib ....... Use a zlib from the operating system http://www.info-zip.org/pub/infozip/zlib * -qt-libpng ......... Use the libpng bundled with Qt. -system-libpng ..... Use a libpng from the operating system. See http://www.libpng.org/pub/png * -no-mng ............ Do not compile in MNG I/O support. - 338 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com -system-libmng ..... Use libmng from the operating system. See http://www.libmng.com * -no-jpeg ........... Do not compile in JPEG I/O support. -system-jpeg ....... Use jpeglib from the operating system. See http://www.ijg.org * -no-nas-sound ...... Do not compile in NAS sound support. -system-nas-sound .. Use NAS libaudio from the operating system. See http://radscan.com/nas.html -no- ....... Disables a module, where module can can be one of: opengl table network canvas -kde ............... Builds the Qt Designer with KDE 2 support, so that KDE 2 widgets can be used directly in the Qt Designer. $KDEDIR must be set to point to a KDE 2 installation. See http://www.kde.org -no-g++-exceptions . Disable exceptions on platforms using the GNU C++ compiler by using the -fno-exceptions flag. -no-xft ............ Disable support for Anti-Aliased fonts through the Xft extension library (XFree86 4.0.2 and newer). -xft ............... Enable support for Anti-Aliased fonts. Xft support is auto-detected, but you may use these flags to explicitly enable/disable support. -platform target ... The platform you are building on (linux-x86-g++) -xplatform target .. The platform when cross-compiling. See the PLATFORMS file for a list of supported operating systems and compilers. -Istring ........... Add an explicit include path. -Lstring ........... Add an explicit library path. -Rstring ........... Add an explicit dynamic library runtime search path. -lstring ........... Add an explicit library. Qt/Embedded only: -qconfig local ..... Use src/tools/qconfig-local.h rather than the - 339 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com default (qconfig.h). -depths list ....... Comma-separated list of supported bit-per-pixel depths, from: v, 4, 8, 16, 24, and 32. 'v' is VGA16. -accel-voodoo3 ..... Enable Voodoo3 acceleration. -accel-mach64 ...... Enable Mach64 acceleration. -accel-matrox ...... Enable Matrox MGA acceleration. -qvfb .............. Enable X11-based Qt Virtual Frame Buffer. -vnc ............... Enable VNC server (requires network module). 8.5.3 解压 Qtopia 在安装 Qt/Embedded 的时候,需要使用 Qtopia 的配置文件,因而需要先将 Qtopia 解压。 解压完毕会在当前目录下多出文件夹 qtopia-free-1.7.0,这就是 qtopia 的安装目录。 $ tar xzvf qtopia-free-1.7.0.tar.gz $ export QPEDIR=$PWD/qtopia-free-1.7.0 8.5.4 安装 Qt/Embedded 可以参考安装说明文件 INSTALL 文件。 使用 tar 命令对 qt-embedded-2.3.7.tar.gz 进行解压,解压完毕,在当前目录下会多出文 件夹 qt-2.3.7,这是 Qt/Embedded 的安装目录。 在编译 Qt/Embedded 的过程中,会到 qt/src/tools 目录下寻找 qconfig-xxx.h 文件,参数 “-qconfig xxx”指定“qconfig-xxx.h”文件。xxx 具体可以设置为哪些选项,可以参考 src/tools 目录下的配置文件,如可设置为“large”、“small”等。但是最终我们要使用 Qtopia,为了 配置方便,我们使用 QPE 的配置文件,将其配置文件 qconfig-qpe.h 复制到 src/tools 目录下。 $ tar xzvf qt-embedded-2.3.2.tar.gz $ cd qt-2.3.7 $ export QTDIR=$PWD $ export QTEDIR=$QTDIR $ export PATH=$QTDIR/bin:$PATH $ export LD_LIBRARY_PATH=$QTDIR/lib:$LD_LIBRARY_PATH $ cp $QPEDIR/src/qt/qconfig-qpe.h src/tools $ ./configure –platform linux-x86-g++ –qconfig –qvfb –depth 4,8,16,32 $ make sub-src $ cd .. Qt 的配置比较复杂,根据配置的不同,需要的编译参数也不尽相同。 “./configure –platform linux-x86-g++ –qconfig –qvfb –depth 4,8,16,32”指定 Qt 生成虚拟 帧缓冲工具 qvfb,并支持 4/8/16/32 位的显示颜色深度。 在提示“Do you accept the terms of the license?”后回答“yes”,接受 License 的条款方 可继续进行编译。使用“echo yes | ./configure –platform linux-x86-g++ –qconfig –qvfb –depts 4,8,16,32”则可免去手动输入“yes”的工作。 如果不指定“-qvfb”选项,则会出现对话“Enable Qt Virtual Framebuffer support for development on X11(default yes)?”,输入“yes”即可。 如果用户希望 Qtopia 平台能够支持 jpeg、gif 图像,可以在 configure 的参数中添加 - 340 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com “-system-jpeg 和 gif”。 “make sub-src”指定按精简方式编译 Qt,当然,用户也可以直接使用 make 命令进行 编译。 亦可“./configure --help”可以查看 qt 的详细配置说明。 8.5.5 编译安装 Qtopia 请参考 qtopia 目录下的 README.html 文件对环境变量进行设置。 进入 Qtopia 的安装目录,编译并安装 Qtopia。 $ cd qtopia-1.7.0 $ export QTDIR=$QTEDIR $ export QPEDIR=$PWD $ export PATH=$QPEDIR/bin:$PATH $ cd src $ ./configure -platform linux-x86-g++ $ make $ cd ../.. 提示:将光盘 x86-qtopia 目录下的 build 复制到该目录下直接运行即可完成所有 安装。安装上述软件包,需要输入很多命令,很容易出错,再次安装的时候也 非常麻烦,为此我们将所有操作步骤编写成一个 Shell 文件 build,只需执行该文 件即可轻松完成安装。 将 build 文件复制到/zylinux/x86-qtopia 目录下,增加可执行权限并执行。 $ ./build 提示:如果复制的文件没有可执行权限,请使用 chmod 命令为其增加可执行权限: $ chmod 755 文件名 为了方便使用各软件包的兼容版本,我们对解压后的文件夹进行了改名操作,使用 build 文件安装后,各软件安装路径如下。 基于 PC 的 Qt/Embedded&Qtopia 的安装路径:/zylinux/x86-qtopia tmake 软件安装路径: /zylinux/x86-qtopia/tmake Qtopia 的安装路径: /zylinux/x86-qtopia/qtopia Qt/Embedded 的安装路径: /zylinux/x86-qtopia/qt Qt/X11 的安装路径: /zylinux/x86-qtopia/qt-x11 8.5.6 运行 Qtopia (1)设置环境变量 在运行 Qtopia 之前请先确保有 Qtopia 运行的必要环境变量设置。将光盘 x86-qtopia 目 录下的文件 set-env 复制到/zylinux/x86-qtopia 目录下,并执行“source set-env”命令(或 者.+空格+set-env),设置环境变量。如果用户退出了登录,再次进入的时候,需要重新为 Qt 设置环境变量。 - 341 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com $ source set-env 或者 . set-env set-env 是一个脚本文件,用于设置环境变量,其内容如下: export QTDIR=$PWD/qt export QPEDIR=$PWD/qtopia export TMAKEDIR=$PWD/tmake export TMAKEPATH=$TMAKEDIR/lib/qws/linux-generic-g++ export PATH=$QTDIR/bin:$QPEDIR/bin:$TMAKEDIR/bin:$PATH (2)启动虚拟帧缓冲 $ qvfb & (3)运行 Qtopia $ qpe & 将会得到如图 8.2 所示的 Qtopia 界面。 如果在运行的时候,出现某些库找不到的错误的话,可以在配置文件中为 Qt 的库进行 定位,在/etc/ld.so.conf 文件中增加 Qt 库的路径,如下方框部分所示(需要 root 权限)。 /zylinux/x86-qtopia/lib /zylinux/x86-qtopia/qtopia/lib /usr/kerberos/lib /usr/X11R6/lib /usr/lib/sane /usr/lib/qt-3.1/lib /usr/lib/mysql /usr/lib/qt2/lib /usr/local/lib 添加完毕,在/etc 目录下,以 root 身份执行 ldconfig 命令,让 Qt 的库生效。 - 342 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 图 8.2 Qtopia 在 PC 的界面 说明:默认情况下,显示窗口大小为 240×320 象素,如果在启动虚拟帧缓冲的时候指 定了显示尺寸参数,则窗口大小会相应改变。 例如,指定显示窗口大小为 640×480,将会得到如图 8.3 所示的窗口界面。 $ qvfb –width 640 -height 480 & 图 8.3 640×480 象素的 Qtopia 窗口 - 343 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 8.5.7 在 PC 上运行 Hello 程序 在编译/运行程序之前,请先设置环境变量。 将光盘 x86-qtopia 目录下的 Hello 程序复制到/zylinux/x86-qtopia 目录下。 (1)进入 hello 目录,执行 make 命令编译 hello 程序,编译完毕后程序生成在 $QPEDIR/bin 目录下。 $ make (2)准备运行环境 为了让应用程序在 Qtopia 中运行,需要制作一个配置文件 xxx.desktop,并需将配置文 件复制到 Qtopia 的配置文件目录“$QPEDIR/apps/Applications”下。复制 hello.desktop。 $ cp hello.desktop $QPEDIR/apps/Applications 该配置文件有固定的格式,以 Hello 程序的配置文件为例进行说明。 [Desktop Entry] Comment=A Hello Demo. Exec=hello Icon=Hello Type=Application Name=Hello (3)启动虚拟帧缓冲和 Qtopia 启动后,在 Qtopia 界面将会看到刚才的 Hello 程序,如图 8.4 所示。 $ qvfb & $ qpe 图 8.4 Qtopia 中的 Hello 程序 - 344 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 点击 Hello 程序图标,将会得到如图 8.5 所示的程序运行结果。 如果不希望将应用程序安装到 Qtopia 中,而又希望在虚拟缓冲区中显示图形应用程序, 可将显示结果输出到虚拟帧缓冲中,运行程序的时候,在程序名称后加上“-qws”即可。 $ ./hello –qws 可以得到和图 8.5 一样的运行结果。这种方法在调试阶段经常使用。 图 8.5 在 Qtopia 中运行 Hello 程序 从图 8.4 可以看到,目前的 Hello 程序图标是一个 Qt 通用图标,如果想制作个性化图 标的话,需要使用专门的工具。在 qt-x11-free-3.3.3 有一个叫 qembed 的工具,可以将 /pics/inline 下所有的图形文件转换成一个 C 语言的头文件,此头文件包含了该目录 下的图形文件的 RGB 信息。如果需要制作个性化图标,请将 32×32 的 PNG 图片放在 /pics/inline 目录下,然后进行转换。 qembed –images $QPEDIR/pics/liline/*.* > $QPEDIR/src/libraries/qtopia/inlinepics_p.h 8.6 建立交叉编译的 Qt/Embedded 开发环境 8.6.1 安装开发环境 注意:在安装交叉编译的 Qt/Embedded 开发环境之前,必须安装交叉编译器,参考 4.2 小节。 交叉编译的 Qt/Embedded 开发环境,须建立在和基于 PC 的 Qt/Embedded 开发环境不同 目录下,安装过程类似,只要在配置编译器的时候选择 ARM 的交叉编译器即可。 - 345 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 说明:由于各 Linux 发行版自带的 Qt/X11 不同,所以在安装编译过程中, 可能会出现某些软件包的依赖关系的问题。一般在默认安装的情况下,我们还 还需要安装 e2fsprogs-devel 和 libjpeg-devel 两个包。因为我们需要 e2fsprogs-devel 包里的 uuid 和 libjpeg-deve 包里的 jpeg 的头文件。 光盘提供的 cross_2.95.3-zhiyuan.tar.bz2 已经包含了这些必要文件,如果在 安装交叉编译器的时候使用光盘提供的 cross_2.95.3-zhiyuan.tar.bz2,则不用另外 安装。 在/zylinux 目录下为此建立工作目录 arm-qtopia,将下载的软件包 tmake1.11.tar.gz、 qt-embedded-2.3.7.tar.gz、qt-x11-2.3.2.tar.gz 和 qtopia-free-1.7.0.tar.gz 复制到该目录下,并进 入该目录。 将光盘 arm-qtopia 目录下的 build 文件复制到当前目录下,为其增加可执行权限并执行, 即完成交叉编译环境的建立。 $ ./build 同样,为了使用各软件包的兼容版本,build 文件对各软件包解压后的文件夹进行了改 名操作,使用脚本文件 build 建立的 Qt/Embedded&Qtopia 交叉开发环境工作路径和各软件 包的安装路径如下。 交叉环境 Qt/Embedded&Qtopia 的安装路径:/zylinux/arm-qtopia tmake 软件安装路径: /zylinux/arm-qtopia/tmake Qtopia 的安装路径: /zylinux/arm-qtopia/qtopia Qt/Embedded 的安装路径: /zylinux/arm-qtopia/qt Qt/X11 的安装路径: /zylinux/arm-qtopia/qt-x11 8.6.2 在 ARM 中运行 Hello 程序 在编译/运行程序之前,请先设置环境变量。 (1)设置环境变量 将光盘 arm-qtopia 目录下的 set-env 文件复制到/zylinux/arm-qtopia 目录下,并进入该目 录,增加可执行权限后运行,设置 Qt 编译所需的环境变量。 $ source set-env 或者 . set-env set-env 是一个脚本文件,用于设定交叉编译 Qt/Embedded&Qtopia 应用程序的环境变量, 其内容如下。 export QTDIR=$PWD/qt export QPEDIR=$PWD/qtopia export TMAKEDIR=$PWD/tmake export TMAKEPATH=$TMAKEDIR/lib/qws/linux-arm-g++ export PATH=$QTDIR/bin:$QPEDIR/bin:$TMAKEDIR/bin:$PATH (2)编译 Hello 程序 将光盘 arm-qtopia 目录下的 Hello 程序复制到/zylinux/arm-qtopia 目录下。 进入/zylinux/arm-qtopia/hello 目录,执行 make 命令,编译程序。hello 程序将生成在 - 346 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com /zylinux/arm-qtopia/bin 目录下。 $ make (3)安装和运行程序 Qtopia 安装在文件系统的 opt 目录下。 将生成的 hello 程序复制到 MagicARM2410 Linux 文件系统的 Qtopia 安装目录的 bin 目 录,并将 hello 程序的配置文件 hello.desktop 复制到 Qtopia 安装目录的 apps/Applications 目 录下。重新制作文件系统并更新,然后重新启动 MagicARM2410 系统,在 Qtopia 界面即可 看到添加的 Hello 程序,点击 Hello 图标将会出现与图 8.5 一样的运行结果。 - 347 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 第9章 Qt/Embedded 编程实战 Qt 编程,可参考 Qt 自带的帮助文档,亦可参考网络资源。Qt 编程可使用的网络资源有 Qt 官方网站:http://www.trolltech.com Qt 在线文档:http://doc.trolltech.com Qt 中文网论坛:http://www.qtcn.org Qt 非官方中文翻译:http://www.qiliang.net/qt/index.html 国外 Qt 论坛:http://www.qtforum.org 9.1 Hello 程序 1. 实验目的 (1) 掌握 Qt/e 编程的基本框架; (2) 掌握 Qt/e 程序编写和调试的基本方法。 (3) 掌握 Qt/e 标签的使用。 2. 实验设备 硬件: 软件: PC 机 MagicARM2410 教学实验开发平台 RedHat Linux 9.0 操作系统 Windows 98/2000/XP 操作系统(可选) 嵌入式 Linux 开发环境(含 Qt/e 和 Qtopia) 一台 一套 3. 实验内容 创建和显示一个简单的窗口,使用标签显示字符串“Hello, Qt!”,在 PC 机上调试通过后 交叉编译下载至 MagicARM2410 上运行。 4. 实验预习要求 (1) 熟悉基于 PC 的 Qt 和 Qtopia 模拟环境; (2) 预习 C++程序编写方法; (3) 预习 Qt 的帮助手册,了解 Qt 编程的大致方法。 (4) 熟悉更新文件系统的基本方法。 5. 实验原理 标签是设计图形界面不可或缺的基本组件,利用标签我们可以显示各种信息。Qt 为标 签提供了一系列 API 函数,通过调用这些函数,可以很容易设计各种标签。调用 Qt 中标签 的 API 函数,必须包含标签的头文件 qlabel.h。 如果需要显示的字符串信息很长,建议不要使用 QLabel,改用其它部件如 MultiLineedit (多行编辑区)。 6. 实验步骤 (1) 进入/zylinux/x86-qtopia 目录,运行 set-env 脚本,为本实验设置环境变量,然后创建 文件夹 hello。 $ cd /zylinux/x86-qtopia - 348 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com $ . set-env $ mkdir hello (2) 进入 hello 目录,新建文件 hello.cpp,并编写如程序清单 9.1 所示的程序,然后用 progen 工具生成工程文件 hello.pro。 $ cd hello $ vi hello.cpp $ progen –t app.t –o hello.pro (3) 使用 tmake 工具,生成 hello 工程的 Makefile 文件。 $ tmake -o Makefile hello.pro (4) 修改 Makefile 文件,在 LIBS 变量中增加需要用到的库,然后输入 make 命令编译。 LIBS = $(SUBLIBS) -L$(QTDIR)/lib -lqte -lm -lstdc++ $ make (5) 启动虚拟控制台,运行 hello 程序,将会得到如图 9.1 所示的实验结果(主机须启 动帧缓冲,必须能够访问/dev/fb0)。 $ cd /zylinux/x86-qtopia $ . set-env $ cd hello $ ./hello –qws 或者在终端,启动虚拟缓冲区和 QPE,启动 Qtopia 的终端,输入./hello 运行程序,亦 可得到和图 9.1 一样的结果。 $ cd /zylinux/x86-qtopia $ . set-env $ cd hello $ qvfb& $ qpe 图 9.1 Hello 程序结果 如果要将 Hello 程序发布到 MagicARM2410 上运行,还需进行以下工作: (6) 进入/zylinux/arm-qtopia 目录,并将 hello 工程复制到当前目录下。 $ cd /zylinux/arm-qtopia $ cp –av /zylinux/x86-qtopia/hello . (7) 运行当前目录下的 set-env 文件,重新设置环境变量,进入 hello 目录,使用 tmake - 349 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 工具,重新生成 Makefile 文件。 $ . set-env $ cd hello $ tmake -o Makefile hello.pro (8) 按照步骤(4)的方法修改包含库,编译,得到可执行文件 hello,将 hello 文件添加到 文件系统中,更新文件系统。 (9) 插入 USB 鼠标和 USB 键盘,启动 MagicARM2410。启动 Qtopia 的终端,运行 hello 程序,亦将得到和图 9.1 一样的结果。 7. 实验参考程序 实验程序很简单,只有一个源文件,如程序清单 9.1 所示。程序创建一个主窗口,添加 一个标签,在标签上显示字符串“Hello, Qt!”。 程序清单 9.1 Hello 实验参考程序 #include #include //Qt 应用程序必须包含该文件 //使用标签所需头文件 int main(int argc, char **argv) { QApplication app(argc, argv); //创建一个名为 app 的 QApplication 对象 QLabel *label = new QLabel("Hello, Qt!", 0); //创建一个 QLabel 部件 label->setAlignment(Qt::AlignVCenter|Qt::AlignHCenter); //设置标签在水平/垂直方向位于中心位置 label->setGeometry(10, 10, 200, 80); //标签坐标(10,10)和大小(200×80) app.setMainWidget(label); //将 QLabel 对象插入到主窗口中 label->show(); //显示标签。创建的标签默认不可见。 int result = app.exec(); return result; } //进入循环,调用 exec()函数,处理来自系统和用户的事件 8. 思考 (1) 如果在 PC 中运行 hello 程序,出现某些库找不到,该如何处理? 提示:将所缺的库从/zylinux/x86-qtopia/qt/lib 目录下复制到主机系统/usr/lib 目录下即可。 (2) 在 ARM 上运行时如果也出现类似问题,又该如何解决? 提示:将所缺的库从/zylinux/arm-qtopia/qt/lib 目录下复制到目标系统/usr/lib 目录下即可。 (3)setGeometry(10, 10)在显示器的什么位置? 9.2 按钮 1. 实验目的 (1) 巩固 Qt/e 编程的基本方法; (2) 掌握 Qt/e 中按钮的基本使用方法。 - 350 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com (3) 掌握 Qt/e 中字体的基本设置方法。 2. 实验设备 硬件: 软件: PC 机 MagicARM2410 教学实验开发平台 RedHat Linux 9.0 操作系统 Windows 98/2000/XP 操作系统(可选) 嵌入式 Linux 开发环境(含 Qt/e 和 Qtopia) 一台 一套 3. 实验内容 创建一个窗口,添加一个按钮,并在按钮上显示字符串“Hello, Button!”。 4. 实验预习要求 (1) 熟悉基于 PC 的 Qt 和 Qtopia 模拟环境; (2) 预习 C++程序编写方法; (3) 预习 Qt 的帮助手册,了解 Qt 按钮和字体相关部分。 5. 实验原理 按钮是设计图形界面的基本组件,Qt 中为按钮提供了一系列的 API 函数,调用基本 API 函数,可以轻松进行设计。调用按钮的 API 函数,必须包含按钮的头文件 qbutton.h。 字体在图形界面设计中有着非常重要的作用,一个图形界面,字体搭配得当,可以增加 整个界面的美感,让人赏心悦目。Qt 中有很多字体可以选择,如果不想使用系统默认的字 体,编程人员可以自行指定,只需调用相关的 API 函数即可。使用字体相关的 API 函数, 必须包含头文件 qfont.h。 6. 实验步骤 (1) 进入/zylinux/x86-qtopia 目录,运行 set-env 脚本,设置环境变量,然后创建文件夹 button。 $ cd /zylinux/x86-qtopia $ . set-env $ mkdir button (2) 进入 button 目录,新建文件 button.cpp,并编写如程序清单 9.2 所示的程序,然后 用 progen 工具生成工程文件 button.pro。 $ cd button $ vi button.cpp $ progen –t app.t –o button.pro (3) 使用 tmake 工具生成 Makefile 文件,并按照 9.1 小节进行修改,编译程序,得到可 执行文件 button。 $ tmake –o Makefile button.pro $ make (4) 启动虚拟控制台,运行 button 程序,将会得到如图 9.2 所示的结果。 $ ./button -qws - 351 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 图 9.2 按钮实验结果 如果要在 QPE 或者 ARM 上运行 button 程序,请参考 9.1 小节进行操作。 7. 实验参考程序 实验程序和前一个实验程序差别不大,先创建一个窗口,然后添加一个按钮,在按钮上 显示字符串“Hello, Button!”,参考程序清单 9.2。 程序清单 9.2 按钮实验参考程序 #include #include #include //Qt 应用程序必须包含该头文件 //使用按钮所需头文件 //字体 int main(int argc, char **argv) { QApplication button(argc, argv); //创建一个名为 button 的 QApplication 对象 QPushButton hello("Hello, Button!", 0); hello.resize(150, 30); //创建一个名为 hello 的按钮 //设置按钮大小为 150×30 hello.setFont(QFont("Helvetica", 18, QFont::Bold)); //设置按钮的字体 button.setMainWidget(&hello); hello.show(); //将按钮作为主窗口部件 //显示按钮 int result = button.exec(); return result; } 8. 思考 单选按钮和多选按钮如何使用? //进入循环 9.3 Qt 信号和插槽 1. 实验目的 (1) 巩固 Qt/e 中按钮的基本使用方法。 (2) 掌握 Qt/e 中对象间通信的信号和插槽机制。 2. 实验设备 硬件: PC 机 MagicARM2410 教学实验开发平台 - 352 - 一台 一套 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 软件: RedHat Linux 9.0 操作系统 Windows 98/2000/XP 操作系统(可选) 嵌入式 Linux 开发环境(含 Qt/e 和 Qtopia) 3. 实验内容 创建一个窗口,添加一个按钮,并在按钮上显示“Quit”,点击按钮,程序退出。 4. 实验预习要求 (1) 熟悉基于 PC 的 Qt 和 Qtopia 模拟环境; (2) 预习 C++程序编写方法; (3) 预习 Qt 的帮助手册,特别注意信号和插槽相关部分。 5. 实验原理 Signal 和 Slot 是 Qt 中一种用于对象间通信的调用机制,不同于传统的函数回调方式。 信号和插槽是 Qt 中非常有特色的地方,可以说是 Qt 编程区别于其它编程的标志。 信号和插槽不是标准 C++功能,需要特殊的语句才能创建信号和插槽,但是 C++编译 器不能理解这些语句。必须经过特殊的工具对象编辑器 MOC(Meta Object Compiler)将源代 码中创建信号和插槽的语句翻译成 C++编译器能够理解的代码。 6. 实验步骤 (1) 进入/zylinux/x86-qtopia 目录,运行 set-env 脚本,设置环境变量,然后创建文件夹 signalslot。 $ cd /zylinux/x86-qtopia $ mkdir signalslot (2) 进入 signalslot 目录,建立文件 signalslot.cpp,并编写如程序清单 9.3 所示的程序, 然后用 progen 命令生成工程文件 signalslot.pro。 $ cd signalslot $ vi signalslot.cpp $ progen –t app.t –o signalslot.pro (3) 使用 tmake 工具,生成 signalslot 工程的 Makefile 文件,并按照 9.1 小节进行修改, 然后编译,得到可执行文件 signalslot。 $ tmake –o Makefile signalslot.pro (4) 启动虚拟控制台,运行 signalslot 程序,将会得到如图 9.3 所示的结果,点击“Quit” 按钮,程序将退出。 $ ./signalslot -qws 图 9.3 信号和插槽实验结果 - 353 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 7. 实验参考程序 程序创建一个按钮,设置大小和字体,然后将按钮的 clicked()信号和对象的 qiut()槽连 接起来。具体实现参考程序清单 9.3。 程序清单 9.3 信号和插槽实验参考程序 #include #include #include //Qt 应用程序必须包含的头文件 //按钮 //字体 int main(int argc, char **argv) { QApplication app(argc, argv); //创建一个名为 app 的 QApplication 类对象 QPushButton quit("Quit", 0); //创建按钮“quit” quit.resize(100, 30); //设置按钮大小 quit.setFont(QFont("Times", 18, QFont::Bold)); //设置按钮的字体 //将按钮的 clicked()信号和 app 的 quit()槽连接起来,当按钮被按下,程序退出。 QObject::connect(&quit, SIGNAL(clicked()), &app, SLOT(quit())); app.setMainWidget(&quit); quit.show(); return app.exec(); } //将 app 对象添加到主程序中 //显示 quit 按钮 8. 思考 (1) 信号和插槽机制和普通的函数指针回调有何区别?使用信号和插槽有何利弊? (2) 如何断开信号和插槽的连接? (3) 可否将一个信号连接到多个插槽? (4) 信号和信号可以连接吗? 9.4 对话框 1. 实验目的 掌握 Qt/e 中对话框的基本使用方法。 巩固 Qt/e 中对象间通信的信号和插槽机制。 2. 实验设备 硬件: 软件: PC 机 MagicARM2410 教学实验开发平台 RedHat Linux 9.0 操作系统 Windows 98/2000/XP 操作系统(可选) 嵌入式 Linux 开发环境(含 Qt/e 和 Qtopia) 一台 一套 - 354 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 3. 实验内容 创建一个窗口,添加一个按钮,点击按钮,弹出一个对话框。 4. 实验预习要求 (1) 熟悉基于 PC 的 Qt 和 Qtopia 模拟环境; (2) 预习 C++程序编写方法; (3) 预习 Qt 的帮助手册,特别注意对话框以及信号和插槽相关部分。 5. 实验原理 一个友好的图形界面,一般都会有对话框,用于人机交互。Qt 中有很多类型的对话框, 如颜色对话框、字体对话框、文件对话框、输入对话框和消息对话框等。不同对话框都有一 系列的 API 函数,调用这些函数必须包含头文件 qdialog.h。 6. 实验步骤 (1) 进入/zylinux/x86-qtopia 目录,运行 set-env 脚本,设置环境变量,然后创建文件夹 dialog.。 $ cd /zylinux/x86-qtopia $ mkdir dialog (2) 进入 dialog 目录,建立文件 userdialog.h 和 userdialog.cpp,并编写如程序清单 9.4 和程序清单 9.5 所示的程序,然后用 progen 工具生成工程文件 userdialog.pro。 $ cd dialog $ vi userdialog.h $ vi userdialog.cpp $ progen –t app.t –o userdialog.pro (3) 使用 tmake 工具生成 userdialog 工程的 Makefile 文件,并按照 9.1 小节进行修改, 编译生成可执行文件 userdialog。 $ tmake –o Makefile userdialog.pro $ make (4) 启动虚拟控制台,运行 userdialog 程序,点击 POPUP 按钮,将会弹出一个新的对 话框,如图 9.4 所示,点击对话框的 POPDOWN 按钮,新对话框将关闭。 $ ./userdialog -qws - 355 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 图 9.4 对话框实验结果 7. 实验参考程序 userdialog.h 定义了一个继承 QWidget 类的 usrDialog 对象,如程序清单 9.4 所示。 程序清单 9.4 对话框实验-userdialog.h 文件内容 #ifndef _USERDIALOG_H_ #define _USERDIALOG_H_ #include #include #include //Qt 应用程序必须包含的头文件 //对话框 //按钮 class userDialog:public QWidget { Q_OBJECT public: userDialog(QWidget *parent = 0, const char *name = 0); private slots: void popupDialog(); }; #endif userdialog.cpp,程序如程序清单 9.5 所示。 程序清单 9.5 对话框实验-userdialog.cpp 文件内容 #include "userdialog.h" userDialog::userDialog(QWidget *parent, const char *name):QWidget(parent, name) { QPushButton *btn = new QPushButton("POPUP", this); //创建 POPUP 按钮 - 356 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com btn->setGeometry(50, 20, 100, 40); //设置按钮位置和大小 //将 btn 的 clicked()信号和 popoDialog()槽连接 connect(btn, SIGNAL(clicked()), this, SLOT(popupDialog())); } void userDialog::popupDialog() { QDialog *dlg = new QDialog(0, "popup", FALSE); dlg->setCaption("A QDialog Window"); //创建对话框 //设置对话框标题 QPushButton *btn = new QPushButton("POPDOWN", dlg); btn->setGeometry(50, 20, 100, 40); connect(btn, SIGNAL(clicked()), dlg, SLOT(accept())); //创建 POPDOWN 按钮 //设置按钮的位置和大小 //将 btn 的 clicked()信号和 accept()槽连接 dlg->show(); } int main(int argc, char **argv) { QApplication app(argc, argv); userDialog udlg; udlg.show(); app.setMainWidget(&udlg); //创建一个名为 app 的 QApplication 对象 //创建对话框 //显示对话框 //添加到主程序中 return(app.exec()); } 8. 思考 实验没有用到的其它对话框如何使用?请用程序实现。 9.5 Qt 布局 1. 实验目的 掌握 Qt/e 中布局的应用。 2. 实验设备 硬件: 软件: PC 机 MagicARM2410 教学实验开发平台 RedHat Linux 9.0 操作系统 Windows 98/2000/XP 操作系统(可选) 嵌入式 Linux 开发环境(含 Qt/e 和 Qtopia) 3. 实验内容 设计 4 个按钮和一个标签,按一定规则进行布局。 一台 一套 - 357 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 4. 实验预习要求 (1) 熟悉基于 PC 的 Qt 和 Qtopia 模拟环境; (2) 预习 C++程序编写方法; (3) 预习 Qt 的帮助手册,特别注意 Qt 布局相关部分。 5. 实验原理 一个用户图形界面,布局也是至关重要,合理的布局能增加界面的美感,亦能够提高软 件的易用性。图形界面编程,一般包括基本组件、组件的布局以及组件的回调。Qt 中有很 多种布局,最基本的就是 QLayout(包括 QBoxLayout:QHBoxLayout,QVBoxLayout)和 QGridLayout。使用了布局相关 API 函数的应用程序,需要包含头文件 qlayout.h。 6. 实验步骤 (1) 进入/zylinux/x86-qtopia 目录,运行 set-env 脚本,设置环境变量,然后创建文件夹 layout。 $ cd /zylinux/x86-qtopia $ . set-env $ mkdir layout (2) 进入 layout 目录,建立文件 layout.cpp,并编写如程序清单 9.6 所示的程序,然后 用 progen 工具生成工程文件 layout.pro。 $ cd layout $ vi layout.cpp $ progen –t app.t –o layout.pro (3) 使用 tmake 工具,生成 layout 工程的 Makefile 文件,并按照 9.1 小节进行修改,编 译,得到可执行文件 layout。 $ tmake –o Makefile layout.pro (4) 启动虚拟控制台,运行 layout 程序,将会得到如图 9.5 所示的结果。 $ ./layout -qws 图 9.5 Qt 布局实验结果 7. 实验参考程序 程序创建 4 个按钮和一个标签,同时使用垂直容器和水平容器进行布局。4 个标签放置 在水平容器中,标签放置在垂直容器中。实验参考程序如程序清单 9.6 所示。 程序清单 9.6 Qt 布局实验参考程序 #include //Qt 应用程序必须包含的头文件 - 358 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com #include #include #include //标签 //按钮 //布局 class DemoWidget:public QWidget { public: DemoWidget( QWidget *parent=0, const char *name=0); }; DemoWidget::DemoWidget( QWidget *parent, const char *name):QWidget(parent, name) { setCaption("QT_LAYOUT_DEMO"); //设置标题 QBoxLayout *demoLayout = new QVBoxLayout (this, 5); //垂直布局容器 QBoxLayout *buttons = new QHBoxLayout(demoLayout); //水平布局容器 //创建 4 个按钮 int i; for (i=1; i<=4; i++) { QPushButton *btn = new QPushButton(this); QString s; s.sprintf( "Button %d", i ); btn->setText(s); //添加到水平容器中 buttons->addWidget( btn, 10 ); } //创建标签,添加到垂直容器中 QLabel *lbl = new QLabel(this); lbl->setText("This is a Label"); lbl->setFrameStyle( QFrame::Panel | QFrame::Sunken ); lbl->setFixedHeight( lbl->sizeHint().height() ); lbl->setAlignment( AlignVCenter | AlignLeft); demoLayout->addWidget(lbl); //添加标签 demoLayout->activate(); //激活布局 } int main(int argc, char **argv) { QApplication app(argc, argv); - 359 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com DemoWidget demo; app.setMainWidget(&demo); demo.show(); return app.exec(); } 8. 思考 QLayout 和 QGridLayout 有何区别?该如何使用? 9.6 进度条 1. 实验目的 (1) 掌握 Qt/e 中进度条的基本设计方法。 (2) 巩固 Qt/e 中布局的应用。 (3) 进一步巩固 Qt/e 中信号和插槽的使用。 2. 实验设备 硬件: 软件: PC 机 MagicARM2410 教学实验开发平台 RedHat Linux 9.0 操作系统 Windows 98/2000/XP 操作系统(可选) 嵌入式 Linux 开发环境(含 Qt/e 和 Qtopia) 3. 实验内容 制作一个进度条,可以暂停、继续和重置等操作。 一台 一套 4. 实验预习要求 (1) 熟悉基于 PC 的 Qt 和 Qtopia 模拟环境; (2) 预习 C++程序编写方法; (3) 预习 Qt 的帮助手册,特别注意进度条以及信号和插槽相关部分。 5. 实验原理 进度条在图形界面中也是非常重要,如果一个应用程序执行需要的时间很长,那么,用 进度条来指示程序运行的进度是非常人性的做法,如软件安装通常都有进度条,复制、移动 等操作也有进度条。 进度条通常都是水平的,按百分比显示进度。使用进度条的应用程序需要包含头文件 qprogressbar.h。 6. 实验步骤 (1) 进入/zylinux/x86-qtopia 目录,运行 set-env 脚本,设置环境变量,然后建立文件夹 progressbar。 $ cd /zylinux/x86-qtopia $ . set-env - 360 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com $ mkdir progressbar (2) 进入 progressbar 目录,建立文件 progressbar.h 和 progressbar.cpp 文件,建立如程序 清单 9.8 和程序清单 9.9 所示的程序,然后用 progen 工具生成工程文件 progressbar.pro。 $ cd progressbar $ vi progressbar.h $ vi progressbar.cpp $ progen –t app.t –o progressbar.pro (3) 使用 tmake 工具生成 progressbar 工程的 Makefile 文件,并按照 9.1 小节进行修改, 然后编译,生成可执行文件 progressbar。 $ tmake –o Makefile progressbar.pro (4) 启动虚拟控制台,运行 progressbar 程序,将会得到如图 9.6 所示的结果,点击按钮 可以对进度条进行控制。 $ ./progressbar -qws 图 9.6 进度条实验结果 7. 实验参考程序 progressbar.h 文件包含了该工程所需的头文件,同时声明了实验程序所使用的类。程序 如程序清单 9.7 所示。 程序清单 9.7 进度条实验-progressbar.h 文件内容 #ifndef _PROGRESSBARDEMO_H_ #define _PROGRESSBARDEMO_H_ #include #include #include #include #include //Qt 应用程序必须包含的头文件 //按钮 //进度条 //布局 //定时器 class QPushButton; class QProgressBar; class ProgressBarDemo: public QWidget { Q_OBJECT - 361 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com public: ProgressBarDemo( QWidget *parent=0, const char *name=0); protected slots: void slotStart(); void slotReset(); void slotTimeout(); protected: QPushButton *start, *pause, *reset; QProgressBar *progressbar; QTimer *timer; }; #endif 实验使用 Qt 定时器 QTimer 来控制进度条,通过按钮控制进度条的启动、暂停等操作。 progressbar.cpp 文件内容如程序清单 9.8 所示。 程序清单 9.8 进度条实验-progressbar.cpp 文件内容 #include "progressbar.h" ProgressBarDemo::ProgressBarDemo( QWidget *parent, const char *name ):QWidget( parent, name ) { //建立布局 QVBoxLayout *vbox = new QVBoxLayout(this); QHBoxLayout *hbox = new QHBoxLayout(vbox); //创建 2 个按钮 start = new QPushButton( "&Start", this ); hbox->addWidget(start); reset = new QPushButton( "&Reset", this ); hbox->addWidget(reset); vbox->addStretch(0); //创建进度条 progressbar = new QProgressBar( 100, this ); progressbar->setCenterIndicator(TRUE); vbox->addWidget(progressbar); connect( start, SIGNAL( clicked() ), this, SLOT( slotStart() ) ); connect( reset, SIGNAL( clicked() ), this, SLOT( slotReset() ) ); //建立定时器 timer = new QTimer(this); connect( timer, SIGNAL( timeout() ), this, SLOT( slotTimeout() ) ); - 362 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com start->setFixedWidth(80); reset->setFixedWidth(80); } void ProgressBarDemo::slotStart() { //进度条步长为 1000 progressbar->setTotalSteps(1000); if(!timer->isActive()) { //进度条没有激活 timer->start(1); start->setText( "&Pause" ); }else{ timer->stop(); start->setText( "&Countinue" ); } } void ProgressBarDemo::slotReset() { timer->stop(); start->setText( "&Start" ); start->setEnabled( TRUE ) ; progressbar->reset(); } void ProgressBarDemo::slotTimeout() { int p = progressbar->progress(); if( p == progressbar->totalSteps() ) { start->setText( "&Start" ); start->setEnabled( FALSE ); return; } progressbar->setProgress( ++p ); } int main(int argc, char **argv) { QApplication app(argc, argv); //声明对象 - 363 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com app.setFont( QFont("Times", 16, QFont::Normal) ); //设置字体 ProgressBarDemo progressbardemo; progressbardemo.resize(320, 80); progressbardemo.setCaption( "ProgressBar DEMO" ); //创建类 //设置大小 //设置标题 app.setMainWidget(&progressbardemo); progressbardemo.show(); //添加到主程序 //显示 return app.exec(); } 8. 思考 进度条有哪些属性,具体该如何使用? 9.7 文本输入 1. 实验目的 掌握 Qt/e 中的文本输入方法。 巩固 Qt/e 中布局的应用。 2. 实验设备 硬件: 软件: PC 机 MagicARM2410 教学实验开发平台 RedHat Linux 9.0 操作系统 Windows 98/2000/XP 操作系统(可选) 嵌入式 Linux 开发环境(含 Qt/e 和 Qtopia) 3. 实验内容 以多种方式进行文本输入。 一台 一套 4. 实验预习要求 (1) 熟悉基于 PC 的 Qt 和 Qtopia 模拟环境; (2) 预习 C++程序编写方法; (3) 预习 Qt 的帮助手册,特别注意文本输入相关部分。 5. 实验原理 在很多应用中,都需要用户输入一些信息。在 Qt 中,有多种方式可用于信息编辑和输 入:单行输入的输入条和多行编辑区。输入条可以设置回显模式、只读等属性,多行编辑区 可以设置折行和只读等属性。使用输入条需要包含头文件 qlineedit.h,使用多行编辑区需要 包含头文件 qmultilineedit.h。 6. 实验步骤 (1) 进入/zylinux/x86-qtopia 目录,运行 set-env 脚本,设置环境变量,然后建立文件夹 - 364 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com textedit。 $ cd /zylinux/x86-qtopia $ . set-env $ mkdir textedit (2) 进入 textedit 目录,建立文件 edit.cpp,并编写如程序清单 9.9 所示的代码,然后使 用 progen 工具生成工程文件 edit.pro。 $ cd textedit $ vi edit.cpp $ progen –t app.t –o edit.pro (3) 使用 tmake 工具,生成 edit 工程的 Makefile 文件,并按照 9.1 小节进行修改,编译, 得到可执行文件 edit。 $ tmake –o Makefile edit.pro $ make (4) 启动虚拟控制台,运行 edit 程序,在得到界面即可进行文本输入,如图 9.7 所示。 $ ./edit -qws 图 9.7 文本输入实验结果 7. 实验参考程序 实验参考程序如程序清单 9.9 所示。 程序清单 9.9 文本输入实验参考程序 #include #include #include #include #include #include //Qt 应用程序必须包含的头文件 //窗体 //标签 //行编辑 //多行编辑 //布局 class EditDemo:public QWidget { public: EditDemo( QWidget *parent=0, const char *name=0); - 365 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com }; EditDemo::EditDemo( QWidget *parent, const char *name):QWidget(parent, name) { QGridLayout *grid = new QGridLayout(this, 3, 2, 2, 2); //普通输入模式 QLabel *label1 = new QLabel( "Normal Input Mode:", this); grid->addWidget( label1, 0, 0 ); QLineEdit *edit1 = new QLineEdit(this); grid->addWidget( edit1, 0, 1 ); //口令输入模式 QLabel *label2 = new QLabel( "PassWord Input Mode:", this); grid->addWidget( label2, 1, 0); QLineEdit *edit2 = new QLineEdit(this); edit2->setEchoMode( QLineEdit::Password ); grid->addWidget( edit2, 1, 1); //多行编辑模式 QLabel *label3 = new QLabel( "MultiLine Edit Mode:", this); grid->addWidget(label3, 2, 0); QMultiLineEdit *multiedit = new QMultiLineEdit(this); grid->addMultiCellWidget( multiedit, 2, 2, 1, 1 ); } int main(int argc, char **argv) { QApplication app(argc, argv); app.setFont( QFont("Times", 16, QFont::Normal)); EditDemo editdemo; editdemo.resize(320, 160); editdemo.setCaption( "Text Edit Demo" ); app.setMainWidget(&editdemo); editdemo.show(); return app.exec(); } 8. 思考 输入条和多行编辑区的其它属性如何使用?请编程。 - 366 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 9.8 菜单 1. 实验目的 (1) 掌握 Qt/e 中菜单的使用。 (2) 熟悉 Qt/e 中信号和插槽的应用; (3) 掌握 Qt/e 中字体的设置方法。 2. 实验设备 硬件: 软件: PC 机 MagicARM2410 教学实验开发平台 RedHat Linux 9.0 操作系统 Windows 98/2000/XP 操作系统(可选) 嵌入式 Linux 开发环境(含 Qt/e 和 Qtopia) 3. 实验内容 创建一个窗口,添加两个下拉菜单。 一台 一套 4. 实验预习要求 (1) 熟悉基于 PC 的 Qt 和 Qtopia 模拟环境; (2) 预习 C++程序编写方法; (3) 预习 Qt 的帮助手册,了解 Qt 菜单、字体、信号及插槽相关部分。 5. 实验原理 在图形界面中,菜单是再常用不过的部件了。菜单包括菜单条和弹出菜单(下拉菜单) 两种。菜单条通常位于窗口的上方,使用下拉菜单,用于存放不同分类的菜单,使用菜单条 需要包含头文件 qmenubar.h;弹出菜单里面包含了不同的菜单项,使用弹出菜单需要包含头 文件 qpopupmenu.h。 在菜单中,我们经常会使用快捷键,如常用的保存文件(Ctrl+S),在 Qt 中,也可以设 置快捷键,在相应字母之前用&标记即可进行标注。 6. 实验步骤 (1) 进入/zylinux/x86-qtopia 目录,运行 set-env 脚本,设置环境变量,然后创建文件夹 menu。 $ cd /zylinux/x86-qtopia $ . set-env $ mkdir menu (2) 进入 menu 目录,新建文件 menu.h 和 menu.cpp,并编写如程序清单 9.10 和程序清 单 9.11 所示的程序,然后用 progen 命令生成工程文件 menu.pro。 $ cd menu $ vi menu.h $ vi menu.cpp $ progen –t app.t –o menu.pro (3) 使用 tmake 工具生成 Makefile 文件,并按照 9.1 小节进行修改,编译程序,得到可 - 367 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 执行文件 menu。 $ tmake –o Makefile menu.pro $ make (4) 启动虚拟控制台,运行 menu 程序,将会得到如图 9.8 所示的结果。 $ ./menu –qws 图 9.8 菜单实验结果 7. 实验参考程序 本实验程序较前两个实验稍微复杂一些,为了程序结构清晰和维护方便,将实验程序分 2 个文件编写。 头文件 menu.h,定义了一个公共继承 QMainWindow 的类 MainWidget;该类有 6 个公 有插槽和一个 QLabel 类的私有成员,参考程序清单 9.10。 程序清单 9.10 菜单实验-menu.h 文件内容 #ifndef _MAINWIDGET_H_ #define _MAINWIDGET_H_ #include #include #include #include #include //Qt 应用程序必须的头文件 //QMainWindow 类 //弹出菜单 //菜单条 //标签 class MainWidget:public QMainWindow { Q_OBJECT public: MainWidget(QWidget *parent = 0, const char *name = 0); public slots: - 368 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com void newFile(); void openFile(); void saveFile(); void quitMain(); void helpFile(); void aboutMe(); private: QLabel *label; }; #endif menu.cpp 通过实现构造函数 MainWidget()完成菜单的制作和实现,参考程序清单 9.11。 在具体实现中,完成了对不同菜单的字体设置,以及插槽的应用,另外,还为菜单和菜单项 设置了快捷键。main()函数创建 MainWidget 类对象,设置位置和大小,并将 MainWidget 对 象插入到主窗口中。 程序清单 9.11 菜单实验-menu.cpp 文件内容 #include "menu.h" MainWidget::MainWidget(QWidget *parent, const char *name): QMainWindow(parent, name) { //设置标题和背景色 setCaption("Qt_MENU_Example"); setBackgroundColor(white); //创建 File 菜单 QPopupMenu *file = new QPopupMenu; QFont f1("Helvetica", 14, QFont::Bold); setFont(f1); file->setFont(f1); file->insertItem("&New", this, SLOT(newFile()), CTRL+Key_N); //添加 New 菜单项(CRTL+N) file->insertItem("&Open", this, SLOT(openFile()), CTRL+Key_O); //添加 Open 菜单项(CTRL+O) file->insertItem("&Save", this, SLOT(saveFile()), CTRL+Key_S); //添加 Save 菜单项(CTRL+S) file->insertItem("&Quit", this, SLOT(quitMain()), CTRL+Key_Q); //添加 Quit 菜单项(CTRL+Q) //创建 Help 菜单 QPopupMenu *help = new QPopupMenu; help->setFont(f1); help->insertItem("&Help", this, SLOT(helpFile()), CTRL+Key_H); //添加 Help 菜单项(CTRL+H) help->insertItem("About", this, SLOT(aboutMe())); //添加 About 菜单项 //在水平菜单栏添加 File 和 Help 菜单 QMenuBar *menu; menu = new QMenuBar(this); QFont f2("Helvetica", 18, QFont::Bold); - 369 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com setFont(f2); menu->setFont(f2); menu->insertItem("&File", file); menu->insertItem("&Help", help); //设置字体 //添加 File 菜单(CTRL+F) //添加 Help 菜单(CTRL+H) //创建标签 label = new QLabel("", this); label->setGeometry(60, 100, 250, 20); label->setBackgroundColor(white); label->setFont(f1); } //设置标签的位置和大小 //设置标签的背景色 //设置标签文字字体 //File->New 菜单项的操作 void MainWidget::newFile() { label->setText("Create a New File!"); } //File->Open 菜单项的操作 void MainWidget::openFile() { label->setText("File has been opened!"); } //File->Save 菜单项的操作 void MainWidget::saveFile() { label->setText("File has been saved!"); } //File->Quit 菜单项的操作 void MainWidget::quitMain() { QApplication::exit(); } //Help->Help 菜单项的操作 void MainWidget::helpFile() { label->setText("Help Files, or press F1."); } //Help->About 菜单项的操作 void MainWidget::aboutMe() - 370 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com { label->setText("(C) GUANGZHOU ZHIYUAN"); } int main(int argc, char **argv) { QApplication app(argc, argv); //创建名为 app 的 QApplication 对象 MainWidget *mainwidget = new MainWidget(0); //创建 MainWidget 类对象 mainwidget->setGeometry(10, 30, 320, 240); //设置位置和大小 app.setMainWidget(mainwidget); //插入到主窗口中 mainwidget->show(); //显示 MainWidget 类对象 int result = app.exec(); return result; } 8. 思考 (1)阅读 Qt 帮助手册,仔细区分菜单条和弹出菜单的区别以及应用。 (2)如何设置菜单的快捷键? (3)菜单(项)的其它操作如删除、激活和禁止等该如何使用? (4)如何为菜单增加状态条? (5)如何在菜单栏(条)添加图标? 9.9 Qt 绘图 1. 实验目的 熟悉 Qt/e 中的绘图。 2. 实验设备 硬件: 软件: PC 机 MagicARM2410 教学实验开发平台 RedHat Linux 9.0 操作系统 Windows 98/2000/XP 操作系统(可选) 嵌入式 Linux 开发环境(含 Qt/e 和 Qtopia) 一台 一套 3. 实验内容 创建一个窗口,在窗口进行画图,如直线、矩形和椭圆等。 4. 实验预习要求 (1) 熟悉基于 PC 的 Qt 和 Qtopia 模拟环境; (2) 预习 C++程序编写方法; (3) 预习 Qt 的帮助手册,了解 Qt 画图相关部分。 - 371 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 5. 实验原理 在图形界面编程中,用户可能需要绘制一些有特殊意义的图形。Qt 中提供了 QPainter、 QPen 和 QBrush 等机制用于绘图,有非常灵活的 API 函数用于画图,如画点、画线、画矩 形、椭圆和扇形等,使用这些 API 函数需要包含头文件 qpainter.h 和 qbrush.h 等。 6. 实验步骤 (1) 进入/zylinux/x86-qtopia 目录,运行 set-env 脚本,设置环境变量,然后创建文件夹 draw。 $ cd /zylinux/x86-qtopia $ . set-env $ mkdir draw (2) 进入 draw 目录,建立文件 draw.cpp,并编写如程序清单 9.12 所示的程序,然后使 用 progen 工具生成工程文件 draw.pro。 $ cd draw $ vi draw.cpp $ progen –t app.t –o draw.pro (3) 使用 tmake 工具,生成 draw 工程的 Makefile 文件,并按照 9.1 小节进行修改,编 译,得到可执行文件 draw。 $ tmake –o Makefile draw.pro $ make (4) 启动虚拟控制台,运行 draw 程序,将会得到如图 9.9 所示的结果。 $ ./draw -qws 图 9.9 绘图实验结果 7. 实验参考程序 实验程序调用相应的绘图函数,绘制矩形、圆角矩形、椭圆、扇形和直线等基本图形, 程序如程序清单 9.12 所示。 - 372 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com #include #include #include #include 程序清单 9.12 绘图实验参考程序 //Qt 应用程序 //窗体 //绘图 //绘图(刷子) class DrawDemo:public QWidget { public: DrawDemo( QWidget *parent=0, const char *name=0 ); void paintEvent( QPaintEvent *); private: void drawPrimitives( QPainter *p); }; DrawDemo::DrawDemo( QWidget *parent, const char *name):QWidget(parent, name) { setBackgroundColor(white); } void DrawDemo::drawPrimitives(QPainter *p) { //设置画笔 QBrush b1( Qt::blue ); QBrush b2( Qt::green, Qt::Dense6Pattern ); QBrush b3( Qt::NoBrush ); QBrush b4( Qt::CrossPattern ); //绘矩形 p->setPen( Qt::red ); p->setBrush( b1 ); p->drawRect( 20, 20, 120, 90 ); //绘圆角矩形 p->setBrush( b2 ); p->drawRoundRect( 180, 20, 120, 90, 20, 20 ); //绘椭圆 p->setBrush( b3 ); p->drawEllipse( 20, 140, 120, 60 ); //绘扇形 p->setBrush( b4 ); p->drawPie( 180, 140, 120, 120, 45*16, 90*16 ); - 373 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com //绘直线 p->setBrush( b1 ); p->drawLine( 20, 220, 300, 220 ); } void DrawDemo::paintEvent( QPaintEvent *) { QPainter paint(this); drawPrimitives(&paint); } int main(int argc, char **argv) { QApplication app(argc, argv); DrawDemo drawdemo; drawdemo.resize( 320, 240 ); drawdemo.setCaption( "QT DRAW DEMO" ); app.setMainWidget(&drawdemo); drawdemo.show(); return app.exec(); } 8. 思考 (1)如果需要绘制 Qt 没有可直接使用的 API 函数的图形,该如何进行绘制? (2)示例中各绘制图形的各参数是什么意义? (3)怎样使用 Qt 绘图 API 绘制文本? 9.10 国际化 1. 实验目的 掌握 Qt/e 国际化编程方法。 2. 实验设备 硬件: 软件: PC 机 MagicARM2410 教学实验开发平台 RedHat Linux 9.0 操作系统 Windows 98/2000/XP 操作系统(可选) 嵌入式 Linux 开发环境(含 Qt/e 和 Qtopia) 一台 一套 - 374 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 3. 实验内容 采用国际化编程方法,对实验 9.8 加以改造。 4. 实验预习要求 (1) 熟悉基于 PC 的 Qt 和 Qtopia 模拟环境; (2) 预习 C++程序编写方法; (3) 预习 Qt 的帮助手册,了解 Qt 国际化编程相关部分。 5. 实验原理 国际化全称是 Internationalization,因为首字母 I 和尾字母 N 之间有 18 个字母,因而简 称 I18N。国际化可以让一个程序可以被使用不同语言的用户使用,国际化是 Qt 编程中非常 重要的一个环节。 Qt 的国际化,首先需要使用 QString 处理所有用户可见文本,使用 QOBject::tr()从 Qt 的.qm 信息文件中提取信息,在处理编码的时候,还需要用到 QTranslator 类。国际化需要 使用 Qt 的实用工具 findtr 和 msg2qm 等。 特别的,在 Qt 中也可以直接使用 QtextCodec 进行字符编码转换,这样可以直接在程序 中嵌入中文等,这非常有利于开发中文软件,但是这种方法并不符合国际化/本地化标准。 6. 实验步骤 (1) 进入/zylinux/x86-qtopia 目录,运行 set-env 脚本,设置环境变量,然后创建文件夹 i18n。 $ cd /zylinux/x86-qtopia $ mkdir i18n (2) 进入 i18n 目录,创建文件 menu_i18n.h 和 menu_i18n.cpp 文件,编写如程序清单 9.13 和程序清单 9.14 所示的程序,然后用 progen 工具生成工程文件 menu_i18n.pro。 $ cd i18n $ vi menu_i18n.h $ vi menu_i18n.cpp $ progen –t app.t –o menu_i18n.pro (3) 使用 tmake 工具生成 menu_i18n 工程的 Makefile 文件,并按照 9.1 小节进行修改, 编译,得到可执行文件 menu_i18n。 $ tmake –o Makefile menu_i18n.pro $ make (4) 启动虚拟控制台,运行 menu_i18n 程序,只能到英文菜单,如图 9.10 所示,若要 得到中文菜单,还需进行国际化/中文化工作。 $ ./menu_i18n –en - 375 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 图 9.10 国际化编程实验结果-英文菜单 (5) 使用 Qt 的 findtr 命令提取需要翻译信息,然后对需要翻译的信息进行翻译,翻译 后的文件如程序清单 9.15 所示。 $ findtr menu_i18n.cpp > menu_i18n.po $ cp menu_i18n.po menu_i18n_cn.po $ vi menu_i18n_vn.po (6) 使用 Qt 的 msg2qm 工具将翻译后的文件转换为 Qt 程序能够直接调用的.qm 文件。 $ msg2qm2 menu_i18n_cn.po menu_i18n_cn.qm (7) 再次运行程序,启动中文菜单,如图 9.11 所示。 $ ./menu_i18n -cn 图 9.11 国际化编程实验结果-中文菜单 7. 实验参考程序 menu_i18n.h 文件如程序清单 9.13 所示。 - 376 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 程序清单 9.13 国际化编程实验-menu_i18n.h 文件内容 #ifndef _MENU_I18N_H_ #define _MENU_I18N_H_ #include #include #include #include #include #include #include //Qt 应用程序必须包含的头文件 //主窗口 //弹出菜单 //菜单条 //标签 //装载翻译信息 //标准输入输出 class MainWidget:public QMainWindow { Q_OBJECT public: MainWidget(QWidget *parent = 0, const char *name = 0); public slots: void newFile(); void openFile(); void saveFile(); void quitMain(); void helpFile(); void aboutMe(); private: QLabel *label; }; #endif menu_i18n.cpp 文件如程序清单 9.14 所示,程序中,需要翻译的信息都使用 tr()进行处 理。 程序清单 9.14 国际化编程实验-menu_i18n.cpp 文件内容 #include "menu_i18n.h" MainWidget::MainWidget(QWidget *parent, const char *name): QMainWindow(parent, name) { setCaption( QObject::tr("Qt_MENU_Example") ); //需要翻译的信息 setBackgroundColor(white); QPopupMenu *file = new QPopupMenu; QFont f("Times", 16, QFont::Normal); setFont(f); file->setFont(f); - 377 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com file->insertItem( tr("&New"), this, SLOT(newFile()), CTRL+Key_N); file->insertItem( tr("&Open"), this, SLOT(openFile()), CTRL+Key_O); file->insertItem( tr("&Save"), this, SLOT(saveFile()), CTRL+Key_S); file->insertItem( tr("&Quit"), this, SLOT(quitMain()), CTRL+Key_Q); //需要翻译的信息 //需要翻译的信息 //需要翻译的信息 //需要翻译的信息 QPopupMenu *help = new QPopupMenu; help->setFont(f); help->insertItem( tr("&Help"), this, SLOT(helpFile()), CTRL+Key_H); help->insertItem( tr("About"), this, SLOT(aboutMe())); //需要翻译的信息 //需要翻译的信息 QMenuBar *menu; menu = new QMenuBar(this); menu->insertItem( tr("&File"), file); menu->insertItem( tr("&Help"), help); //需要翻译的信息 //需要翻译的信息 label = new QLabel("", this); label->setGeometry(60, 100, 250, 20); label->setBackgroundColor(white); } void MainWidget::newFile() { label->setText( tr("Create a New File!") ); } //需要翻译的信息 void MainWidget::openFile() { label->setText( tr("File has been opened!") ); } //需要翻译的信息 void MainWidget::saveFile() { label->setText( tr("File has been saved!") ); } //需要翻译的信息 void MainWidget::quitMain() { QApplication::exit(); } void MainWidget::helpFile() { label->setText( tr("Help Files, or press F1.") ); } //需要翻译的信息 - 378 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com void MainWidget::aboutMe() { label->setText( tr("(C) GUANGZHOU ZHIYUAN") ); } //需要翻译的信息 int main(int argc, char **argv) { QApplication app(argc, argv); if(argc<2) { cout << "Usage: ./menu_i18n -[cn/en]\n" <load("menu_i18n_cn.qm", "."); } //装载翻译信息 qApp->installTranslator(tran); //qApp 内置指针,总是指向 QApplication 对象 MainWidget *mainwidget = new MainWidget(0); mainwidget->setGeometry(10, 30, 320, 240); app.setMainWidget(mainwidget); mainwidget->show(); int result = app.exec(); return result; } 程序清单 9.15 国际化编程实验-翻译信息文件 # This is a Qt message file in .po format. Each msgid starts with # a scope. This scope should *NOT* be translated - eg. translating # from French to English, "Foo::Bar" would be translated to "Pub", # not "Foo::Pub". msgid "" msgstr "" "Project-Id-Version: PROJECT VERSION\n" "POT-Creation-Date: 2006-03-01 10 时 32 分 38 秒 CST\n" "PO-Revision-Date: YYYY-MM-DD\n" "Last-Translator: FULLNAME \n" - 379 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com "Content-Type: text/plain; charset=gb2312\n" #: menu_i18n.cpp:30 msgid "::&File" msgstr "文件(&F)" #: menu_i18n.cpp:31 msgid "::&Help" msgstr "帮助(&H)" #: menu_i18n.cpp:13 msgid "::&New" msgstr "新建(&N)" #: menu_i18n.cpp:14 msgid "::&Open" msgstr "打开(&O)" #: menu_i18n.cpp:16 msgid "::&Quit" msgstr "退出(&Q)" #: menu_i18n.cpp:15 msgid "::&Save" msgstr "保存(&S)" #: menu_i18n.cpp:67 msgid "::(C) GUANGZHOU ZHIYUAN" msgstr "(c)版权所有,广州致远电子" #: menu_i18n.cpp:22 msgid "::About" msgstr "关于" #: menu_i18n.cpp:42 msgid "::Create a New File!" msgstr "新建一个文件" #: menu_i18n.cpp:47 msgid "::File has been opened!" msgstr "文件已经打开" #: menu_i18n.cpp:52 msgid "::File has been saved!" - 380 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com msgstr "文件已经保存" #: menu_i18n.cpp:62 msgid "::Help Files, or press F1." msgstr "帮助文件,或者按 F1" #: menu_i18n.cpp:5 msgid "::Qt_MENU_Example" msgstr "Qt 菜单(国际化版)" 8. 思考 (1) 仔细阅读 Qt 帮助手册国际化相关部分,熟悉 Qt 国际化的各种方法,并实践。 (2) 如果仅仅编写中文应用程序,如何在程序中直接使用中文? 9.11 往 Qtopia 中安装应用程序 1. 实验目的 掌握往 Qtopia 中安装应用程序的方法。 2. 实验设备 硬件: 软件: PC 机 MagicARM2410 教学实验开发平台 RedHat Linux 9.0 操作系统 Windows 98/2000/XP 操作系统(可选) 嵌入式 Linux 开发环境(含 Qt/e 和 Qtopia) 一台 一套 3. 实验内容 选择以往任何一个能够成功运行的应用程序,安装到 Qtopia 中。 4. 实验预习要求 (1) 熟悉基于 PC 的 Qt 和 Qtopia 模拟环境; (2) 预习 Qtopia 的帮助手册,了解程序添加相关部分。 5. 实验原理 Qtopia 是基于 Qt 的一个桌面程序,往其中安装应用程序需要一个桌面文件,以及相应 的可执行文件。 6. 实验步骤 以上一个实验为例进行介绍。 (1) 进入/zylinux/x86-qtopia/i18n 目录,建立该程序的桌面文件 menu.desktop,并将该文 件复制到 Qtopia 安装目录的 apps/Applications 目录下。 $ cd /zylinux/x86-qtopia/i18n $ vi menu.desktop $ cp menu.desktop ../qtopia/apps/Applications - 381 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 桌面文件有固定的格式,可以参考 Qtopia 中原有的桌面文件。 [Desktop Entry] Comment=A Qtopia Demo Exec=menu_i18n -cn Icon=menu Type=Application Name=Menu (2) 将 menu_i18n 文件和翻译文件 menu_i18n_cn.qm 复制到/zylinux/x86-qtopia/qtopia/bin 目录下。 $ cp menu_i18n ../qtopia/bin $ cp menu_i18n_cn.qm ../qtopia/bin (3) 在虚拟帧缓冲中运行 Qtopia,在 Qtopia 中将会看到 Menu 图标,点击 Menu 图标, 程序将会运行,结果如图 9.12 所示。 $ cd /zylinux/x86-qtopia $ . set-env $ qvfb –width 640 –height 480& $ qpe 图 9.12 在 Qtopia 中运行 Menu 程序 9.12 Designer 设计器 Designer 是 Qt 提供的用于设计 Qt 程序界面的工具。使用 Designer 设计器可以很方便、 - 382 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 轻松的设计各种复杂的图形界面,也能够减少编程中可能出现的错误。Designer 设计器的使 用方法,不同版本都不太一样,请参考相应版本的帮助手册。本小节仅对 Designer 设计器 的基本使用方法进行介绍。 1. 建立工程文件 进入/zylinux/x86-qtopia 目录,运行 set-env 脚本,设置环境变量,然后为工程建立独立 的文件夹,如为 HelloWorld 程序新建工作文件夹 helloworld,并进入该目录,再使用 progen 工具生成工程文件 helloworld.pro。 $ cd /zylinux/x86-qtopia $ . set-env $ mkdir helloworld $ progen –t app.t –o helloworld.pro 这样建立的工程并不能直接使用,还需要为该工程添加头文件、源文件等信息,将在稍 后介绍。 2. 建立窗体 使用 Qt 的图形设计器 designer,设计将要建立的窗体图形。运行/zylinux/x86-qtopia/qt/bin 目录下的 designer 命令,启动 Qt 图形设计器 designer。 $ ./../qt/bin/designer 图 9.13 设置窗体属性 从文件菜单 File,选择新建菜单 New,在弹出的 New Form 对话框中选择窗体 Widget, 然后点击 OK 确定。 接下来需要为窗体设置属性:设置其大小为 240×320,当然也可设置为液晶大小;设 置其属性为 Hello, World,name 为 HelloWorld,如图 9.13 所示。设置完成后将其保存为 helloworld.ui,存放到新建的 helloworld 目录下。 - 383 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 3. 生成头文件和源文件 根据前面所生成的 helloworld.ui 文件,使用 uic 工具先生成 HelloWorld 工程的头文件, 然后再生成源文件。 $ uic –o helloworld.h helloworld.ui $ uic –o helloworld.cpp –impl helloworld.h helloworld.ui 源文件的具体实现代码根据具体应用而不同,需要用户自行实现,在光盘中提供了一个 例程。 4. 建立和编写主函数文件 Qt/Embedded 应用程序需要一个包含 main 入口的主函数文件,如 main.cpp,它是应用 程序执行的入口,但是这个文件不能自动生成,需要用户自行建立。 $ vi main.cpp 然后编写 main.cpp 的实现代码。 5. 编辑工程文件 建立工程时候得到的 helloworld.pro 并不完整,需要添加一些头文件和源文件信息,到 目前为止,所有源文件已经准备完毕,需要将头文件和源文件添加到工程中。编辑工程文件 进行编辑,以便得到一个完整的工程。完整的 HelloWorld 工程文件如下。 TEMPLATE = app CONFIG = qt warn_on release HEADERS = helloworld.h SOURCES = helloworld.cpp \ main.cpp INTERFACES = 6. 生成 Makefile 文件 Makefile 是工程的管理文件,编译器编译工程也是根据 Makefile 文件进行的。Makefile 文件可以自行编写,但很繁琐。在 Qt 下,使用 Qt 提供的 tmake 工具可以非常方便的生成 Makefile 文件。在生成 Makefile 文件之前,必须确保环境变量的路径是正确的,可使用 set-env 文件进行设置。 $ tmake –o Makefile helloworld.pro 我们将会得到一个 Makefile 文件,大部分情况下只需进行少量修改即可使用,如添加 一些特殊的包含库等信息。 7. 编译/运行程序 添加实现代码后,编译工程,得到可执行文件 helloworld,在虚拟帧缓冲中运行程序, 或者按照 9.11 小节的方法,将 helliworld 程序安装到 PC 的 Qtopia 中,然后在 Qtopia 界面中 点击相应图标,运行程序。 $ make $ ./helloworld –qws - 384 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 8. 发布程序到 ARM 在 PC 上调试通过后,经过交叉编译即可将 helloworld 程序发布到 MagicARM2410 中运 行。先将 HelloWorld 工程复制到/zylinux/arm-qtopia 目录下,为交叉编译设置环境变量后, 使用 tmake 工具重新生成使用 arm-linux-交叉编译器的 Makefile 文件,或者手工修改原来的 Makefile 文件,再次编译,得到可以在 ARM 上运行的 helloworld 文件。 $ cd /zylinux/arm-qtopia $ cp –av /zylinux/x86-qtopia/helloworld . $ . set-env $ cd helloworld $ tmake –o Makefile helloworld.pro $ make 然后将桌面文件和编译后得到的二进制文件添加到文件系统中,更新文件系统,然后在 MagicARM2410 中运行 HelloWorld 程序。 - 385 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 第10章 MiniGUI 图形界面实验 10.1 MiniGUI 移植实验 1. 实验目的 (1)了解 MiniGUI 的基本特点和 MiniGUI 源文件目录结构。 (2)掌握 MiniGUI 在 ARM 嵌入式 Linux 操作系统下的应用配置和交叉编译。 2. 实验设备 硬件:PC 机 一台 MagicARM2410 教学实验开发平台 一套 USB 鼠标 一个 USB 键盘 一个 软件:RedHat Linux 9.0 操作系统(安装有 Autoconf 和 Automake 工具) 嵌入式 Linux 开发环境 MiniGUI-STR(for Linux)软件 3. 实验内容 学习移植 MiniGUI-STR(for Linux)软件到 MagicARM2410 的基本方法,然后编写一个简 单的 MiniGUI 应用程序,在液晶屏上显示“Hello MiniGUI!”字符串。 4. 实验预习要求 (1)必须先做本书第 4 章、第 5 章的实验,在 RedHat Linux 9.0 操作系统上建立交叉 编译环境,掌握交叉编译和下载 Linux 应用程序到 MagicARM2410 上并运行。 (2)仔细阅读本书第 1 章的内容,了解 MagicARM2410 实验箱的硬件结构,注意彩色 液晶屏驱动电路。 (3)阅读参考文献[4]以及 MiniGUI 的文档<>、<>,了解 MiniGUI 的基本特点和应用配置选项,以及应用程序的编写。 5. 实验原理 (1) MiniGUI 简介 MiniGUI 项目的最初目标是为基于 Linux 的实时嵌入式操作系统提供一个轻量级的图形 用户界面支持系统,发展到今天,MiniGUI 已进入成熟和稳定阶段,并且所支持的操作系统 已不仅仅限于 Linux,它还可以在µCLinux、µC/OS-II、eCos、VxWorks 等系统上运行。 MiniGUI 为应用程序定义了一组轻量级的窗口和图形设备接口,利用这些接口,每个应 用程序可以建立多个主窗口,然后在这些主窗口中创建按钮、编辑框等控件。MiniGUI 还为 用户提供了丰富的图形功能,以显示各种格式的位图并在窗口中绘制复杂图形。 MiniGUI 和嵌入式操作系统的关系如图 10.1 所示,基于 MiniGUI 的应用程序一般通 过 ANSI C 库以及 MiniGUI 自身提供的 API 函数来实现自己的功能。 - 386 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 图 10.1 MiniGUI 和嵌入式操作系统的关系 MiniGUI 是由北京飞漫软件技术有限公司拥有版权并主持和维护的自由软件,相关信息 可以访问 www.minigui.com 网站。 (2) MiniGUI-STR 功能特性 MiniGUI-STR 版本具有以下功能特性: 支持 MiniGUI-Threads、MiniGUI-Lite 和 MiniGUI-Standalone 三种运行模式; 完整的窗口/消息 API 及基本的绘图 API; 两种 GAL 图形引擎:FrameBuffer 和 qvfb; 字符集的支持:ISO8859-1~ISO8859-16、GB2312 和 BIG5; RBF 及 VBF 字体的支持,在资源包中包含设备字体: rbf-fixed-rrncnn-8-16-ISO8859-1、rbf-fixed-rrncnn-16-16-GB2312.1980-0、 rbf-fixed-rrncnn-16-16-BIG5、vbf-Courier-rrncnn-10-15-ISO8859-1、 vbf-Helvetica-rrncnn-15-16-ISO8859-1、vbf-Times-rrncnn-13-15-ISO8859-1 支持 Windows BMP、GIF、JPEG 和 PNG 图像文件格式; 窗口支持 PC 3D、Flat 和 Phone 三种风格; 对键盘布局的支持; 对 GB2312 全拼输入法的支持; 基本控件包括: Static、Button、Simple edit box、Single-line edit box、Multiple-line edit box、 ListBox、ComboBox、ProgressBar、NewToolbar、MenuButton、TrackBar、 PropertySheet、ScrollView MiniGUI-STR 版本与 MiniGUI 增值版本相比,MiniGUI-STR 缺少以下特性:不支持 NEWGAL 图形引擎,不支持基于 NEWGAL 的高级 GDI 接口及高级 2 维图形接口,不支持 QPF、TrueType 等字体,不支持 MiniGUI 扩展库,不支持 PCX、TGA、PBM 等图像格式。 (3) MiniGUI-STR 软件包 MiniGUI-STR for Linux 版本一般有 4 个压缩包,文件名及说明如下: libminigui-str-1.6.2.tar.gz,MiniGUI-STR 函数库源代码。 minigui-res-str-1.6.tar.gz,MiniGUI-STR 所使用的资源文件,包括基本字体、图标 和位图等等。 mg-samples-str-1.6.2.tar.gz,MiniGUI-STR 应用示例程序。 - 387 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com mde-str-1.6.2.tar.gz,MiniGUI-STR 的演示程序包。 (4) MiniGUI 的运行模式 为了适合于不同的操作系统环境,MiniGUI v1.6.x 可以配置为三种运行模式,分别为 MiniGUI-Threads 模式、MiniGUI-Lite 模式和 MiniGUI-Standalone 模式。但无论采用哪种运 行模式,MiniGUI 为上层应用软件提供了最大程度上的一致性,只有少数几个涉及初始化 的接口在不同运行模式上有所不同。 MiniGUI-Threads 模式 多线程的应用模式,运行在 MiniGUI-Threads 上的程序可以在不同的线程中建立多个窗 口,但所有窗口在同一个进程或者地址空间中运行。这种运行模式非常适合于大多数传统意 义上的嵌入式操作系统,如µC/OS-II、eCOS 等等。当然,这种运行模式也适用于 Linux 和 µCLinux 操作系统。 MiniGUI-Threads 模式是 MiniGUI v1.6.x 默认配置的运行模式。 MiniGUI-Lite 模式 多进程的应用模式,运行在 MiniGUI-Lite 上的每一个程序是单独的进程,每一个进程 也可以建立多个窗口。MiniGUI-Lite 适合于具有完整 UNIX 特性的嵌入系统式操作系统,如 嵌入式 Linux。 使用 MiniGUI-Lite 模式时,需要有一个服务器进程(mginit),负责初始化一些输入设备, 并通过 UNIX Domain 套接字将输入设备的消息发送到前台的 MiniGUI-Lite 客户进程。 MiniGUI-Standalone 模式 独立进程的应用模式,此时 MiniGUI 程序以独立进程的方式运行,既不需要多线程的 支持,也不需要多进行的支持,这种运行模式适合于功能单一的应用场合。 MiniGUI-Standalone 模式的适应面最广,可以支持几乎所有的操作系统,甚至包括类似 DOS 这样的操作系统。 (5) MiniGUI 的使用 要在目标板的 Linux 操作系统上运行 MiniGUI 应用程序,首先要使用宿主机(即 PC 机) 对 MiniGUI 的源代码进行编译(交叉编译),生成 MiniGUI 静态链接库文件。然后,MiniGUI 应用程序也在宿主机上进行交叉编译,并且与 MiniGUI 静态链接库链接生成目标板可运行 的 FLAT 格式文件,交叉编译示意图如图 10.2 所示。最后,在目标板的 Linux 操作系统上 搭建 MiniGUI 运行环境,即安装 MiniGUI 的资源文件和运行时配置文件,再将 MiniGUI 应 用程序(FLAT 格式文件)下载和运行。 当然,由于不同目标机的图形显示设备和输入设备是不一致的,所以用户需要为 MiniGUI 编写相应的图形引擎和输入引擎(即驱动程序),再与 MiniGUI 的源代码一起交叉编 译生成 MiniGUI 静态链接库文件。如果目标机的 Linux 操作系统上已移植好 FrameBuffer 设 备,则 MiniGUI 可以直接使用 FrameBuffer 设备进行图形输出,不需要另外编写图形引擎。 MiniGUI 函 数 库 源代码 交叉编译 MiniGUI 应 用 程 序源代码 交叉编译 MiniGUI 静态库 目标文 件 链接 可用于目标板的 FLAT 格式文件 图 10.2 交叉编译 MiniGUI 应用程序示意图 - 388 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com (6) 在 PC 机上安装 MiniGUI 这里所说的“安装”,是将 MiniGUI 函数库源代码、资源文件(即 MiniGUI-STR 压缩包) 复制到 PC 机的 ReadHat Linux 操作系统的特定目录上,然后解压,以便于进行交叉编译。 MiniGUI 安装操作步骤说明如下: 启动 RedHat Linux 9.0 系统时,以 root 用户登录系统; 在/home 目录下新建一个文件夹,将名字改为 minigui,从产品配套光盘上把 MiniGUI-STR 的 libminigui-str-1.6.2.tar.gz、minigui-res-str-1.6.tar.gz 和 mg-samples-s tr-1.6.2.tar.gz 文件复制到此文件夹内。 解压 libminigui-str-1.6.2.tar.gz、minigui-res-str-1.6.tar.gz 和 mg-samples-str-1.6.2.tar.gz 文件,可以直接选中要解压的文件,单击鼠标右键,在弹出的浮动菜单中选择“解 压到这里…”,如图 10.3 所示,再按提示操作完成解压。 图 10.3 解压 MiniGUI-STR 压缩包 用户也可以在“终端”窗口使用以下命令完成解压,打开“终端”窗口操作如图 10.4 所示。说明,对于较长的文件名或目录名,可以使用“*”通配符指定。 #cd /home/minigui #tar zxf lib*.gz #tar zxf mini*.gz #tar zxf mg*.gz 说明,Linux 操作系统下的目录路径采用“/”分隔。 - 389 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 图 10.4 打开“终端” 说明:由于交叉编译 MiniGUI 时需要使用到 Autoconf 及 Automake 工具,倘若在安装 RedHat Linux 9.0 操作系统时没有选择 Autoconf 及 Automake 工具,可以使用系统的“添加/ 删除应用程序”来安装,操作如图 10.5、图 10.6 所示。 图 10.5 启动“添加/删除应用程序” 图 10.6 选择安装“开发工具” - 390 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com (7) MiniGUI 的 GAL 的移植 从 MiniGUI v0.3.xx 版本开始,MiniGUI 引入了图形抽象层和输入抽象层(Graphics and Input Abstract Layer,即 GAL 和 IAL)的概念,它定义了一组不依赖于任何特殊硬件的抽象 接口,所有顶层的图形操作和输入处理都建立在抽象接口之上。而用于实现这一抽象接口的 底层代码称为“图形引擎”和“输入引擎”,类似于操作系统中的驱动程序。 MagicARM2410 实验箱上的 Linux 系统包括有 FrameBuffer 驱动,MiniGUI 可以直接使 用 FrameBuffer 设备进行图形输出,因此不需要用户另外编写 GAL 图形引擎。在编译配置 MiniGUI 时,使能 galfbcon 选项,即可使用 FrameBuffer 接口(当然,运行时配置文件 MiniG UI.cfg 中要指定 gal_engine=fbcon)。 (8) MiniGUI 的 IAL 的移植 MagicARM2410 实验箱上的 Linux 系统包含有通用的鼠标、键盘驱动程序,MiniGUI 可以直接使用它们来接收用户的操作输入,因此不需要另外编写 IAL 图形引擎。在编译配 置 MiniGUI 时,使能 nativeial 选项,即可使用通用的鼠标、键盘驱动(当然,运行时配置文 件 MiniGUI.cfg 中要指定 ial_engine=console)。 (9) 交叉编译 MiniGUI 针对 MagicARM2410 实验箱,需要专门编写一个配置脚本 buildlib-magicarm2410,文件 请保存在 libminigui-str-1.6.2 目录下,文件内容如程序清单 10.1 所列。此文件可以在产品配 套光盘中获得,如果复制到 RedHat Linux 9.0 操作系统下后不能运行,请使用“chmod a+x buildlib-magicarm2410”命令来设置文件为可执行属性。 程序清单 10.1 buildlib-magicarm2410 配置脚本 #!/bin/sh rm config.cache config.status –f CC=arm-linux-gcc \ CFLAGS=-I/zylinux/kernel/include \ ./configure –prefix=/home/minigui_lib/ \ --build=I386-linux \ --host=arm-linux \ --target=arm-linux \ --with-osname=linux \ --with-style=pc3d \ --disable-shared \ --enable-cursor \ --disable-newgal \ --enable-nativegal \ --enable-galfbcon \ --enable-fblin16 \ --disable-textmode \ --enable-dummyial \ --enable-nativeial \ --disable-qvfbial \ - 391 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com --enable-micemoveable \ --disable-latin9support \ --disable-big5support \ --disable-savebitmap \ --disable-imegb2312 \ --disable-jpgsupport \ --disable-pngsupport \ --disable-aboutdlg \ --disable-savescreen 程序清单 10.1 中,CC 变量指定了使用 arm-linux-gcc 来编译源程序,CFLAGS 变量指 定了 PC 机中 Linux 内核头文件的目录路径,可以根据实际情况修改。其它主要编译配置选 项说明如下: --prefix=/home/minigui_lib/,指定安装目录为/home/minigui_lib(在执行 make install 命令时,编译生成的库文件将会安装到此目录下); --build=i386-linux,表示执行编译的环境为 i386 系统; --host=arm-linux,表示主机(编译器)类型为 arm-linx; --target=arm-linux,表示目标平台类型为 arm-linx; --with-osname=linux,指定 MiniGUI 所运行的操作系统为 Linux; --with-style=pc3d,指定 MiniGUI 控件的外观风格为 PC 的三维风格; --disable-shared,禁止编译生成共享库,只生成静态库,这样应用程序执行时只需 要一个可执行文件即可; 打开“终端”窗口,使用以下指令执行 MiniGUI-STR 的编译和库文件的安装。操作完 成后,在/home/minigui_lib 目录下会有 MiniGUI 的静态库文件,这样 MiniGUI 应用程序只 要 在 编 译 时 指 定 链 接 /home/minigui_lib 目 录 下 的 MiniGUI 库 文 件 , 即 可 生 成 在 MagicARM2410 实验箱上运行的 MiniGUI 程序文件(FLAT 格式文件)。 #cd /home/minigui/libminigui-str-1.6.2 # ./autogen.sh # ./buildlib-magicarm2410 #make clean #make #make install 6. 实验步骤 (1)按照实验原理说明,在 PC 机上安装好 MiniGUI-STR 所有源程序。 (2)按照实验原理说明,交叉编译 MiniGUI,安装 MiniGUI 静态库。 (3)在 mg-samples-str-1.6.2/src 目录下建立源文件 hello.c,编写一个在液晶屏上显示 “Hello MiniGUI!”字符串的 MiniGUI 应用程序。 说 明 : MiniGUI 的 应 用 程 序 的 编 写 可 以 参 考 文 档 <> 以 及 mg-samples-str-1.6.2/src 目录下的例子。 (4)在 mg-samples-str-1.6.2 目录下编写一个配置脚本 build-magic2410,内容如程序清 单 10.2 所列。在编译参数中,使用"-I/home/minigui_lib/include"指定 MiniGUI 头文件路径, 使用“-L/home/minigui_lib/lib”指定链接 MiniGUI 静态库。 说明:build-magic2410 文件可以在产品配套光盘中获得,如果复制到 RedHat Linux 9.0 - 392 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 操作系统下后不能运行,请使用“chmod a+x build-magic2410”命令来设置文件为可执 行属性。 程序清单 10.2 配置脚本 build-magic2410 #!/bin/sh rm config.cache config.status -f CC=arm-linux-gcc \ CFLAGS=-I/home/minigui_lib/include \ LDFLAGS=-L/home/minigui_lib/lib \ ./configure \ --build=i386-linux \ --target=arm-linux \ --host=arm-linux (5)修改 mg-samples-str-1.6.2/src 目录下的 Makefile.am 文件,设置编译 hello.c 文件, 如程序清单 10.3 所列(打红圈的为新添加的代码)。 程序清单 10.3 配置编译新增的 hello.c COMMON_PROGS=helloworld mycontrol dialogbox simplekey \ static button listbox edit combobox menubutton progressbar trackbar newtoolbar propsheet \ scrollbar painter capture bitblt stretchblt loadbmp drawicon \ createicon caretdemo cursordemo input bmpbkgnd hello …… noinst_PROGRAMS=$(COMMON_PROGS) $(LITE_PROGS) hello_SOURCES=hello.c …… (6)打开“终端”窗口,执行以下指令编译 MiniGUI 应用程序。编译通过后,在 mg-samples-str-1.6.2/src 目录下会生成 hello 文件(FLAT 格式文件)。 #cd /home/minigui/mg-samples-str-1.6.2 # ./build-magic2410 #make clean #make (7)打开“终端”窗口,执行以下指令安装资源文件。执行完以下指令后,在 /usr/local/lib/minigui 目录下会产生一个 res 目录,该目录下保存有 MiniGUI 的资源文件(如图 片、图标和字体等等)。 #cd /home/minigui/minigui-res-str-1.6 #make install (8)MiniGUI 运行时需要使用 MiniGUI.cfg(即 MiniGUI 运行时配置文件),主要配置使 用的图形引擎、输入引擎、窗口字体等等。修改/home/minigui_lib/etc 目录下 MiniGUI.cfg 文 件,使用“fbcon”图形引擎和“console”输入引擎,如程序清单 10.4 所列。 - 393 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com …… [system] # GAL engine gal_engine=fbcon 程序清单 10.4 修改运行时配置文件 # IAL engine ial_engine=console mdev=/dev/input/mouse0 mtype=IMPS2 [fbcon] defaultmode=640x480-16bpp …… (9)至此,MiniGUI 的资源文件、运行时配置文件和应用程序(FLAT 格式文件)都已经 产生了,接下来就要在目标板的 Linux 操作系统上建立 MiniGUI 运行环境。连接好 MagicARM2410 实验箱硬件(包括串口线、网线和 USB 键盘鼠标),将实验箱主板上的 JP1、 JP7 跳线短接,JP8 跳线断开。启动实验箱主板上的 Linux,然后使用 NFS 复制以下目录或 文件到实验箱主板的指定目录下(NFS 的操作可以参考第 5 章的介绍)。在 MagicARM2410 上需要建立相应的子目录,如/usr/local/lib/minigui/res/bmp、/usr/local/lib/minigui/res/font 和 /usr/pro 等等。 PC 机端 MagicARM2410 实验箱端 ------------------------------------------------------------------------------------------------------------- /home/minigui/mg-samples-str-1.6.2/src/hello ------> /usr/pro /usr/local/lib/minigui/res/* ------> /usr/local/lib/minigui/res /home/minigui_lib/etc/MiniGUI.cfg ------> /usr/local/etc (10)MiniGUI 不能在 Linux 的图形界面模式下运行,所以需要修改实验箱上 Linux 系 统的 usr/etc/rc 文件来禁止启动 QT,如下所示,修改完成后保存文件并重新启动系统。 …… # /usr/etc/qtopia & …… (11)在 PC 机端使用 minicom 软件操作实验箱(即操作实验箱主板上的 Linux 操作系统), 执行以下指令,即可运行 MiniGUI 程序,正确运行程序后在实验箱的液晶屏幕上应显示一 个“Hello MiniGUI!”的窗口。程序运行结果参考如图 10.7 所示。 /> cd /usr/pro /usr/pro> ./hello - 394 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 图 10.7 hello.c 运行结果参考图 说明:为了方便调试,可以将 PC 机上的 mg-samples-str-1.6.2 目录(通过 NFS)mount 到 实验箱 Linux 操作系统的目录下(如/mnt),然后直接在此目录下执行编译后的程序,不需要 进行复制操作。 (12)使用鼠标点击窗口中的“×”关闭窗口按钮,则 MiniGUI 窗口被关闭,程序运行 结束,此时液晶屏上没有任何东西显示。然后右击 MiniGUI 程序桌面,在浮动菜单中选中 “结束会话”来终止 MiniGUI。 说明:至此,MiniGUI 编译和实验箱主板上的运行环境已经搭建完成,以后编写的 MiniGUI 应用程序只需要按处理 hello.c 的方法操作即可。另外,这里介绍的编译 MiniGUI 应用程序方法是直接利用 mg-samples-str-1.6.2 现成的 Automake/Autoconf 脚本,如果用户已 经 熟 悉 Automake/Autoconf 脚 本 的 编 写 规 则 , 可 以 自 己 建 立 用 户 的 工 程 目 录 和 Automake/Autoconf 脚本,然后直接编译自己的工程文件。 7. 实验参考程序 MiniGUI 移植实验的参考代码见程序清单 10.5。 程序清单 10.5 MiniGUI 移植实验参考程序 /**************************************************************************** * 文件名:hello.c * 功能:MiniGUI 应用例子。 * 创建一个主窗口,并在窗口中显示字符串" Hello MiniGUI!"。 ****************************************************************************/ /* 包含 MiniGUI 头文件 */ #include #include #include #include #include /* 主窗口起始位置及大小 */ #define MWINDOW_LX 10 #define MWINDOW_TY 50 #define MWINDOW_RX 460 #define MWINDOW_BY 360 /* 窗口左边框的 x 值 */ /* 窗口上边框的 y 值 */ /* 窗口右边框的 x 值 */ /* 窗口下边框的 y 值 */ /* 主窗口需要显示的字符串 */ - 395 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com static char *hello_str = "Hello MiniGUI!"; HWND hMainWnd; // 主窗口句柄 /**************************************************************************** * 名称:WinProc() * 功能:主窗口过程函数。 * 处理 MSG_PAINT 消息,在窗口中显示 hello_str 字符串。 * 入口参数:hWnd 窗口句柄 * message 消息 * wParam 消息附加参数 1(对于不同的消息,有不同的用途) * lParam 消息附加参数 2(对于不同的消息,有不同的用途) * 出口参数:消息已处理则返回 0。 ****************************************************************************/ static int WinProc(HWND hWnd, int message, WPARAM wParam, LPARAM lParam) { HDC hdc; // 定义一个图形设备上下文对象,输出字符时需要。 RECT rc; // 定一个 RECT 对象(矩形) switch(message) { case MSG_PAINT: hdc = BeginPaint(hWnd); // 获得设备 hdc //TextOut(hdc, 10, 50, hello_str); // 可以使用 TextOut 函数在指定位置上显示字符串 GetClientRect(hWnd, &rc); // 取得窗口客户区矩形 DrawText(hdc, hello_str, -1, &rc, DT_LEFT); // 输出 hello_str 字符串 EndPaint(hWnd, hdc); // 释放设备 hdc break; case MSG_CLOSE: DestroyMainWindow(hWnd); // 销毁主窗口 PostQuitMessage(hWnd); // 发送 MSG_QUIT 消息,通知"消息循环"结束 break; default: return(DefaultMainWinProc(hWnd, message, wParam, lParam)); } return(0); } /**************************************************************************** * 名称:InitMainWindow() * 功能:建立主窗口。 * 入口参数:无 * 出口参数:建立成功返回 1,否则返回 0。 ****************************************************************************/ int InitMainWindow(void) { MAINWINCREATE window_info; - 396 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com window_info.dwStyle = WS_VISIBLE | WS_BORDER | WS_CAPTION; // 窗口风格设置 window_info.dwExStyle = WS_EX_NONE; // 不使用窗口扩展风格 window_info.spCaption = "MiniGUI"; // 窗口标题 window_info.hMenu = 0; // 无菜单 window_info.hCursor = GetSystemCursor(0); // 设置窗口光标 window_info.hIcon = 0; // 无窗口图标 window_info.MainWindowProc = WinProc; // 窗口过程函数 window_info.lx = MWINDOW_LX; // 窗口的位置及大小设置 window_info.ty = MWINDOW_TY; window_info.rx = MWINDOW_RX; window_info.by = MWINDOW_BY; window_info.iBkColor = COLOR_lightwhite; // 窗口背景色 window_info.dwAddData = 0; window_info.hHosting = HWND_DESKTOP; // 托管窗口句柄 hMainWnd = CreateMainWindow(&window_info); // 建立主窗口 if(hMainWnd == HWND_INVALID) return(0); else return(1); } /**************************************************************************** * 名称:MiniGUIMain() * 功能:MiniGUI 程序入口点。 * 入口参数:argc 参数个数 * argv 参数字符串指针 * 出口参数:返回 0。 ****************************************************************************/ int MiniGUIMain(int argc, const char *argv[]) { MSG Msg; #ifdef _LITE_VERSION SetDesktopRect(0,0, 800,600); #endif InitMainWindow(); // 建立主窗口 ShowWindow(hMainWnd, SW_SHOWNORMAL); // 显示主窗口 /* 消息循环 */ while(GetMessage(&Msg, hMainWnd)) { TranslateMessage(&Msg); DispatchMessage(&Msg); } MainWindowThreadCleanup(hMainWnd); return(0); } - 397 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com /* 定义桌面接口函数 */ #ifndef _LITE_VERSION #include #endif 8. 思考 如果要在目标板上运行 MiniGUI-STR,需要做哪些步骤,请简单描述。 10.2 对话框应用编程实验 1. 实验目的 (1)掌握 MiniGUI 的模态对话框应用编程。 (2)了解 MiniGUI 控件的基本应用方法。 2. 实验设备 硬件:PC 机 一台 MagicARM2410 教学实验开发平台 一套 USB 鼠标 一个 USB 键盘 一个 软件:RedHat Linux 9.0 操作系统(安装有 Autoconf 和 Automake 工具) 嵌入式 Linux 开发环境 MiniGUI-STR(for Linux)软件 3. 实验内容 使用 MiniGUI 创建一个模态对话框,要求包含“OK”、“CANCEL”两个按钮,并且在 对话框中显示“This is MiniGUI dlg!”(使用 MiniGUI 的“static”控件显示字符串)。 4. 实验预习要求 (1)必须先做本书第 10.1 章的实验,搭建好 MiniGUI 编译和实验箱主板上的运行环境, 掌握交叉编译和下载 Linux 应用程序到 MagicARM2410 上并运行。 (2)仔细阅读本书第 1 章的内容,了解 MagicARM2410 实验箱的硬件结构,注意彩色 液晶屏驱动电路。 (3)阅读参考文献[4]以及 MiniGUI 的文档<>,了解 MiniGUI 的 对话框编程方法。 5. 实验原理 在 MiniGUI 中,对话框是一类特殊的主窗口,这种窗口一般只关注与用户的交互(主要 是参数输入)。对话框可分为模态对话框和非模态对话框,模态对话框显示之后,用户就不 - 398 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 能再切换到其它主窗口进行工作,而非模态对话框就没有这样的限制。MiniGUI 使用了结构 DLGTEMPLATE 表示对话框模板,结构 CTRLDATA 表示控件模板(用于对话框的控件)。用 户需要使用这两个结构来定义对话框,而且定义的控件要挂接到对话框上。 模态对话框使用 InitDialogBox 函数启动(显示),然后在对话框的回调函数(即窗口过程 函数)实现对控件消息的处理,包含结束对话框(使用 EndDialog 函数)。 以下简要的说明模态对话框的建立过程,更详细的说明请参考 MiniGUI 的应用资料。 (1) 定义资源 ID 首先要定义对话框内的控件的 ID 值,ID 值应大于 100,且不要重复,如程序清单 10.6 所示。MiniGUI 在 windows.h 文件中也定义了一些标准控件的 ID,如 IDOK、IDCANCEL 和 IDABORT 等等,用户可以直接使用这些 ID。 程序清单 10.6 对话框内的控件 ID 值定义 #define IDC_DISP1 … 1001 (2) 定义对话框模板 使用 DLGTEMPLATE 来定义一个对话框对象,并设置对话框的风格、大小、标题以及 控件个数等等,如程序清单 10.7 所示。程序清单 10.7 中,图标和菜单变量设置为 0,表明 不使用图标和菜单;控件个数设置为 3,而控件对象的地址设置为 NULL,所以在调用 InitDialogBox 函数之前必须给它正确赋值。 程序清单 10.7 对话框定义示范 static DLGTEMPLATE DlgInitProgress = { WS_BORDER | WS_CAPTION, /* 风格 */ WS_EX_NONE, /* 扩展风格 */ 20, 50, 380, 260, /* 对话框起始坐标,宽度、高度 */ "Dlg demo", /* 对话框标题 */ 0, /* 图标 */ 0, /* 菜单 */ 3, /* 内含控件个数 */ NULL, /* 控件对象的地址 */ 0 /* 附加数据 */ }; (3) 定义对话框内的控件 控件是一个子窗口,每一类控件仅用于实现某些较为固定的功能,比如静态框(“static” 类控件)就用于文字显示输出,对话框常常使用控件来实现提示或设置等功能。 定义控件示范如程序清单 10.8 所示,使用了 MiniGUI 的“static” 类控件(静态框)和 “button”类控件(按钮)。 程序清单 10.8 对话框内的控件定义示范 static CTRLDATA CtrlInitData[] = { { "static", /* 控件类名 */ - 399 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com }, { }, … }; WS_VISIBLE | SS_SIMPLE, 100,60, 200, 20, IDC_DISP1, "This is MiniGUI dlg!", 0, WS_EX_NONE /* 控件风格 */ /* 控件的起始坐标,宽度、高度 */ /* 控件 ID */ /* 控件标题 */ /* 附加参数 */ /* 扩展风格 */ "button", WS_TABSTOP | WS_VISIBLE | BS_DEFPUSHBUTTON, 40,140, 70,25, IDOK, "OK", 0, WS_EX_NONE (4) 编写对话框过程函数 使用对话框时,用户需要编写相应的过程函数,主要处理的消息为 MSG_INITDIALOG 和 MSG_COMMAND 消息,处理 MSG_INITDIALOG 消息时要返回 1,即“return(1);”;而 MSG_COMMAND 消息要根据命令进行处理,结束对话框使用 EndDialog 函数,如程序清 单 10.9 所示。 程序清单 10.9 对话框过程函数示范 static int DialogBoxProc(HWND hdlg, int message, WPARAM wParam, LPARAM lParam) { switch(message) { case MSG_INITDIALOG: return(1); case MSG_COMMAND: switch(wParam) { case IDOK: case IDCANCEL: EndDialog(hdlg, wParam); DestroyAllControls(hdlg); break; } break; } return(DefaultDialogProc(hdlg, message, wParam, lParam)); } (5) 启动对话框 如前面所介绍,用户需要调用 InitDialogBox 函数启动对话框,调用此函数时需要一个 对话框对象(使用 DLGTEMPLATE 来定义的对话框对象),如程序清单 10.10 所示。 - 400 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 程序清单 10.10 启动对话框示范 DlgInitProgress.controls = CtrlInitData; /* 设置控件对象地址 */ /* 启动对话框"DlgInitProgress" */ DialogBoxIndirectParam(&DlgInitProgress, hWnd, DialogBoxProc, 0L); 6. 实验步骤 (1)在 PC 机的 mg-samples-str-1.6.2/src 目录下建立源文件 dlg.c,编写实验程序代码。 (2)修改 mg-samples-str-1.6.2/src 目录下的 Makefile.am 文件,设置编译 dlg.c 文件,如 程序清单 10.11 所列。 程序清单 10.11 配置编译新增的 dlg.c COMMON_PROGS=helloworld mycontrol dialogbox simplekey \ static button listbox edit combobox menubutton progressbar trackbar newtoolbar propsheet \ scrollbar painter capture bitblt stretchblt loadbmp drawicon \ createicon caretdemo cursordemo input bmpbkgnd dlg …… noinst_PROGRAMS=$(COMMON_PROGS) $(LITE_PROGS) dlg_SOURCES=dlg.c …… (3)打开“终端”窗口,执行以下指令编译 MiniGUI 应用程序。编译通过后,在 mg-samples-str-1.6.2/src 目录下会生成 dlg 文件(FLAT 格式文件)。 #cd /home/minigui/mg-samples-str-1.6.2 #make (4)连接好 MagicARM2410 实验箱硬件(包括串口线、网线和 USB 键盘鼠标),将实验 箱主板上的 JP1、JP7 跳线短接,JP8 跳线断开。启动实验箱主板上的 Linux,然后使用 NFS 复制 dlg 程序文件到实验箱主板的/usr/pro 目录下(具体操作可以参考第 5 章的介绍)。 (5)在 PC 机端使用 minicom 软件操作实验箱(即操作实验箱主板上的 Linux 操作系统), 执行以下指令,即可运行 MiniGUI 程序,正确运行 dlg 程序后在实验箱的液晶屏幕上应显示 一个对话框。程序运行结果参考如图 10.8 所示。 /> cd /usr/pro /usr/pro> ./dlg 图 10.8 dlg.c 运行结果参考图 (6)使用鼠标点击对话框的“OK”按钮或“CANCEL”按钮,对话框将会关闭,程序 - 401 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 运行结束,此时液晶屏上没有任何东西显示。当然,按下键盘上的 Enter 键,也可以确定当 前对话框。 7. 实验参考程序 对话框应用编程实验的参考程序见产品配套光盘。 8. 思考 (1)请描述 MiniGUI 对话框模板(数据结构)各成员变量的作用。 (2)如果要将实验参考程序的对话框标题改为 Hello,只需要一个“OK”按钮,应如 何修改? 10.3 简易编辑器实验 1. 实验目的 掌握 MiniGUI 字符消息的相关知识和基本应用。 2. 实验设备 硬件:PC 机 一台 MagicARM2410 教学实验开发平台 一套 USB 鼠标 一个 USB 键盘 一个 软件:RedHat Linux 9.0 操作系统(安装有 Autoconf 和 Automake 工具) 嵌入式 Linux 开发环境 MiniGUI-STR(for Linux)软件 3. 实验内容 使用 MiniGUI 创建主窗口,在窗口过程函数中处理字符消息,实现一个简易编辑器的 功能。 4. 实验预习要求 (1)必须先做本书第 10.1 章的实验,搭建好 MiniGUI 编译和实验箱主板上的运行环境, 掌握交叉编译和下载 Linux 应用程序到 MagicARM2410 上并运行。 (2)仔细阅读本书第 1 章的内容,了解 MagicARM2410 实验箱的硬件结构,注意彩色 液晶屏驱动电路。 (3)阅读参考文献[4]以及 MiniGUI 的文档<>,了解键盘输入和 字符消息的相关内容。 5. 实验原理 键盘是基本的输入设备之一,MiniGUI 程序通过处理窗口的键盘事件来接收按键输入, - 402 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 键盘事件有 MSG_KEYDOWN(键按下)、MSG_KEYUP(键释放)、MSG_SYSKEYDOWN(系 统击键消息,即 ALT 键)、MSG_SYSKEYUP(系统击键消息)等等。 一般窗口用户程序不直接处理键盘事件,而是处理 MSG_CHAR、MSG_SYSCHAR 事 件 , 即 字 符 消 息 。 字 符 消 息 是 由 消 息 循 环 代 码 中 的 TranslateMessage 函 数 产 生 , TranslateMessage 函数是将键盘消息 MSG_KEYDOWN、MSG_SYSKEYDOWN 转换成字符 消息的,同时也将按键扫描码转换成为相应的字符编码(字符消息中的 wParam 参数)。 对于字符消息的处理,用户只需要在窗口过程函数中添加相应的处理代码即可,更详细 的说明请参考 MiniGUI 的应用资料。字符消息处理示范代码如程序清单 10.12 所示。 程序清单 10.12 字符消息处理示范 case MSG_CHAR: if(wParam==127) { if(no>0) { no--; str_buf[no] = ' '; } } else { str_buf[no++] = wParam; str_buf[no] = '\0'; } /* 字符消息 */ /* 判断是否 Back Space 键,若是则删除前一个字符 */ /* 不是 Back Space 键,添加字符 */ /* 取得字符,并加入 str_buf 字符串 */ if( ((no%68) == 0) || (wParam == 0x0D ) ) { if(no>0) { y = y + char_h; no = 0; sprintf(str_buf, ""); } } /* 以 68 个字符为一行 */ /* 若有回车键,则换行 */ hdc = BeginPaint(hWnd); TextOut(hdc, 0, y, str_buf); /* 显示当前行字符 */ EndPaint(hWnd, hdc); SetCaretPos(hWnd, no * char_w, y); /* 设置插入符位置,即光标位置 */ break; 6. 实验步骤 (1)在 PC 机的 mg-samples-str-1.6.2/src 目录下建立源文件 sedit.c,编写实验程序代码。 (2)修改 mg-samples-str-1.6.2/src 目录下的 Makefile.am 文件,设置编译 sedit.c 文件, 如程序清单 10.11 所列。 - 403 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 程序清单 10.13 配置编译新增的 sedit.c COMMON_PROGS=helloworld mycontrol dialogbox simplekey \ static button listbox edit combobox menubutton progressbar trackbar newtoolbar propsheet \ scrollbar painter capture bitblt stretchblt loadbmp drawicon \ createicon caretdemo cursordemo input bmpbkgnd sedit …… noinst_PROGRAMS=$(COMMON_PROGS) $(LITE_PROGS) sedit_SOURCES=sedit.c …… (3)打开“终端”窗口,执行以下指令编译 MiniGUI 应用程序。编译通过后,在 mg-samples-str-1.6.2/src 目录下会生成 sedit 文件(FLAT 格式文件)。 #cd /home/minigui/mg-samples-str-1.6.2 #make (4)连接好 MagicARM2410 实验箱硬件(包括串口线、网线和 USB 键盘鼠标),将实验 箱主板上的 JP1、JP7 跳线短接,JP8 跳线断开。启动实验箱主板上的 Linux,然后使用 NFS 复制 sedit 程序文件到实验箱主板的/usr/pro 目录下(具体操作可以参考第 5 章的介绍)。 (5)在 PC 机端使用 minicom 软件操作实验箱(即操作实验箱主板上的 Linux 操作系统), 即可运行 MiniGUI 程序,正确运行 sedit 程序后在实验箱的液晶屏幕上将会显示一个简易编 辑窗口。程序运行结果参考如图 10.9 所示。 图 10.9 sedit.c 运行结果参考图 (6)使用 USB 键盘输入任意字符,简易编辑窗口上将会显示所输入的字符。 7. 实验参考程序 简易编辑器实验的参考程序见产品配套光盘。 8. 思考 请简单描述一下键盘消息和字符消息的差别? - 404 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 10.4 位图显示实验 1. 实验目的 了解 MiniGUI 位图操作的相关 API 函数,并能够使用它们来实现位图的显示。 2. 实验设备 硬件:PC 机 一台 MagicARM2410 教学实验开发平台 一套 USB 鼠标 一个 USB 键盘 一个 软件:RedHat Linux 9.0 操作系统(安装有 Autoconf 和 Automake 工具) 嵌入式 Linux 开发环境 MiniGUI-STR(for Linux)软件 3. 实验内容 创建一个 MiniGUI 主窗口,在窗口中间显示 Linux 吉祥物小企鹅(使用 PC 机上的 /usr/local/lib/minigui/res/bmp 目录下的 logo256.bmp 文件)。 4. 实验预习要求 (1)必须先做本书第 10.1 章的实验,搭建好 MiniGUI 编译和实验箱主板上的运行环境, 掌握交叉编译和下载 Linux 应用程序到 MagicARM2410 上并运行。 (2)仔细阅读本书第 1 章的内容,了解 MagicARM2410 实验箱的硬件结构,注意彩色 液晶屏驱动电路。 (3)阅读参考文献[4]以及 MiniGUI 的文档<>,了解位图文件的 装载和显示输出的相关内容。 5. 实验原理 MiniGUI 提供了众多的位图操作函数,支持单色、16 色、256 色和 24 位色的 BMP 文 件、JPG 文件、GIF 文件和 PCX 文件等等,MiniGUI 可以从 File(使用文件系统读取文件)或 Memory(内嵌在工程代码中的数据,即内建式资源)中取得位图文件数据。 如果要显示一个 BMP 图,可以先将 BMP 文件复制到 MiniGUI 应用程序的工作目录下。 然后 MiniGUI 应用程序使用 LoadBitmapFromFile 函数读取 BMP 文件的数据,使用 FillBoxWithBitmap 函数将 BMP 图输出到液晶屏显示。最后,使用 UnloadBitmap 函数清除 已加载的位图文件资源。 更详细的说明请参考 MiniGUI 的应用资料。 6. 实验步骤 (1)在 PC 机的 mg-samples-str-1.6.2/src 目录下建立源文件 dispbmp.c,编写实验程序代 码。 (2)修改 mg-samples-str-1.6.2/src 目录下的 Makefile.am 文件,设置编译 dispbmp.c 文 件,如程序清单 10.14 所列。 - 405 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 程序清单 10.14 配置编译新增的 dispbmp.c COMMON_PROGS=helloworld mycontrol dialogbox simplekey \ static button listbox edit combobox menubutton progressbar trackbar newtoolbar propsheet \ scrollbar painter capture bitblt stretchblt loadbmp drawicon \ createicon caretdemo cursordemo input bmpbkgnd dispbmp …… noinst_PROGRAMS=$(COMMON_PROGS) $(LITE_PROGS) dispbmp_SOURCES=dispbmp.c …… (3)打开“终端”窗口,执行以下指令编译 MiniGUI 应用程序。编译通过后,在 mg-samples-str-1.6.2/src 目录下会生成 dispbmp 文件(FLAT 格式文件)。 #cd /home/minigui/mg-samples-str-1.6.2 #make (4)连接好 MagicARM2410 实验箱硬件(包括串口线、网线和 USB 键盘鼠标),将实验 箱主板上的 JP1、JP7 跳线短接,JP8 跳线断开。启动实验箱主板上的 Linux,然后使用 NFS 复制 dispbmp 程序文件到实验箱主板的/usr/pro 目录下(具体操作可以参考第 5 章的介绍)。 (5)在 PC 机端使用 minicom 软件操作实验箱(即操作实验箱主板上的 Linux 操作系统), 即可运行 MiniGUI 程序,正确运行 dispbmp 程序后在实验箱的液晶屏幕上将会显示一个可 爱的小企鹅。程序运行结果参考如图 10.10 所示。 图 10.10 dispbmp.c 运行结果参考图 7. 实验参考程序 位图显示实验的参考程序见产品配套光盘。 8. 思考 在 MiniGUI 中,如何实现位图的缩放操作(即使用什么 API 函数实现)? - 406 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 10.5 GDI 绘图实验 1. 实验目的 熟悉 MiniGUI 的绘图属性,掌握基本 GDI 绘图函数的应用。 2. 实验设备 硬件:PC 机 一台 MagicARM2410 教学实验开发平台 一套 USB 鼠标 一个 USB 键盘 一个 软件:RedHat Linux 9.0 操作系统(安装有 Autoconf 和 Automake 工具) 嵌入式 Linux 开发环境 MiniGUI-STR(for Linux)软件 3. 实验内容 使用 MiniGUI 创建主窗口,然后在窗口中以客户区中心点为中心,画出随机颜色、随 机长度和随机角度的 50 根直线。 4. 实验预习要求 (1)必须先做本书第 10.1 章的实验,搭建好 MiniGUI 编译和实验箱主板上的运行环境, 掌握交叉编译和下载 Linux 应用程序到 MagicARM2410 上并运行。 (2)仔细阅读本书第 1 章的内容,了解 MagicARM2410 实验箱的硬件结构,注意彩色 液晶屏驱动电路。 (3)阅读参考文献[4]以及 MiniGUI 的文档<>,了解 MiniGUI 的 GDI 绘画函数的使用方法。 5. 实验原理 MiniGUI 提供了众多的 GDI 绘图函数,包括基本的二维图形绘制函数,矩形操作,区 域操作,位图显示和文字输出等等。进行 GDI 绘图操作之前,首先要获得设备 hdc(即设备 上下文),然后调用相应的 GDI 函数进行设置及绘图操作,最后还需要释放设备 hdc。注意, 程序必须在处理单个消息期间获取设备 hdc 和释放设备 hdc。一般用户可以通过 BeginPaint、 GetDC 函数来取得设备 hdc,然后使用 EndPaint、ReleaseDC 函数释放设备 hdc。BeginPaint 是只针对窗口的客户区,而 GetDC 则是针对整个窗口。函数 BeginPaint 和 EndPaint 常用于 窗口过程函数中的 MSG_PAINT 消息处理中。 更详细的说明请参考 MiniGUI 的应用资料。 6. 实验步骤 (1)在 PC 机的 mg-samples-str-1.6.2/src 目录下建立源文件 line.c,编写实验程序代码。 (2)修改 mg-samples-str-1.6.2/src 目录下的 Makefile.am 文件,设置编译 line.c 文件, 如程序清单 10.15 所列。 - 407 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 程序清单 10.15 配置编译新增的 line.c COMMON_PROGS=helloworld mycontrol dialogbox simplekey \ static button listbox edit combobox menubutton progressbar trackbar newtoolbar propsheet \ scrollbar painter capture bitblt stretchblt loadbmp drawicon \ createicon caretdemo cursordemo input bmpbkgnd line …… noinst_PROGRAMS=$(COMMON_PROGS) $(LITE_PROGS) line_SOURCES=line.c …… (3)打开“终端”窗口,执行以下指令编译 MiniGUI 应用程序。编译通过后,在 mg-samples-str-1.6.2/src 目录下会生成 line 文件(FLAT 格式文件)。 #cd /home/minigui/mg-samples-str-1.6.2 #make (4)连接好 MagicARM2410 实验箱硬件(包括串口线、网线和 USB 键盘鼠标),将实验 箱主板上的 JP1、JP7 跳线短接,JP8 跳线断开。启动实验箱主板上的 Linux,然后使用 NFS 复制 line 程序文件到实验箱主板的/usr/pro 目录下(具体操作可以参考第 5 章的介绍)。 (5)在 PC 机端使用 minicom 软件操作实验箱(即操作实验箱主板上的 Linux 操作系统), 即可运行 MiniGUI 程序,正确运行 line 程序后在实验箱的液晶屏幕上可以观察到画有随机 直线的窗口。程序运行结果参考如图 10.11 所示。 图 10.11 line.c 运行结果参考图 7. 实验参考程序 GDI 绘图实验的参考程序见产品配套光盘。 8. 思考 如果想要在窗口的随机位置,显示随机大小(当然还是要规定在合理的范围内)随机颜色 的圆,应如何修改实验参考程序? - 408 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 附录 A USB 分析仪 USB Analyst-I 简介 USB Analyst-I 是广州致远电子有限公司独立设计的 USB 开发工具,是国内第一款自主 设计的 USB 分析工具,完全打破了国外技术垄断,价格仅为欧美同类产品的几十分之一。 纵观国内外的 USB 分析仪,本 USB 协议分析仪具有很高的性价比,本 USB 协议分析仪采 用了 PHILIPS 公司的 USB 专用芯片、增强型单片机,结合数字锁相环(DPLL)、先入先出 (FIFO)、自动同步跟踪、总线干扰检测和 USB1.1、USB2.0 等技术精心制作而成。该分析 仪完全支持 USB2.0(FS/LS)协议,界面友好,直接搭配个人电脑或笔记本使用,是广大 USB 接口设备开发工程师的得力助手。 实物和软件界面 USB Analyst-I 的实物外观如图 A.1 所示,USB 分析软件界面如图 A.2 所示。 图 A.1 USB 分析仪实物外观(正面和侧面) 图 A.2 USB 分析软件界面 - 409 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 主要功能 同时支持 PC 主机和嵌入式主机 USB 设备开发; 快速分析和解决 USB 传输令牌问题; 自动分析 USB 传输速度和提示解决办法; 全面支持 USB2.0 全速、低速数据采集分析; 完善的 USB 协议解码功能,数据阅读更加轻松; USB2.0 传输接口,支持 2000、XP 等操作系统; 采集低速设备时支持实时数据显示; 传输级别和事务级别显示数据,直观明了; 支持 PID 或人工多种触发条件选择; 随意定义 1~99Mbyte 的采集容量并显示采集进度; 标签功能,可任意添加标签和跳转到任意标签上; 强大的搜索功能,可以以事务级别搜索数据; 完善的数据统计功能,带宽利用随手可得; USB 总线错误分析和传输数据错误分析功能; 空闲时间统计功能,数据传输过程一目了然; USB 总线数据自动跟踪,确保数据完整无误; 人性化的显示设置方法; 完善的多文档管理和多种的界面风格; 抓图功能,框选部分可保存成图片或复制到前贴板; 体积小,重量轻,方便携带; 两种供电方式,满足各种计算机的要求。 技术参数 监控 USB 端口支持:USB2.0 端口,USB1.1 端口 采集 USB 端口支持:USB2.0(FS/LS) 端口 采集端 USB 口输入阻抗:>10MΩ 数据采集深度:1~99Mbyte 采集速度:USB2.0 全速(Full Speed)、低速(Low Speed) 采集内容:USB 传输数据(Sync、PID、ADDR、ENDP、CRC5 、CRC16、Frame Number 、DATA), 位填充错误,数据传输间隔时间(IDLE) 触发条件: -PID 触发:USB2.0 规范内的所有 PID -手动触发; IDLE 时间统计: -最小值:83nS; -最大值:1189mS; - 410 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 附录 B LA1032 逻辑分析仪简介 LA 系列逻辑分析仪是广州致远电子有限公司独立设计的分析仪器,采用计算机作为显示 平台,采用 USB 接口通讯,即插即用,采用广泛使用的 Windows 系统,界面美观实用,容 易上手。强大的触发功能,让您不用金晴火眼就能发现隐藏在系统中的错误。完善的协议分 析功能,让您在不熟悉的协议下也能挥洒自如。高效的数据压缩算法,让您总是看到更多的 信息,处处领先一步。自动升级功能,让您随时可以分享我们的技术进步。 LA 系列逻辑分析仪采用了先进的大规模集成电路,整合了 USB2.0、CPLD、FPGA、嵌 入式系统等先进的技术,具有高性能低价格、携带方便、简单易用、扩展性好等优点,是替 代传统设备的最佳选择。 LA 系列逻辑分析仪是集逻辑分析仪、总线分析仪、协议分析仪、 频率计、逻辑笔等多种测量开发仪器之大成于一身,适用于各种数字电路的开发、测量、分 析和调试工作,是电子研发、电子测量工程师、高校师生的科研开发和教学的得力助手。 LA1032 逻辑分析仪性能参数 逻辑分析仪: 最高采样频率: 实时显示: 最大储存深度: 数据压缩功能: 输入阻抗: 门限电压: 信号输入范围: USB 传输协议: 触发位置设置: 快速触发: 可视触发: 插件触发: 自定义高级触发: 自动升级: 多语言支持: 多文档结构: 波形打印: 支持系统: 100MHz 支持 32K/路 支持 1MΩ 0~4.6V(两路可调) 0~5V USB2.0 (HighSpeed、FullSpeed) 可任意位置 支持 12 种快速触发(立即触发、上升沿、下降沿、边沿、 特定数据、数据队列、特定数据及上升沿、特定数据及下降 沿、数据宽度、数据到来延时、数据结束延时、数据次数等 触发方式) 支持 支持 支持 支持 支持 支持 支持 Windows2000,Windows XP 总线分析功能: UART 总线分析: I2C 总线分析: SPI 总线分析: SSI 总线分析: 1-Wire 总线分析: 支持 支持 支持 支持 支持 - 411 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com A/D 采样分析: 支持 协议分析功能: MODBus 协议分析: CF 卡协议分析: SD/MMC 卡分析: 支持 支持 支持 频率计功能: 测量范围: 10Hz~50MHz 逻辑笔功能: 采样刷新周期: 1ms LA1032 逻辑分析仪外观 LA1032 使用铝合金外壳,其外观如图 B.1 所示。 图 B.1 LA1032 逻辑分析仪外观 LA1032 左侧外观如图 B.2 所示。 图 B.2 逻辑分析仪侧面图 POWER:为 5V 电源输入,通常 LA1032 具备使用计算机 USB 总线供电工作的能力,可 以不连接外部电源供电。 USB:为 USB2.0 接口,用于与计算机通讯。 POW 指示灯:电源指示灯,当接通电源时,POW 指示灯发亮。 USB 指示灯:当进行 USB 数据传输时,该指示灯发亮。 RUN 指示灯:当逻辑分析仪工作时,该指示灯发亮。 RST 按钮:当逻辑分析仪工作异常时可以按此按钮复位逻辑分析仪。 - 412 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com LA1032 逻辑分析仪硬件连接 取出 LA1032 及所附的 USB 连接线,将 USB B 型接头的一端(截面为正方形)连接至 LA1032 的 USB 插座,另一端 USB B 型接头(截面为长方形)连接至计算机的 USB A 型插座。不使 用附带电源。LA1032 与 PC 连接如图 B.3 所示。 图 B.3 LA1032 与 PC 连接实物图 数据压缩算法 LA1032 内置与众不同的高效非线性数据压缩算法,对采集数据进行实时压缩,不会造 成任何性能和指标降低,不用减少输入采集通道,真正实现完整的数据压缩,而这么强大的 功能都只需要您在使用时把压缩选择框打钩就可以了。 例如同样对 100Hz 的频率采用 1K 的采样频率进行记录,非压缩时记录时间为 32 秒, 而压缩时记录时间长达 80 秒以上,记录时间上延长了一倍以上。 数据压缩采用非线性数据压缩方式,压缩比率会不断自动调整到最佳位置。 - 413 - 广州致远电子有限公司 Tel: (020) 22644399 Fax: (020) 38601859 http:// www.zyinside.com 参考文献 1. 田泽等译.ARM SOC 体系结构.北京航空航天大学出版社,2002 年. 2. Samsung 公司.S3C2410A user’s manual Revision 1.0.Samsung,2004 年. 3. 周立功等,ARM 嵌入式 uCLinux 系统构建与驱动开发范例. 北京航空航天大学出版社,2005 年. 4. 周立功等编著.ARM 嵌入式 MiniGUI 初步与应用开发范例.北京航空航天大学出版社,2005 年. 5. Jean. Labrosse 著,邵贝贝等译.嵌入式实时操作系统μC/OS-II(第 2 版).北京航空航天大学出版 社,2003 年 5 月. - 414 -

Top_arrow
回到顶部
EEWORLD下载中心所有资源均来自网友分享,如有侵权,请发送举报邮件到客服邮箱bbs_service@eeworld.com.cn 或通过站内短信息或QQ:273568022联系管理员 高进,我们会尽快处理。