关于位带操作的PAin与PAout
PAIN(0)表示CPU读取PA_0引脚的电平状态,而PAOUT(0)表示CPU控制PA_0输出高电位或低电位。
关于GPIO的输入模式和输出模式
输入模式是指将GPIO的引脚信息放入输入寄存器,便于CPU提取。
输出模式是指将输出寄存器的数字信号输出到相应引脚,由此实现CPU对其的电位控制。
关于实时操作系统移植到单片机以及对其代码运行流程的理解
实时操作系统中将单片机轮询的运行方式变更为抢占式任务调度的运行方式,首先对各任务设立不同优先级并不断循环运行,再将所有任务放入就绪队列。对于高优先级的任务,在其中加入vTaskDelay函数(操作系统自带的延时函数),从而让CPU释放出来去运行其他优先级较低的任务,结合相应的任务挂起函数和任务恢复函数,实现对各个任务的调度运行。
如下是一个简单的移植RTOS的单片机程序,用于学习和理解实时操作系统。
#include "system.h"
#include "SysTick.h"
#include "led.h"
#include "usart.h"
#include "FreeRTOS.h"
#include "task.h"
#include "key.h"
//任务优先级
#define START_TASK_PRIO 1
//任务堆栈大小
#define START_STK_SIZE 128
//任务句柄
TaskHandle_t StartTask_Handler;
//任务函数
void start_task(void *pvParameters);
//任务优先级
#define LED1_TASK_PRIO 2
//任务堆栈大小
#define LED1_STK_SIZE 50
//任务句柄
TaskHandle_t LED1Task_Handler;
//任务函数
void led1_task(void *pvParameters);
//任务优先级
#define LED2_TASK_PRIO 3
//任务堆栈大小
#define LED2_STK_SIZE 50
//任务句柄
TaskHandle_t LED2Task_Handler;
//任务函数
void led2_task(void *pvParameters);
//任务优先级
#define KEY_TASK_PRIO 4
//任务堆栈大小
#define KEY_STK_SIZE 50
//任务句柄
TaskHandle_t KEYTask_Handler;
//任务函数
void key_task(void *pvParameters);
/*******************************************************************************
* 函 数 名 : main
* 函数功能 : 主函数
* 输 入 : 无
* 输 出 : 无
*******************************************************************************/
int main()
{
SysTick_Init(72);
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);//设置系统中断优先级分组4
LED_Init();
KEY_Init();
USART1_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(); //进入临界区
//创建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);
//创建LED2任务
xTaskCreate((TaskFunction_t )led2_task,
(const char* )"led2_task",
(uint16_t )LED2_STK_SIZE,
(void* )NULL,
(UBaseType_t )LED2_TASK_PRIO,
(TaskHandle_t* )&LED2Task_Handler);
//创建KEY任务
xTaskCreate((TaskFunction_t )key_task,
(const char* )"key_task",
(uint16_t )KEY_STK_SIZE,
(void* )NULL,
(UBaseType_t )KEY_TASK_PRIO,
(TaskHandle_t* )&KEYTask_Handler);
vTaskDelete(StartTask_Handler); //删除开始任务
taskEXIT_CRITICAL(); //退出临界区
}
//LED1任务函数
void led1_task(void *pvParameters)
{
while(1)
{
LED1=0;
vTaskDelay(200);
LED1=1;
vTaskDelay(800);
}
}
//LED2任务函数
void led2_task(void *pvParameters)
{
while(1)
{
LED2=0;
vTaskDelay(800);
LED2=1;
vTaskDelay(200);
}
}
//KEY任务函数
void key_task(void *pvParameters)
{
u8 key=0;
while(1)
{
key=KEY_Scan(0);
if(key==KEY_UP_PRESS)
{
printf("挂起LED任务!\n");
vTaskSuspend(LED2Task_Handler);/* 挂起LED任务 */
printf("挂起LED任务成功!\n");
}
else if(key==KEY1_PRESS)
{
printf("恢复LED任务!\n");
vTaskResume(LED2Task_Handler);/* 恢复LED任务!*/
printf("恢复LED任务成功!\n");
}
vTaskDelay(20);
}
}