网站推广托管,京山网站制作,漯河网站建设网站建设,佛系汉化组wordpress博客准备工作
FreeRTOS系统源码基础工程#xff0c;这里我们用跑马灯实验
1.在工程里面添加FreeRTOS源码
在工程里面新建一个名为FreeROTS的文件夹 将FreeRTOS源码添加到这个文件夹里面 protable里面只需留下Keil、MemMang、RVDS文件夹
2、向工程分组中添加文件 FreeRTOS_C…准备工作
FreeRTOS系统源码基础工程这里我们用跑马灯实验
1.在工程里面添加FreeRTOS源码
在工程里面新建一个名为FreeROTS的文件夹 将FreeRTOS源码添加到这个文件夹里面 protable里面只需留下Keil、MemMang、RVDS文件夹
2、向工程分组中添加文件 FreeRTOS_CORE的文件在FreeRTOS源码的首目录下FreeRTOS_PORTABLE的port.c在RVDS文件夹下的ARM_CM4F中heap_4.c在MenMang中是内存管理方法
3、添加相应的头文件路径 4、添加FreeRTOSConfig.h文件
放在include文件夹下这个文件官方的例程有是FreeRTOS的配置文件 打开FreeRTOSConfig.h文件修改下图代码为
#if defined(__ICCARM__) || defined(__CC_ARM ) || defined (__GNUC__)#include stdint.hextern uint32_t SystemCoreClock;
#endif 4、屏蔽port.c和stmf32f4xx_it.c重复定义的函数
void PendSV_Handler(void)void SysTick_Handler(void)void PPP_IRQHandler(void)5、修改system文件
5.1 sys.h
SYSTEM_SUPPORT_OS修改成1
//0,不支持os
//1,支持os
#define SYSTEM_SUPPORT_OS 1 //定义系统文件夹是否支持OS5.2 usart.c
修改成以下内容
#include usart.h
#include delay.h
//
//如果使用os,则包括下面的头文件即可.
#if SYSTEM_SUPPORT_OS
#include FreeRTOS.h //os 使用
#endif//加入以下代码,支持printf函数,而不需要选择use MicroLIB
//#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#if 1
#pragma import(__use_no_semihosting)
//标准库需要的支持函数
struct __FILE
{ int handle;
}; FILE __stdout;
//定义_sys_exit()以避免使用半主机模式
void _sys_exit(int x)
{ x x;
}
//重定义fputc函数
int fputc(int ch, FILE *f)
{ while((USART1-SR0X40)0);//循环发送,直到发送完毕 USART1-DR (u8) ch; return ch;
}
#endif #if EN_USART1_RX //如果使能了接收
//串口1中断服务程序
//注意,读取USARTx-SR能避免莫名其妙的错误
u8 USART_RX_BUF[USART_REC_LEN]; //接收缓冲,最大USART_REC_LEN个字节.
//接收状态
//bit15 接收完成标志
//bit14 接收到0x0d
//bit13~0 接收到的有效字节数目
u16 USART_RX_STA0; //接收状态标记 u8 aRxBuffer[RXBUFFERSIZE];//HAL库使用的串口接收缓冲
UART_HandleTypeDef UART1_Handler; //UART句柄//初始化IO 串口1
//bound:波特率
void uart_init(u32 bound)
{ //UART 初始化设置UART1_Handler.InstanceUSART1; //USART1UART1_Handler.Init.BaudRatebound; //波特率UART1_Handler.Init.WordLengthUART_WORDLENGTH_8B; //字长为8位数据格式UART1_Handler.Init.StopBitsUART_STOPBITS_1; //一个停止位UART1_Handler.Init.ParityUART_PARITY_NONE; //无奇偶校验位UART1_Handler.Init.HwFlowCtlUART_HWCONTROL_NONE; //无硬件流控UART1_Handler.Init.ModeUART_MODE_TX_RX; //收发模式HAL_UART_Init(UART1_Handler); //HAL_UART_Init()会使能UART1HAL_UART_Receive_IT(UART1_Handler, (u8 *)aRxBuffer, RXBUFFERSIZE);//该函数会开启接收中断标志位UART_IT_RXNE并且设置接收缓冲以及接收缓冲接收最大数据量}//UART底层初始化时钟使能引脚配置中断配置
//此函数会被HAL_UART_Init()调用
//huart:串口句柄void HAL_UART_MspInit(UART_HandleTypeDef *huart)
{//GPIO端口设置GPIO_InitTypeDef GPIO_Initure;if(huart-InstanceUSART1)//如果是串口1进行串口1 MSP初始化{__HAL_RCC_GPIOA_CLK_ENABLE(); //使能GPIOA时钟__HAL_RCC_USART1_CLK_ENABLE(); //使能USART1时钟GPIO_Initure.PinGPIO_PIN_9; //PA9GPIO_Initure.ModeGPIO_MODE_AF_PP; //复用推挽输出GPIO_Initure.PullGPIO_PULLUP; //上拉GPIO_Initure.SpeedGPIO_SPEED_FAST; //高速GPIO_Initure.AlternateGPIO_AF7_USART1; //复用为USART1HAL_GPIO_Init(GPIOA,GPIO_Initure); //初始化PA9GPIO_Initure.PinGPIO_PIN_10; //PA10HAL_GPIO_Init(GPIOA,GPIO_Initure); //初始化PA10#if EN_USART1_RXHAL_NVIC_EnableIRQ(USART1_IRQn); //使能USART1中断通道HAL_NVIC_SetPriority(USART1_IRQn,3,3); //抢占优先级3子优先级3
#endif }}void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{if(huart-InstanceUSART1)//如果是串口1{if((USART_RX_STA0x8000)0)//接收未完成{if(USART_RX_STA0x4000)//接收到了0x0d{if(aRxBuffer[0]!0x0a)USART_RX_STA0;//接收错误,重新开始else USART_RX_STA|0x8000; //接收完成了 }else //还没收到0X0D{ if(aRxBuffer[0]0x0d)USART_RX_STA|0x4000;else{USART_RX_BUF[USART_RX_STA0X3FFF]aRxBuffer[0] ;USART_RX_STA;if(USART_RX_STA(USART_REC_LEN-1))USART_RX_STA0;//接收数据错误,重新开始接收 } }}}
}//串口1中断服务程序
void USART1_IRQHandler(void)
{ u32 timeout0;u32 maxDelay0x1FFFF;HAL_UART_IRQHandler(UART1_Handler); //调用HAL库中断处理公用函数timeout0;while (HAL_UART_GetState(UART1_Handler) ! HAL_UART_STATE_READY)//等待就绪{timeout;超时处理if(timeoutmaxDelay) break; }timeout0;while(HAL_UART_Receive_IT(UART1_Handler, (u8 *)aRxBuffer, RXBUFFERSIZE) ! HAL_OK)//一次处理完成之后重新开启中断并设置RxXferCount为1{timeout; //超时处理if(timeoutmaxDelay) break; }
}
#endif /*下面代码我们直接把中断控制逻辑写在中断服务函数内部。*/
/*//串口1中断服务程序
void USART1_IRQHandler(void)
{ u8 Res;if((__HAL_UART_GET_FLAG(UART1_Handler,UART_FLAG_RXNE)!RESET)) //接收中断(接收到的数据必须是0x0d 0x0a结尾){HAL_UART_Receive(UART1_Handler,Res,1,1000); if((USART_RX_STA0x8000)0)//接收未完成{if(USART_RX_STA0x4000)//接收到了0x0d{if(Res!0x0a)USART_RX_STA0;//接收错误,重新开始else USART_RX_STA|0x8000; //接收完成了 }else //还没收到0X0D{ if(Res0x0d)USART_RX_STA|0x4000;else{USART_RX_BUF[USART_RX_STA0X3FFF]Res ;USART_RX_STA;if(USART_RX_STA(USART_REC_LEN-1))USART_RX_STA0;//接收数据错误,重新开始接收 } }} }HAL_UART_IRQHandler(UART1_Handler);
}
#endif
*/
5.3 delay.c
修改成以下内容
#include delay.h
#include sys.h
//
//如果使用OS,则包括下面的头文件即可.
#if SYSTEM_SUPPORT_OS
#include FreeRTOS.h //FreeRTOS使用
#include task.h
#endifstatic u32 fac_us0; //us延时倍乘数#if SYSTEM_SUPPORT_OS static u16 fac_ms0; //ms延时倍乘数,在os下,代表每个节拍的ms数
#endifextern void xPortSysTickHandler(void);
//systick中断服务函数,使用OS时用到
void SysTick_Handler(void)
{ if(xTaskGetSchedulerState()!taskSCHEDULER_NOT_STARTED)//系统已经运行{xPortSysTickHandler(); }HAL_IncTick();
}//初始化延迟函数
//当使用ucos的时候,此函数会初始化ucos的时钟节拍
//SYSTICK的时钟固定为AHB时钟
//SYSCLK:系统时钟频率
void delay_init(u8 SYSCLK)
{u32 reload;HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK);//SysTick频率为HCLKfac_usSYSCLK; //不论是否使用OS,fac_us都需要使用reloadSYSCLK; //每秒钟的计数次数 单位为K reload*1000000/configTICK_RATE_HZ; //根据configTICK_RATE_HZ设定溢出时间//reload为24位寄存器,最大值:16777216,在180M下,约合0.745s左右 fac_ms1000/configTICK_RATE_HZ; //代表OS可以延时的最少单位 SysTick-CTRL|SysTick_CTRL_TICKINT_Msk;//开启SYSTICK中断SysTick-LOADreload; //每1/configTICK_RATE_HZ断一次 SysTick-CTRL|SysTick_CTRL_ENABLE_Msk; //开启SYSTICK
} //延时nus
//nus:要延时的us数.
//nus:0~190887435(最大值即2^32/fac_usfac_us22.5)
void delay_us(u32 nus)
{ u32 ticks;u32 told,tnow,tcnt0;u32 reloadSysTick-LOAD; //LOAD的值 ticksnus*fac_us; //需要的节拍数 toldSysTick-VAL; //刚进入时的计数器值while(1){tnowSysTick-VAL; if(tnow!told){ if(tnowtold)tcnttold-tnow; //这里注意一下SYSTICK是一个递减的计数器就可以了.else tcntreload-tnowtold; toldtnow;if(tcntticks)break; //时间超过/等于要延迟的时间,则退出.} };
} //延时nms,会引起任务调度
//nms:要延时的ms数
//nms:0~65535
void delay_ms(u32 nms)
{ if(xTaskGetSchedulerState()!taskSCHEDULER_NOT_STARTED)//系统已经运行{ if(nmsfac_ms) //延时的时间大于OS的最少时间周期 { vTaskDelay(nms/fac_ms); //FreeRTOS延时}nms%fac_ms; //OS已经无法提供这么小的延时了,采用普通方式延时 }delay_us((u32)(nms*1000)); //普通方式延时
}//延时nms,不会引起任务调度
//nms:要延时的ms数
void delay_xms(u32 nms)
{u32 i;for(i0;inms;i) delay_us(1000);
}
编译一下如果没有错误就可以了
测试
main.c文件内容如下
#include sys.h
#include delay.h
#include usart.h
#include led.h
#include FreeRTOS.h
#include task.h//任务优先级
#define START_TASK_PRIO 1
//任务堆栈大小
#define START_STK_SIZE 128
//任务句柄
TaskHandle_t StartTask_Handler;
//任务函数
void start_task(void *pvParameters);//任务优先级
#define LED0_TASK_PRIO 2
//任务堆栈大小
#define LED0_STK_SIZE 50
//任务句柄
TaskHandle_t LED0Task_Handler;
//任务函数
void led0_task(void *pvParameters);//任务优先级
#define LED1_TASK_PRIO 3
//任务堆栈大小
#define LED1_STK_SIZE 50
//任务句柄
TaskHandle_t LED1Task_Handler;
//任务函数
void led1_task(void *pvParameters);//任务优先级
#define FLOAT_TASK_PRIO 4
//任务堆栈大小
#define FLOAT_STK_SIZE 128
//任务句柄
TaskHandle_t FLOATTask_Handler;
//任务函数
void float_task(void *pvParameters);int main(void)
{HAL_Init(); //初始化HAL库 Stm32_Clock_Init(360,25,2,8); //设置时钟,180Mhzdelay_init(180); //初始化延时函数LED_Init(); //初始化LED uart_init(115200); //初始化串口//创建开始任务xTaskCreate((TaskFunction_t )start_task, //任务函数(const char* )start_task, //任务名称(uint16_t )START_STK_SIZE, //任务堆栈大小(void* )NULL, //传递给任务函数的参数(UBaseType_t )START_TASK_PRIO, //任务优先级(TaskHandle_t* )StartTask_Handler); //任务句柄 vTaskStartScheduler(); //开启任务调度
}//开始任务任务函数
void start_task(void *pvParameters)
{taskENTER_CRITICAL(); //进入临界区//创建LED0任务xTaskCreate((TaskFunction_t )led0_task, (const char* )led0_task, (uint16_t )LED0_STK_SIZE, (void* )NULL, (UBaseType_t )LED0_TASK_PRIO, (TaskHandle_t* )LED0Task_Handler); //创建LED1任务xTaskCreate((TaskFunction_t )led1_task, (const char* )led1_task, (uint16_t )LED1_STK_SIZE, (void* )NULL,(UBaseType_t )LED1_TASK_PRIO,(TaskHandle_t* )LED1Task_Handler); //浮点测试任务xTaskCreate((TaskFunction_t )float_task, (const char* )float_task, (uint16_t )FLOAT_STK_SIZE, (void* )NULL, (UBaseType_t )FLOAT_TASK_PRIO,(TaskHandle_t* )FLOATTask_Handler); vTaskDelete(StartTask_Handler); //删除开始任务taskEXIT_CRITICAL(); //退出临界区
}//LED0任务函数
void led0_task(void *pvParameters)
{while(1){LED0~LED0;vTaskDelay(500);}
} //LED1任务函数
void led1_task(void *pvParameters)
{while(1){LED10;vTaskDelay(200);LED11;vTaskDelay(800);}
}//浮点测试任务
void float_task(void *pvParameters)
{static float float_num0.00;while(1){ float_num0.01f;printf(float_num的值为: %.4f\r\n,float_num);vTaskDelay(1000);}
}
编译将程序烧录到开发板中可以发现LED0、LED1闪烁移植成功