一、新建STM32工程项目
(1)打开keil新建工程文件夹
(2)选择芯片型号
接下来会弹出来一个新建工程的小助手,我们关闭就好,接下来我们的工程就创建好了,但是工程还是空的
二、添加STM32的相关固件
2.1 启动文件
(STM32的程序就是从启动文件开始执行的)
STM32F10x_StdPeriph_Lib_V3.5.0\Libraries\CMSIS\CM3\DeviceSupport\ST\STM32F10x\startup\arm
2.2 STM32的外设寄存器描述文件与配置时钟相关文件
STM32F10x_StdPeriph_Lib_V3.5.0\Libraries\CMSIS\CM3\DeviceSupport\ST\STM32F10x
1.stm32f10x.h就是STM32的外设寄存器描述文件,它的作用就是和51单片机的头文件REGX52.H一样,是用来描述STM32着哪些寄存器和它对应的地址的
2.这两个system文件是用来配置时钟的;STM32主频72MHz,就是system文件里的函数配置的
2.3 内核的寄存器描述文件
STM32F10x_StdPeriph_Lib_V3.5.0\Libraries\CMSIS\CM3\CoreSupport
因为这个STM32是内核和内核外围的设备组成的,而且这个内核的寄存器描述和外围设备的描述文件不是在一起的,所以我们还需要添加一个内核寄存器的描述文件;这两个cm3(Cortex-M3)文件就是内核的寄存器描述,当然他还带了一些内核的配置函数,所以就多了个.c文件
2.4 工程文件Start文件夹
(1)新建Start文件夹
在新建的工程中新建一个Start文件夹将上述文件复制到Start文件夹中
(2)将需要的文件添加到Start组中
(3)添加Start文件夹的路径
2.5 工程文件User文件夹
(1)新建文件夹
(2)新建组
(3)添加main.c文件进去
(3)编译看看是否报错
2.6 修改字体编码格式
(1)使用utf-8格式
(2)修改代码的字体
2.7 工程文件Library文件夹
STM32F10x_StdPeriph_Lib_V3.5.0\Libraries\STM32F10x_StdPeriph_Driver
(1)把这个文件夹下的.c和.h文件全部添加到Library文件夹下
(2)新建Library组
2.8 向User文件夹中添加conf.h和中断相关的文件
STM32F10x_StdPeriph_Lib_V3.5.0\Project\STM32F10x_StdPeriph_Template
stm32f10x_conf.h:用来配置库函数头文件的包含关系(还有个用来参数检查的函数定义)
两个it文件:是用来存放中断函数的
(1)工程文件夹中添加文件
(2)keil工作组中添加文件
(3)添加宏定义
编译没有问题
至此新建一个STM32的工程文件夹结束
三、使用dap-Link进行烧录
代码下载成功
STM32的LED开始闪烁
四、移植FreeRtos文件
4.1 精简官方源码
(1)下载官方源码
(2)对官方源码进行精简
4.2 将官方源码移植到Keil工程
(1)新建组
(2)向组内添加文件
(3)添加头文件路径
(4)进行编译,查看是否有问题
(5)添加FreeRtosConfig.h文件
(6)只留一种内存管理方式
(7)修改FreeRtosConfig.h文件
(7)修改中断文件将几个函数给注释掉
最终通过上面系列操作移植成功
五、仿真调试
(1)我们在进行仿真时会出现如下的问题
这里我们需要点击魔术棒去配置对应的选项
Dialog DLL改为 DARMSTM.DLL
Parameter改为 -pSTM32F103ZE(此项根据具体型号而定)
程序烧录到开发板通过串口工具打印
六、全部代码
#include "stm32f10x.h" // Device header
#include "FreeRTOS.h"
#include "task.h"
/* Standard includes. */
#include <stdio.h>
/* Scheduler includes. */
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
/* Library includes. */
#include "stm32f10x_it.h"
#include "USART.h"
#include "semphr.h"/*
任务目的:任务一执行使PC13端口的LED灯闪烁并且在串口打印
任务二:在串口打印任务二信息
*//*************************全局变量****************************/
static SemaphoreHandle_t xSemphoreuMutexsart;//这里的全局变量使用static表示只在本文件中使用,更加规范
/******************任务句柄***************************/
TaskHandle_t xtask1TCB;
TaskHandle_t xtask2TCB;/******************任务追踪变量***************************/int task1flagrun=0;int task2flagrun=0;int task3flagrun=0;
/******************任务一***************************/
void mytask1(void*para){while(1){task1flagrun = 1;task2flagrun = 0;// 切换 LED 状态 GPIO_WriteBit(GPIOC, GPIO_Pin_13, (BitAction)(1 - GPIO_ReadOutputDataBit(GPIOC, GPIO_Pin_13))); // 延时 1 秒 vTaskDelay(pdMS_TO_TICKS(1000)); // 修改为1000ms xSemaphoreTakeRecursive(xSemphoreuMutexsart, portMAX_DELAY);printf("task 1 is running\r\n");xSemaphoreGiveRecursive(xSemphoreuMutexsart);vTaskDelay(pdMS_TO_TICKS(1)); // 阻塞1ms,之前单位未明确,这里假设是ms }
}
/******************任务二***************************/
void mytask2(void*para){while(1){task1flagrun = 0;task2flagrun = 1;xSemaphoreTakeRecursive(xSemphoreuMutexsart, portMAX_DELAY);printf("task 2 is running\r\n");xSemaphoreGiveRecursive(xSemphoreuMutexsart);vTaskDelay(pdMS_TO_TICKS(1));}
}/*************为空闲任务创建对应的栈和堆******************/
StaticTask_t xIdelTaskTCB ;
StackType_t xIdleTaskStack[100];
void vApplicationGetIdleTaskMemory( StaticTask_t **ppxIdleTaskTCBBuffer, StackType_t **ppxIdleTaskStackBuffer, uint32_t *pulIdleTaskStackSize )
{ *ppxIdleTaskTCBBuffer = &xIdelTaskTCB; *ppxIdleTaskStackBuffer = xIdleTaskStack; *pulIdleTaskStackSize = 100;
}
int main(void){#ifdef DEBUGdebug();#endifUsart_Init();/*初始化GPIO*/RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;// 修正GPIO端口配置错误 GPIO_Init(GPIOC, &GPIO_InitStructure); GPIO_SetBits(GPIOC, GPIO_Pin_13); /************1.使用递归锁*************///实现互斥锁xSemphoreuMutexsart=xSemaphoreCreateRecursiveMutex();//在创建好之后就可以take了//在Take和Give时都要加上Recursive/************2.创建三个任务*************/xTaskCreate(mytask1,"task1",100,NULL,1,&xtask1TCB);xTaskCreate(mytask2,"task2",100,NULL,1,&xtask2TCB);/* Start the scheduler. */vTaskStartScheduler();//在这里创建空闲任务// 如果vTaskStartScheduler返回,则表示有错误 while (1) { } }