从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任务中。
图 1 硬件电路

STM32f103的开拓环境利用的是Keil MKD5,资源库是利用的STM32F10x_AN2824_FW_V4.0.0官方库。RTOS移植前的代码已经实现了stm32的GPIO掌握、EXTI中断、定时器中断、spi接口、串口等功能。RTOS移植前的项目代码构造如图 2所示。
图 2 代码构造
STM32项目模板就不做详细的先容了,跟普通的硬件开拓流程一样。下面详细说下RTOS移植过程。RTOS的下载地址是https://freertos.org/index.html,下载到本地的文件内容如图 3所示:FreeRTOS文件夹包含了RTOS根本代码,FreeRTOS-Plus文件夹里面的代码是RTOS增强功能,如tcp、fat等,这个项目紧张利用根本功能。
图 3 RTOS代码包
打开FreeRTOS\Source文件夹,这里面包含了须要移植的大部分代码。如图 4所示,须要移植的源文件有:include里面的所有文件,portable里面两个源文件一个头文件,以及图 4里面标红的list.c、queue.c、task.c。由于在这个项目里没有利用诸如任务间通报、动态增删任务等功能,以是在Source根目录下的其他源文件不须要移植,如果有须要,的自行添加到项目中。
图 4 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。
图 5 Portable
末了,复制一个FreeRTOSConfig.h头文件到FreeRTOS\Source\include目录中。FreeRTOSConfig.h的原始路径是
这样,freeRTOS文件夹中就包含了移植所须要的所有源文件,然后把freeRTOS文件夹复制到项目目录中。移植完毕后,我的项目目录构造如图 6所示。
图 6 项目目录构造
代码复制完毕,下一步,将复制的文件添加到项目中,详细步骤就不啰嗦了,添加完毕后的项目构造如图 7。
图 7 rtos代码构造
文件添加往后,不要忘却重新指定下MDK项目的编译器include路径,将rtos头文件的路径添加进项目,要不然会出编译缺点,如图 8。
图 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(171024),由于STM32F103R6统共才10K RAM,以是我这改成了81024。这是利用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。
图 9 启动文件中内存参数
图 10 rtos参数设置
代码修正完毕后,如果没有缺点,就可以下载到电路中运行了,如图 11所示,这个电路里一共添加了四个任务,分别是LED、数码管、spi、串口任务,都已经正常的跑了起来。
图 11 项目运行演示
末了一点要把稳的是,由于RTOS的任务调度利用的是Systick定时器,以是在利用定时器的时候,要避开SYSTICK。我在这个项目里面是利用的TIME3作为自定义定时器。
附:项目运行的其它代码。
/const difinition/
int main(void)
{
u8 x=0;
int speed=10000;//电机速率
RCC_Configuration(); //SET RCC TO: HSI&56Mhz(87)
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#:");
}