ARM体系结构的演变与发展

ARM公司简介

ARM(Advanced RISC Machine Limited)于1991年成立于英国剑桥,最早由Acorn、Apple和VLSI合资成立,主要出售芯片设计技术的授权。
ARM 公司不生产芯片,只是出售芯片设计方案。

ARM技术特征

体积小、低功耗、低成本、高性能。
支持32位ARM指令集和16位Thumb指令集
寄存器数量多,指令的执行速度快
寻址方式简单高效
大部分数据操作都在寄存器中完成
指令长度固定

ARM体系架构的发展历程

v1架构 地址空间采用26位寻址方式,寻址空间是64MB
v2架构 相比于v1架构,增加了乘法指令集。并且支持协处理器指令
v3架构 ARM处理器的体系架构实现了32位地址空间,完善了前面版本的指令结构
v4 增加了半字符指令的读取和写入操作,增加了处理器系统模式
v5 v架构的ARM处理器提升了ARM和Thumb两种指令的交互工作能力,通知有了DSP指令
v6 2001年发布的v6架构,在该版本中增加了媒体指令
v7 基于V6架构采用Thumb-2技术,他是在ARM的Thumb代码压缩技术基础上发展起来的,并保持了对现存ARM解决方案的完整的代码兼容性。
v8 在32位ARM架构上进行开发,v8包含两个执行状态:AArch64和AArch32。

Cortex-A9内核工作模式

Cortex-A9基于ARMv7-A架构,共有8种工作模式。

用户模式(user) 非特权模式,大多数的任务执行在此工作模式下
FIQ:快速中断模式 当一个高优先级(fast)中断产生时,会进入这种模式
IRQ:外部中断模式 当一个低优先级(normal)中断产生时,会进入这种模式
Supervisor:特权模式【权限最大】 当复位按键按下或者软中断指令执行时,将会进入SVC模式
Abort:数据访问指令终止 当存取异常时,将会进入这种模式
Undef:未定义指令终止模式 此时使用User模式相同寄存器集的特权模式
Monitor:监控模式【Crotex-A系列专有模式】 为了安全二扩展出来的用于执行安全监控代码的模式,也是一种特权模式

嵌入式系统:

嵌入式系统 = 嵌入式硬件 + 嵌入式软件
嵌入式软件分为:

裸机 APP
非裸机 APP + OS操作系统

嵌入式硬件分为:

控制器 CPU
输入设备 鼠标、键盘
输出设备 显示器、音响
存储器 内存、外存
运算器 ALU
总线 APB

存储器又被分为:

辅助存储器 硬盘、U盘、光盘 【CPU不能直接访问】
主存储器 内存SDRAM 【CPU可以直接访问】
高速缓存器 Cache 【CPU可直接访问】
寄存器 用来存放CPU在运算过程中的数据和结果值 【CPU可直接访问】
名称 功能
控制器 整个嵌入式设备的指挥部
运算器(ALU) 信息进行处理和运算的额部件
寄存器 运算器的数据被寄存在这里
CPU 控制器 + 运算器 + 寄存器组
SOC(System on Chip) 片上系统,指一块芯片上面集成了CPU和外围组件
总线(Bus) 连接嵌入式设备的各个模块,传输数据
flash 存储数据

SOC:

总线分为三类:

  • 控制总线
  • 数据总线
  • 地址总线

flash包括:

Nor Flash 既能存储数据,又能运行程序
Nand Flash 只能存储数据

甚么是处理器的内核?

内核等同与架构,而处理器的架构是由控制时序电路和ARM指令集/Thumb指令集组成的。

ARM指令集:32bit。当ARM内核处于ARM态时,使用ARM指令集
Thumb指令集:16bit。当ARM内核处于Thumb态时,使用Thumb指令集。

ARM启动后默认为ARM态,默认也是执行ARM指令集,只有当用户手动切换到Thumb态时,才会执行Thumb指令集。

处于ARM态的内核有8中工作模式

二进制 : M[4:0] 工作模式 介绍
10000 User:用户模式 非特权模式,大部分任务执行在这种工作模式下
10001 FIQ:快速中断模式 当一个高优先级(FAST)中断产生时,会进入这种模式。
10010 IRQ:外部中断模式 当一个低优先级(Normal)中断产生时,会进入这种模式。
10011 Supervisor:特权模式(权限最大) 当复位键按下或者软中断指令执行时,会进入SVC模式
10111 Abort:数据访问终止模式 当存取异常时会进入这种模式
11011 Undef:未定义指令中断模式 当执行未定义的指令时会进入这种模式
11111 System:系统模式 使用User模式相同

-------------------------------------------------------------------------------------------------

ARM指令集【汇编指令】

助记符 操作 助记符 操作
MOV 数据传送 AND 逻辑与&
MVN 数据取反传送 ORR 逻辑或|
ADD EOR 逻辑异或^
ADC 带进位的加 BIC 位清零
SUB CMP 比较
SBC 带错位的减 CMN 相反数比较
RSB 逆向减 TST 位测试
RSC 带错位的逆向减 TEQ 测试相等

1.MOV指令

语法格式:MOV {<cond>} {S} <Rd> , <shifter_operand>
例如:

MOV R0,#0X123        @R0=0X123
MOV R0,R1           @将R1寄存器的值赋值给R0

MOV指令主要完成以下的功能:

  • 将数据从一个寄存器传送至另一个寄存器
  • 将一个常数值传送到寄存器中
  • 实现单纯的移位操作:操作数*2^n相当于左移n位
    操作数/2^nX相当于右移动n位
  • 当PC指针(R15寄存器)用作目标寄存器Rd时,可以实现程序跳转
  • 当PC作为目标寄存器Rd且指令中有后缀’S’时,在执行跳转指令的同时也会改变CPSR状态寄存器的相应位。

3.ADD指令

4.ADC指令

5.SUB指令

6.SBC指令

7.AND指令

8.ORR指令

9.EOR指令

10.TST指令

寄存器介绍

寄存器(Register):用在指令执行过程中,存放运算数据和结果的一种容器


一共有40个寄存器,其中有5类特殊寄存器是用来做辅助计算使用的。
我只介绍重要的寄存器:

r13(SP):存放SP栈指针,常用作堆栈指针

r14(LR):在程序执行中断或者函数调用时,保存当前执行的指令的下一条指令的地址。

这里做一下说明:

指令流水线:
为了增加处理器的指令流速度,ARM7系列使用了3级流水线。程序执行时有一个PC(Program Counter,PC指针),它用来存放当前欲执行指令的地址。

三级流水线的执行分为三个步骤:

取指令—>译码—>编译

流水线执行就是在第一条指令进行编译的时候,同时第二条指令在进行译码,同时第三条指令正在从存储器种被读取。

得益于指令流水线,能够在同一时间执行多一条指令,所以会提高程序的执行效率。

r15(PC):程序的取值位置

程序的串行与并行:


正如汤老师所说:Obviously!并行比串行节省时间!

中间先省略

通信方式

并行通信 串行通信
并行速度快,但是占用IO口 串行比并行速度慢,但节省IO口

串口在通信过程中,一次只能传输一个比特的数据,其单位是bps(波特率)。

信道分类:

单工通信 只能由一方向另一方通信 而没有反方向的交互,eg:广播
半双工通信 双方都可以通信,但是同一时刻仅能有一方发送,另一方只能接收 eg:对讲机
全双工通信 通信双方能同时收发数据 eg:电话

数据单位

  1. 码元


  1. 波特率(Baud)
    波特率是马原传输速率的单位。1波特<==>每秒传输一个码元。
  2. 信息的传输速率:比特/秒(bit/s)
  3. 比特率与码元的传输速率"波特"在数量上有一定的关系。
  4. 若1个码元只携带1bit的信息量,此时bit/s = Baud
  5. 若一个码元携带n bit的信息量,则M Baud的码元传输速率所对应的信息传输速率为:M * n bit/s。

串行通信

1.同步通信方式

同步通信方式( Synchronous )所用的数据格式没有起始位、停止位,一次传送的字符个数可变。在传送前,先按照一定的格式将各种信息装配成一个包,该包包括供接收方识别用的同步字符一个或两个,其后紧跟着要传送的n个字符,再后就是校验字符。

2.异步通信方式

异步方式(Asynchronous) :也称“起止同步式”。

查看原理图,找到串口

开发板型号:华清远见FS4412_DEV_V5,基于三星ExynosF4412的ARM芯片,主频为1.4~1.6GHz。

首先对照原理图,找到UART口
这里使用的是板子上的COM2,对应原理图就是CON7

顺着串口的接线反向查找,会发现从ARM芯片引出的串口并不是直接接到9针的RS-232接口上面,而是先后经过两个小芯片:74ALVC164245DGG、SP3232EEA

为什么要这样接线?
答:因为ARM的标准工作电压是1.8V左右,而RS-232串口通信需要的电压在-15V~+15V这个区间:
1:在电路中用3-15V的正电压表示1
0:用-3~-15V的电压表示0

所以通常用+12V表示高电平’1’,用-12V表示低电平’0’
为了顺利实现通信,需要进行两次的电压转换,先将1.8V的电压通过74ALVC164245DGG芯片升高至3.3V左右,然后再使用SP3232EEA芯片将3.3V的电压继续抬高。实现0和1的转换。

配置寄存器

通过逆向查找最终我们找到了串口在芯片上的哪一个寄存器上。现在就需要打开ARM的芯片手册,查看相关寄存器的位介绍了。
下图为ARM芯片关于当前UART的引脚标识:


不难看出,我们所使用的UART串口需要在GPA1寄存器中进行配置。接下来就去查看GPX1寄存器。

如何查看芯片手册

以Exynos 4412的手册为例:
  1. 打开芯片手册,将手册的导航窗口打开,浏览并找到【General Purpose Input/Output (GPIO) Control】,直译过来就是:通用I/O控制,也就是通用寄存器。

  2. 选择这个通用I/O,你会看到里面又有分类:

  3. 我们可以看到开头是寄存器的概述,里面注明了寄存器名称、起始地址、简述以及复位后的初始值。但是这不是我们要找的,我们要找的是某一个寄存器的全部比特位的详细介绍,所以继续从列表中找,分别点开Part1、2、3、4部分,寻找我们的GPA1寄存器。

    很快啊!一下就找到了,就在第一部分的开头,可以看到有GPA1CON和GPA1DAT,下面还有一堆,发生甚么事了?这么多分类的嘛?

  4. 我们目前实现UART通信只需要配置GPA1CON控制寄存器。
    寄存器都是有32个bit位,但不一定都全部使用,有的寄存器只使用8位,有的使用16位,但是每一个寄存器都有32位。如下图所示,一个寄存器共引出8个引脚,也就是每4个bit位控制一个引脚的功能。
    所以理论上来说,每个引脚最大可以通过4个bit位提供2^4=16种功能选项,16进制也就是0-F。


    GPA1寄存器就仅仅使用了24个bit位,共输出6个引脚:GPA1CON[0]–GPA1CON[5]
    我们使用的UART是0引脚和1引脚,座椅只需要配置GPAICON[0]和GPA1CON[1]即可。

    配置将[3:0]–>(意思就是0bit至3bit位)设置为0x2
    [7:4]比特位也设置为0x2

  5. 如何配置

    我们要找到该寄存器的首地址,然后通过加上该位的偏移地址,就能得出寄存器的某一位在内存中的地址。最后将该地址经过与或非取反等一系列逻辑运算就能够将我们需要的位给设置好

//uart 寄存器
#define GPA1CON (* (volatile unsigned int *)0x11400020)
//bit7-bit4 === 2,    GPA1_1  配置为uart 2  的输出
//bit3-bit0 === 2,    GPA1_0  配置为uart 2  的输入

宏定义吧!我能理解;
无符号整型变量把!我也能理解;
但是你前面加的 volatile是个甚么意思?

解释:用volatile修饰的变量,是为了防止变量被编译器优化

CPU第一次读取数据时,是通过APB总线从内存中拿到数据,然后放在寄存器中,这样能够方便下次对数据的调用。所以当下一次CPU再次需要使用该数据时,它不会再去从内存中取数据,而是直接从寄存器中获取。

但是,寄存器一共就那么几个,当CPU处理很多数据时,最开始存入寄存器的该变量的值有可能会被重写,所以CPU再次使用时再从寄存其中调用该数据时,其实就已经发生了调用出错。

我们再=在声明的变量前面加上volatile关键字后,CPU每次使用该变量时都会去内存中调用,而不会去寄存器中获取。这就是防止被优化的意思。

  1. 配置ULCON2 帧格式控制寄存器
一帧8个bit位 [1:0] ----->0x11
无校验位 bit5 == 0
1个停止位 bit2 == 0
#define ULCON2 (* (volatile unsigned int *)0x13820000)
//帧格式控制
//bit5 ==0   无校验
//bit2 == 0  ,  1个停止位
//bit1--bit0 === 11            , 8个数据位

  1. 配置UCON2 ,UART的控制寄存器
    设置阻塞的发送和接收:
    [1:0]---->0x01
    [3:2]---->0x01
#define UCON2 (* (volatile unsigned int *)0x13820004)
//uart2 的控制寄存器
//bit3--bit2  ====   01          发送是阻塞模式
//bit1--bit0  ====   01          接收是阻塞模式

  1. UTRSTAT2寄存器,UART2的状态寄存器
    当发送结束后bit1会自动置为1,当接收成功后bit0会置为1。
    我们可以通过这两个位来判断发送和接收。
  2. UTXH2,发送buffer寄存器
  3. URXH2,接收buffer寄存器
#define UTXH2 (* (volatile unsigned int *)0x13820020)
//发送buffer 寄存器 , 写入该寄存器的值  被 uart2 发送出去 #define URXH2 (* (volatile unsigned int *)0x13820024)
//接收buffer 寄存器 ,   uart2 收到的数据保存在这里

  1. UBRDIV2,存储分频后的整数部分,控制波特率
    apb 总线的时钟是100m, uart 需要的工作时钟是11520016
    分频数 = 100m / (115200
    16) ======== 54.25 -1 ===== 53.25
#define UBRDIV2 (* (volatile unsigned int *)0x13820028)
//控制波特率的 ,    分频数 的 整数 部分      ==================53

  1. UFRACVAL2,控制波特率,存储分频数的小数部分。
#define UFRACVAL2 (* (volatile unsigned int *)0x1382002C)
//控制波特率的 ,    分频数 的 小数部分*16

代码实现(C和汇编混编)

通过虚拟机里面安装用于编译源码的交叉编译工具链 ,从而实现用C语言编写ARM的汇编语言。
将交叉编译工具链压缩文件拷贝至虚拟机的家目录,也就是cd后的那个目录。

拷贝gcc-4.6.4.tar.xz 到 用户家目录下,并解压tar -xvf gcc-4.6.4.tar.xz
进入解压后的gcc-4.6.4/bin 输入pwd 查看当前路径(如/home/你的虚拟机名/gcc-4.6.4/bin)
输入 export PATH=$PATH:/home/farsight/gcc-4.6.4/bin
想永远有效,需追加该行到当前用户启动脚本(~/.bashrc)的末尾,方法:
$ vim ~/.bashrc
在最后一行下面添加
export PATH=$PATH:/home/farsight/gcc-4.6.4/bin
:wq 保存退出
$ source ~/.bashrc
切换到别的目录, 输入arm-n ,按tab键能补全为arm-none-linux-gnueabi- 说明OK

配置完环境后开始编写代码:


#define GPX1CON (*(volatile unsigned int *)0x11000C20)  //LED2  [3:0]
#define GPX1DAT (*(volatile unsigned int *)0x11000C24)#define GPX2CON (*(volatile unsigned int *)0x11000C40)    //LED3 [31:28]
#define GPX2DAT (*(volatile unsigned int *)0x11000C44)#define GPF3CON (*(volatile unsigned int *)0x114001E0)    //LED4[19:16]
#define GPF3DAT (*(volatile unsigned int *)0x114001E4)  //LED5[23:20]//uart 寄存器
#define GPA1CON (* (volatile unsigned int *)0x11400020)
//bit7-bit4 === 2,    GPA1_1  配置为uart 2  的输出
//bit3-bit0 === 2,    GPA1_0  配置为uart 2  的输入#define ULCON2 (* (volatile unsigned int *)0x13820000)
//帧格式控制
//bit5 ==0   无校验
//bit2 == 0  ,  1个停止位
//bit1--bit0 === 11            , 8个数据位
#define UCON2 (* (volatile unsigned int *)0x13820004)
//uart2 的控制寄存器
//bit3--bit2  ====   01          发送是阻塞模式
//bit1--bit0  ====   01          接收是阻塞模式#define UTRSTAT2 (* (volatile unsigned int *)0x13820010)
//uart2  状态寄存器
//bit0 === 1?   1 , uart2 收到了数据
//bit1 === 1?   1 , 之前的数据发送完毕, 可以发新的数据
#define UTXH2 (* (volatile unsigned int *)0x13820020)
//发送buffer 寄存器 , 写入该寄存器的值  被 uart2 发送出去 #define URXH2 (* (volatile unsigned int *)0x13820024)
//接收buffer 寄存器 ,   uart2 收到的数据保存在这里 #define UBRDIV2 (* (volatile unsigned int *)0x13820028)
//控制波特率的 ,    分频数 的 整数 部分      ==================53#define UFRACVAL2 (* (volatile unsigned int *)0x1382002C)
//控制波特率的 ,    分频数 的 小数部分*16                  ============ 0.25*16  =======4//apb 总线的时钟是100m,  uart 需要的工作时钟是115200*16
//分频数 = 100m / (115200*16)  ======== 54.25  -1  ===== 53.25   /*ADC寄存器配置*/
#define ADCCON (* (volatile unsigned int *)0x126C0000)          //ADC3
/*bit16 = 1 ---> 12位分辨率*转换完成后bit15=1bit14 = 1---->ADC的工作时钟为APB总线时钟:100Mbit[13:6] = 19,ADC的最大工作频率为5M,因为他会自动加1,所以设置为19(100/(19+1) = 5)bit2 = 0 ---->Adc工作在normal模式bit1 = 0----->0=禁用读取启动操作1=启用按读启动操作bit0 = 1----->开始ADC转换,0:转换结束* */
#define ADCDAT (* (volatile unsigned int *)0x126C000C)#define ADCMUX (* (volatile unsigned int *)0x126C001C)/*宏定义蜂名气的IO口*/
#define GPD0CON (* (volatile unsigned int *)0x114000A0)         //GPD0_0-->0X2:TOUT_0 Timer_0的输出/*配置定时器0 PWM*/
//一级分频
#define TCFG0 (* (volatile unsigned int *)0x139D0000)//二级分频
#define TCFG1 (* (volatile unsigned int *)0x139D0004)//TCON定时器控制器
#define TCON (* (volatile unsigned int *)0x139D0008)//TCNTB0 计数寄存器
#define TCNTB0 (* (volatile unsigned int *)0x139D000C)//TCMPB0 比较寄存器
#define TCMPB0 (* (volatile unsigned int *)0x139D0010)void pwmInit(void)
{GPD0CON = GPD0CON & ~(0XF << 0);        //清空[3:0]GPD0CON = GPD0CON | (0X2 << 0);         //设置GPD0_0引脚为Timer0的输出口TCFG0 = TCFG0 & ~(0XFF << 0);         //将TCFG0一级分频寄存器的[7:0]置为0TCFG0 = TCFG0 | (199 << 0);              //一级分频/200TCFG1 = TCFG1 & ~(0XF << 0);           //由于使用的是定时器0,所以二级分频选择TCFG1的0引脚TCFG1 = TCFG1 | (2 << 0);              //4分频 1000hzTCON = TCON | (0X1 << 3);                //TCON的bit3置为1:自动重载模式TCON = TCON & ~(0X1 << 2);              //TCON的bit2置为0,输出电平不反转TCNTB0 = 125;                            //100M / 200 / 4 = 125000 ---> TCNTB0 = (1/f) / (1/F)TCMPB0 = 100;                            //站空比0.8                             PWM频率  2分频后的频率 ==>t/T }void  uartInit(void)       //uart初始化
{GPA1CON = GPA1CON & ~(0xf << 0);    //将GPA1CON寄存器的[3:0]位设置为0GPA1CON = GPA1CON | (0x2 << 0);      //将GPA1CON寄存器的[3:0]设置为2,UART_2_RXDGPA1CON = GPA1CON & ~(0XF << 4);   //将GPA1CON寄存器的[7:4]位设置为0GPA1CON = GPA1CON | (0x2 << 4);      //将GPA1CON寄存器的[7:4]位置为2,UART_2_TXDULCON2 = ULCON2 & ~(0x1 << 5);     //将ULCON2的bit5置为0:无校验ULCON2 = ULCON2 & ~(0x1 << 2);      //将ULCON2的bit2置为0:1个停止位ULCON2 = ULCON2 | (0x3 << 0);     //bit1,2 = 1,1; bit3,4,5 = 0,0,0UCON2 = UCON2 & ~(0x3 << 0);       //将UCON2寄存器的bit[1:0]置为0UCON2 = UCON2 | (0x1 << 0);           //将UCON2寄存器的bit[1:0]设置为1:阻塞模式UCON2 = UCON2 & ~(0x3 << 2);        //同理,[3:2]位置0UCON2 = UCON2 | (0x1 << 2);         //[3:2]位设为1:阻塞模式UBRDIV2 = 53;                      //波特率除数的整数部分UFRACVAL2 = 4;                     //小数部分
}void ADCInit()
{ADCCON = ADCCON | (1 << 16);        //设置ADC为12位分辨率2^12次方ADCCON = ADCCON | (1 << 14);     //设置ADC的工作时钟为APB总线时钟:100MADCCON = ADCCON & ~(0XFF << 6);     //将bit[13:6]清零ADCCON = ADCCON | (0X13 << 6);     //19ADCCON = ADCCON & ~(1 << 2);     //bit2=0ADCCON = ADCCON & ~(1 << 1);        //bit1=0ADCMUX = 0X3;     //使用ADC3通道}unsigned int ADCread()
{unsigned int i;ADCCON = ADCCON | (1 << 0);              //bit0=1   开始转换while(! (ADCCON & (0X1 << 15)));      //循环判断bit15是否=1,1:ADC开始//                    0:ADC关闭i = ADCDAT & 0XFFF;                               //将ADC的值赋值给变量ireturn i;
}void uartSend(char chr);
void DispADC(unsigned int adc)
{int tmp;uartSend(adc / 1000 + '0');tmp = adc % 1000;uartSend(tmp / 100 + '0');tmp = tmp % 100;uartSend(tmp / 10 + '0');uartSend(tmp % 10 + '0');uartSend(' ');}void uartSend(char chr)
{//UTRSTAT2     bit1 //UTRSTAT2while(! (UTRSTAT2 & (1 << 1 ))) ;  //阻塞的发送UTXH2 = chr;//UTXH2  = chr;
}char uartGet(void)
{char tmp;while(! (UTRSTAT2 & (1 << 0))) ;        //阻塞发送//UTRSTAT2     bit0  tmp = URXH2;return tmp;
}void myDelay()
{int i;for(i=0 ;i<200000 ;i++);
}void led2()
{   GPX1CON = GPX1CON & ~(15<<0);    //  清空GPD0控制寄存器的低四位GPX1CON = GPX1CON | (1<<0);       //将GPD0控制寄存器的最低位置为1,设置为Output模式GPX1DAT = GPX1DAT | (1<<0);//延时几秒myDelay();GPX1DAT = GPX1DAT & ~(1<<0);myDelay();
}void led3()
{GPX2CON = GPX2CON & ~(15<<28);GPX2CON = GPX2CON | (1<<28);GPX2DAT = GPX2DAT | (1<<7);myDelay();GPX2DAT = GPX2DAT & ~(1<<7);myDelay();
}void led4()
{GPF3CON = GPF3CON & ~(0xff<<16);GPF3CON = GPF3CON | (0x11<<16);GPF3DAT = GPF3DAT | (1<<4);myDelay();GPF3DAT = GPF3DAT & ~(1<<4);myDelay();
}void led5()
{   GPF3CON = GPF3CON & ~(0xff<<16);GPF3CON = GPF3CON | (0x11<<16);GPF3DAT = GPF3DAT | (1<<5);myDelay();GPF3DAT = GPF3DAT & ~(1<<5);myDelay();
}void BZ_ON()
{TCON = TCON | (0X1 << 1);       //更新计数器的值TCON = TCON & ~(0X1 << 1);      //关闭更新TCON = TCON | (0X1 << 0);                      //打开计数器
}void BZ_OFF()
{//TCON = TCON | (0X1 << 1);     //更新计数器的值//TCON = TCON & ~(0X1 << 1);        //关闭更新TCON = TCON & ~(0X1 << 0);                     //打开计数器//TCON = 0;                     //关闭计数器
}int main()
{char i;unsigned int j;uartInit();      //初始化uartADCInit();     //初始化ADCpwmInit();while(1){i = uartGet();j = ADCread();DispADC(j);if(i == 'a'){led2();        //led2闪烁DispADC(j);BZ_ON();if(j>0 && j <500){led3();led4();}uartSend(i + 1);}else if(i == 'b'){led3();BZ_OFF();if(j>=500 && j<2000){led4();led5();}uartSend(i + 1);}if(i == 'c'){if(j>=2000 && j<4500){led2();led3();led4();led5();}//uartSend((char)j);}else{continue;}}return 0;
}

代码实现的功能不仅仅是UART通信,还有ADC转换、LED闪烁。
链接文件、启动文件、Makefile我会打包上传,需要的请自取。
完整代码

先到这里。我困了。

嵌入式学习硬件篇------初识ARM相关推荐

  1. 嵌入式成长轨迹34 【嵌入式学习阶段】【ARM环境调试】【QT 移植环境及简单程序示例】---补充《ok6410 Qt移植百科全书》...

    更新版 http://www.cnblogs.com/zeedmood/archive/2012/12/08/2808393.html 书上提及的有这些,分别说明下,里边打*可以不弄:   Tslib ...

  2. 嵌入式成长轨迹33 【嵌入式学习阶段】【ARM环境调试】【在虚拟机下Ubuntu建立NFS网络文件系统】...

    更新版 http://www.cnblogs.com/zeedmood/archive/2012/12/08/2808376.html (以防参考资料链接无效,将所有参考文章都附后了,所以非常长;实际 ...

  3. 备赛电赛学习硬件篇(七):智能小车底板设计,暂时停更该系列

    一.智能小车底板 亚克力板和铝合金板直接用相对应的建模软件去设计然后发给厂商就行,设计方法和pcb大同小异,车的底板需要整体对于车有一个良好的了解,即需要知道这个车需要什么样的模块,每个模块之间的关系 ...

  4. 备赛电赛学习硬件篇(五):硬件框图、无线通信模块、OLED模块设计

    目录 一.硬件框图绘制 二.无线通信模块 三.OLED模块 一.硬件框图绘制 个人强烈推荐visionon, VisionOn是一款可免费使用,亦可免注册使用(不能在线存储)的在线类Visio制图软件 ...

  5. 备赛电赛学习硬件篇(一):电机部分

    目录 一.电机选型 二.电机的正反转,刹车  一.电机选型 1.电机类型 无刷电机较贵,但是静音且损耗小,由于霍尔元件的特殊性(不带霍尔需要转速高的时候才可以利用反电动势准确确定转子的位置,而带霍尔可 ...

  6. 备赛电赛学习硬件篇(四):红外光电测速传感器电路以及红外寻迹和避障电路设计

    目录 一.红外光电测速传感器模块 二.红外寻迹模块 三.红外避障模块 一.红外光电测速传感器模块 U2为一个施密特触发器,利用它规整波形,如2脚输入1.2V,如直接接入单片机可能会判断不准状态,但是经 ...

  7. 备赛电赛学习硬件篇(二):电源板电路设计

    目录 一.接口 二.稳压部分 三. 防反接电路 四.电流与线宽 一.接口 1.输入接口 要准

  8. 如何学习嵌入式系统(硬件篇),含51单片机学习资料

    学习嵌入式之前我们需要了解什么是嵌入式. (官方说法)嵌入式系统是一种专用的计算机系统,作为装置或设备的一部分.国内普遍认同的嵌入式系统定义为:以应用为中心,以计算机技术为基础,软硬件可裁剪,适应应用 ...

  9. 嵌入式-ARM-学习总结(1):初识ARM

    嵌入式-ARM-学习总结(1):初识ARM ARM的特点 冯诺依曼结构与哈佛结构 内存与外存 S5PV210的启动过程 ARM的7种工作模式 ARM汇编指令集 8种寻址方式 ARM的特点 ARM采用R ...

最新文章

  1. python单词词频字典_python利用多种方式来统计词频(单词个数)
  2. python 单例模式的四种创建方式
  3. Ubuntu16.04 php7.0+mysql5.7+apache2环境搭配
  4. .NET 排序 Array.SortT 实现分析
  5. qt客户端连接服务器不响应,qt判断tcp客户端是否连接服务器
  6. java字符串拼接例子_Java详解【String】+【StringBuilder vs StringBuffer】+【字符串拼接】...
  7. PHPcms框架的Webshell
  8. Ubuntu16.04 UltraEdit 安装破解使用
  9. 两个多变量分布间的KL散度+变分子编码
  10. linux系统小米球(ngrok)实现内网穿透
  11. matlab 求导的一个简单程序
  12. 扑克牌发牌游戏python_Python随机扑克牌生成器游戏
  13. http://blog.csdn.net/pizi0475/article/details/48286579 -------------(Collada 快速入门)
  14. 如何将base64码保存为图片
  15. 虚拟邮箱怎么设置方法_商务邮箱一般用什么邮箱正式?VIP邮箱名怎么设置好?...
  16. Node.js知识点整理之----Buffer类
  17. Office 365身份认证--深度解析(二)
  18. Go学习笔记 -- 方法
  19. [书籍翻译]12周撰写期刊文章 学术出版成功指南——第 6 周:加强结构
  20. 抠人像,只需要一个网站就够了

热门文章

  1. 宠物店会员管理系统| 宠物店小程序
  2. 加壳器第二部分,加壳器
  3. [清新]黄花菜花盛开的季节
  4. Vue2+VueRouter2+Webpack+Axios 构建项目实战2017重制版(十一)阶段性小结
  5. TCL发布两款可穿戴设备;中兴通讯推出第三代5G室内路由器;绘王联合制作《河岸》获棕榈泉国际短片电影节最佳动画奖 | 全球TMT...
  6. 华为千元旗舰迎GPU Turbo会员不限量升级,这件事很“吓人”
  7. 为什么许多计算机相关书籍都以动物做封面?
  8. storm流程——storm
  9. 卸载chrome浏览器_如何在Chrome,Firefox和其他浏览器中卸载扩展程序
  10. 数据输入流与数据输出流