从Proteus8.7开始,Labcenter Electronics公司在CPU仿真中加入了对CortexM3内核的支持,STM32F103系列单片机的大部分基础功能都可以在新版本的Proteus中仿真实现,经过多次调试,终于在8.7版本的proteus中实现了RTOS的移植,下面记录下移植过程。
项目仿真使用的CPU型号是STM32F103R6,截止RTOS移植前,项目已经实现了GPIO控制、SPI输出(管脚模拟的方式)、数码管显示(使用串口同步功能)、以及串口(异步)通信功能。电路如图 1所示。其中黄色的LED灯模拟GPIO输出功能;APA102真彩RGB灯来仿真SPI接口;串口通信用Proteus自带的终端测试,用到了USART1;数码管驱动使用的是74HC595,应用了USART2的同步功能。按键功能使用了74ls148芯片来实现,但是这次测试并没有添加到RTOS任务中。
STM32f103的开发环境使用的是Keil MKD5,资源库是使用的
STM32F10x_AN2824_FW_V4.0.0官方库。RTOS移植前的代码已经实现了stm32的GPIO控制、EXTI中断、定时器中断、spi接口、串口等功能。RTOS移植前的项目代码结构如图 2所示。
STM32项目模板就不做详细的介绍了,跟普通的硬件开发流程一样。下面详细说下RTOS移植过程。RTOS的下载地址是
https://freertos.org/index.html,下载到本地的文件内容如图 3所示:FreeRTOS文件夹包含了RTOS基础代码,FreeRTOS-Plus文件夹里面的代码是RTOS增强功能,如tcp、fat等,这个项目主要使用基础功能。
打开FreeRTOS\Source文件夹,这里面包含了需要移植的大部分代码。如图 4所示,需要移植的源文件有:include里面的所有文件,portable里面两个源文件一个头文件,以及图 4里面标红的list.c、queue.c、task.c。由于在这个项目里没有使用诸如任务间消息传递、动态增删任务等功能,所以在Source根目录下的其他源文件不需要移植,如果有需要,的自行添加到项目中。
\\FreeRTOSv10.1.1\FreeRTOS\Source\portable文件夹中包含了编译器相关的接口和内存管理代码,由于本项目使用的是MDK5,所以只保留Keil跟RVDS,再加一个内存管理接口代码的文件夹MemMang,其他的内容删掉,并且将RVDS中的源文件复制到Keil中,如图 5。Portable中需要添加到项目中的两个源文件及一个头文件分别是MemMang文件夹中的heap_3.c以及\\portable\Keil\ARM_CM3中的portmacro.h和port.c。
最后,复制一个FreeRTOSConfig.h头文件到FreeRTOS\Source\include目录中。FreeRTOSConfig.h的原始路径是
这样,freeRTOS文件夹中就包含了移植所需要的所有源文件,然后把freeRTOS文件夹复制到项目目录中。移植完毕后,我的项目目录结构如图 6所示。
代码复制完毕,下一步,将复制的文件添加到项目中,具体步骤就不啰嗦了,添加完毕后的项目结构如图 7。
文件添加以后,不要忘记重新指定下MDK项目的编译器include路径,将rtos头文件的路径添加进项目,要不然会出编译错误,如图 8。
所有准备工作做完,就可以修改代码,代码修改共分为几个部分,包括:
添加头文件
在程序中,添加rtos需要的头文件
重新实现三个中断函数。
在FreeRTOSConfig.h头文件中,添加如下三行#define语句,用xPortPendSVHandler、SysTick_Handler、SVC_Handler重新实现PendSV_Handler、SysTick_Handler、SVC_Handler三个中断函数,由于原stm32f10x_it.c 源文件中已经有这三个中断函数的定义了,所以需要将原来的定义屏蔽掉,这里使用了__weak关键字。
添加任务代码
内存管理参数修改
由于freeRTOS的多任务调度,是占用了STM32内存系统的堆空间,所以需要对内存参数进行修改。如图 10,其中#define configTOTAL_HEAP_SIZE默认的是17K(17*1024),由于STM32F103R6总共才10K RAM,所以我这改成了8*1024。这是使用heap_1.c、heap_2.c、heap_4.c的情况,heap_5.c测试未成功,原因未知。如果跟前面移植步骤一样,使用的是heap_3.c的话,heap_3.c内存管理方式跟其它几种都不一样,堆空间是使用的startup_stm32f10x_ld.s中的配置,所以需要修改启动文件中关于堆设置的代码,我这里将原始的200改成了2000,如图 9。
代码修改完毕后,如果没有错误,就可以下载到电路中运行了,如图 11所示,这个电路里一共添加了四个任务,分别是LED、数码管、spi、串口任务,都已经正常的跑了起来。
最后一点要注意的是,由于RTOS的任务调度使用的是Systick定时器,所以在使用定时器的时候,要避开SYSTICK。我在这个项目里面是使用的TIME3作为自定义定时器。
附:项目运行的其它代码。
/***************const difinition****************/
int main(void)
{
u8 x=0;
int speed=10000;//电机速度
RCC_Configuration(); //SET RCC TO: HSI&56Mhz(8*7)
GPIOInit(); //GPIO初始化
seg7_init(); //同步串口初始化
NVIC_Configuration();
//设置systick时钟源
SysTick_CLKSourceConfig(
SysTick_CLKSource_HCLK_Div8);GPIO_ResetBits(GPIOD, GPIO_Pin_2);//PD2输出低电平,点亮ARMLED
Time3Init();
timer1PWM_Init();
Usart1_Init();
TIM_Cmd(TIM3, ENABLE);//启动定时器3
sSPI2_Init();
/******rtos task******/
xTaskCreate(led_task1,"LED_TASK1",40,NULL,3,NULL);
xTaskCreate(seg_task2,"seg_TASK2",40,NULL,2,NULL);
xTaskCreate(usart_task3,"usart_TASK3",40,NULL,2,NULL);
xTaskCreate(apa_task4,"apa_TASK4",40,NULL,2,NULL);
vTaskStartScheduler();
}
/**freeRTOS head**/
#include "FreeRtos.h"
#include "task.h"
#include "queue.h"
//FreeRTOSConfig.h
#define xPortPendSVHandler PendSV_Handler
#define xPortSysTickHandler SysTick_Handler
#define vPortSVCHandler SVC_Handler
....
//stm32f10x_it.c屏蔽库函数
void __weak SVC_Handler(void)
...
xTaskCreate(led_task1,"LED_TASK1",40,NULL,3,NULL);
xTaskCreate(seg_task2,"seg_TASK2",40,NULL,2,NULL);
xTaskCreate(usart_task3,"usart_TASK3",40,NULL,2,NULL);
xTaskCreate(apa_task4,"apa_TASK4",40,NULL,2,NULL);
vTaskStartScheduler();
#include "stm32f10x_gpio.h"
/*user lib*/
#include "user_misc.h"
#include "7seg.h"
#include "motostep.h"
#include "user_uart.h"
#include "tc72.h"
/**freeRTOS head**/
#include "FreeRtos.h"
#include "task.h"
#include "queue.h"
/*public varble */
u16 keyPC=0xFF;//portPC status readin
u8 led1_onoff=0xff;
u16 publicTIMER=0;//全局定时器
u16 recvDATA[maxUARTData];
u8 recvNewFLAG=0; //1 means new frame received
//功能:LED闪烁
void led_task1(void *aa);
void seg_task2(void *aa);
void usart_task3(void *aa);
void apa_task4(void *aa);
void d_welcom(void);
void led_task1(void *aa)
{
while(1)
{
LED1^=1;
vTaskDelay(50);
}
}
void seg_task2(void *aa)
{
u8 x=0;
while(1)
{
seg7_put(x);
vTaskDelay(20);
x++;
if(x>999)
x=0;
}
}
void usart_task3(void *aa)
{
u8 x=0;
while(1)
{
apaDIS(x);
vTaskDelay(20);
x++;
if(x>8)
x=0;
}
}
void apa_task4(void *aa)
{
while(1)
{
printf("\n\rho ho,usart ok"); ;
vTaskDelay(50);
}
}
void d_welcom(void)
{
printf("\r ====STM32 Vsm DEMO====\r");
printf("\r 1、USART TESTing");
printf("\r 2、motoSTEP S/T");
printf("\r 3、AD Sampling");
printf("\r 4、KEY TESTing");
printf("\re.g input func num ->\r#:");
}
本文暂时没有评论,来添加一个吧(●'◡'●)