01-第一个裸机程序led及其引申
目录
- 第一节 硬件知识_LED原理图
- 1、 点亮LED需要做的事情:
- 2、 LED原理图
- 第二节:S3C2440启动流程与GPIO
- 1、原理图中的net
- 2、看芯片手册
- 3、补充几个概念、补充S3C2440框架知识、启动过程知识
- 第三节:编写第一个程序点亮LED
- 1、几条汇编代码:
- 2、汇编程序为:
- 3、 编译、烧写程序
- 第四节:汇编与机器码
- 1、几个CPU寄存器名称(别称)的概念
- 2、查看机器码的方法:
- 4、 一个作业:
- 第5节:编程知识_进制
- 第6节:字节序和位操作
- 1、 字节序
- 2、 位操作
- (1) 移位:移位运算符可以在二进制的基础上对数字进行平移。
- (2) 取反:
- (3) 位与:
- (4) 位或:
- (5) 置位:这里举的例子是想要把bit7、8置为1
- (6) 清位:这里举的例子是想要把bit7、8置为0
- 第7讲:编写C程序控制LED
- 1、 C指针操作
- 2、 控制LED
- 第7节:几个汇编指令
- 1、 add和sub
- 2、BL:(branch and linlc)(跳转并返回)
- 3、ldm和stm(操作多个寄存器)
- 第9讲:解剖c程序的内部机制
- 第10节:完善LED程序_编写案件程序
- 1、 看门狗概念:
- 2、 led循环点亮三盏灯程序
- 3、编写按键程序
第一节 硬件知识_LED原理图
1、 点亮LED需要做的事情:
(1) 看原理图确定控制LED的引脚;
(2) 看主芯片手册,确定如何设置/控制引脚;
(3) 写程序。
2、 LED原理图
再改进:如果引脚能力不足,可以用三极管,使引脚仅起开关作用。
注:主芯片引脚输出高/低电平即可改变LED状态,所以我们不用去关心GPIO引脚输出的到底是3.3V还是1.2V。
第二节:S3C2440启动流程与GPIO
1、原理图中的net
注:韦东山的LED1的引脚为GPF4,我的友善之臂板子是GPB5;另外,所说的“输出I/O”指电平。
2、看芯片手册
GPBCON是端口配置寄存器,用来配置为输出引脚。设置GPBCON[11:10] = 0b01,GPB5配置为输出;注:[11:10]表示第11和第10位(位就是比特,就是bits,一个二进制就是一比特); 0b01中,0b表示二进制,01表示11和10这两位分别是01。就是说把0x400写入到GPBCON寄存器,即写到地址0x56000010上(0x400是用“寄存器位查看小工具”把第11位和第10位置为01得到的十六进制数)。
GPBDAT是端口数据寄存器,用来设置端口电平状态,方法为把0或1写到对应的位。设置GPBDAT[5] = 1,则输出高电平;设置GPBDAT=0,则输出低电平。就是说若输出高电平的话则把0x20写到地址0x56000014上,若输出低电平则把写到地址0x56000014上(0x20是第五位置为1得到的十六进制数)。
3、补充几个概念、补充S3C2440框架知识、启动过程知识
概念补充:
Nor flash 一般是小程序用,nand flash用于大程序;
GPIO就是通用I/O口;
SOC是system on chip片内系统;
SRAM(static read access memory静态随机存储器,RAM存储在断电后数据消失);
基地址即起始地址。
框架为:
启动过程:
(1) NOR启动:NOR Flash基地址为0,片内RAM地址为0x40000000;
过程为:CPU读出NOR上第1个指令(前4字节),然后执行,然后再读第2个指令(也是4字节),然后执行。以此一直执行。
(2) NAND 启动:片内4kRAM基地址为0
过程为:2440硬件把nand前4k内容复制到片内RAN,然后CPU从0地址取出第一条指令执行。
注意flash与SRAM的区别:
(1)FLASH是用来存储程序的,SRAM是用来存储程序运行中的中间变量(SRAM一般作为CPU的二级缓存)。
(2)flash写入的内容不会因电源关闭而失去,读取速度慢,成本较低,一般用作程序存储器或者低速数据读取的情况;
SRAM有最快的读写速度,但电源掉落后其内容也会失去,价格昂贵,一般用作cpu的二级缓存,内存条也不用这个,适合高速数据读取的场合。
两者的关系为flash为ROM,sram为RAM。
第三节:编写第一个程序点亮LED
1、几条汇编代码:
(可以理解[R1]表示的是内存的地址,(1)、(2)所说的“R1的值x”实际上是地址)
(1)LDR:读内存。格式为:LDR R0, [R1] (假设R1的值是x,读取地址x上的数据(4字节)保存到R0中)。
(2)STR:写内存命令。格式为:STR R0,[R1] (假设R1的值是x,把R0的值写到地址x中去(也是4字节))。
(3)B:跳转
(4)MOV:格式为:MOV R0,R1 (把R1的值给赋值给R0,R0 = R1)
MOV R0,#0x100 (就是R0 = 0x100)
(5)LDR R0,= 0x12345678 (这是伪指令,它会被拆分为几条真正的RAM指令,最终结果为:R0 = 0x12345678)
注意第(4)个指令MOV和第(5)个指令的区别:MOV的R1只能是简单数(立即数),比如#0x100。具体原因如下图:
2、汇编程序为:
(这是一个.S文件)
/*
*点亮LED:GPB5
*/.text
.global _start
_start:/*配置GPB5为输出引脚
*把0x400写到地址0x56000010
*我理解,0x56000010这个端口配置寄存器(包含所有的GPB)的地址给CPU的r1寄存器,再把0x400这个十六进制数给CPU的r0寄存器,再把r0的值给r1寄存器,则5这个口被激活
*/ldr r1, =0x56000010/*把0x56000010这个地址作为值给r1*/ldr r0, =0x400/*把0x400这个地址作为值给r0。或者用mov r0, #0x400*/str r0, [r1]/*把r0的值写到r1的地址中去*//*设置GPB5输出高电平
*把0写到地址0x56000014
*/ldr r1, =0x56000014/*把0x56000014这个地址给r1*/ldr r0, =0/*把0这个地址给r0*/str r0, [r1]/*把r0的值写到r1的地址中去*//*死循环*/
halt:b halt
3、 编译、烧写程序
韦东山是用的在线远程Ubuntu系统,我用的是我电脑上的Ubuntu系统:
写好的汇编程序,要在Ubuntu中输入以下指令分别进行编译、链接、转bin文件
arm-linux-gcc -c -o led_on.o led_on.S
arm-linux-ld -Ttext 0 led_on.o -o led_on.elf
arm-linux-objcopy -O binary -S led_on.elf led_on.bin
注:为了方便,可以用makefile
第四节:汇编与机器码
1、几个CPU寄存器名称(别称)的概念
pc(program cunter程序计数器):把一个地址写到R15寄存器(也就是pc寄存器)中去的时候,程序就跳到那个地址去。
当执行一条指令时,首先需要根据PC中存放的指令地址,将指令由内存取到指令寄存器中,此过程称为“取指令”。与此同时,PC中的地址或自动加1或由转移指针给出下一条指令的地址。此后经过分析指令,执行指令。完成第一条指令的执行,而后根据PC取出第二条指令的地址,如此循环,执行每一条指令。
lr(link register返回地址):当一个函数执行结束后,要返回刚开始的地址,这个寄存器就是存放这个地址的。
sp(stack pointer):栈指针
2、查看机器码的方法:
在Ubuntu系统执行命令:
arm-linux-objdump -D led_on.elf > led_on.dis
把led_on.dis文件(反汇编文件)用notepad++打开
注:编译器把汇编码转换为机器码,机器码就是bin文件里的内容
led_on.dis如下:
bin文件要用UltraEdit这个软件打开如下:
对于上面这一副图片中蓝色框选的部分,[0x1c]是地址,地址中的内容是下面蓝色横线中的0x000050。
ldr r1,[pc,#20]的意思就是把0x5000050存到r1中去。
4、 一个作业:
直接在上面的led_on.bin文件(机器码)做修改,使得led2点亮。注:led2的引脚为GPB6。若写汇编程序则应该将前面汇编编码的“ldr r0, = 0x400”换成ldr r0, = 0x1000
作业答案如下:
我们需要直接修改机器码,就相当于是把汇编码中的mov r0,#0x400 转换为mov r0,#0x1000,即确定mov r0,#0x1000的机器码。
先打开ARM架构手册(ARM Architecture Reference Manual.pdf)查看MOV指令机器码的结构:
Shifter_operand是立即数,由rotate(4位)和immed(8位)两部分组成。如果确定了rotate和immed的值那么机器码就确定了。确定rotate和immed方法如下:
比如说,我们要确定mov r0,#0x1000的机器码,方法如下:
0x1000的二进制为:
第12位为1,也就是说需要由00000001(注:immed是始终等于1的)到第12位为1需要循环右移20位,20/2=10,也就是说rotate为10(即1010),即其立即数为1010 0000 0001;然后把e3a00b01(这是GPB5的)的二进制的后12为位的立即数改成1010 0000 0001就得到了mov r0,#0x1000的机器码0xe3a00a01,然后把led1的bin文件的e3a00b01替换为e3a00a01,led2就亮了。
第5节:编程知识_进制
1、 在windows cmd命令中输入calc就会弹出计算器。Windows计算器中的程序员计算器可以进行进制的转换
2、 N进制逢n进1
3、 为什么引入二进制?
因为晶体管只有2个状态(on:1;off : 0),数据使用多个晶体管表示,使用二进制可以与硬件的晶体管对应,如:8bit数据如下图表示:
为什么用八进制?答案如下图:
如何快速地转换2/8/16进制:
二进制到8/16进制,用8421法,8进制是3位一组(421),然后相加;16进制是4位一组(8421),然后相加。
8/16进制到二进制,是把8进制的每位展开为3位2进制数,把16进制数的每位展开为4位2进制数。
C语言各种进制表示方法:
第6节:字节序和位操作
1、 字节序
一般的arm芯片默认是小字节序,对于2440可以设置某个寄存器来设置使用小字节序还是大字节序。注:下面图片中的A就是低地址,A+3是高地址。
2、 位操作
(1) 移位:移位运算符可以在二进制的基础上对数字进行平移。
左移运算是将一个二进制位的操作数按指定移动的位数向左移动,移出位被丢弃,右边移出的空位一律补0。右移运算是将一个二进制位的操作数按指定移动的位数向右移动,移出位被丢弃,左边移出的空位一律补0,或者补符号位,这由不同的机器而定。在使用补码作为机器数的机器中,正数的符号位为0,负数的符号位为1。
左移n位就相当于乘以2的n次方;右移n位相当于除以2的n次方。具体这样算的原因是,左移了以后,剩下的所有值的权重增加了;右移了以后,剩下的所有值的权重减少加了。
(2) 取反:
(3) 位与:
(4) 位或:
(5) 置位:这里举的例子是想要把bit7、8置为1
(6) 清位:这里举的例子是想要把bit7、8置为0
第7讲:编写C程序控制LED
1、 C指针操作
(1) 变量和指针的原理
(2) 指针的使用方法
2、 控制LED
所以由上得到main函数:
int main() {unsigned *pGPBCON = 0x56000010;unsigned *pGPBDAT = 0x56000014;*pGPBCON = 0x400;*pGPBDAT = 0;return 0;
}
那么问题来了:
(1)写出了main函数之后,谁来调用它;
(2)main函数中的变量(pGPBCON、pGPBDAT)保存在内存中,这个内存地址是多少?
怎么来回答呢,我们写一个汇编程序,新建文件start.S,用于给main函数设置内存和调用main函数,写程序如下:
注:普及一下sp指针 在随机存储器区划出一块区域作为堆栈区,数据可以一个个顺序地存入(压入)到这个区域之中,这个过程称为‘压栈’(push)。通常用一个指针(堆栈指针SP—StackPointer)实现做一次调整,SP总指向最后一个压入堆栈的数据所在的数据单元(栈顶)。从堆栈中读取数据时,按照堆栈指针指向的堆栈单元读取堆栈数据,这个过程叫做 ‘弹出’(pop ),每弹出一个数据,SP 即向相反方向做一次调整,如此就实现了后进先出的原则。
在Ubuntu中执行:(注:我编写的led.c和start.S)
arm-linux-gcc -c -o led.o led.carm-linux-gcc -c -o start.o start.Sarm-linux-ld -Ttext 0 start.o led.o -o led.elfarm-linux-objcopy -O binary -S led.elf led.binarm-linux-objdump -D led.elf > led.dis
至于为什么这样操作(.c文件+.S文件两个文件),原因见下一节。
第7节:几个汇编指令
执行arm-linux-objdump -D led.elf > led.dis得到反汇编文件led.dis并用notepad打开,如下:
1、 add和sub
sub r0 , r1 , #4 意为r0 = r1 – 4
sub r0, r1 , r2 意为r0 = r1 – r2
add r0, r1 , #4 意为 r0 = r1 +4
2、BL:(branch and linlc)(跳转并返回)
注:返回地址就是下一条指令的地址。
3、ldm和stm(操作多个寄存器)
下图中ia、db的意思:
过后增加(Increment After)、预先增加(Increment Before)、过后减少(Decrement After)、预先减少(Decrement Before)。
对下面这两幅图注解:
db表示先减后存,假设sp=4096,则需要先减为4092再存。存的时候规则是高编号寄存器存高地址,即pc(r15)先存,存入内存中的4092~4095。然后依次是lr、ip、fp的存储
下面这两幅图片讲的是ldmid sp,{fp,sp,pc}
第9讲:解剖c程序的内部机制
分析start.S和led.c,剖析其内部机制,把程序的反汇编搞明白就理解了C程序的内部机制:
提出以下五个问题:
先补充一下理论知识:
(1)r0-r3寄存器是传参和传递函数返回值。用于调用者和被调用者之间的参数传递。
(2)r4-r11寄存器,在你的函数中有可能其中的一些会被用到。入口处保存,出口处恢复。
看上面的反汇编,mov sp, #4096,说明这是nand启动,程序(即机器码)拷贝到片内4k内存,从片内内存的0地址开始存放(e3a0da01存放到0地址,依次储存)。
注:反汇编中的00000000<.comment>不存放。comment是注释。
一上电,执行0地址的e3a0da01,即sp指到4096.然后执行eb0000000,即跳转到c地址(去执行main()),并把返回地址8赋予lr寄存器。
现在来分析主函数反汇编语言,看下图。(注意,下图是对主函数反汇编的解释,你需要同时结合着下下一幅图一块看,看主函数在内存上的机制。如stmdb sp!,{fp,ip,lr,pc}在内存上的机制是在下下图从左往右数的第三个内存图)
对于10地址语句stmdb sp!,{fp,ip,lr,pc}进行注解:
(1)pc=当前指令地址+8,所以pc=10+8=0x18;
(2)上图已经说了lr=8;
(3)fp是未定义值。
下图是片内4k内存的分析:
结合上图和下面这幅图,你会看到:机器码存到了内存中的位置,寄存器如何存到内存中,局部变量是如何存到栈中。最重要的是,结合上下两幅图,你会明白你控制led时对端口配置寄存器和端口状态寄存器所进行的操作,在内存中是如何进行的。
从以上可知:所谓栈就是sp寄存器指向的内存。
注:关于第五个问题,怎么从栈中恢复寄存器。反汇编中内存地址54-57、58-61两个语句就是恢复内存的。
还有一个问题是,怎么传参数到被调用函数(main())的?下面写一个程序进行验证。
start.S文件
.text
.global _start_start:/* 设置内存: sp 栈 */ldr sp, =4096 /* nand启动 */
// ldr sp, =0x40000000+4096 /* nor启动 */mov r0, #4/*把4赋给r0寄存器,也就是把4传入led_on(int which)中的形参*/bl led_onldr r0, =100000/*传参*/bl delaymov r0, #5/*传参*/bl led_onhalt:b halt
led.c文件
void delay(volatile int d)/*volatile的作用是作为指令关键字,确保本条指令不会因编译器的优化而省略*/
{while (d--);
}int led_on(int which)
{unsigned int *pGPFCON = (unsigned int *)0x56000050;unsigned int *pGPFDAT = (unsigned int *)0x56000054;if (which == 4){/* 配置GPF4为输出引脚 */*pGPFCON = 0x100;}else if (which == 5){/* 配置GPF5为输出引脚 */*pGPFCON = 0x400;}/* 设置GPF4/5输出0 */*pGPFDAT = 0;return 0;
}
现在将上面这个start.S和led_on编译完成后,生成一个反汇编文件并查看,如下:
led.elf: file format elf32-littlearmDisassembly of section .text:00000000 <_start>:0: e3a0da01 mov sp, #4096 ; 0x10004: e3a00004 mov r0, #4 ; 0x48: eb000012 bl 58 <led_on>c: e59f000c ldr r0, [pc, #12] ; 20 <.text+0x20>/*注:地址20的000186a0转成十进制是10000*/10: eb000003 bl 24 <delay>14: e3a00005 mov r0, #5 ; 0x518: eb00000e bl 58 <led_on>0000001c <halt>:1c: eafffffe b 1c <halt>20: 000186a0 andeq r8, r1, r0, lsr #1300000024 <delay>:24: e1a0c00d mov ip, sp28: e92dd800 stmdb sp!, {fp, ip, lr, pc}2c: e24cb004 sub fp, ip, #4 ; 0x430: e24dd004 sub sp, sp, #4 ; 0x434: e50b0010 str r0, [fp, #-16]38: e51b3010 ldr r3, [fp, #-16]3c: e2433001 sub r3, r3, #1 ; 0x140: e50b3010 str r3, [fp, #-16]44: e51b3010 ldr r3, [fp, #-16]48: e3730001 cmn r3, #1 ; 0x14c: 0a000000 beq 54 <delay+0x30>50: eafffff8 b 38 <delay+0x14>54: e89da808 ldmia sp, {r3, fp, sp, pc}00000058 <led_on>:58: e1a0c00d mov ip, sp5c: e92dd800 stmdb sp!, {fp, ip, lr, pc}60: e24cb004 sub fp, ip, #4 ; 0x464: e24dd00c sub sp, sp, #12 ; 0xc68: e50b0010 str r0, [fp, #-16]6c: e3a03456 mov r3, #1442840576 ; 0x5600000070: e2833050 add r3, r3, #80 ; 0x5074: e50b3014 str r3, [fp, #-20]78: e3a03456 mov r3, #1442840576 ; 0x560000007c: e2833054 add r3, r3, #84 ; 0x5480: e50b3018 str r3, [fp, #-24]84: e51b3010 ldr r3, [fp, #-16]88: e3530004 cmp r3, #4 ; 0x48c: 1a000003 bne a0 <led_on+0x48>90: e51b2014 ldr r2, [fp, #-20]94: e3a03c01 mov r3, #256 ; 0x10098: e5823000 str r3, [r2]9c: ea000005 b b8 <led_on+0x60>a0: e51b3010 ldr r3, [fp, #-16]a4: e3530005 cmp r3, #5 ; 0x5a8: 1a000002 bne b8 <led_on+0x60>ac: e51b2014 ldr r2, [fp, #-20]b0: e3a03b01 mov r3, #1024 ; 0x400b4: e5823000 str r3, [r2]b8: e51b3018 ldr r3, [fp, #-24]bc: e3a02000 mov r2, #0 ; 0x0c0: e5832000 str r2, [r3]c4: e3a03000 mov r3, #0 ; 0x0c8: e1a00003 mov r0, r3cc: e24bd00c sub sp, fp, #12 ; 0xcd0: e89da800 ldmia sp, {fp, sp, pc}
Disassembly of section .comment:00000000 <.comment>:0: 43434700 cmpmi r3, #0 ; 0x04: 4728203a undefined8: 2029554e eorcs r5, r9, lr, asr #10c: 2e342e33 mrccs 14, 1, r2, cr4, cr3, {1}10: Address 0x10 is out of bounds.
第10节:完善LED程序_编写案件程序
1、 看门狗概念:
看门狗定时器(WDT,Watch Dog Timer)是单片机的一个组成部分,它实际上是一个计数器,一般给看门狗一个数字,程序开始运行后看门狗开始从这个数字开始倒计时计数。倒计时到0的时候系统便会复位。
2、 led循环点亮三盏灯程序
start.S文件
.text
.global _start_start:/* 关闭看门狗 */ldr r0, =0x53000000ldr r1, =0str r1, [r0]/* 设置内存: sp 栈 *//* 分辨是nor/nand启动* 写0到0地址, 再读出来* 如果得到0, 表示0地址上的内容被修改了, 它对应ram, 这就是nand启动* 否则就是nor启动*/mov r1, #0ldr r0, [r1] /* 读出原来的值备份 */str r1, [r1] /* 0->[0] */ ldr r2, [r1] /* r2=[0] */cmp r1, r2 /* r1==r2? 如果相等表示是NAND启动 */ldr sp, =0x40000000+4096 /* 先假设是nor启动 */moveq sp, #4096 /* nand启动 */streq r0, [r1] /* 恢复原来的值 */bl mainhalt:b halt
main.c
void delay(volatile int d)
{while (d--);
}int main(void)
{volatile unsigned int *pGPFCON = (volatile unsigned int *)0x56000050;volatile unsigned int *pGPFDAT = (volatile unsigned int *)0x56000054;int val = 0; /* val: 0b000, 0b111 */int tmp;/* 设置GPFCON让GPF4/5/6配置为输出引脚 */*pGPFCON &= ~((3<<8) | (3<<10) | (3<<12));//清零*pGPFCON |= ((1<<8) | (1<<10) | (1<<12));//置一/* 循环点亮 */while (1){tmp = ~val;tmp &= 7;*pGPFDAT &= ~(7<<4);//清零*pGPFDAT |= (tmp<<4);delay(100000);val++;if (val == 8)val = 0;}return 0;
}
对上面的led.c进行改进:把寄存器定义为一个宏,并且把宏直接放到一个头文件中。这样更方便了。
改变如下:
#include "s3c2440_soc.h"/*
s3c2440_soc.h中包含:
#define GPFCON (*((volatile unsigned int *)0x56000050))
#define GPFDAT (*((volatile unsigned int *)0x56000054))
*/void delay(volatile int d)
{while (d--);
}int main(void)
{int val = 0; /* val: 0b000, 0b111 */int tmp;/* 设置GPFCON让GPF4/5/6配置为输出引脚 */GPFCON &= ~((3<<8) | (3<<10) | (3<<12));GPFCON |= ((1<<8) | (1<<10) | (1<<12));/* 循环点亮 */while (1){tmp = ~val;tmp &= 7;GPFDAT &= ~(7<<4);GPFDAT |= (tmp<<4);delay(100000);val++;if (val == 8)val =0;}return 0;
}
3、编写按键程序
首先看原理图,找按键对应的端口寄存器,再对该寄存器进行操作。
key_led.c
#include "s3c2440_soc.h"void delay(volatile int d)
{while (d--);
}int main(void)
{int val1, val2;/* 设置GPFCON让GPF4/5/6配置为输出引脚 */GPFCON &= ~((3<<8) | (3<<10) | (3<<12));GPFCON |= ((1<<8) | (1<<10) | (1<<12));/* 配置3个按键引脚为输入引脚:* GPF0(S2),GPF2(S3),GPG3(S4)* 注:00为input*/GPFCON &= ~((3<<0) | (3<<4)); /* gpf0,2 */GPGCON &= ~((3<<6)); /* gpg3 *//* 循环点亮 */while (1){val1 = GPFDAT;val2 = GPGDAT;if (val1 & (1<<0)) /* s2 --> gpf6 */{/* 松开 */GPFDAT |= (1<<6);}else{/* 按下 */GPFDAT &= ~(1<<6);}if (val1 & (1<<2)) /* s3 --> gpf5 */{/* 松开 */GPFDAT |= (1<<5);}else{/* 按下 */GPFDAT &= ~(1<<5);}if (val2 & (1<<3)) /* s4 --> gpf4 */{/* 松开 */GPFDAT |= (1<<4);}else{/* 按下 */GPFDAT &= ~(1<<4);}}return 0;
}
01-第一个裸机程序led及其引申相关推荐
- OpenRisc-14-or1200第一个裸机程序
经过前面千辛万苦.爬山涉水.纠结了好久才弄好的环境,现在我们终于可以把FPGA当成个单片机使了,稍微比单片机猛一点,但是绝对比单片机贵一个数量级,FPGA现在能完成由CPU做的事,我们就把它当成一个大 ...
- OpenRics-14-or1200第一个裸机程序
经过前面千辛万苦.爬山涉水.纠结了好久才弄好的环境,现在我们终于可以把FPGA当成个单片机使了,稍微比单片机猛一点,但是绝对比单片机贵一个数量级,FPGA现在能完成由CPU做的事,我们就把它当成一个大 ...
- 第三章 裸机_第一个裸机程序(上)
第一章 裸机调试入门知识 1.对于友善之臂Micro2440开发板进行裸机调试时,需要将启动FLASH选项开关拨动到NOR FLASH上.这样做的原因:裸机程序里面会包含很多的初始化,这些初始化一般都 ...
- 零起点学算法01——第一个程序Hello World!
零起点学算法01--第一个程序Hello World! Description 题目很简单 输出"Hello World!"(不含引号),并换行. Input 没有输入 Outpu ...
- iar 连接linux开发板,LED裸机程序(IAR)
LED裸机程序(IAR) 一.实验环境 开发环境:IAR5.30 开发板:UT-S3C6410 开发工具:JLINK V8 二.实验目的 在无操作系统的开发板上,运行程序,掌握裸机程序的开发过程,熟悉 ...
- linux开发板led怎么亮,飞凌OK6410开发板(裸板) 第一个点亮LED灯程序
飞凌OK6410开发板(裸板) 第一个点亮LED灯程序,主要的C程序,完整程序请下载附件. #define rGPMCON (*(volatile unsigned *)(0x7F0 ...
- mini2440开发板学习裸机开发——day1 裸机运行LED灯程序
开发背景:系统:ubuntu18.04系统 开发板:mini2440 串口连接工具 J-link连接工具 工具:secureCRT J-link 本次学习基于韦东山老师的嵌入式linux应用开发手册书 ...
- 4412裸机程序之点亮LED
4412裸机程序之点亮LED 看一下Tiny4412原理图: 在Tiny4412核心板上有4个可编程控制LED,我们来点亮led1, led1右边接3.3V电源,左边接GPM4_0接口,把GPM4_0 ...
- 01火山PC开发网站-我的第一个网页程序
大家好,我是你们的老师利快云,后续我们将会持续性的更新火山PC开发网站的文章,欢迎大家持续性的关注~ PS:文章正式开始~ 首先我们新建一个火山PCMFC窗口项目,并添加我们所安装的模块,如下图: 添 ...
最新文章
- Docker 的优势
- Jquery获取参数(解决参数中文乱码问题)
- 基于NVIDIA显卡的硬编解码的一点心得 (完结)
- RabbitMQ添加用户
- 【AI学院】有三AI博士小姐姐带你学深度学习之图像识别下篇,附上篇回顾
- Python-统计svn变更代码行数
- (转载)java list排序
- PortraitFCN算法详解
- ux和ui_UI和UX设计师的10种软技能
- 云湖共生-释放企业数据价值
- virtualbox 命令
- 数据结构Java版之基数排序(四)
- Dreamweaver 8 jquery 代码提示
- PLC控制步进电机在机床自动线中的应用
- 阿里云罗庆超:我为什么写《对象存储实战指南》这本书
- 汽车软件开发流程及代码提交
- 一、软件测试概念和理论
- DC-DC升压IC测试及EN脚讲解
- 不要再被骗了------QQ盗号原理大揭秘
- solidworks背景改为纯白色