STM32 实现类似手机运行APP的方法(篇四:中断服务)

一、APP中的中断函数

1、本来以为经过前3篇文章的说明,stm32运行APP的功能已经实现了,但是在今天编写app代码的时候总感觉差点什么,由于需要写一个支持串口收发数据功能的app,发现不能实现接收串口数据,因为app不能定义中断服务函数(中断服务函数全部弱定义在stm32_startup.s文件中),想到安卓手机app开发有一种叫做监听的做法,监听到某事件发生是自动执行一段代码,本文将实现类似功能。

二、系统工程的修改

新建 irq_vector.c文件,编写以下代码:

#include "irq_vector.h"
#include "base.h"
#include "mymem.h"
#include "rthw.h"

extern int __Vectors;
extern int __Vectors_Size;


static void *g_base=0;
static void **g_irq_vector=0;

//此函数用于在系统初始化后重定位中断向量表
//把中断向量表定位在内存中才可以在运行时动态修改
void irq_vector_init(void)
{
	if(g_irq_vector==0)
	{
		//向量表必须0x200字节对齐,这里申请大于0x200字节的内存,然后所申请的内存一定有0x200对齐的部分
		g_base=mymalloc((int)&__Vectors_Size+0x200);
		g_irq_vector=(void **)(((int)g_base+0x200)&0xfffffe00);
		mymemcpy(g_irq_vector,(void *)&__Vectors,(int)&__Vectors_Size);
		rt_base_t level=rt_hw_interrupt_disable();
		NVIC_SetVectorTable(NVIC_VectTab_RAM,(u32)g_irq_vector-NVIC_VectTab_RAM);		
		rt_hw_interrupt_enable(level);
	}
}


//设置中断函数,同时返回旧的中断函数,irq_fun==0时不做修改
void *irq_vector_set_irq(int irq_num,void *irq_fun)
{
	void *ret=0;
	irq_num+=16;//前16个中断是内核中断,中断号为负数
	rt_base_t level=rt_hw_interrupt_disable();
	ret=g_irq_vector[irq_num];
	if(irq_fun)
		g_irq_vector[irq_num]=irq_fun;
	rt_hw_interrupt_enable(level);
	return ret;
}



其中 irq_vector_init 函数用于重定位中断向量表,并把以前中断向量表的内容复制出来,这个函数越早调用越好,因为要使用内存分配,所以我把他安排在内存初始化之后:

/**
 * This function will initial your board.
 */
void rt_hw_board_init()
{		
	_SysTick_Config (SystemCoreClock/1000);
	mymem_init();
	irq_vector_init();//重定位中断向量表
	Touch_Init();			
	USART3_Init();
	RANDOM_Init();
	USBD_InitAsVcp ( );

}


irq_vector_set_irq 函数用来修改中断函数,相当于注册监听事件,当中断事件发生时,函数自动执行。

三、APP工程的修改

找到上篇文章中的app示例程序,做如下修改:

https://blog.csdn.net/Ranchaun/article/details/108394101


//串口中断服务函数
void usart1_irq(void)
{
	u8 res=0;
	if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)	
	{
		res=USART_ReceiveData(USART1);
		USART_SendData( USART1,res );	// 原样返回串口收到的数据
		while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);	//等待发送完毕 
	}
	
}

//打开或关闭串口接收中断
void usart1_irq_power(int power)
{
	NVIC_InitTypeDef NVIC_InitStructure;
	
	if(power)
	{
		NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;											//串口中断通道
		NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3;								//抢占优先级3
		NVIC_InitStructure.NVIC_IRQChannelSubPriority =3;											//子优先级3
		NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;												//IRQ通道使能
		NVIC_Init(&NVIC_InitStructure);																				//根据指定的参数初始化VIC寄存器、
		USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);	
	}
	else
	{
		NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;											//串口中断通道
		NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3;								//抢占优先级3
		NVIC_InitStructure.NVIC_IRQChannelSubPriority =3;											//子优先级3
		NVIC_InitStructure.NVIC_IRQChannelCmd = DISABLE;												//IRQ通道使能
		NVIC_Init(&NVIC_InitStructure);																				//根据指定的参数初始化VIC寄存器、
		USART_ITConfig(USART1, USART_IT_RXNE, DISABLE);	
	}

}

WIN_DemoStruct *WIN_CreatDemo (WIN_WindowStruct *base,
			void (*msgLoop)(struct _WIN_WindowStruct *win,WIN_MsgStruct *msg),
			int x,int y,int x_size,int y_size)
{
...
//省略无关代码
...
			//窗口关闭时需要关闭串口中断,这里重新设置窗口销毁函数
			((WIN_WindowStruct *)ret)->deleteWindow=(WIN_WindowStruct *))Demo_Delete;
			//重设串口中断服务函数
			ret->uart_irq=irq_vector_set_irq(USART1_IRQn,usart1_irq);
			//打开串口中断
			usart1_irq_power(1);
		}
	}
	return ret;
}

//窗口销毁时关闭串口中断并设置为以前的中断服务函数
void Demo_Delete(WIN_DemoStruct *axis)
{
	irq_vector_set_irq(USART1_IRQn,axis->uart_irq);
	usart1_irq_power(0);
	
	//调用父类的销毁函数
	WIN_DeleteWindow((WIN_WindowStruct *)axis);
}


//绘制函数
void Demo_DefaultPaint (WIN_DemoStruct *axis)
{
...
//省略无关代码
...
	char *txt=mymalloc(128);
	int font=WIN_SetFontType(16);
	
	//显示中断服务函数地址
	sprintf(txt,"-原中断函数地址-%0X",(int)axis->uart_irq);
	WIN_DrawTxtAt(txt,0,16);
	sprintf(txt,"-新中断函数地址-%0X",(int)usart1_irq);
	WIN_DrawTxtAt(txt,0,32);
	
	WIN_SetFontType(font);
	myfree(txt);
}


此APP的功能是打开后把系统的串口中断服务函数替换为app中定义的中断服务函数,打开串口接收中断,然后会原样返回收到的数据。

四、实验现象

APP中显示的函数地址
运行串口助手,正常收到了数据:
串口助手数据
在syscall.sym文件中查找地址0x08024DE5,发现正是串口1的中断服务函数地址:
中断服务函数

本次调用时新的中断服务函数地址是0x2001A441,在我后台播放音乐(增加内存使用)之后,新中断函数的地址改为了0x200A8E1:
新中断函数地址
暂时就写这么多吧。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值