本帖最后由 八度空间 于 2017-3-12 11:32 编辑
移植硬件平台:项目板子
编译环境:IAR7.6
库版本:V1.2.2
FreeRTOS版本:V9.0.0
一、下载FreeRTOS源码
官网直接下载
http://www.freertos.org/a00104.html或者原子哥光盘附带的,本贴也上传
二、解压源码
2.1、新建工程,工程中建FreeRTOS文件夹存放源码
2.2、打开解压文件“..FreeRTOSv9.0.0”
2.3、打开“FreeRTOS”文件夹,看到“Source”文件夹,这就是源码了,至于“FreeRTOS-Plus”文件夹就大家自己研究了,像研究水果6plus一样研究
将此文件夹所有东西拷贝到工程新建的“FreRTOS”文件夹中
2.4、在源码demo文件夹里“..FreeRTOSv9.0.0FreeRTOSDemoCORTEX_M4F_STM32F407ZG-SK”(STM32F302是Cortex-M4内核的)拷贝“FreeRTOSConfig.h”文件到工程中(放位置随意)
二、打开IAR软件新建工程(可参考
http://www.openedv.com/thread-74004-1-1.html这贴进行,至于MDK就大家自行新建了
),往文件夹丢文件就是了
“port.c和portmacro.h”文件路径“..FreeRTOSportableIARARM_CM4F”
“portasm.s”文件路径(IAR工程必须添加,MDK工程没有的):“..FreeRTOSportableIARARM_CM4F”
”heap_x“文件路径:”..FreeRTOSportableMemMang“
三、配置工程,添加头文件路径(可参考
http://www.openedv.com/thread-74004-1-1.html这贴进行)
四、配置IAR环境完成
4.1、编写main函数
就弄了两个任务在跑,一个是闪灯(板子上只有一个LED),一个是串口每隔1s就输出一个浮点运算(前面说的STM32F302使用的是Cortex-M4内核),有带浮点计算单元的FPU
4.2、修改文件”FreeRTOSConfig.h“
打开文件,在开头位置,增加相关的环境预编译条件
上一个框框就是文件自带的,我增加几个编译环境的宏定义判断,或者去掉也行,下面一个框框就是MDK编译环境的区别了,接下来就是FreeRTOS裁剪宏定义了
4.3、修改”SYSTEM“相关文件
4.3.1、修改”sys“文件
主要是增加宏定义相关说明,详见工程
4.3.2、修改”delay“文件
增加FreeRTOS支持
[mw_shl_code=applescript,true]/**
*****************************************************************************
*
@name : 初始化延时函数
*
* @Brief : 主要Cortex-M3内核对系统时钟计数单元
* 详细见《Cortex-M3权威指南(中文)》第216页 a) 时钟周期(CYCCNT) 的内容
* 周立功《CM3计数参考手册》第28、29页、第110、125页
*
* @Input : none
*
* @Output : none
*
* @Return : none
*****************************************************************************
**/
void delay_init(void)
{
#if _DELAY_TYPE == 1 //使用其他资源做延时时基
DEM_CTRL |= 1<<24; //该位必须为1,使能跟踪和调试模块的使用。详细见:周立功《CM3计数参考手册》第115页介绍
//在没有使用跟踪时,该位使能对功率使用的控制。它能够由应用程序或调试器使能,供ITM使用
//在DWT能够使用之前,调试异常和监控控制寄存器的TRCENA(bit24)位必须置位
DWT_CTRL |= 1<<0; //使能DWT_CYCCNT计数器。
//如果不使能,则计数器不执行计数操作,因此不会产生PC采样或CYCCNTENA事件。
//在正常使用时,CYCCNT计数器应由调试器初始化为0。
#else //使用嘀嗒定时器做延时时基
#if _SYSTEM_SUPPORT_ROTS == 1 //运行了OS
uint32_t RELOAD = 0; //挡计数器倒数到0时的重装值,有效位:0 ~ 23
#endif
#if _SYSTEM_SUPPORT_ROTS == 1 //运行了OS
#if _RTOS_TYPE == 2 //FreeRTOS
SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK);
fac_us = SystemCoreClock / 1000000;
RELOAD = SystemCoreClock / 1000000;
#endif
#else
/* 根据SysTick定时器的时钟分频来确定重装值 */
/* 8分频时除以8000‘000,1分频时除以1000’000 */
SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8); //选择外部时钟 HCLK / 8
fac_us = SystemCoreClock / 8000000; //系统时钟的 1/8
#endif
#if _SYSTEM_SUPPORT_ROTS == 1 //运行了OS
#if _RTOS_TYPE == 0 //uCOS
RELOAD = SystemCoreClock / 8000000; //每秒钟的计数次数,单位Hz
RELOAD *= 1000000 / OS_TICKS_PER_SEC; //根据操作系统的心跳时长来计算溢出时间,单位:KHz
//RELOAD为24位计数器,最大值为:16777216
fac_ms = 1000 / OS_TICKS_PER_SEC;
#elif _RTOS_TYPE == 1 //RAW-OS
RELOAD = SystemCoreClock / 8000000; //每秒钟的计数次数,单位Hz
RELOAD *= 1000000 / RAW_TICKS_PER_SECOND; //根据操作系统的心跳时长来计算溢出时间,单位:KHz
//RELOAD为24位计数器,最大值为:16777216
fac_ms = 1000 / RAW_TICKS_PER_SECOND;
#elif _RTOS_TYPE == 2 //FreeRTOS
RELOAD *= 1000000 / configTICK_RATE_HZ; //设置溢出时间
//RELOAD为24位计数器,最大值为:16777216
fac_ms = 1000 / configTICK_RATE_HZ;
#endif
SysTick->CTRL |= SysTick_CTRL_TICKINT_Msk; //开启SysTick定时器中断请求
SysTick->LOAD = RELOAD; //溢出计数值,每1/TICKINT_CNT秒中断一次
SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk; //开始倒数
#else //没有运行OS
fac_ms = (uint16_t)fac_us*1000; //ms需要的SysTick时钟数
#endif
#endif //end _DELAY_TYPE
}[/mw_shl_code]
[mw_shl_code=applescript,true]/**
*****************************************************************************
* @Name : 延时n个us
*
* @Brief : none
*
* @Input : nus:要延时的us数
*
* @Output : none
*
* @Return : none
*****************************************************************************
**/
void delay_us(uint32_t nus)
{
#if _DELAY_TYPE == 1 //使用其他资源做延时时基
uint32_t savecount,endcnt,CPU_cnt;
savecount = DWT_CYCCNT; //保存计数器当前数值
CPU_cnt = nus*(SystemCoreClock/(1000*1000)); //计算达到所需延时值的CPU时钟数。即多少个系统时钟计数
//得到更精确延时时间,减去前面代码运行的时间即可
endcnt = savecount + CPU_cnt; //计算所需延时时间DWT_CYCCNT的计数值,在溢出时返回到0
if(endcnt > savecount) //所需延时值大于当前计数值
{
while(DWT_CYCCNT < endcnt); //循环等待所需要的延时时间的CPU时钟计数值
}
else //小于当前计数值
{
while(DWT_CYCCNT > endcnt); //等待计数器溢出翻转
while(DWT_CYCCNT < endcnt); //等待所需延时时间到达
}
#else //使用嘀嗒定时器做延时时基
uint32_t temp=0;
#if _SYSTEM_SUPPORT_ROTS == 1 //运行了OS
uint32_t VAL_Prev=0; //开始计时之前的值
uint32_t VAL_Now=0; //当前计时值
uint32_t VAL_cnt=0; //计数
uint32_t Reload=SysTick->LOAD; //获取到LOAD的值
temp = nus*fac_us; //得到延时的节拍数
#if _RTOS_TYPE == 0 //uCOS
OSSchedLock(); //阻止ucos调度,防止打断us延时
#elif _RTOS_TYPE == 1 // RAW-OS
raw_disable_sche(); //阻止RAW-OS调度,防止打断us延时
#elif _RTOS_TYPE == 2 //FreeRTOS
#endif
VAL_Prev = SysTick->VAL; //保存当前的计数值
while(1)
{
VAL_Now = SysTick->VAL; //读取数值
if(VAL_Now != VAL_Prev)
{
if(VAL_Now < VAL_Prev) VAL_cnt += VAL_Prev-VAL_Now; //因为SysTick是一个递减的定时器
else VAL_cnt += Reload - VAL_Now + VAL_Prev;
VAL_Prev = VAL_Now; //刷新
if(VAL_cnt >= temp) break; //超过/等于需要的延时值了,则退出循环
}
};
#if _RTOS_TYPE == 0 //uCOS
OSSchedUnlock(); //开启ucos调度
#elif _RTOS_TYPE == 1 // RAW-OS
raw_enable_sche(); //开启RAW-OS调度
#elif _RTOS_TYPE == 2 //FreeRTOS
#endif
#else //没有运行os
SysTick->LOAD = nus*fac_us; //时间加载
SysTick->VAL = 0x00; //清空计数器
SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk; //开始倒数
do
{
temp = SysTick->CTRL;
}while(temp&0x01&&!(temp&(1<<16))); //等待时间到达
SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk; //关闭计数器
SysTick->VAL = 0x00; //清空计数器
#endif //end _SYSTEM_SUPPORT_ROTS
#endif //end _DELAY_TYPE
}
/**
*****************************************************************************
* @Name : 延时n个ms
*
* @Brief : 1、延时ms级定义,延时范围:1 ~ 65535ms。延时最大值可变,不爆机uint32_t/1000范围即可
* 2、SysTick->LOAD为24位寄存器,所以,最大延时为:
* nms <= 0xffffff*8*1000/SYSCLK
* SYSCLK单位为Hz,nms单位为ms
* 注意nms的范围 0 ~ 1864(72M情况下)
*
* @Input : nms:要延时的ms数
*
* @Output : none
*
* @Return : none
*****************************************************************************
**/
void delay_ms(uint16_t nms)
{
#if _DELAY_TYPE == 1 //使用其他资源做延时时基
delay_us((uint32_t)(nms*1000)); //采用普通的延时
#else //使用嘀嗒定时器做延时时基
#if _SYSTEM_SUPPORT_ROTS == 1 //运行了OS
#if _RTOS_TYPE == 0 //uCOS
if (OSRunning == OS_TRUE && OSLockNesting == 0) //ucos已经在跑了
#elif _RTOS_TYPE == 1 // RAW-OS
if (raw_os_active == RAW_OS_RUNNING && raw_int_nesting == 0)
#elif _RTOS_TYPE == 2 //FreeRTOS
if (xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED) //系统已经在运行
#endif
{
if(nms > fac_ms) //延时大于ucos基数
{
#if _RTOS_TYPE == 0 //uCOS
OSTimeDly(nms/fac_ms); //采用ucos延时
#elif _RTOS_TYPE == 1 // RAW-OS
raw_sleep(nms / fac_ms);
#elif _RTOS_TYPE == 2 //FreeRTOS
vTaskDelay(nms/fac_ms); //FreeRTOS延时
#endif
}
nms %= fac_ms; //ucos无法提供小于节拍的延时了
}
if (nms == 0) return; //没意义了,直接退出,不加这句,在运行RAW-OS时会死机
delay_us((uint32_t)(nms*1000)); //采用普通的延时
#else //没有运行os
uint32_t temp;
SysTick->LOAD = (uint32_t)nms*fac_ms; //时间加载(SysTick->LOAD为24bit)
SysTick->VAL = 0x00; //清空计数器
SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk; //开始倒数
do
{
temp = SysTick->CTRL;
}while(temp&0x01&&!(temp&(1<<16))); //等待时间到达
SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk; //关闭计数器
SysTick->VAL = 0x00; //清空计数器
#endif //end _SYSTEM_SUPPORT_ROTS
#endif //end _DELAY_TYPE
}[/mw_shl_code]
4.3.3、修改”usart“文件
主要修改串口中断接收函数兼容FreeRTOS
[mw_shl_code=applescript,true]/**
*****************************************************************************
* @Name : 串口接收中断服务程序
*
* @Brief : none
*
* @Input : none
*
* @Output : none
*
* @Return : none
*****************************************************************************
**/
void USART1_IRQHandler(void)
{
#if USART_USER_DMA_EN
uint16_t usart_rx_len = 0;
#else
uint8_t res;
#endif
#if _SYSTEM_SUPPORT_ROTS == 1
#if _RTOS_TYPE == 0 //uCOS
OSIntEnter();
#elif _RTOS_TYPE == 1 //RAW-OS
raw_enter_interrupt();
#elif _RTOS_TYPE == 2 //FreeRTOS
#endif
#endif
#if USART_USER_DMA_EN
if (USART_GetITStatus(USART1, USART_IT_IDLE) != RESET)
{
/* ==================== STM32F0xx Series chips ==================== */
#if __STM32xx == 0x00 //STM32F0xx
DMA_Cmd(DMA1_Channel3, DISABLE); //先关闭,预防干扰
usart_rx_len = USART_REC_LEN - DMA_GetCurrDataCounter(DMA1_Channel3);
DMA1_Channel3->CNDTR = (uint16_t)USART_REC_LEN;
/* ==================== STM32F4xx Series chips ==================== */
#elif __STM32xx == 0x04 //STM32F4xx
DMA_Cmd(DMA2_Stream5, DISABLE); //先关闭,预防干扰
DMA_ClearFlag(DMA2_Stream5, DMA_FLAG_TCIF5);
usart_rx_len = USART_REC_LEN - DMA_GetCurrDataCounter(DMA2_Stream5);
DMA2_Stream5->NDTR = (uint16_t)USART_REC_LEN;
#else //STM32F10x or STM32F3xx
DMA_Cmd(DMA1_Channel5, DISABLE); //先关闭,预防干扰
usart_rx_len = USART_REC_LEN - DMA_GetCurrDataCounter(DMA1_Channel5);
DMA1_Channel5->CNDTR = (uint16_t)USART_REC_LEN;
#endif
//
//判断是否接受到回车符
//
if (USART_RX_BUF[usart_rx_len-2] == 0x0D) //CR (carriage return)
{
if (USART_RX_BUF[usart_rx_len-1] == 0x0A) //LF (NL line feed, new line)
{
usart_rx_len -= 2; //
不计算在内
USART_RX_STA = (usart_rx_len & 0x3FFF); //得到接收数据长度
USART_RX_STA |= 0x8000; //标志接收完成标志
}
else
{
USART_RX_STA = 0;
}
}
/* ==================== STM32F0xx Series chips ==================== */
#if __STM32xx == 0x00 //STM32F0xx
DMA_Cmd(DMA1_Channel3, ENABLE);
/* ==================== STM32F4xx Series chips ==================== */
#elif __STM32xx == 0x04 //STM32F4xx
DMA_Cmd(DMA2_Stream5, ENABLE);
#else //STM32F10x or STM32F3xx
DMA_Cmd(DMA1_Channel5, ENABLE);
#endif
(void)USART_ReceiveData(USART1);
}
USART_ClearITPendingBit(USART1, USART_IT_IDLE);
#else
if (USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) //接收到数据
{
res = USART_ReceiveData(USART1); //读取接收到的数据
if ((USART_RX_STA & 0x8000) == 0) //接收未完成
{
if ((USART_RX_STA & 0x4000) != 0) //接收到了0x0d
{
/***********************************************
修改内容如下
当用户数据当中有0x0d的时候修正的错误的判断
***********************************************/
if(res != 0x0a)
{
USART_RX_BUF[USART_RX_STA & 0x3fff] = 0x0d; //补上丢失的0x0d数据
USART_RX_STA++;
USART_RX_BUF[USART_RX_STA & 0x3fff] = res; //继续接收数据
USART_RX_STA++;
USART_RX_STA &= 0xbfff; //清除0x0d标志
}
/***********************************************
修改完成
***********************************************/
else
{
USART_RX_STA |= 0x8000; //接收完成了
}
}
else //还没收到0x0d
{
if(res == 0x0d)
{
USART_RX_STA |= 0x4000;
}
else
{
USART_RX_BUF[USART_RX_STA & 0x3fff] = res;
USART_RX_STA++;
if (USART_RX_STA > (USART_REC_LEN - 1))
{
USART_RX_STA = 0;//接收数据错误,重新开始接收
}
}
}
} //end 接收未完成
} //end 接收到数据
#endif
#if _SYSTEM_SUPPORT_ROTS == 1
#if _RTOS_TYPE == 0 //uCOS
OSIntExit();
#elif _RTOS_TYPE == 1 // RAW-OS
raw_finish_int();
#elif _RTOS_TYPE == 2 //FreeRTOS
#endif
#endif
}[/mw_shl_code]
五、至此,也差不多了,点击编译改错,最后得到这么一个框框提示
大家是否也觉得不可思议,头文件路径已经添加了,为啥报错???有木有有木有(在这里我想了很久,不明白IAR为啥报错)
打开”FreeRTOSConfig.h“文件查看报错在哪里,仔细看报错文件路径
后面提示的是文件”portasm.s”路径报错,于是打开此文件,是任务切换什么的,汇编文件,再回头看看IAR配置,有这么一项
汇编文件管理,看到一个Preprocessor选项,二话不说,增加路径
再次编译
没错误没警告
六、下载到板子,看到LED在闪烁,接上串口,每隔一段时间输出一个小数,结果一致
一周热门 更多>