Arduino、bootloader、BadUSB、及其相关硬件知识入门学习

catalogue

0. 引言
1. 串行接口
2. USB
3. 单片机
4. BootLoader
5. PWM(脉宽调制 Pulse Width Modulation)
6. EEPROM
7. LCD1602
8.  蜂鸣器、喇叭
9. 直流电机(direct current machine)
10. USB接口芯片
11. arduino系列产品
12. ICSP(In-Circuit Serial Programming 在线串行编程)
13. 人体传感器
14. CMOS
15. HID/ BADUSB
16. Bootloader烧写
17. USB Keylogger

 

0. 引言

很久没在blog里说这些乱七八糟的话,这段时间研究arduino硬件有些感触这里随便说两句

0x1: 硬件(片上)编程和在PC的ring3/ring0编程的异同

在PC上编程函数之间调用,尤其是在用户态,API之间的调用全都是"虚拟"的概念,即你调用的所有仅仅只是一个逻辑上的黑盒子,它会返回一个确定的逻辑结果(数字)。但是到了硬件这个层面,用电路的思维模式去理解函数调用和执行会更贴近实际一些,在硬件层面的API调用常常被翻译为对某些器件的操作,再往底层就是电路的与非门/锁存器/高低电位/译码的操作

程序员在进行硬件编程的时候,不能只专注于逻辑算法的构建和思考,更多地时候需要使用面向硬件器材特征/引脚/使能进行编程,更多的时候我们的代码是在对指定器材的管脚写入高低电位,并根据返回结果进行AD/DA/纯数字的判断,代码更专注的是使用硬件器材的"输入使能特征"并根据"响应电气特征"判断执行的结果(这点在进行传感器编程时尤其明显)

 

1. 串行接口

串行接口简称串口,也称串行通信接口或串行通讯接口(通常指COM接口),是采用串行通信方式的扩展接口

0x1: 定义

串行接口(Serial Interface) 是指数据一位一位地顺序传送,其特点是通信线路简单,只要一对传输线就可以实现双向通信(可以直接利用电话线作为传输线),从而大大降低了成本,特别适用于远距离通信,但传送速度较慢。一条信息的各位数据被逐位按顺序传送的通讯方式称为串行通讯

0x2: 特点

1. 数据位的传送,按位顺序进行,最少只需一根传输线即可完成
2. 成本低但传送速度慢。串行通讯的距离可以从几米到几千米
3. 根据信息的传送方向,串行通讯可以进一步分为
    1) 单工
    2) 半双工
    3) 全双工三种

0x3: 接口划分标准

串口通信的两种最基本的方式

1. 同步串行通信方式: 同步串行是指SPI(Serial Peripheral interface)的缩写,顾名思义就是串行外围设备接口。SPI总线系统是一种同步串行外设接口,它可以使MCU与各种外围设备以串行方式进行通信以交换信息
2. 异步串行通信方式: 异步串行是指UART(Universal Asynchronous Receiver/Transmitter),通用异步接收/发送。UART使一个并行输入成为串行输出的芯片,通常集成在主板上。UART包含
    1) TTL电平的串口: TTL电平是3.3V的
    2) RS232电平的串口: RS232是负逻辑电平,它定义+5~+12V为低电平,而-12~-5V为高电平
//MDS2710、MDS SD4、EL805等是RS232接口,EL806有TTL接口

串行接口按电气标准及协议来分包括RS-232-C、RS-422、RS485等。RS-232-C、RS-422与RS-485标准只对接口的电气特性做出规定,不涉及接插件、电缆或协议

1. RS-232

也称标准串口,最常用的一种串行通讯接口。它是在1970年由美国电子工业协会(EIA)联合贝尔系统、调制解调器厂家及计算机终端生产厂家共同制定的用于串行通讯的标准。它的全名是"数据终端设备(DTE)和数据通讯设备(DCE)之间串行二进制数据交换接口技术标准"。传统的RS-232-C接口标准有22根线,采用标准25芯D型插头座(DB25),后来使用简化为9芯D型插座(DB9),现在应用中25芯插头座已很少采用
RS-232采取不平衡传输方式,即所谓单端通讯。由于其发送电平与接收电平的差仅为2V至3V左右,所以其共模抑制能力差,再加上双绞线上的分布电容,其传送距离最大为约15米,最高速率为20kb/s。RS-232是为点对点(即只用一对收、发设备)通讯而设计的,其驱动器负载为3~7kΩ。所以RS-232适合本地设备之间的通信

“RS-232”的图片搜索结果

2. RS-422

标准全称是"平衡电压数字接口电路的电气特性",它定义了接口电路的特性。典型的RS-422是四线接口。实际上还有一根信号地线,共5根线。其DB9连接器引脚定义。由于接收器采用高输入阻抗和发送驱动器比RS232更强的驱动能力,故允许在相同传输线上连接多个接收节点,最多可接10个节点。即一个主设备(Master),其余为从设备(Slave),从设备之间不能通信,所以RS-422支持点对多的双向通信。接收器输入阻抗为4k,故发端最大负载能力是10 x 4k + 100Ω(终接电阻)。RS-422四线接口由于采用单独的发送和接收通道,因此不必控制数据方向,各装置之间任何必须的信号交换均可以按软件方式(XON/XOFF握手)或硬件方式(一对单独的双绞线)实现
RS-422的最大传输距离为1219米,最大传输速率为10Mb/s。其平衡双绞线的长度与传输速率成反比,在100kb/s速率以下,才可能达到最大传输距离。只有在很短的距离下才能获得最高速率传输。一般100米长的双绞线上所能获得的最大传输速率仅为1Mb/s

3. RS-485

是从RS-422基础上发展而来的,所以RS-485许多电气规定与RS-422相仿。如都采用平衡传输方式、都需要在传输线上接终接电阻等。RS-485可以采用二线与四线方式,二线制可实现真正的多点双向通信,而采用四线连接时,与RS-422一样只能实现点对多的通信,即只能有一个主(Master)设备,其余为从设备,但它比RS-422有改进,无论四线还是二线连接方式总线上可多接到32个设备
RS-485与RS-422的不同还在于其共模输出电压是不同的,RS-485是-7V至+12V之间,而RS-422在-7V至+7V之间,RS-485接收器最小输入阻抗为12kΩ、RS-422是4kΩ;由于RS-485满足所有RS-422的规范,所以RS-485的驱动器可以在RS-422网络中应用
RS-485与RS-422一样,其最大传输距离约为1219米,最大传输速率为10Mb/s。平衡双绞线的长度与传输速率成反比,在100kb/s速率以下,才可能使用规定最长的电缆长度。只有在很短的距离下才能获得最高速率传输。一般100米长双绞线最大传输速率仅为1Mb/s

0x4: 串口的应用

1. 交换机的串口: 交换机的串口的英文就是trunk;是用来做下一跳路由转换用的。每个VLAN只有通过与TRUNK的路由指向后才能上外网
目前较为常用的串口有9针串口(DB9)和25针串口(DB25),通信距离较近时(<12m),可以用电缆线直接连接标准RS232端口(RS422,RS485较远),若距离较远,需附加调制解调器(MODEM)或其他相关设备。最为简单且常用的是三线制接法,即地、接收数据和发送数据三脚相连

2. 电脑主板串口: 进行串行传输的接口,它一次只能传输1Bit。串行端口可以用于连接外置调制解调器、绘图仪或串行打印机。它也可以控制台连接的方式连接网络设备,例如路由器和交换机,主要用来配置它们

0x5: 波特率

单片机或计算机在串口通信时的速率。指的是信号被调制以后在单位时间内的变化,即单位时间内载波参数变化的次数

1. 如每秒钟传送240个字符,而每个字符格式包含10位(1个起始位,1个停止位,8个数据位),这时的波特率为240Bd,比特率为10位*240个/秒=2400bps
2. 如每秒钟传送240个二进制位,这时的波特率为240Bd,比特率也是240bps(但是一般调制速率大于波特率,比如曼彻斯特编码)

波特率,可以通俗的理解为一个设备在一秒钟内发送(或接收)了多少码元的数据。它是对符号传输速率的一种度量,1波特即指每秒传输1个码元符号(通过不同的调制方式,可以在一个码元符号上负载多个bit位信息)
而比特链是对bit位的度量单位,1比特每秒是指每秒传输1比特(bit)
单位"波特"本身就已经是代表每秒的调制数,以"波特每秒"(Baud per second)为单位是一种常见的错误

Relevant Link:

http://baike.baidu.com/view/161117.htm?fromtitle=%E4%B8%B2%E5%8F%A3&fromid=1250303&type=syn
http://baike.baidu.com/link?url=IffrWcK92zwhzTAHNUOjX_BFTO5v91vRCK3Kx9LGoCvKOyBwVixuB-8X3SQJpUzpjlw5Up-b0BLmaGq4puM9o_

 

2. USB

USB(Universal Serial Bus 通用串行总线)的缩写,而其中文简称为"通串线",是一个外部总线标准,用于规范电脑与外部设备的连接和通讯。是应用在PC领域的接口技术。USB接口支持设备的即插即用和热插拔功能。USB是在1994年底由英特尔、康柏、IBM、Microsoft等多家公司联合提出的。
从1994年11月11日发表了USB V0.7版本以后,USB版本经历了多年的发展,已经发展为3.1版本,成为二十一世纪电脑中的标准扩展接口。当前主板中主要是采用USB2.0和USB3.0接口,各USB版本间能很好的兼容。USB用一个4针(USB3.0标准为9针)插头作为标准插头,采用菊花链形式可以把所有的外设连接起来,最多可以连接 127个外部设备,并且不会损失带宽
USB需要主机硬件、操作系统和外设三个方面的支持才能工作。二十一世纪的主板一般都采用支持USB功能的控制芯片组,主板上也安装有USB接口插座,而且除了背板的插座之外,主板上还预留有USB插针,可以通过连线接到机箱前面作为前置USB接口以方便使用。而且USB接口还可以通过专门的USB连机线实现双机互连,并可以通过Hub扩展出更多的接口。USB具有传输速度快,使用方便,支持热插拔,连接灵活,独立供电等优点,可以连接鼠标、键盘、打印机、扫描仪、摄像头、充电器、闪存盘、MP3机、手机、数码相机、移动硬盘、外置光驱/软驱、USB网卡、ADSL Modem、Cable Modem等,几乎所有的外部设备

USB版本
  
最大传输速率
  
速率称号
  
最大输出电流
  
推出时间
  
USB1.0
  
1.5Mbps(192KB/s)
  
低速(Low-Speed)
  
5V/500mA
  
1996年1月
  
USB1.1
  
12Mbps(1.5MB/s)
  
全速(Full-Speed)
  
5V/500mA
  
1998年9月
  
USB2.0
  
480Mbps(60MB/s)
  
高速(High-Speed)
  
5V/500mA
  
2000年4月
  
USB3.0
  
5Gbps(500MB/s)
  
超高速(Super-Speed)
  
5V/900mA
  
2008年11月
  
USB 3.1 10Gbps(1280MB/s)[2] 超高速+(Super-speed+)
  
20V/5A 2013年12月

0x1: 软件结构

每个USB只有一个主机,它包括以下几层

1. USB总线接口: USB总线接口处理电气层与协议层的互连
2. USB系统: USB系统用主控制器管理主机与USB设备间的数据传输,它与主控制器间的接口依赖于主控制器的硬件定义。同时,USB系统也负责管理USB资源,例如带宽和总线能量,这使得客户访问USB成为可能
3. USB客户软件: 位于软件结构的最高层,负责处理特定USB设备驱动器。客户程序层描述所有直接作用于设备的软件入口。当设备被系统检测到后,这些客户程序将直接作用于外围硬件 

0x2: 硬件结构

从硬件结构来说,USB系统采用级联星型拓扑(菊花链),该拓扑由三个基本部分组成: 主机(Host)、集线器(Hub)和功能设备

1. 主机,也称为根、根结点或根Hub,做在计算机主板上或作为适配卡安装在计算机上。主机包含有主控制器和根集线器(Root Hub),控制USB总线上数据和控制信息的流动,每个USB系统只能有一个根集线器,它连接在主控制器上 
2. 集线器是USB结构中的特定部分,它提供端口(Port),以便将设备连接到USB接口上,同时检测连接在总线上的设备,并为这些设备提供电源管理,负责总线的故障检测和恢复。
3. 功能设备通过端口与总线连接 

0x3: 数据传输模式

主控制器负责主机与USB设备间数据流的传输,这些传输数据被当作连续的比特流。每个设备提供了一个或多个可以与客户程序通信的接口,每个接口由0个或多个管道组成,它们分别独立地在客户程序与设备的特定终端间传输数据。通用串行总线驱动程序(USBD)为主机软件的现实需求建立了接口和管道,当提出配置请求时,主控制器根据主机软件提供的参数提供服务
USB支持四种基本的数据传输模式: 控制传输、等时传输、中断传输、数据块传输。每种传输模式应用到同名终端,则具有不同的性质

1. 控制传输类型: 支持外设与主机之间的控制、状态、配置等信息的传输,为外设与主机之间提供一个控制通道。每种外设都支持控制传输类型,这样主机与外设之间就可以传送配置和命令/状态信息
2. 等时(Isochronous)传输类型: 支持有周期性、有限的时延和带宽、且数据传输速率不变的外设与主机间的数据传输。该类型无差错校验,故不能保证正确的数据传输,支持诸如计算机-电话集成系统(CTI)、音频系统与主机的数据传输  
3. 中断传输类型: 支持诸如游戏手柄、鼠标、键盘等输入设备,这些设备与主机间的数据传输量小,无周期性,但对响应时间敏感,要求马上响应 
4. 数据块(Bulk)传输类型: 支持打印机、扫描仪、数码相机等外设,这些外设与主机间的数据传输量大,USB在满足带宽的情况下才进行该类型的数据传输 

0x4: USB转串口

对于单片机,微控制器片上系统来说,出于通用性的考虑,一般都采用串口方式进行通信,而我们的编程环境大多支持USB方式通信,因此就需要转接器充当中间人的角色,将USB数据转换为串口可接受的信号。单片机和PC进行串口通信的时候,单片机接收来自PC的串行bit数据流,同时需要模拟生成USB信号流发给PC、而PC接收来自单片机的USB信号流,同时需要利用设备驱动(COM模拟驱动)生成串行bit流发给单片机

需要明白的是,串口只是单片机上其中一个外接引脚,AVR单片机上有十几个不同功能的外接引脚

1. 卫星机顶盒升级
2. 路由器固件升级
3. 收集系统刷机
4. 硬盘固件修复
5. 单片机程序下载

1. TTL Serial/UARTs

Most microcontrollers these days have built in UARTs (universally asynchronous receiver/transmitter) that can be used to receive and transmit data serially. UARTs transmit one bit at a time at a specified data rate (i.e. 9600bps, 115200bps, etc.). This method of serial communication is sometimes referred to as TTL serial (transistor-transistor logic). Serial communication at a TTL level will always remain between the limits of 0V and Vcc, which is often 5V or 3.3V. A logic high ('1') is represented by Vcc, while a logic low ('0') is 0V.

1. 常见的微控制器中(例如arduino uno r3),都有了内置的UART(Universally Asynchronous Receiver/Transmitter)
2. UART可以用来作为串行方式收发数据
3. UART是,以固定的某个速率(1200bps、9600bps、115200bps等),一次只能只传输一个bit比特位(所以叫做串行传输)
4. 这种串行通信的方法,有时候也被叫做TTL(Transistor-Transistor Logic)Serial,因为本质上是通过高低电位的不同状态表示bit位的
5. 这种串行通信,在TTL级别上来说,对应的物理电平,始终是在0V和Vcc之间,其中常见的Vcc是5V或3.3V
    1) 逻辑高电平 == '1' == Vcc
    2) 逻辑低电平 == '0' == 0V

2. RS-232

The serial port on your computer (if it's lucky enough to have one, they're quickly becoming a relic) complies with the RS-232 (Recommended Standard 232) telecommunications standard. RS-232 signals are similar to your microcontroller's serial signals in that they transmit one bit at a time, at a specific baud rate, with or without parity and/or stop bits. The two differ solely at a hardware level. By the RS-232 standard a logic high ('1') is represented by a negative voltage – anywhere from -3 to -25V – while a logic low ('0') transmits a positive voltage that can be anywhere from +3 to +25V. On most PCs these signals swing from -13 to +13V.
The more extreme voltages of an RS-232 signal help to make it less susceptible to noise, interference, and degradation. This means that an RS-232 signal can generally travel longer physical distances than their TTL counterparts, while still providing a reliable data transmission.

1. 台式机,笔记本等中的串口,是和RS232(通信标准)所兼容的(所一致的) => 不是和TTL的标准所一致的,即通过正负电压来传输bit位

3. RS-232和TTL的区别

对于同样传输0b01010101来说,RS232和TTL的时序对比

1. RS232和TTL在软件协议层面是一样的
2. RS232的标准中,和微控制器中的串行信号是一样的,有
    1) 一次只传输一个bit比特位 -> 表示是serial
    2) 以某个固定的速率去传输的-> baudrate
    3) 带或不带,parity极性 -> 即校验位
    4) 带或不带,停止位stop bit(s)
3. RS232和TTL唯一不同在于硬件: 电平表示的逻辑含义不同(相反)
    1) TTL
    逻辑高电平 == '1' == Vcc == 3.3V或5V    
    逻辑低电平 == '0' == 0V == 0V
    2) RS232
    逻辑高电平 == '0' == 负电压 == -3V~-25V == 常为: -13V
    逻辑低电平 == '1' == 正电压 == 3V~25V == 常为: 13V

4. 为何RS232中要用负电压表示逻辑高电平,因为此设计(用负电压表示逻辑1,正电压表示逻辑0)相对来说,更加
    1) 抗(外界的电磁)干扰
    2) 抗外界的(电磁信号)噪音干扰
    3) 抗(信号的)衰减
    4) 使得和同样的TTL信号相比,RS232信号可以传输的更远,由此使得信号传输,相对更加稳定和可靠 

Relevant Link:

http://baike.baidu.com/item/usb
http://share.onlinesjtu.com/mod/tab/view.php?id=282
https://detail.tmall.com/item.htm?spm=a230r.1.14.1.VIFe5Q&id=45588089152&ns=1&abbucket=14
https://www.sparkfun.com/tutorials/215
http://www.openedv.com/thread-34161-1-1.html
http://baike.baidu.com/link?url=yP4cplmFTPIV5UCM3q_LtjU98bgblLaSGsrgKDjxeyGcCTBGpgh4J2H3xFZqjWzwcaAx4w_6VINjxvKwG4xX6_
http://www.crifan.com/summary_ttl_vs_rs232/

 

3. 单片机

单片机(Microcontrollers)是一种集成电路芯片,是采用超大规模集成电路技术把具有数据处理能力的中央处理器CPU、随机存储器RAM、只读存储器ROM、多种I/O口和中断系统、定时器/计数器等功能(可能还包括显示驱动电路、脉宽调制电路、模拟多路转换器、A/D转换器等电路)集成到一块硅片上构成的一个小而完善的微型计算机系统,在工业控制领域广泛应用。从上世纪80年代,由当时的4位、8位单片机,发展到现在的300M的高速单片机
单片机又称单片微控制器,它不是完成某一个逻辑功能的芯片,而是把一个计算机系统集成到一个芯片上。相当于一个微型的计算机,和计算机相比,单片机只缺少了I/O设备。概括的讲: 一块芯片就成了一台计算机。它的体积小、质量轻、价格便宜、为学习、应用和开发提供了便利条件。同时,学习使用单片机是了解计算机原理与结构的最佳选择
单片机的使用领域已十分广泛,如智能仪表、实时工控、通讯设备、导航系统、家用电器等。各种产品一旦用上了单片机,就能起到使产品升级换代的功效,常在产品名称前冠以形容词:"智能型",如智能型洗衣机等

0x2: 应用分类

单片机(Microcontrollers)作为计算机发展的一个重要分支领域,根据发展情况,从不同角度,单片机大致可以分为通用型/专用型、总线型/非总线型及工控型/家电型

1. 通用型: 这是按单片机(Microcontrollers)适用范围来区分的。例如,80C51式通用型单片机,它不是为某种专门用途设计的
2. 专用型: 针对一类产品甚至某一个产品设计生产的,例如为了满足电子体温计的要求,在片内集成ADC接口等功能的温度测量控制电路
3. 总线型: 这是按单片机(Microcontrollers)是否提供并行总线来区分的。总线型单片机普遍设置有并行地址总线、数据总线、控制总线,这些引脚用以扩展并行外围器件都可通过串行口与单片机连接
4. 非总线型: 许多单片机已把所需要的外围器件及外设接口集成到片内,因此在许多情况下可以不要并行扩展总线,大大减省封装成本和芯片体积,这类单片机称为非总线型单片机
5. 控制型: 这是按照单片机(Microcontrollers)大致应用的领域进行区分的。一般而言,工控型寻址范围大,运算能力强
6. 专用型: 用于家电的单片机多为专用型,通常是小封装、低价格,外围器件和外设接口集成度高

上述分类并不是惟一的和严格的。例如,80C51类单片机既是通用型又是总线型,还可以作工控用

0x3: 发展历史

单片机(Microcontrollers)诞生于1971年,经历了SCM、MCU、SoC三大阶段,早期的SCM单片机都是8位或4位的。其中最成功的是INTEL的8051,此后在8051上发展出了MCS51系列MCU系统。基于这一系统的单片机系统直到现在还在广泛使用。随着工业控制领域要求的提高,开始出现了16位单片机,但因为性价比不理想并未得到很广泛的应用。90年代后随着消费电子产品大发展,单片机技术得到了巨大提高。随着INTEL i960系列特别是后来的ARM系列的广泛应用,32位单片机迅速取代16位单片机的高端地位,并且进入主流市场。
而传统的8位单片机的性能也得到了飞速提高,处理能力比起80年代提高了数百倍。高端的32位Soc单片机主频已经超过300MHz,性能直追90年代中期的专用处理器,而普通的型号出厂价格跌落至1美元,最高端的型号也只有10美元
当代单片机系统已经不再只在裸机环境下开发和使用,大量专用的嵌入式操作系统被广泛应用在全系列的单片机上。而在作为掌上电脑和手机核心处理的高端单片机甚至可以直接使用专用的Windows和Linux操作系统

1. 早期阶段: SCM即单片微型计算机(Microcontrollers)阶段,主要是寻求最佳的单片形态嵌入式系统的最佳体系结构。"创新模式"获得成功,奠定了SCM与通用计算机完全不同的发展道路。在开创嵌入式系统独立发展道路上,Intel公司功不可没 
2. 中期发展: MCU即微控制器(Micro Controller Unit)阶段,主要的技术发展方向是:不断扩展满足嵌入式应用时,对象系统要求的各种外围电路与接口电路,突显其对象的智能化控制能力。它所涉及的领域都与对象系统相关,因此,发展MCU的重任不可避免地落在电气、电子技术厂家。从这一角度来看,Intel逐渐淡出MCU的发展也有其客观因素。在发展MCU方面,最著名的厂家当数Philips公司
Philips公司以其在嵌入式应用方面的巨大优势,将MCS-51从单片微型计算机迅速发展到微控制器
3. 当前趋势: SoC嵌入式系统(System on Chip)式的独立发展之路,向MCU阶段发展的重要因素,就是寻求应用系统在芯片上的最大化解决,因此,专用单片机的发展自然形成了SoC化趋势。随着微电子技术、IC设计、EDA工具的发展,基于SoC的单片机应用系统设计会有较大的发展。因此,对单片机的理解可以从单片微型计算机、单片微控制器延伸到单片应用系统 

Relevant Link:

http://baike.baidu.com/link?url=F8tt5GkAhoWkcpi5fzdK7-CaSwGU46kqL0jf_1Sh_pBw7bx1DqFUMcdafB1hDcydxgGPgkEbj7p6yP48wnfubq

 

4. BootLoader

在嵌入式操作系统中,BootLoader是在操作系统内核运行之前运行。可以初始化硬件设备、建立内存空间映射图,从而将系统的软硬件环境带到一个合适状态,以便为最终调用操作系统内核准备好正确的环境。在嵌入式系统中,通常并没有像BIOS那样的固件程序(注,有的嵌入式CPU也会内嵌一段短小的启动程序),因此整个系统的加载启动任务就完全由BootLoader来完成。在一个基于ARM7TDMI core的嵌入式系统中,系统在上电或复位时通常都从地址0x00000000处开始执行,而在这个地址处安排的通常就是系统的BootLoader程序
Bootloader是嵌入式系统在加电后执行的第一段代码,在它完成CPU和相关硬件的初始化之后,再将操作系统映像或固化的嵌入式应用程序装在到内存中然后跳转到操作系统所在的空间,启动操作系统运行
对于嵌入式系统,Bootloader是基于特定硬件平台来实现的。因此,几乎不可能为所有的嵌入式系统建立一个通用的Bootloader,不同的处理器架构都有不同的Bootloader。Bootloader不但依赖于CPU的体系结构,而且依赖于嵌入式系统板级设备的配置。对于2块不同的嵌入式板而言,即使它们使用同一种处理器,要想让运行在一块板子上的Bootloader程序也能运行在另一块板子上,一般也都需要修改Bootloader的源程序。
反过来,大部分Bootloader仍然具有很多共性,某些Bootloader也能够支持多种体系结构的嵌入式系统。例如,U-Boot就同时支持PowerPC、ARM、MIPS和X86等体系结构,支持的板子有上百种。通常,它们都能够自动从存储介质上启动,都能够引导操作系统启动,并且大部分都可以支持串口和以太网接口
在专用的嵌入式板子运行GNU/Linux系统已经变得越来越流行。一个嵌入式Linux系统从软件的角度看通常可以分为四个层次

1. 引导加载程序。包括固化在固件(firmware)中的boot代码(可选),和BootLoader两大部分
2. Linux内核。特定于嵌入式板子的定制内核以及内核的启动参数
3. 文件系统。包括根文件系统和建立于Flash内存设备之上文件系统。通常用ramdisk来作为rootfs。
4. 用户应用程序。特定于用户的应用程序。有时在用户应用程序和内核层之间可能还会包括一个嵌入式图形用户界面。常用的嵌入式GUI有:MicroWindows和MiniGUI等

通常,BootLoader是严重地依赖于硬件而实现的,特别是在嵌入式世界。因此,在嵌入式世界里建立一个通用的BootLoader几乎是不可能的。尽管如此,我们仍然可以对bootloader归纳出一些通用的概念来,以指导用户特定的BootLoader设计与实现

0x1: 操作模式

1. 自启动模式: 在这种模式下,bootloader从目标机上的某个固态存储设备上将操作系统加载到RAM中运行,整个过程并没有用户的介入
2. 交互模式: 在这种模式下,目标机上的bootloader将通过串口或网络等通行手段从开发主机(Host)上下载内核映像等到RAM中。可以被bootloader写到目标机上的固态存储媒质中,或者直接进入系统的引导。也可以通过串口接收用户的命令 

0x2: 启动过程

Bootloader启动大多数都分为两个阶段

2. 第一阶段: 主要包含依赖于CPU的体系结构硬件初始化的代码,通常都用汇编语言来实现。这个阶段的任务有
    1) 基本的硬件设备初始化(屏蔽所有的中断、关闭处理器内部指令/数据Cache等),在第一阶段中为什么要关闭Cache?通常使用Cache以及写缓冲是为了提高系统性能,但由于Cache的使用可能改变访问主存的数量、类型和时间,因此Bootloader通常是不需要的
    2) 为第二阶段准备RAM空间
    3) 如果是从某个固态存储媒质中,则复制Bootloader的第二阶段代码到RAM
    4) 设置堆栈
    5) 跳转到第二阶段的C程序入口点

2. 第二阶段: 通常用C语言完成,以便实现更复杂的功能,也使程序有更好的可读性和可移植性。这个阶段的任务有
    1) 初始化本阶段要使用到的硬件设备
    2) 检测系统内存映射
    3) 将内核映像和根文件系统映像从Flash读到RAM
    4) 为内核设置启动参数
    5) 调用内核

0x3: 常见的Bootloader

4.1 Redboot
4.2 ARMboot
4.3 U-Boot
4.4 Blob
4.5 Bios-lt
4.6 Bootldr
4.7 vivi
4.8 DSP的BootLoader

0x4: arduino bootloader

在arduino的板子上,作为核心的avr单片机往往都会烧录一个bootloader,这个叫做bootloader的东东其实是arduino研发团队针对arduino板子开发的一小段代码,借助于这段代码,我们可以在不用外部烧录工具的情况下来把我们自己的代码下载到AVR单片机中。为了使一些朋友更容易理解,不妨打个比方,bootloader类似于我们电脑中的windows操作系统,而我们的代码则类似于运行于windows上的各种程序
一般而言,arduino板的卖家都会把每块板的bootloader都烧好后再出售,这样买家直接收到板后就能够把自己在arduino IDE中编写的程序借助PC的USB口来下载到arduino单片机内

类比于操作系统的本质作用是驱动硬件,完成上层应用的需求,对于单片机的bootloader也一样,不同的bootloader具备不同的能力,例如机器人和自动工控设备、模拟键盘上的bootloader肯定是不一样的,这可以理解为bootloader内核提供了不同的系统调用接口

0x5: Bootloader的各个版本

Bootloader有各种各样的版本,因为要在各种不同的硬件上运行,也因为本身在不断地升级、变化
Diecimila和NG(ATmega168)Bootloader的当前版本(如Arduino 0009版自带的)几乎完全相同。以上两者的Bootloader均在19200的波特率下工作,并且占用ATmega168上2K的Flash内存。仅有的区别,就是Bootloader等待新程序到来的时间和开始运行时13脚上LED闪烁的次数。由于Diecimila的自动重启,其Bootloader仅需要等待非常短的时间(少于一秒),为了节约时间,并且仅闪烁13脚LED一次。NG的Bootloader需要等待6至8秒,并且闪烁3次
Arduino NG自带的Bootloader有一点点不同。它启用了6脚的内置上拉电阻,而没有启动RX脚的内置上拉电阻。因此,若在重启NG之后,就立即向它发送数据,会导致它无法正常启动板上的程序,也不会因为收到无效数据就超时退出
Arduino BT的Bootloader会做一些蓝牙模块的初始化工作
ATmega8的Bootloader仅占用1K的Flash空间。当它收到无效数据时不会超时退出,因此需要确保在Bootloader运行的6至8秒中,不能向它发送数据
一些早期的Bootloader版本运行在9600波特率下(而不是19200)。为了正常下载程序,需要修改preferences file文件中的serail.download\_rate参数值为9600

0x6: Bootloader运行原理

Arduino IDE菜单里的"Burn Bootloader"命令使用的是一款开源工具: avrdude,共有4步

1. 解锁芯片上的Bootloader区
2. 设置芯片的熔丝位
3. 下载Bootloader程序到芯片上
4. 锁住芯片上的Bootloader区

这些步骤由Arduino配置文件中的一些设置决定,以ATmega8为例,决定以上步骤的设置是

1. bootloader.atmega8.programmer(默认: stk500): bootloader使用的协议
2. bootloader.atmega8.unlock_bits(默认: 0xFF)为解锁Bootloader区而向ATmega8锁位写入的值
3. bootloader.atmega8.high_fuses(默认: 0xca)写入Atmega8熔丝位中的高位值
4. bootloader.atmega8.low_fuses(默认: 0xdf)写入Atmega8熔丝位中的低位值
5. bootloader.atmega8.path(默认: bootloader)包含编译好的bootloader路径(相对于Arduino的安装目录)
6. bootloader.atmega8.file(默认: ATmegaBOOT.hex)编译好的Bootloader文件名(在bootloader.path目录里)
7. bootloader.atmega8.lock_bits(默认: 0x0F)锁住Bootloader区时向Arduino锁位写的值(这样Bootloader才不会被新上传的程序覆盖)

ATmegaBOOT.c

/**********************************************************/
/* Serial Bootloader for Atmel mega8 AVR Controller       */
/*                                                        */
/* ATmegaBOOT.c                                           */
/*                                                        */
/* Copyright (c) 2003, Jason P. Kyle                      */
/*                                                        */
/* Hacked by DojoCorp - ZGZ - MMX - IVR                   */
/* Hacked by David A. Mellis                              */
/*                                                        */
/* This program is free software; you can redistribute it */
/* and/or modify it under the terms of the GNU General    */
/* Public License as published by the Free Software       */
/* Foundation; either version 2 of the License, or        */
/* (at your option) any later version.                    */
/*                                                        */
/* This program is distributed in the hope that it will   */
/* be useful, but WITHOUT ANY WARRANTY; without even the  */
/* implied warranty of MERCHANTABILITY or FITNESS FOR A   */
/* PARTICULAR PURPOSE.  See the GNU General Public        */
/* License for more details.                              */
/*                                                        */
/* You should have received a copy of the GNU General     */
/* Public License along with this program; if not, write  */
/* to the Free Software Foundation, Inc.,                 */
/* 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA */
/*                                                        */
/* Licence can be viewed at                               */
/* http://www.fsf.org/licenses/gpl.txt                    */
/*                                                        */
/* Target = Atmel AVR m8                                  */
/**********************************************************/

#include <inttypes.h>
#include <avr/io.h>
#include <avr/pgmspace.h>
#include <avr/eeprom.h>
#include <avr/interrupt.h>
#include <util/delay.h>

//#define F_CPU            16000000

/* We, Malmoitians, like slow interaction
 * therefore the slow baud rate ;-)
 */
//#define BAUD_RATE        9600

/* 6.000.000 is more or less 8 seconds at the
 * speed configured here
 */
//#define MAX_TIME_COUNT    6000000
#define MAX_TIME_COUNT (F_CPU>>1)
///#define MAX_TIME_COUNT_MORATORY    1600000

/* SW_MAJOR and MINOR needs to be updated from time to time to avoid warning message from AVR Studio */
#define HW_VER     0x02
#define SW_MAJOR 0x01
#define SW_MINOR 0x12

// AVR-GCC compiler compatibility
// avr-gcc compiler v3.1.x and older doesn't support outb() and inb()
//      if necessary, convert outb and inb to outp and inp
#ifndef outb
    #define outb(sfr,val)  (_SFR_BYTE(sfr) = (val))
#endif
#ifndef inb
    #define inb(sfr) _SFR_BYTE(sfr)
#endif

/* defines for future compatibility */
#ifndef cbi
    #define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#endif
#ifndef sbi
    #define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
#endif

/* Adjust to suit whatever pin your hardware uses to enter the bootloader */
#define eeprom_rb(addr)   eeprom_read_byte ((uint8_t *)(addr))
#define eeprom_rw(addr)   eeprom_read_word ((uint16_t *)(addr))
#define eeprom_wb(addr, val)   eeprom_write_byte ((uint8_t *)(addr), (uint8_t)(val))

/* Onboard LED is connected to pin PB5 */
#define LED_DDR  DDRB
#define LED_PORT PORTB
#define LED_PIN  PINB
#define LED      PINB5


#define SIG1    0x1E    // Yep, Atmel is the only manufacturer of AVR micros.  Single source :(
#define SIG2    0x93
#define SIG3    0x07
#define PAGE_SIZE    0x20U    //32 words


void putch(char);
char getch(void);
void getNch(uint8_t);
void byte_response(uint8_t);
void nothing_response(void);

union address_union {
  uint16_t word;
  uint8_t  byte[2];
} address;

union length_union {
  uint16_t word;
  uint8_t  byte[2];
} length;

struct flags_struct {
  unsigned eeprom : 1;
  unsigned rampz  : 1;
} flags;

uint8_t buff[256];
//uint8_t address_high;

uint8_t pagesz=0x80;

uint8_t i;
//uint8_t bootuart0=0,bootuart1=0;


void (*app_start)(void) = 0x0000;

int main(void)
{
  uint8_t ch,ch2;
  uint16_t w;

  //cbi(BL_DDR,BL);
  //sbi(BL_PORT,BL);

  asm volatile("nop\n\t");

  /* check if flash is programmed already, if not start bootloader anyway */
  //if(pgm_read_byte_near(0x0000) != 0xFF) {

    /* check if bootloader pin is set low */
    //if(bit_is_set(BL_PIN,BL)) app_start();
  //}

  /* initialize UART(s) depending on CPU defined */
  /* m8 */
  UBRRH = (((F_CPU/BAUD_RATE)/16)-1)>>8;     // set baud rate
  UBRRL = (((F_CPU/BAUD_RATE)/16)-1);
  UCSRB = (1<<RXEN)|(1<<TXEN);  // enable Rx & Tx
  UCSRC = (1<<URSEL)|(1<<UCSZ1)|(1<<UCSZ0);  // config USART; 8N1

  //UBRRL = (uint8_t)(F_CPU/(BAUD_RATE*16L)-1);
  //UBRRH = (F_CPU/(BAUD_RATE*16L)-1) >> 8;
  //UCSRA = 0x00;
  //UCSRC = 0x86;
  //UCSRB = _BV(TXEN)|_BV(RXEN);


  /* this was giving uisp problems, so I removed it; without it, the boot
     works on with uisp and avrdude on the mac (at least). */
  //putch('\0');

  //uint32_t l;
  //uint32_t time_count;
  //time_count=0;

  /* set LED pin as output */
  sbi(LED_DDR,LED);
    for (i = 0; i < 16; i++) {
        outb(LED_PORT, inb(LED_PORT) ^ _BV(LED));
        _delay_loop_2(0);
    }
    
    //for (l=0; l<40000000; l++)
        //outb(LED_PORT, inb(LED_PORT) ^= _BV(LED));

  /* flash onboard LED three times to signal entering of bootloader */
  //for(i=0; i<3; ++i) {
    //for(l=0; l<40000000; ++l);
    //sbi(LED_PORT,LED);
    //for(l=0; l<40000000; ++l);
    //cbi(LED_PORT,LED);
  //}

 /* see comment at previous call to putch() */
 //putch('\0'); // this line is needed for the synchronization of the programmer

  /* forever */
  for (;;) {
    //if((inb(UCSRA) & _BV(RXC))){
    /* get character from UART */
        ch = getch();
        
        /* A bunch of if...else if... gives smaller code than switch...case ! */
    
        /* Hello is anyone home ? */ 
        if(ch=='0') {
          nothing_response();
        }
    
        /* Request programmer ID */
        /* Not using PROGMEM string due to boot block in m128 being beyond 64kB boundry  */
        /* Would need to selectively manipulate RAMPZ, and it's only 9 characters anyway so who cares.  */
        else if(ch=='1') {
            if (getch() == ' ') {
                putch(0x14);
                putch('A');
                putch('V');
                putch('R');
                putch(' ');
                putch('I');
                putch('S');
                putch('P');
                putch(0x10);
          }
        }
    
        /* AVR ISP/STK500 board commands  DON'T CARE so default nothing_response */
        else if(ch=='@') {
          ch2 = getch();
          if (ch2>0x85) getch();
          nothing_response();
        }
    
        /* AVR ISP/STK500 board requests */
        else if(ch=='A') {
          ch2 = getch();
          if(ch2==0x80) byte_response(HW_VER);        // Hardware version
          else if(ch2==0x81) byte_response(SW_MAJOR);    // Software major version
          else if(ch2==0x82) byte_response(SW_MINOR);    // Software minor version
          //else if(ch2==0x98) byte_response(0x03);        // Unknown but seems to be required by avr studio 3.56
          else byte_response(0x00);                // Covers various unnecessary responses we don't care about
        }
    
        /* Device Parameters  DON'T CARE, DEVICE IS FIXED  */
        else if(ch=='B') {
          getNch(20);
          nothing_response();
        }
    
        /* Parallel programming stuff  DON'T CARE  */
        else if(ch=='E') {
          getNch(5);
          nothing_response();
        }
    
        /* Enter programming mode  */
        else if(ch=='P') {
          nothing_response();
          // FIXME: modified only here by DojoCorp, Mumbai, India, 20050626
          //time_count=0; // exted the delay once entered prog.mode
        }
    
        /* Leave programming mode  */
        else if(ch=='Q') {
          nothing_response();
          //time_count=MAX_TIME_COUNT_MORATORY;     // once the programming is done, 
                                                // we should start the application
                                                // but uisp has problems with this,
                                                // therefore we just change the times
                                                // and give the programmer 1 sec to react
        }
    
        /* Erase device, don't care as we will erase one page at a time anyway.  */
        else if(ch=='R') {
          nothing_response();
        }
    
        /* Set address, little endian. EEPROM in bytes, FLASH in words  */
        /* Perhaps extra address bytes may be added in future to support > 128kB FLASH.  */
        /* This might explain why little endian was used here, big endian used everywhere else.  */
        else if(ch=='U') {
          address.byte[0] = getch();
          address.byte[1] = getch();
          nothing_response();
        }
    
        /* Universal SPI programming command, disabled.  Would be used for fuses and lock bits.  */
        else if(ch=='V') {
          getNch(4);
          byte_response(0x00);
        }
    
        /* Write memory, length is big endian and is in bytes  */
        else if(ch=='d') {
          length.byte[1] = getch();
          length.byte[0] = getch();
          flags.eeprom = 0;
          if (getch() == 'E') flags.eeprom = 1;
          for (w=0;w<length.word;w++) {
            buff[w] = getch();                            // Store data in buffer, can't keep up with serial data stream whilst programming pages
          }
          if (getch() == ' ') {
                if (flags.eeprom) {                        //Write to EEPROM one byte at a time
                    for(w=0;w<length.word;w++) {
                        eeprom_wb(address.word,buff[w]);
                        address.word++;
                    }            
                } else {                            //Write to FLASH one page at a time
                    //if (address.byte[1]>127) address_high = 0x01;    //Only possible with m128, m256 will need 3rd address byte. FIXME
                    //else address_high = 0x00;
            
                    //address.word = address.word << 1;            //address * 2 -> byte location
                    //if ((length.byte[0] & 0x01)) length.word++;    //Even up an odd number of bytes
                    cli();                    //Disable interrupts, just to be sure
                    while(bit_is_set(EECR,EEWE));            //Wait for previous EEPROM writes to complete
                    asm volatile(
                             "clr    r17        \n\t"    //page_word_count
                             "lds    r30,address    \n\t"    //Address of FLASH location (in words)
                             "lds    r31,address+1    \n\t"
                             "lsl r30                \n\t"  //address * 2 -> byte location
                             "rol r31                \n\t" 
                             "ldi    r28,lo8(buff)    \n\t"    //Start of buffer array in RAM
                             "ldi    r29,hi8(buff)    \n\t"
                             "lds    r24,length    \n\t"    //Length of data to be written (in bytes)
                             "lds    r25,length+1    \n\t"
                             "sbrs r24,0        \n\t"  //Even up an odd number of bytes
                             "rjmp length_loop        \n\t"
                             "adiw r24,1        \n\t"
                             "length_loop:        \n\t"    //Main loop, repeat for number of words in block                                                          
                             "cpi    r17,0x00    \n\t"    //If page_word_count=0 then erase page
                             "brne    no_page_erase    \n\t"                         
                             "rcall  wait_spm        \n\t"
//                             "wait_spm1:        \n\t"
//                             "lds    r16,%0        \n\t"    //Wait for previous spm to complete
//                             "andi    r16,1           \n\t"
//                             "cpi    r16,1           \n\t"
//                             "breq    wait_spm1       \n\t"
                             "ldi    r16,0x03    \n\t"    //Erase page pointed to by Z
                             "sts    %0,r16        \n\t"
                             "spm            \n\t"                             
                             "rcall  wait_spm        \n\t"
//                             "wait_spm2:        \n\t"
//                             "lds    r16,%0        \n\t"    //Wait for previous spm to complete
//                             "andi    r16,1           \n\t"
//                             "cpi    r16,1           \n\t"
//                             "breq    wait_spm2       \n\t"                                     
                             "ldi    r16,0x11    \n\t"    //Re-enable RWW section
                             "sts    %0,r16        \n\t"                                      
                             "spm            \n\t"
                             "no_page_erase:        \n\t"                             
                             "ld    r0,Y+        \n\t"    //Write 2 bytes into page buffer
                             "ld    r1,Y+        \n\t"                             
                                         
                             "rcall  wait_spm        \n\t"
//                             "wait_spm3:        \n\t"
//                             "lds    r16,%0        \n\t"    //Wait for previous spm to complete
//                             "andi    r16,1           \n\t"
//                             "cpi    r16,1           \n\t"
//                             "breq    wait_spm3       \n\t"
                             "ldi    r16,0x01    \n\t"    //Load r0,r1 into FLASH page buffer
                             "sts    %0,r16        \n\t"
                             "spm            \n\t"
                                         
                             "inc    r17        \n\t"    //page_word_count++
                             "cpi r17,%1            \n\t"
                             "brlo    same_page    \n\t"    //Still same page in FLASH
                             "write_page:        \n\t"
                             "clr    r17        \n\t"    //New page, write current one first
                             "rcall  wait_spm        \n\t"
//                             "wait_spm4:        \n\t"
//                             "lds    r16,%0        \n\t"    //Wait for previous spm to complete
//                             "andi    r16,1           \n\t"
//                             "cpi    r16,1           \n\t"
//                             "breq    wait_spm4       \n\t"
                             "ldi    r16,0x05    \n\t"    //Write page pointed to by Z
                             "sts    %0,r16        \n\t"
                             "spm            \n\t"
                             "rcall  wait_spm        \n\t"
//                             "wait_spm5:        \n\t"
//                             "lds    r16,%0        \n\t"    //Wait for previous spm to complete
//                             "andi    r16,1           \n\t"
//                             "cpi    r16,1           \n\t"
//                             "breq    wait_spm5       \n\t"                                     
                             "ldi    r16,0x11    \n\t"    //Re-enable RWW section
                             "sts    %0,r16        \n\t"                                      
                             "spm            \n\t"                              
                             "same_page:        \n\t"                             
                             "adiw    r30,2        \n\t"    //Next word in FLASH
                             "sbiw    r24,2        \n\t"    //length-2
                             "breq    final_write    \n\t"    //Finished
                             "rjmp    length_loop    \n\t"
                             
                             "wait_spm:  \n\t"
                             "lds    r16,%0        \n\t"    //Wait for previous spm to complete
                             "andi    r16,1           \n\t"
                             "cpi    r16,1           \n\t"
                             "breq    wait_spm       \n\t"
                             "ret            \n\t"
                             
                             "final_write:        \n\t"
                             "cpi    r17,0        \n\t"
                             "breq    block_done    \n\t"
                             "adiw    r24,2        \n\t"    //length+2, fool above check on length after short page write
                             "rjmp    write_page    \n\t"
                             "block_done:        \n\t"
                             "clr    __zero_reg__    \n\t"    //restore zero register
                             : "=m" (SPMCR) : "M" (PAGE_SIZE) : "r0","r16","r17","r24","r25","r28","r29","r30","r31");
            
                    /* Should really add a wait for RWW section to be enabled, don't actually need it since we never */
                    /* exit the bootloader without a power cycle anyhow */
                }
                putch(0x14);
                putch(0x10);
            }        
        }
    
        /* Read memory block mode, length is big endian.  */
        else if(ch=='t') {
          length.byte[1] = getch();
          length.byte[0] = getch();
          if (getch() == 'E') flags.eeprom = 1;
          else {
                flags.eeprom = 0;
                address.word = address.word << 1;            // address * 2 -> byte location
          }
          if (getch() == ' ') {                        // Command terminator
                putch(0x14);
                for (w=0;w < length.word;w++) {                // Can handle odd and even lengths okay
                    if (flags.eeprom) {                            // Byte access EEPROM read
                        putch(eeprom_rb(address.word));
                        address.word++;
                    } else {    
                        if (!flags.rampz) putch(pgm_read_byte_near(address.word));
                        address.word++;
                    }
                }
                putch(0x10);
          }
        }
    
        /* Get device signature bytes  */
        else if(ch=='u') {
          if (getch() == ' ') {
                putch(0x14);
                putch(SIG1);
                putch(SIG2);
                putch(SIG3);
                putch(0x10);
          }
        }
    
        /* Read oscillator calibration byte */
        else if(ch=='v') {
          byte_response(0x00);
        }
//    } else {
//            time_count++;
//            if (time_count>=MAX_TIME_COUNT) {
//                app_start();
//            }
//        }
    } /* end of forever loop */
}

void putch(char ch)
{
  /* m8 */
  while (!(inb(UCSRA) & _BV(UDRE)));
  outb(UDR,ch);
}

char getch(void)
{
  /* m8 */
    uint32_t count = 0;
  while(!(inb(UCSRA) & _BV(RXC))) {
        /* HACKME:: here is a good place to count times*/
        count++;
        if (count > MAX_TIME_COUNT)
            app_start();
  }
  return (inb(UDR));
}

void getNch(uint8_t count)
{
  uint8_t i;
  for(i=0;i<count;i++) {
    /* m8 */
    //while(!(inb(UCSRA) & _BV(RXC)));
    //inb(UDR);
        getch(); // need to handle time out
  }
}

void byte_response(uint8_t val)
{
  if (getch() == ' ') {
    putch(0x14);
    putch(val);
    putch(0x10);
  }
}

void nothing_response(void)
{
  if (getch() == ' ') {
    putch(0x14);
    putch(0x10);
  }
}

/* end of file ATmegaBOOT.c */

Relevant Link:

http://baike.baidu.com/link?url=J4DFm0Ge3ALiY0KwV9YG-Fvh8Skn06yyz00rUR_kliwGn2sGGU1ABF4Qw0IPMa2xoSHHiksad4sP3XeZiAxhta
http://bbs.elecfans.com/jishu_455272_1_1.html
http://wiki.geek-workshop.com/doku.php?id=arduino:hacking:bootloader

0x7: Bootloader烧写

1. 使用编程器将Bootloader烧写到falsh中
将Bootloader写入Flash,然后将烧写完毕的Flash插入板子上,这是针对Flash还没有插入板子的情形。编程器也叫device programmer,是对非易失性存储介质和其他电可编程设备进行编程的工具
传统的编程器,需要把Flash从电路板上取下来,插到编程器的接口上,以完成擦除和烧写。现在的编程器发展的方向是ISP(In-System Programming,在系统可编程),就是指电路板上的空白器件可以编程写入最终用户代码,而不需要从电路板上取下器件

2. 使用ADS软件和ARM仿真器
先将编译后的Flash烧写程序加载到SDRAM中,运行Flash烧写程序,在指定Flash烧写的起始地址后,Flash烧写程序将从电脑上把编译好的Bootloader映像烧写到Flash的指定位置

3. 使用Bootloader
这是针对Bootloader已经驻留在Flash的情形,可以通过Bootloader烧Bootloader,Bootloader之所以具有这种功能,是由Bootloader的分段执行特性决定的,当Bootloader在Flash中执行时,主要是把自身剩余的代码复制到SDRAM中,然后进入到SDRAM运行后就可以反过来更新Flash中的Bootloader映像了。如果Bootloader不分段一直在Flash中执行,同时又更新Flash中的数据,这样将造成逻辑错误

4. 处理器支持从ROM启动
有些厂商为了方便用户下载代码和调试,在其处理器内部集成了一个小的ROM,事先固化一小段代码。因为容量有限,代码的功能有限,一般只是初始化串口,然后等待从串口输入数据。这样,串口线实际上就成为了编程器的硬件连接了。比如,Cirrus Logic 的EP93XX系列,它内部集成了一个BootROM,固化代码初始化串口,支持从串口下载数据。那么在Host端只需要相应的开发一个相同串口协议的download程序,就可以完成bootloader(P93XX系列使用的是Redboot)烧写到Falsh里(这里的编程器就可以认为是download+RS-232交叉线),然后从Falsh启动,有Redboot进行下面的工作。因为Redboot实现了串口传输协议和TFTP协议,就可以通过RS-232来进行控制,通过Ethernet完成大的映象文件如kernel和fs的下载固化。这样,从硬件上电,到最后系统启动的所有环节就都很清晰了
ATMEL的AT91RM9200内部也集成了一个ROM,固化代码,同样初始化串口,启动串口传输协议Xmodem,等待输入。官方提供的loader就是完成把U-boot下载固化到flash里面。因为kernel和fs比较大,可以采用压缩,官方提供boot来完成从flash启动后自动解压过程。这样,从flash启动就慢了许多

5. 处理器不支持从ROM启动
还有些厂商为了节省ROM空间,提高集成度,不支持从ROM启动模式。比如三星公司的S3C2410等。这样一种简单的方法就是采用JTAG下载线作为编程器的硬件连接,完成其Bootloader(如Vivi)的烧写。在Windows环境下,针对JTAG硬件连接,编程器的软件有JFlash(JTAG for Flash),SJF,Flash Programmer等。在Linux环境下有JFlash的Linux版本(JFlash+JTAG下载线,S3C2410是提供JTAG接口的)

Relevant Link:

http://ackerman.iteye.com/blog/754053
http://blog.csdn.net/dyzhen/article/details/43580587

 

5. PWM(脉宽调制 Pulse Width Modulation)

脉宽调制(Pulse-Width Modulation,PWM)是利用微处理器的数字输出,来对模拟电路进行控制的一种非常有效的技术,通过对一系列脉冲的宽度进行调制,来等效的获得所需要的波形(含形状和幅值),即通过改变导通时间占总时间的比例,也就是占空比,达到调整电压和频率的目的
广泛应用在从测量、通信到功率控制与变换的许多领域中,用于调压调频,最突出的是针对各种类型的电机应用

0x1: 分类

随着电子技术的发展,出现了多种PWM技术,其中包括

1. 相电压控制PWM
2. 脉宽PWM
3. 随机PWM
4. SPWM(Sinusoidal PWM,正弦曲线PWM)
5. 线电压控制PWM

在镍氢电池智能充电器中采用的脉宽PWM法,它是把每一脉冲宽度均相等的脉冲列作为PWM波形,通过改变脉冲列的周期可以调频,改变脉冲的宽度或占空比可以调压,采用适当控制方法即可使电压与频率协调变化。可以通过调整PWM的周期、PWM的占空比而达到控制充电电流的目的
模拟信号的值可以连续变化,其时间和幅度的分辨率都没有限制。模拟信号与数字信号的区别在于后者的取值通常只能属于预先确定的可能取值集合之内,例如在{0V,5V}这一集合中取值
尽管模拟控制看起来可能直观而简单,但它并不总是非常经济或可行的。其中一点就是,模拟电路容易随时间漂移,因而难以调节。能够解决这个问题的精密模拟电路可能非常庞大、笨重(如老式的家庭立体声设备)和昂贵。模拟电路还有可能严重发热,其功耗相对于工作元件两端电压与电流的乘积成正比。模拟电路还可能对噪声很敏感,任何扰动或噪声都肯定会改变电流值的大小。
通过以数字方式控制模拟电路,可以大幅度降低系统的成本和功耗。此外,许多微控制器和DSP已经在芯片上包含了PWM控制器,这使数字控制的实现变得更加容易

0x2: 原理(冲量守恒原理)

对逆变电路开关器件的通断进行控制,使输出端得到一系列幅值相等的脉冲,用这些脉冲来代替正弦波或所需要的波形。也就是在输出波形的半个周期中产生多个脉冲,使各脉冲的等值电压为正弦波形,所获得的输出平滑且低次谐波少。按一定的规则对各脉冲的宽度进行调制,即可改变逆变电路输出电压的大小,也可改变输出频率
例如,把正弦半波波形分成N等份,就可把正弦半波看成由N个彼此相连的脉冲所组成的波形。这些脉冲宽度相等,都等于 ∏/n ,但幅值不等,且脉冲顶部不是水平直线,而是曲线,各脉冲的幅值按正弦规律变化。如果把上述脉冲序列用同样数量的等幅而不等宽的矩形脉冲序列代替,使矩形脉冲的中点和相应正弦等分的中点重合,且使矩形脉冲和相应正弦部分面积(即冲量)相等,就得到一组脉冲序列,这就是PWM波形。可以看出,各脉冲宽度是按正弦规律变化的。根据冲量相等效果相同的原理,PWM波形和正弦半波是等效的。对于正弦的负半周,也可以用同样的方法得到PWM波形
在PWM波形中,各脉冲的幅值是相等的,要改变等效输出正弦波的幅值时,只要按同一比例系数改变各脉冲的宽度即可,因此在交-直-交变频器中,PWM逆变电路输出的脉冲电压就是直流侧电压的幅值
根据上述原理,在给出了正弦波频率,幅值和半个周期内的脉冲数后,PWM波形各脉冲的宽度和间隔就可以准确计算出来。按照计算结果控制电路中各开关器件的通断,就可以得到所需要的PWM波形

0x3: 优点

1. PWM的一个优点是从处理器到被控系统信号都是数字形式的,无需进行数模转换。让信号保持为数字形式可将噪声影响降到最小。噪声只有在强到足以将逻辑1改变为逻辑0或将逻辑0改变为逻辑1时,也才能对数字信号产生影响
2. 对噪声抵抗能力的增强是PWM相对于模拟控制的另外一个优点,而且这也是在某些时候将PWM用于通信的主要原因。从模拟信号转向PWM可以极大地延长通信距离。在接收端,通过适当的RC或LC网络可以滤除调制高频方波并将信号还原为模拟形式
3. PWM既经济、节约空间、抗噪性能强,是一种值得广大工程师在许多设计应用中使用的有效技术

Relevant Link:

http://baike.baidu.com/link?url=OHjAPOBqtajBxSfE8vQ7Lc9FVCbdfBE9hGqoeKXhdfj2tIDnnWd1oXyax76Fc7UFHCrN0Mm238wlTm5ho78n6_

 

6. EEPROM

EEPROM(Electrically Erasable Programmable Read-Only Memory),电可擦可编程只读存储器,一种掉电后数据不丢失的存储芯片。 EEPROM 可以在电脑上或专用设备上擦除已有信息,重新编程。一般用在即插即用
EEPROM(带电可擦写可编程只读存储器)是用户可更改的只读存储器(ROM),其可通过高于普通电压的作用来擦除和重编程(重写)。不像EPROM芯片,EEPROM不需从计算机中取出即可修改。在一个EEPROM中,当计算机在使用的时候可频繁地反复编程,因此EEPROM的寿命是一个很重要的设计考虑参数。EEPROM是一种特殊形式的闪存,其应用通常是个人电脑中的电压来擦写和重编程
EEPROM一般用于即插即用(Plug & Play),常用在接口卡中,用来存放硬件设置数据,也常用在防止软件非法拷贝的"硬件锁"上面

0x1: 基本原理

由EPROM操作的不便,后来出的主板上BIOS ROM芯片大部分都采用EEPROM(Electrically Erasable Programmable ROM,电可擦除可编程ROM)。EEPROM的擦除不需要借助于其它设备,它是以电子信号来修改其内容的,而且是以Byte为最小修改单位,不必将资料全部洗掉才能写入,彻底摆脱了EPROM Eraser和编程器的束缚。EEPROM在写入数据时,仍要利用一定的编程电压,此时,只需用厂商提供的专用刷新程序就可以轻而易举地改写内容,所以,它属于双电压芯片。借助于EEPROM芯片的双电压特性,可以使BIOS具有良好的防毒功能,在升级时,把跳线开关打至"on"的位置,即给芯片加上相应的编程电压,就可以方便地升级;平时使用时,则把跳线开关打至"off"的位置,防止CIH类的病毒对BIOS芯片的非法修改。所以,至今仍有不少主板采用EEPROM作为BIOS芯片并作为自己主板的一大特色

Relevant Link:

http://baike.baidu.com/link?url=tZFa1CQMpXfPqsSuaRmez6k6NKqAn1c3XUl8pBBLJc5LZueQ4k8cnFHwMMxNP7nPdibyljRY3mJUURc-0I2A7_

 

7. LCD1602

0x1: 显示原理

通过电压来改变填充在两块平行板之间的液晶材料内部分子的排列状况,以达到遮光和透光的目的来显示深浅不一,错落有致的图象,而且只要在两块平板间再加上三元色的滤光层,就可实现显示彩色图象。液晶是具有流动特性的物质,所以只需外加很微小的力量即可使液晶分子运动,以最常见普遍的向列型液晶为例,液晶分子可轻易的借着电场作用使得液晶分子转向,由于液晶的光轴与其分子轴相当一致,故可借此产生光学效果,而当加于液晶的电场移除消失时,液晶将借着其本身的弹性及黏性,液晶分子将十分迅速的回撤消来未加电场前的状态

0x2: 显示特点

1. 显示质量高: 由于1602LCD每一个点在收到信号后就一直保持那种色彩和亮度,恒定发光,画质高且不会闪烁
2. 数字式接口: 1602液晶屏都是数字式的,和单片机系统的接口更加简单可靠,操作更加方便
3. 体积小、重量轻: 1602液晶模块通过显示屏上的电极控制液晶分子状态来达到显示的目的,在重量上比相同显示面积的传统显示屏要轻得多
4. 功耗低: 相对而言,1602液晶显示屏的功耗主要消耗在其内部的电极和驱动IC上,因而耗电量比其它显示屏要少得多

0x3: 电路图

1602LCD采用标准的14脚(无背光)或16脚(带背光)接口,各引脚接口说明如下表所示:

编号 符号 引脚说明 编号 符号 引脚说明
1 VSS 电源地 9 D2 数据
2 VDD 电源正极 10 D3 数据
3 VL 液晶显示偏压 11 D4 数据
4 RS 数据/命令选择 12 D5 数据
5 R/W 读/写选择 13 D6 数据
6 E 使能信号 14 D7 数据
7 D0 数据 15 BLA 背光源正极
8 D1 数据 16 BLK 背光源负极

1602液晶模块引脚说明:

第1脚:VSS为地电源。
第2脚:VDD接5V正电源
第3脚:VL为液晶显示器对比度调整端,接正电源时对比度最弱,接地时对比度最高,对比度过高时会产生"鬼影",使用时可以通过一个10K的电位器调整对比度
第4脚:RS为寄存器选择,高电平时选择数据寄存器、低电平时选择指令寄存器
第5脚:R/W为读写信号线,高电平时进行读操作,低电平时进行写操作。当RS和R/W共同为低电平时可以写入指令或者显示地址,当RS为低电平R/W为高电平时可以读忙信号,当RS为高电平R/W为低电平时可以写入数据
第6脚:E端为使能端,当E端由高电平跳变成低电平时,液晶模块执行命令
第7~14脚:D0~D7为8位双向数据线
第15脚:背光源正极
第16脚:背光源负极

0x4: 指令说明及时序

1602液晶模块内部的控制器共有11条控制指令,如下表所示

序号 指令 RS R/W D7 D6 D5 D4 D3 D2 D1 D0
1 清显示 0 0 0 0 0 0 0 0 0 1
2 光标返回 0 0 0 0 0 0 0 0 1 *
3 置输入模式 0 0 0 0 0 0 0 1 I/D S
4 显示开/关控制 0 0 0 0 0 0 1 D C B
5 光标或字符移位 0 0 0 0 0 1 S/C R/L * *
6 置功能 0 0 0 0 1 DL N F * *
7 置字符发生存贮器地址 0 0 0 1 字符发生存贮器地址
8 置数据存贮器地址 0 0 1 显示数据存贮器地址
9 读忙标志或地址 0 1 BF 计数器地址
10 写数到CGRAM或DDRAM) 1 0 要写的数据内容
11 从CGRAM或DDRAM读数 1 1 读出的数据内容

1602液晶模块的读写操作、屏幕和光标的操作都是通过指令编程来实现的。(说明:1为高电平、0为低电平)

指令1:清显示,指令码01H,光标复位到地址00H位置。
指令2:光标复位,光标返回到地址00H。
指令3:光标和显示模式设置 I/D:光标移动方向,高电平右移,低电平左移 S:屏幕上所有文字是否左移或者右移。高电平表示有效,低电平则无效。
指令4:显示开关控制。 D:控制整体显示的开与关,高电平表示开显示,低电平表示关显示 C:控制光标的开与关,高电平表示有光标,低电平表示无光标 B:控制光标是否闪烁,高电平闪烁,低电平不闪烁。
指令5:光标或显示移位 S/C:高电平时移动显示的文字,低电平时移动光标。
指令6:功能设置命令 DL:高电平时为4位总线,低电平时为8位总线 N:低电平时为单行显示,高电平时双行显示 F: 低电平时显示5x7的点阵字符,高电平时显示5x10的点阵字符。
指令7:字符发生器RAM地址设置。
指令8:DDRAM地址设置。
指令9:读忙信号和光标地址 BF:为忙标志位,高电平表示忙,此时模块不能接收命令或者数据,如果为低电平表示不忙。
指令10:写数据。
指令11:读数据。

0x5: 1602LCD的RAM地址映射及标准字库表

液晶显示模块是一个慢显示器件,所以在执行每条指令之前一定要确认模块的忙标志为低电平,表示不忙,否则此指令失效。要显示字符时要先输入显示字符地址,也就是告诉模块在哪里显示字符,下图是1602的内部显示地址(汇编编程思想)

Arduino、bootloader、BadUSB、及其相关硬件知识入门学习_第1张图片

例如第二行第一个字符的地址是40H,那么是否直接写入40H就可以将光标定位在第二行第一个字符的位置呢?这样不行,因为写入显示地址时要求最高位D7恒定为高电平1所以实际写入的数据应该是01000000B(40H)+10000000B(80H)=11000000B(C0H)。
在对液晶模块的初始化中要先设置其显示模式,在液晶模块显示字符时光标是自动右移的,无需人工干预。每次输入指令前都要判断液晶模块是否处于忙的状态。
1602液晶模块内部的字符发生存储器(CGROM)已经存储了160个不同的点阵字符图形,如图10-58所示,这些字符有:阿拉伯数字、英文字母的大小写、常用的符号、和日文假名等,每一个字符都有一个固定的代码
Relevant Link:

http://www.xyhlcd.com/proshow_486.html

 

8.  蜂鸣器、喇叭

0x1: 蜂鸣器

蜂鸣器的作用  蜂鸣器是一种一体化结构的电子讯响器,采用直流电压供电,广泛应用于计算机、打印机、复印机、报警器、电子玩具、汽车电子设备、电话机、定时器等电子产品中作发声器件。蜂鸣器主要分为压电式蜂鸣器和电磁式蜂鸣器两种类型

1. 电磁式蜂鸣器: 电磁式蜂鸣器由振荡器、电磁线圈、磁铁、震动膜片及外壳组成。接通电源后,振荡器产生的音频信号电流通过电磁线圈,使电磁线圈产生磁场,震动膜片在电磁线圈和磁铁的相互作用下,周期性地振动发声
2. 压电式蜂鸣器: 压电式蜂鸣器主要由多谐振荡器、压点蜂鸣片、阻抗匹配器及共鸣箱、外壳组成。有的压电式蜂鸣器外壳上还装有发光二极管。多谐振荡器由晶体管或集成电路构成,当接通电源后(5V ~ 15V直流工作电压),多谐振荡器起振,输出1.5 ~ 2.5kHZ的音频信号,阻抗匹配器推动压电蜂鸣片发声

蜂鸣器在电路中用字母"H"或"HA"(旧标准用"FM"、"LB"、"JD"等)表示

0x2: 有源蜂鸣器与无源蜂鸣器的区别
这里的“源”不是指电源。而是指震荡源。 也就是说,有源蜂鸣器内部带震荡源,所以只要一通电就会叫
而无源内部不带震荡源,所以如果用直流信号无法令其鸣叫。必须用2K~5K的方波去驱动它
有源蜂鸣器往往比无源的贵,就是因为里面多个震荡电路。
无源蜂鸣器的优点是:1.便宜,2.声音频率可控,可以做出“多来米发索拉西”的效果。3.在一些特例中,可以和LED复用一个控制口 有源蜂鸣器的优点是:程序控制方便
0x3: 扬声器

喇叭又叫扬声器,是一种十分常用的电声换能器件,在出声的电子电路中都能见到它
喇叭的种类繁多,而且价格相差很大。音频电能通过电磁、压电或静电效应,使其纸盆或膜片振动周围空气造成音响。按换能机理和结构分为

1. 动圈式(电动式): 电动式喇叭具有电声性能好、结构牢固、成本低等优点,应用广泛
2. 电容式(静电式)
3. 压电式(晶体或陶瓷)
4. 电磁式(压簧式)
5. 电离子式
6. 气动式喇叭等

按声辐射材料分为

1. 纸盆式
2. 号筒式
3. 膜片式

按纸盆形状分圆形、椭圆形、双纸盆和橡皮折环;按工作频率分低音、中音、高音,有的还分成录音机专用、电视机专用、普通和高保真喇叭等;按音圈阻抗分低阻抗和高阻抗;按效果分直辐和环境声等.

0x4: 扬声器(喇叭)工作原理

不同的喇叭工作原理是不一样的
最常见最典型的是纸盆式喇叭又称为动圈式喇叭它由三部分组成

1. 振动系统: 包括锥形纸盆、音圈和定心支片等
2. 磁路系统: 包括永义磁铁、导磁板和场心柱等
3. 辅助系统: 包括盆架、接线板、压边和防尘盖等。当处于磁场中的音圈有音频电流通过时,就产生随音频电流变化的磁场,这一磁场和永久磁铁的磁场发生相互作用,使音圈沿着轴向振动,由于喇叭结构简单、低音丰满、音质柔和、频带宽,但效率较低

Relevant Link:

http://www.hongyan-e.com/web/fmqyl.htm
http://baike.baidu.com/link?url=hIj5NFZGxccNjOFgCOq-1b9XfliSZva2PbDKU56lvBsfrcJeXT8V7qm-f9qL_d7_2pMsQLeNN_YTtjkmhJzXbK
http://baike.baidu.com/link?url=qRI9ZZP2fx7Lidn5Z375GMaeY1_DNGr53NgxaIvkz0vuaCWg_5hQEkp6WoLQ6eON7S5lZIbQyf1oQBLQHEHRoK 
http://baike.baidu.com/link?url=QIJICyXgqCAphS4YX0WMNPEPaW-oMa6WfuiciJxrMaUOYH5XdlebgVWQi8bHR5sk7zp3MjTX35XJkKcv5wBraK

 

9. 直流电机(direct current machine)

直流电机(direct current machine)是指能将直流电能转换成机械能(直流电动机)或将机械能转换成直流电能(直流发电机)的旋转电机。它是能实现直流电能和机械能互相转换的电机。当它作电动机运行时是直流电动机,将电能转换为机械能;作发电机运行时是直流发电机,将机械能转换为电能

0x1: 组成结构

直流电机的结构应由"定子"和"转子"两大部分组成

1. 直流电机运行时静止不动的部分称为定子,定子的主要作用是产生磁场,由机座、主磁极、换向极、端盖、轴承和电刷装置等组成
2. 运行时转动的部分称为转子,其主要作用是产生电磁转矩和感应电动势,是直流电机进行能量转换的枢纽,所以通常又称为电枢,由转轴、电枢铁心、电枢绕组、换向器和风扇等组成

1. 定子

Arduino、bootloader、BadUSB、及其相关硬件知识入门学习_第2张图片

1. 主磁极: 主磁极的作用是产生气隙磁场。主磁极由主磁极铁心和励磁绕组两部分组成 
    1) 铁心一般用0.5mm~1.5mm厚的硅钢板冲片叠压铆紧而成,分为极身和极靴两部分,上面套励磁绕组的部分称为极身,下面扩宽的部分称为极靴,极靴宽于极身,既可以调整气隙中磁场的分布,又便于固定励磁绕组
    2) 励磁绕组用绝缘铜线绕制而成,套在主磁极铁心上。整个主磁极用螺钉固定在机座上,
2. 换向极: 换向极的作用是改善换向,减小电机运行时电刷与换向器之间可能产生的换向火花,一般装在两个相邻主磁极之间,由换向极铁心和换向极绕组组成。换向极绕组用绝缘导线绕制而成,套在换向极铁心上,换向极的数目与主磁极相等
3. 机座: 电机定子的外壳称为机座。机座的作用有两个
    1) 固定主磁极、换向极和端盖,并起整个电机的支撑和固定作用;
    2) 机座本身也是磁路的一部分,借以构成磁极之间磁的通路,磁通通过的部分称为磁轭。为保证机座具有足够的机械强度和良好的导磁性能,一般为铸钢件或由钢板焊接而成。
4. 电刷装置: 电刷装置是用来引入或引出直流电压和直流电流的。电刷装置由电刷、刷握、刷杆和刷杆座等组成。电刷放在刷握内,用弹簧压紧,使电刷与换向器之间有良好的滑动接触,刷握固定在刷杆上,刷杆装在圆环形的刷杆座上,相互之间必须绝缘。刷杆座装在端盖或轴承内盖上,圆周位置可以调整,调好以后加以固定

2. 转子

Arduino、bootloader、BadUSB、及其相关硬件知识入门学习_第3张图片

1. 电枢铁心: 电枢铁心是主磁路的主要部分,同时用以嵌放电枢绕组,一般电枢铁心采用由0.5mm厚的硅钢片冲制而成的冲片叠压而成,以降低电机运行时电枢铁心中产生的涡流损耗和磁滞损耗。叠成的铁心固定在转轴或转子支架上。铁心的外圆开有电枢槽,槽内嵌放电枢绕组。
2. 电枢绕组: 电枢绕组的作用是产生"电磁转矩""感应电动势",是直流电机进行能量变换的关键部件,所以叫电枢。它是由许多线圈按一定规律连接而成,线圈采用高强度漆包线或玻璃丝包扁铜线绕成,不同线圈的线圈边分上下两层嵌放在电枢槽中,线圈与铁心之间以及上、下两层线圈边之间都必须妥善绝缘。为防止离心力将线圈边甩出槽外,槽口用槽楔固定。线圈伸出槽外的端接部分用热固性无纬玻璃带进行绑扎
3. 换向器: 在直流电动机中,换向器配以电刷,能将外加直流电源转换为电枢线圈中的交变电流,使电磁转矩的方向恒定不变;在直流发电机中,换向器配以电刷,能将电枢线圈中感应产生的交变电动势转换为正、负电刷上引出的直流电动势。换向器是由许多换向片组成的圆柱体,换向片之间用云母片绝缘
4. 转轴: 转轴起转子旋转的支撑作用,需有一定的机械强度和刚度,一般用圆钢加工而成 

Relevant Link:

http://baike.baidu.com/link?url=LpKxhOLQdhig_rIGLuMl5NqLd03-YBWfx_Ckj731-2cUl8P3MQglVFgz1_77Pj01Iz3uy1yiyIXwzdjvbqEqIa
http://www.dzkfw.com.cn/jichu/jidian/1276.html

 

10. USB接口芯片

Arduino UNO上搭载ATmega8U2/ATmega16U2 USB接口芯片,其特征包括

1. 8K/16K字节的Flash,支持自擦写功能。512字节EEPROM和512字节SRAM (8U和16U的不同处是Flash容量)
2. 内置Boot-Loader功能
3. 支持USB全速,包含4个USB输入输出端口
4. 包含内置晶振
5. 操作电压范围为2.7V~5.5V
    1) 2.7V时,最大工作频率是8MHz
    2) 4.5V时,最大工作频率是16MHz

Relevant Link:

http://blog.sina.com.cn/s/blog_89999fc70100zujs.html
http://www.atmel.com/zh/cn/Images/7799S.pdf
http://pdf.114ic.com/ATMEGA16U2.html

 

11. arduino系列产品

0x1: Arduino Leonardo atmega328p-pu

你可能感兴趣的:(Arduino、bootloader、BadUSB、及其相关硬件知识入门学习)