前后台系统
早期嵌入式开发没有嵌入式操作系统概念,直接操作裸机,直接在逻辑上写程序,比如51单片机没有操作系统的概念。通常把程序分为前台系统和后台系统。
签单的小系统通常是前后台系统。这样的程序包括一个死循环和若干个中断服务程序:应用程序是一个无限循环,循环中调用API库函数完成作需的操作,大循环叫做后台系统。中断服务程序用于处理系统的异步事件,也就是前台系统。前台是中断级,后台是任务级。
RTOS系统
RTOS全称为:Real time OS ,就是实时操作系统,强调的是:实时性。
实时操作系统又分为软实时和硬实时。硬实时要求在规定的时间内必须完成操作,硬实时不允许超时,软实时里面处理过程超时的后果就没有那么严格。
在实时操作系统种,我们可以把要实现的功能划分为多个任务,每个任务负责实现其中的一部分,每个任务都是一个很简单的程序,通常是一个死循环。 RTOS操作系统: Freertos, UCOS,RTX,RT-THread,DJYOS等
RTOS操作系统的核心内容在于: 实时内核。
可剥夺型内核
RTOS的内核负责管理所有的任务,内核决定了运行哪个任务,何时停止当前任务切换到其他任务,这个是内核的多任务管理能力。多任务管理给人的感觉就是芯片有多个CPU,多任务管理实现了CPU资源的最大化利用,多任务管理有助于实现程序的模块化开发,能够实现复杂的实时用。
可剥夺型内核顾名思义就是可以剥夺其他任务的CPU使用权,他总是运行就绪任务中优先级最高的任务。
FreeRtos系统简介
Freertos是一个可剪裁,可剥夺型的多任务内核,而且没有任务数限制。Freertos提供了实时操作系统所需的所有功能,包括资源管理、同步、任务通信等。
Freertos是用C和汇编来写的,其中绝大部分都是用C语言编写的,只有极少数的与处理器密切相关的部分代码才是用汇编写的,Freertos结构简洁,可读性很强!最主要的是非常适合初次接触嵌入式实时操作系统开发者。
FreeRTOS任务特性
1.任务简单
2.任务没有数量使用限制
3.任务支持抢占(抢占式内核)
4.任务支持优先级
5.每个任务都拥有堆栈导致了RAM使用量增大
6.如果使用抢占的话必须仔细的考虑重入问题
FreeRTOS任务状态
FreeRTOS任务优先级
任务优先级决定了任务的执行优先级别,在FreeRTOS中优先级可选范围位:
0 ~ configMAX_PRIORITIES-1
数字越大,优先级越高
FreeRTOS任务实现
任务实现即为任务的具体工作内容
void vATaskFuntion(void *pvParameters )
{
for(;;)
{ --任务应用程序-- vTaskDelay(); /*不能从任务函数中直接退出, 否则会调用configASSERT(),要退出一定要调用vTaskDelete(NULL)删除此任务。*/
}
vTaskDelete(NULL);
}
FreeRTOS任务控制块
描述任务属性的数据结构称为任务控制块,称为TCB_t.
typedef struct tskTaskControlBlock {
volatile StackType_t * pxTopOfStack; #if ( portUSING_MPU_WRAPPERS == 1 ) xMPU_SETTINGS xMPUSettings;
#endif
ListItem_t xStateListItem;
ListItem_t xEventListItem;
UBaseType_t uxPriority;
StackType_t * pxStack;
} tskTCB typedef tskTCB TCB_t;
FreeRTOS任务堆栈
任务堆栈用来保存任务现场(CPU寄存器值),创建任务的时候需要指定任务堆栈, 任务堆栈的变量类型为 StackType_t ,此变量类型如下:
#define portSTACK_TYPE uint32_t
#define portBASK_TYPE long
#define portSTACK_TYPE StackType_t
任务创建和删除API函数
建立一个任务,控制led灯的闪烁
led灯的初始化
void LED_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC|RCC_APB2Periph_GPIOE, ENABLE); //ʹÄÜPB,PE¶Ë¿ÚʱÖÓ
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13; //LED0-->PB.5 ¶Ë¿ÚÅäÖÃ
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //ÍÆÍìÊä³ö
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //IO¿ÚËÙ¶ÈΪ50MHz
GPIO_Init(GPIOC, &GPIO_InitStructure); //¸ù¾ÝÉ趨²ÎÊý³õʼ»¯GPIOB.5
GPIO_SetBits(GPIOC,GPIO_Pin_13); //PB.5 Êä³ö¸ß
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; //LED1-->PE.5 ¶Ë¿ÚÅäÖÃ, ÍÆÍìÊä³ö
GPIO_Init(GPIOA, &GPIO_InitStructure); //ÍÆÍìÊä³ö £¬IO¿ÚËÙ¶ÈΪ50MHz
GPIO_SetBits(GPIOA,GPIO_Pin_5); //PE.5 Êä³ö¸ß
}
延迟初始化
void delay_init()
{
u32 reload;
SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK);//Ñ¡ÔñÍⲿʱÖÓ HCLK
fac_us=SystemCoreClock/1000000; //²»ÂÛÊÇ·ñʹÓÃOS,fac_us¶¼ÐèҪʹÓÃ
reload=SystemCoreClock/1000000; //ÿÃëÖӵļÆÊý´ÎÊý µ¥Î»ÎªM
reload*=1000000/configTICK_RATE_HZ; //¸ù¾ÝconfigTICK_RATE_HZÉ趨Òç³öʱ¼ä
//reloadΪ24λ¼Ä´æÆ÷,×î´óÖµ:16777216,ÔÚ72MÏÂ,Ô¼ºÏ0.233s×óÓÒ
fac_ms=1000/configTICK_RATE_HZ; //´ú±íOS¿ÉÒÔÑÓʱµÄ×îÉÙµ¥Î»
SysTick->CTRL|=SysTick_CTRL_TICKINT_Msk; //¿ªÆôSYSTICKÖжÏ
SysTick->LOAD=reload; //ÿ1/configTICK_RATE_HZÃëÖжÏÒ»´Î
SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk; //¿ªÆôSYSTICK
}
串口初始化
void uart_init(u32 bound){
//GPIO¶Ë¿ÚÉèÖÃ
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOA, ENABLE); //ʹÄÜUSART1£¬GPIOAʱÖÓ
//USART1_TX GPIOA.9
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //PA.9
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //¸´ÓÃÍÆÍìÊä³ö
GPIO_Init(GPIOA, &GPIO_InitStructure);//³õʼ»¯GPIOA.9
//USART1_RX GPIOA.10³õʼ»¯
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;//PA10
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//¸¡¿ÕÊäÈë
GPIO_Init(GPIOA, &GPIO_InitStructure);//³õʼ»¯GPIOA.10
//Usart1 NVIC ÅäÖÃ
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3 ;//ÇÀÕ¼ÓÅÏȼ¶3
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; //×ÓÓÅÏȼ¶3
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQͨµÀʹÄÜ
NVIC_Init(&NVIC_InitStructure); //¸ù¾ÝÖ¸¶¨µÄ²ÎÊý³õʼ»¯VIC¼Ä´æÆ÷
//USART ³õʼ»¯ÉèÖÃ
USART_InitStructure.USART_BaudRate = bound;//´®¿Ú²¨ÌØÂÊ
USART_InitStructure.USART_WordLength = USART_WordLength_8b;//×Ö³¤Îª8λÊý¾Ý¸ñʽ
USART_InitStructure.USART_StopBits = USART_StopBits_1;//Ò»¸öֹͣλ
USART_InitStructure.USART_Parity = USART_Parity_No;//ÎÞÆæżУÑéλ
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//ÎÞÓ²¼þÊý¾ÝÁ÷¿ØÖÆ
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; //ÊÕ·¢Ä£Ê½
USART_Init(USART1, &USART_InitStructure); //³õʼ»¯´®¿Ú1
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//¿ªÆô´®¿Ú½ÓÊÜÖжÏ
USART_Cmd(USART1, ENABLE); //ʹÄÜ´®¿Ú1
}
动态
//ÈÎÎñÓÅÏȼ¶
#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);
int main(void)
{
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);//ÉèÖÃϵͳÖжÏÓÅÏȼ¶·Ö×é4
delay_init(); //ÑÓʱº¯Êý³õʼ»¯
uart_init(115200); //³õʼ»¯´®¿Ú
LED_Init(); //³õʼ»¯LED
//´´½¨¿ªÊ¼ÈÎÎñ
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);
vTaskDelete(StartTask_Handler); //ɾ³ý¿ªÊ¼ÈÎÎñ
taskEXIT_CRITICAL(); //Í˳öÁÙ½çÇø
}
//LED0ÈÎÎñº¯Êý
void led0_task(void *pvParameters)
{
while(1)
{
LED0=~LED0;
vTaskDelay(500);
printf("tash0");
}
}
//LED1ÈÎÎñº¯Êý
void led1_task(void *pvParameters)
{
while(1)
{
LED1=0;
vTaskDelay(200);
LED1=1;
vTaskDelay(800);
printf("task1");
}
}
静态
//¿ªÊ¼ÈÎÎñ
#define STARE_SIZE 120
#define START_PRIO 1
void start_task(void *pvParameters);
TaskHandle_t StartTask_Handle;
StaticTask_t startTIDLTCB;
StackType_t startidletaskstack[STARE_SIZE];
//led0
#define LED0_STK_SIZE 120
#define LED0_TASK_PRIO 1
TaskHandle_t LED0Task_Handler;
void start_task(void *pvParameters);
void led0_task(void *pvParameters);
StaticTask_t led0TIDLTCB;
StackType_t led0idletaskstack[LED0_STK_SIZE];
//led1
#define LED1_STK_SIZE 120
#define LED1_TASK_PRIO 1
void start_task(void *pvParameters);
void led1_task(void *pvParameters);
TaskHandle_t LED1Task_Handler;
StaticTask_t led1TIDLTCB;
StackType_t led1idletaskstack[LED1_STK_SIZE];
//¿ÕÏÐÈÎÎñ
static StaticTask_t TIDLTCB;
static StackType_t idletaskstack[configMINIMAL_STACK_SIZE];
void vApplicationGetIdleTaskMemory( StaticTask_t ** ppxIdleTaskTCBBuffer,
StackType_t ** ppxIdleTaskStackBuffer,
uint32_t * pulIdleTaskStackSize )
{
* ppxIdleTaskTCBBuffer=&TIDLTCB;
* ppxIdleTaskStackBuffer=idletaskstack;
* pulIdleTaskStackSize=configMINIMAL_STACK_SIZE;
}
static StaticTask_t TimerLTCB;
static StackType_t timerletaskstack[configTIMER_TASK_STACK_DEPTH];
//¶¨Ê±Æ÷ÈÎÎñ
extern void vApplicationGetTimerTaskMemory( StaticTask_t ** ppxTimerTaskTCBBuffer,
StackType_t ** ppxTimerTaskStackBuffer,
uint32_t * pulTimerTaskStackSize )
{
* ppxTimerTaskTCBBuffer=&TimerLTCB;
* ppxTimerTaskStackBuffer=timerletaskstack;
* pulTimerTaskStackSize=configTIMER_TASK_STACK_DEPTH;
}
int main(void)
{
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);//ÉèÖÃϵͳÖжÏÓÅÏȼ¶·Ö×é4
delay_init(); //ÑÓʱº¯Êý³õʼ»¯
uart_init(115200); //³õʼ»¯´®¿Ú
LED_Init(); //³õʼ»¯LED
GPIO_SetBits(GPIOA,GPIO_Pin_5);
//´´½¨¿ªÊ¼ÈÎÎñ
StartTask_Handle = xTaskCreateStatic( (TaskFunction_t) start_task,
(char * ) "start_task",
(uint32_t) STARE_SIZE,
(void *) NULL,
(UBaseType_t) START_PRIO,
(StackType_t *) startidletaskstack,
(StaticTask_t *) &startTIDLTCB);
vTaskStartScheduler();
}
//¿ªÊ¼ÈÎÎñÈÎÎñº¯Êý
void start_task(void *pvParameters)
{
taskENTER_CRITICAL(); //½øÈëÁÙ½çÇø
//´´½¨LED0ÈÎÎñ
LED0Task_Handler = xTaskCreateStatic( (TaskFunction_t) led0_task,
(char * ) "led0_task",
(uint32_t) LED0_STK_SIZE,
(void *) NULL,
(UBaseType_t) LED0_TASK_PRIO,
(StackType_t *) led0idletaskstack,
(StaticTask_t *) &led0TIDLTCB);
//´´½¨LED1ÈÎÎñ
LED1Task_Handler = xTaskCreateStatic( (TaskFunction_t) led1_task,
(char * ) "led1_task",
(uint32_t) LED1_STK_SIZE,
(void *) NULL,
(UBaseType_t) LED1_TASK_PRIO,
(StackType_t *) led1idletaskstack
,
(StaticTask_t *) &led1TIDLTCB);
vTaskDelete(StartTask_Handle); //ɾ³ý¿ªÊ¼ÈÎÎñ
}
//LED0ÈÎÎñº¯Êý
void led0_task(void *pvParameters)
{
while(1)
{
LED0=~LED0;
vTaskDelay(500);
printf("led0");
}
}
//LED1ÈÎÎñº¯Êý
void led1_task(void *pvParameters)
{
while(1)
{
LED1=~LED1;
vTaskDelay(500);
printf("led1");
}
}
任务的恢复和挂起API
我在动态的基础上加了一个振动器
振动器的初始化
void key_init(void)
{
GPIO_InitTypeDef keyinit;
RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOB , ENABLE);
keyinit.GPIO_Mode = GPIO_Mode_IPD;
keyinit.GPIO_Pin = GPIO_Pin_10;
keyinit.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &keyinit);
keyinit.GPIO_Mode = GPIO_Mode_IPD;
keyinit.GPIO_Pin = GPIO_Pin_8;
GPIO_Init(GPIOB, &keyinit);
}
振动器在主函数的使用
创建任务
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);
key任务函数
void KEY_task(void *pvParameters)
{
while(1)
{
if(GPIO_ReadInputDataBit( GPIOB, GPIO_Pin_10)==0)
{
vTaskDelay(800);
vTaskSuspend(LED0Task_Handler);
printf("led0 is supsend");
}
else if(GPIO_ReadInputDataBit( GPIOB, GPIO_Pin_8)==0)
{
vTaskDelay(800);
vTaskResume(LED0Task_Handler);
printf("led0 is supsend");
}
}
}
如果要是外部中断的话跟上面的是一样,不一样的地方就是将恢复状态放到中断函数的处理函数中
Cortex-M中断
中断简介
中断是微控制器一个很常见的特性,中断由硬件产生,当中断产生之后CPU就会中断当前的流程而去处理中断服务,Cortex-M 内核的MCU提供了一个用于中断管理的嵌套向量中断控制器NVIC。 Cotex-M3和M4的NVIC最多支持240个IRQ(中断请求),1个不可屏蔽中断(NMI),1个Systick(滴答定时器)定时器中断和多个系统异常。 与中断相关的寄存器都在NVIC和SCB中。
优先级分组
为了使抢占机能变得更加可控,CM3还把256级优先级按位分成高低两段,分别是抢占优先级和亚优先级,MSB所在的位段(左边的)对应抢占优先级,而LSB所在的位段(右边的)对应亚优先级。
优先级设置
对于外设中断优先级的设置可以通过寄存器: 0XE000_E400 ~ 0XE000E4EF
系统异常中断通过寄存器 0XE000_ED18 ~ 0XE000ED23
中断屏蔽寄存器
中断屏蔽寄存器有3个:
1.PRIMASK
2.PAULTMASK
3.BASEPRI
1.开中断函数 portENABLE_INTERRUPTS()
2.关中断函数 portDISABLE_INTERRUPTS()
FreeRtos中断实验
初始化两个定时器中断
Timer3
void TIM3_Int_Init(u16 arr,u16 psc)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); //ʱÖÓʹÄÜ
//¶¨Ê±Æ÷TIM3³õʼ»¯
TIM_TimeBaseStructure.TIM_Period = arr; //ÉèÖÃÔÚÏÂÒ»¸ö¸üÐÂʼþ×°Èë»î¶¯µÄ×Ô¶¯ÖØ×°ÔؼĴæÆ÷ÖÜÆÚµÄÖµ
TIM_TimeBaseStructure.TIM_Prescaler =psc; //ÉèÖÃÓÃÀ´×÷ΪTIMxʱÖÓƵÂʳýÊýµÄÔ¤·ÖƵֵ
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //ÉèÖÃʱÖÓ·Ö¸î:TDTS = Tck_tim
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIMÏòÉϼÆÊýģʽ
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); //¸ù¾ÝÖ¸¶¨µÄ²ÎÊý³õʼ»¯TIMxµÄʱ¼ä»ùÊýµ¥Î»
TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE ); //ʹÄÜÖ¸¶¨µÄTIM3ÖжÏ,ÔÊÐí¸üÐÂÖжÏ
//ÖжÏÓÅÏȼ¶NVICÉèÖÃ
NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn; //TIM3ÖжÏ
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 4; //ÏÈÕ¼ÓÅÏȼ¶4¼¶
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; //´ÓÓÅÏȼ¶0¼¶
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQͨµÀ±»Ê¹ÄÜ
NVIC_Init(&NVIC_InitStructure); //³õʼ»¯NVIC¼Ä´æÆ÷
TIM_Cmd(TIM3, ENABLE); //ʹÄÜTIMx
}
Timer5
void TIM5_Int_Init(u16 arr,u16 psc)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5, ENABLE); //ʱÖÓʹÄÜ
//¶¨Ê±Æ÷TIM5³õʼ»¯
TIM_TimeBaseStructure.TIM_Period = arr; //ÉèÖÃÔÚÏÂÒ»¸ö¸üÐÂʼþ×°Èë»î¶¯µÄ×Ô¶¯ÖØ×°ÔؼĴæÆ÷ÖÜÆÚµÄÖµ
TIM_TimeBaseStructure.TIM_Prescaler =psc; //ÉèÖÃÓÃÀ´×÷ΪTIMxʱÖÓƵÂʳýÊýµÄÔ¤·ÖƵֵ
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //ÉèÖÃʱÖÓ·Ö¸î:TDTS = Tck_tim
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIMÏòÉϼÆÊýģʽ
TIM_TimeBaseInit(TIM5, &TIM_TimeBaseStructure); //¸ù¾ÝÖ¸¶¨µÄ²ÎÊý³õʼ»¯TIMxµÄʱ¼ä»ùÊýµ¥Î»
TIM_ITConfig(TIM5,TIM_IT_Update,ENABLE ); //ʹÄÜÖ¸¶¨µÄTIM5ÖжÏ,ÔÊÐí¸üÐÂÖжÏ
//ÖжÏÓÅÏȼ¶NVICÉèÖÃ
NVIC_InitStructure.NVIC_IRQChannel = TIM5_IRQn; //TIM5ÖжÏ
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 5; //ÏÈÕ¼ÓÅÏȼ¶5¼¶
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; //´ÓÓÅÏȼ¶0¼¶
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQͨµÀ±»Ê¹ÄÜ
NVIC_Init(&NVIC_InitStructure); //³õʼ»¯NVIC¼Ä´æÆ÷
TIM_Cmd(TIM5, ENABLE); //ʹÄÜTIM5
}
定时器3的服务中断函数
void TIM3_IRQHandler(void)
{
if(TIM_GetITStatus(TIM3,TIM_IT_Update)==SET) //Òç³öÖжÏ
{
printf("TIM3Êä³ö.......\r\n");
}
TIM_ClearITPendingBit(TIM3,TIM_IT_Update); //Çå³ýÖжϱê־λ
}
定时器5的服务中断函数
void TIM5_IRQHandler(void)
{
if(TIM_GetITStatus(TIM5,TIM_IT_Update)==SET) //Òç³öÖжÏ
{
printf("TIM5Êä³ö.......\r\n");
}
TIM_ClearITPendingBit(TIM5,TIM_IT_Update); //Çå³ýÖжϱê־λ
}
主函数中的测试任务函数
void interrupt_task(void *pvParameters)
{
static u32 total_num=0;
while(1)
{
total_num+=1;
if(total_num==5)
{
printf("¹Ø±ÕÖжÏ.............\r\n");
portDISABLE_INTERRUPTS(); //¹Ø±ÕÖжÏ
delay_xms(5000); //ÑÓʱ5s
printf("´ò¿ªÖжÏ.............\r\n"); //´ò¿ªÖжÏ
portENABLE_INTERRUPTS();
}
LED0=~LED0;
vTaskDelay(1000);
}
}
列表和列表项
Freertos列表与列表项是Freertos的一个数据结构,类似于链表。 Freertos中大量使用了列表和列表项,它是Freertos中的基石 方便我们学习Freertos源码和原理。
列表
列表是 Freertos中的一个数据结构,概念上和链表有点类似,列表被用于跟踪Freertos的任务。列表结构为List_t,在文件list.h中定义:
列表项相关API函数
注意在插入一般是按照插入数字的大小来排序的,列表其实就是一个双向链表,如果要是只有两个的话,就是两者互相指。
FreeRTOS信息查询和任务统计
可以根据操作手册简单测试一下
ESP8266 WIFI
ESP-01s模块它是由一颗ESP8266作为主控再由一颗flash作为存储芯片组成的,带有板载芯片供电采用3.3V电压使用串口进行烧写程序和AT指令集调试的,注意芯片一旦烧写了程序便不可使用AT指令集需要重新刷回AT指令集固件才可以使用AT指令集 。
AT指令
CR (Carriage Return ) 表示回车 \r
LF (Line Feed)表示换行 \n
Dos和Windows采用回车+换行(CR+LF)
表示下一行 Unix/Linux采用换行符(LF)表示下一行 MAC OS 系统采用和回车符(CR)
表示下一行 Windows下编写的Shell脚本,直接放到Linux/unix下执行会报错, 就是因为行结束符不一样导致的。 \r 表示回车 \n 表示换行 \r\n表示回车换行
AT指令说明
常用AT指令
ESP8266三种模式
1.Station(客户端模式)
2.AP(接入点模式)
3.Station+AP模式