求一个51单片机延时1秒的程序,用汇编!!

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了求一个51单片机延时1秒的程序,用汇编!!相关的知识,希望对你有一定的参考价值。

我是初学者,不太会!求一个51单片机延时1秒的程序,用汇编!用软件的方法

DEL1S:MOV R7,#10
D1: MOV R6,#200
D2: MOV R5,#250
DJNZ R5,$
DJNZ R6,D2
DJNZ R7,D1
RET

说明:1、如果不使用R5、R6、R7可以用别的单元替换,比如换成30H、31H、32H等等
2、这个程序是12M时钟,如果时钟不同,要修改数值。如6M时钟,要把MOV R7,#10 修改成:MOV R7,#5
参考技术A 时钟频率为12MHz的一秒延时汇编代码(8051):机器周期T=(1/12M)*12=1us
因为一个机器周期=6个接拍、1个节拍=2个时钟周期,这是机器周期的定义。
ORG 1000H
MOV R5, #4
L3: MOV R6, #250 ;1T
L2: MOV R7, #200 ;1T
L1: NOP ;1T
NOP ;1T
NOP ;1T
DJNZ R7, L1 ;(1+1+1+2)*200T=1ms
DJNZ R6, L2 ;1+2+(1+1+1+2)*200*250T=250750us
DJNZ R5, L3 ;(3+250750)*4=1003012us=1.003012s
RET
END
仅供参考,期中R7可以设成256,误差会小点,这为了好算就设成200。
参考技术B 如果用6M晶振的话,一个机器周期为2*10(-6)s
那么1s=2*500000
2*500000=250*200*10

DELAY: mov r5,#10 ;延时子程序
D1: mov r1,#200
D2: mov r2,#250
djnz r2,$
djnz r1,d2
djnz r5,r1
ret

S5PV210开发板用汇编设置栈和调用C语言

使用C语言前为什么要先用汇编设置栈?
C语言程序运行时需要栈,因为C语言中的局部变量都是用栈来实现的,如果没有设置栈就使用C语言,局部变量就会落空,程序就会死掉,所以在使用C语言前,我们需要先在汇编编写的启动代码中设置栈。

为什么使用51单片机和Ubuntu编写应用程序时我们没有设置栈依然能使用C语言?
原因是在单片机中已经由硬件设置提供了一个默认可用的栈,而在应用程序中我们编写的C程序其实并不是全部,编译器(gcc)在链接时会帮我们自动添加一个头,这个头就是一段引导C程序能够执行的汇编代码,在这个代码中就帮我们的C程序设置了栈及其他的运行时需要。

为什么不同CPU模式下都有各自独立的sp寄存器?
如果各个模式都使用同一个sp,意味着整个程序(操作系统内核程序,用户应用程序)都使用同一个栈,这样做,一旦用户程序编写出错(栈溢出),将会影响操作系统的正常运行,操作系统会崩溃,同时运行在操作系统上的其他应用程序也会崩溃。所以各个模式下要使用不同的sp,使用不同的栈,操作系统有自己的栈,每个应用程序也有自己的栈,互不干扰。

怎么设置栈?
我们要设置栈,并不是设置所有CPU模式下的栈,而是设置当前CPU模式下的栈,因为这个程序可能只用到一种CPU模式。S5PV210复位后默认是进入SVN模式下的,我们设置当前模式下的栈,只需直接操作sp即可。
需要注意的是,栈必须是当前一段可用的内存(可用的意思是这个地方是有被初始化过的可以访问的内存,而且这个内存只会被我们用作栈,不会被其他程序征用)
当前CPU刚复位(刚启动),外部的DDR尚未初始化,需要我们后续对其初始化,所以目前可用的内存只有内部的SRAM(因为它不需初始化即可使用)。因此我们只能在SRAM中找一段内存来作为SVC的栈。

在ARM中,ATPCS(ARM关于程序应该怎么实现的一个规范)要求使用满减栈,结合iROM_application_note中的memory map,可知SVC栈应该设置为0xD0037D80。
示例代码:
start.S

#define WTCON   0xE2700000

#define SVN_STACK 0xD0037D80
.global _start
_start:
	/*关看门狗*/
	ldr r0, =0
	ldr r1, =WTCON
	str r0, [r1]
	/*设置SVN栈*/
	ldr sp, =SVN_STACK
	/*开/关icache*/
	mrc p15,0,r0,c1,c0,0;			// 读出cp15的c1到r0中
	//bic r0, r0, #(1<<12)			// bit12 置0  关icache
	orr r0, r0, #(1<<12)			// bit12 置1  开icache
	mcr p15,0,r0,c1,c0,0;			// 把r0写到cp15的c1中
	/*流水灯*/
    bl led_blink
	
	b .

led.c

#define GPJ0CON 0xE0200240
#define GPJ0DAT	0xE0200244
#define rGPJ0CON *((volatile unsigned int*)GPJ0CON)
#define rGPJ0DAT *((volatile unsigned int*)GPJ0DAT)
void delay(void);
void led_blink(void)

	rGPJ0CON = 0x11111111; 
	while(1)
	
		rGPJ0DAT = ~(1<<3);
		delay();
		rGPJ0DAT = ~(1<<4);
		delay();
		rGPJ0DAT = ~(1<<5);
		delay();
	


void delay(void)

	volatile unsigned int i = 3000000;
	while(i--);

/* volatile的作用是防止编译器优化我们的变量,有时候编译器会认为我们对这个变量的操作是无意义的,例如对一个数+1然后-1,有些编译器会直接保持原值不变
,这样做的结果可能导致我们的程序不对,所以为了不受编译器的这个影响,加上
volatile会使程序更加稳定,一般对易变的变量都加上volatile,至于加不加volatile结果会不会有什么不同,取决于编译器,一些编译器不会对此优化,一些则会。 */

Makefile

led.bin: start.o led.o
	arm-linux-ld -Ttext 0x0 -o led.elf $^
	arm-linux-objcopy -O binary led.elf led.bin
	arm-linux-objdump -D led.elf > led_elf.dis
	gcc mkv210_image.c -o mkx210
	./mkx210 led.bin 210.bin
	
%.o : %.S
	arm-linux-gcc -o $@ $< -c -nostdlib

%.o : %.c
	arm-linux-gcc -o $@ $< -c -nostdlib
	#这里要加-nostdlib,作用是不使用编译器自带的标准函数库文件
	#因为led.c文件中的delay函数与编译器自带的标准函数库中的delay重名
	#默认会去使用编译器自带的,我们要使用自己定义的话就会报错
	#相当于你一个C程序定义了两个同名函数
clean:
	rm *.o *.elf *.bin *.dis mkx210 -f

以上是关于求一个51单片机延时1秒的程序,用汇编!!的主要内容,如果未能解决你的问题,请参考以下文章

单片机定时器问题

请问51单片机定时器延时的调用是怎么调用的我有点不明白,谢谢

51单片机外部中断INT0实例(汇编程序)

51单片机C语言程序中延时函数delay的原理是啥?

51单片机定时器问题

单片机求一用C编写的延时1小时的子程序,要精确到秒级别