GD32 裸机开发实现按键点灯(汇编实现)

先导知识

汇编语言:

;加载寄存器
ldr r0,=0x40021018	;这是内存地址
ldr r1,[r0]						; r1 = *r0 将r0的值赋值给r1
orr r1, r1, #0x10				;将第4位置1(从0开始的哦)
bic r1, r1, #0xf				;将低4位清0
str r1, [r0]					;将r1的值写入r0这个地址	*r1 = r0 
blx lr							;函数返回 return

;CBNZ
mov r0, #0
cbnz r1, KEY2_press	;当r1不等于0的时候跳转到KEY2_press
nop		;r1==0 跳到这儿

KEY2_press
	nop

eor r1, r1,#0x800	;异或操作 即可让灯翻转	

mov r1, #3
mov r2, #5
and r3, r1, r2			;r3 = r1 & r2  结果是5

如何在C代码中调用汇编呢?
main.c

//导入汇编的函数
extern void led_init(void);

int main(){
	led_init();	//这是汇编函数
	return 0;
}

asm.s

	;这句话一定不要顶格写
	AREA	My_Function,CODE,READONLY
	;要被C调用的函数 都需要声明EXPORT
	EXPORT led_init	

;对应的汇编函数
led_init	
	mov r0, #0xff
	blx lr

C语言又是如何向汇编代码传参的呢?
r0-r3会接收C语言的参数,超过四个参数的自己想办法

如何找寄存器?
我以前写过,这里不写了

汇编实现按键点灯

main.c


#include "gd32c10x.h"
#include "systick.h"
#include <stdio.h>
#include "main.h"
#include "gd32c10x_eval.h"


void led_spark(void)
{
    static __IO uint32_t timingdelaylocal = 0U;

    if(timingdelaylocal){

        if(timingdelaylocal < 500U){
            //gd_eval_led_on(LED2);
        }else{
            //gd_eval_led_off(LED2);
        }

        timingdelaylocal--;
    }else{
        timingdelaylocal = 1000U;
    }
}
/**********上面代码不重要,下面才是重点********************/
extern void led_init(void);
extern void led_on(int led_num);
extern void led_off(int led_num);
extern void key_init(void);
extern void key1_scan(void);	//这是4个按键都会检测

/*led灯的枚举定义*/
typedef enum 
{
    led1 = 0,
    led2 = 1,
    led3 = 2,
    led0 = 3
}LED;


int main(void)
{
		//所有灯的初始化
		led_init();
		//关闭灯
		led_off(led1);
		led_off(led2);
		led_off(led3);
		led_off(led0);
		//按键初始化
		key_init();
		

		while(1){
			key1_scan();
		}
}

led_asm.s

	AREA	My_Function,CODE,READONLY
	;要被C调用的函数 都需要声明EXPORT
	EXPORT led_init	
	EXPORT led_on
	EXPORT led_off
	EXPORT key_init	
	EXPORT key1_scan

led_init	
	;时钟使能
	ldr r0,=0x40021018
	ldr r1, [r0]
	orr r1, r1, #0x10	;C口时钟
	orr r1, r1, #0x1	;AFIO端口时钟
	orr r1, r1, #0x4	;A口端口时钟
	str r1, [r0]
	
	;LED0 pA15需要关闭JTAG 打开SWJ使能
	ldr r2,=0x40010004
	ldr r3, [r2]
	orr r3, r3, #0x1
	bic r3, r3, #0x7000000
	orr r3, r3, #0x2000000
	str r3, [r2]
	
	;led1的初始化
	;GPIOC控制寄存器  0x40011004
	;推挽输出 10MHZ  8~11为清0 再变成0x1
	;GPIOC_CON &= ~(0xf<<8);	//清0	[8:11]
	;GPIOC_CON |= (0x1<<8);	//清0后把最后一位置1

	;推挽输出 10MHZ
	ldr r2,=0x40011004
	ldr r3, [r2]	;r3 = *r2
	;LED1
	bic r3, r3, #0xf00
	orr r3, r3, #0x100
	;LED2
	bic r3, r3, #0xf000
	orr r3, r3, #0x1000
	;LED3
	bic r3, r3, #0xf0000
	orr r3, r3, #0x10000
	str r3, [r2]	; *r2 = r3
	
	;LED0初始化 推挽输出 10MHZ	
	ldr r2,=0x40010804
	ldr r3, [r2]
	bic r3, r3, #0xf0000000
	orr r3, r3, #0x10000000
	str r3, [r2]
	
	;让LD0亮起来,其他灯初始化后就会亮,这个不会
	ldr r2,=0x4001080C
	ldr r3, [r2]
	bic r3, r3, #0x8000
	str r3, [r2]
	
	blx lr
	

led_on	
	cmp r0, #0
	beq LED1_on
	cmp r0, #1
	beq LED2_on
	cmp r0, #2
	beq LED3_on
	cmp r0, #3
	beq LED0_on
	

led_off
	cmp r0, #0
	beq LED1_off
	cmp r0, #1
	beq LED2_off
	cmp r0, #2
	beq LED3_off
	cmp r0, #3
	beq LED0_off
	
;led灯熄灭的跳转
LED0_off
	ldr r2,=0x4001080C
	ldr r1, [r2]
	orr r1, r1, #0x8000
	str r1, [r2]
	blx lr
LED1_off
	ldr r2,=0x4001100c
	ldr r1, [r2]
	orr r1, r1,#0x400
	str r1, [r2]
	blx lr
LED2_off
	ldr r2,=0x4001100c
	ldr r1, [r2]
	orr r1, r1,#0x800
	str r1, [r2]
	blx lr
LED3_off
	ldr r2,=0x4001100c
	ldr r1, [r2]
	orr r1, r1,#0x1000
	str r1, [r2]
	blx lr

;led灯亮的跳转
LED0_on
	ldr r2,=0x4001100c
	ldr r1, [r2]
	ldr r2,=0x4001080C
	ldr r1, [r2]
	bic r1, r1, #0x8000
	str r1, [r2]
	blx lr
LED1_on
	ldr r2,=0x4001100c
	ldr r1, [r2]
	bic r1, r1,#0x400
	str r1, [r2]
	blx lr
LED2_on
	ldr r2,=0x4001100c
	ldr r1, [r2]
	bic r1, r1,#0x800
	str r1, [r2]
	blx lr
LED3_on
	ldr r2,=0x4001100c
	ldr r1, [r2]
	bic r1, r1,#0x1000
	str r1, [r2]
	blx lr
	
;按键初始化	
key_init
	ldr r0,=0x40021018
	ldr r1, [r0]
	orr r1, r1, #0x8	;B口端口时钟
	str r1, [r0]
	
	;KEY1 KEY2 KEY3 KEY4的配置 悬浮输入 
	ldr r0,=0x40010C04
	ldr r1,[r0]
	bic r1, r1, #0xf0000
	orr r1, r1, #0x40000
	bic r1, r1, #0xf00000
	orr r1, r1, #0x400000
	bic r1, r1, #0xf000000
	orr r1, r1, #0x4000000
	bic r1, r1, #0xf0000000
	orr r1, r1, #0x40000000
	str r1, [r0]
	
	blx lr
	
;按键检测
key1_scan
	ldr r0,=0x40010C08
	ldr r1,[r0]
	and r2, r1, #0x1000
	cbnz r2, KEY2_scan	;结果非0跳转KEY2_scan
		
	ldr r2,=0x4001100c
	ldr r1, [r2]
	eor r1, r1,#0x400	;r1的第10位置
	str r1, [r2]
	
	blx lr
	
KEY2_scan
	ldr r0,=0x40010C08
	ldr r1,[r0]
	and r2, r1, #0x2000
	cbnz r2, KEY3_scan
	
	ldr r2,=0x4001100c
	ldr r1, [r2]
	eor r1, r1,#0x800
	str r1, [r2]
	
	blx lr

KEY3_scan
	ldr r0,=0x40010C08
	ldr r1,[r0]
	and r2, r1, #0x4000
	cbnz r2, KEY4_scan
	
	ldr r2,=0x4001100c
	ldr r1, [r2]
	eor r1, r1,#0x1000
	str r1, [r2]
	
	blx lr
	
KEY4_scan
	ldr r0,=0x40010C08
	ldr r1,[r0]
	and r2, r1, #0x8000
	cbnz r2, KEY_end
	
	ldr r2,=0x4001100c
	ldr r1, [r2]
	ldr r2,=0x4001080C
	ldr r1, [r2]
	eor r1, r1, #0x8000
	str r1, [r2]
	
	blx lr
	
KEY_end
	blx lr

总结

汇编代码if else有点挑战,还需要对各种寄存器比较熟悉,比如pc,lr这些。
如何去找寄存器这些都要对硬件有一定了解才行。
灯已电亮,按键也能按下进行电平翻转,用到异或操作。
汇编代码的清0和置1、异或等操作非常方便。
汇编代码全程都是在操作寄存器哦。

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
GD32微控制器中,可以通过配置外部中断线(EXTI)来实现外部中断。以下是一个简单的GD32 EXTI中断实现的示例代码: 首先,需要在NVIC中开启外部中断线的中断: ```c NVIC_InitPara NVIC_InitStructure; NVIC_InitStructure.NVIC_IRQ = EXTI0_IRQn; // 外部中断线0 NVIC_InitStructure.NVIC_IRQPreemptPriority = 0; NVIC_InitStructure.NVIC_IRQSubPriority = 0; NVIC_InitStructure.NVIC_IRQEnable = ENABLE; NVIC_Init(&NVIC_InitStructure); ``` 然后,需要配置外部中断线的触发方式和GPIO口: ```c EXTI_InitPara EXTI_InitStructure; EXTI_InitStructure.EXTI_Line = EXTI_Line0; // 外部中断线0对应GPIO口0 EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling; // 下降沿触发 EXTI_InitStructure.EXTI_LineEnable = ENABLE; EXTI_Init(&EXTI_InitStructure); GPIO_InitPara GPIO_InitStructure; GPIO_InitStructure.GPIO_Pin = GPIO_PIN_0; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; GPIO_Init(GPIOA, &GPIO_InitStructure); ``` 最后,实现外部中断的处理函数: ```c void EXTI0_IRQHandler(void) { if(EXTI_GetITStatus(EXTI_Line0) != RESET) { // 处理外部中断事件 // ... EXTI_ClearITPendingBit(EXTI_Line0); } } ``` 在处理函数中,可以根据具体的需求进行相应的处理操作。 以上是一个简单的GD32 EXTI中断实现的示例代码。需要注意的是,为了保证稳定性和可靠性,具体的实现需要根据具体的硬件和软件环境进行调整和优化。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值