基于FreeRTOS的智能家居系统

材料

STM32F103C8T8最小开发版,直流电机,舵机,OLED,LED两个,蜂鸣器,光敏传感器,按键两个,面包板 ,若干杜邦线

功能描述

  1. 按下Key1,电机的速度增加,一共20 40 60 60 100 、 -(20 40 60 60 100)和 0一共11个挡位;按下Key2,LED1的亮度增加,一共20 40 60 80 100  5个挡位;
  2. 创建了定时器,每隔两秒进行舵机的驱动,30 60 90 180 四个转动方向,舵机转动的同时,也带着电机进行旋转;从而实现了”摇头风扇“。。当然定时器的开启和关门可以使用Key2和Key1进行控制;
  3. 受光敏传感器的控制,当检测到当前的光线比较暗,LED2可以实现自我开启,模拟傍晚来临,门外路灯开启的情况
  4. LED显示电机速度信息,LED亮度信息,舵机的角度信息,AD1的光敏转换信息
  5. 当LED1的亮度为100,电机的速度为100,LED2(门外的路灯)也为亮状态,会触发蜂鸣器报警,说明用电功率过大;

程序设计

所使用的Keil5编写;

int main()
{
//	TaskHandle_t xHandleTask1;
	/* create Event_Group */
	xEventGroupCalc = xEventGroupCreate();
	/* create Task_Init , Delete(NULL) */
	xTaskCreate(Task_Init, "Task_Init", 256, NULL, 3, NULL);
	/* create MOTOR TASK */
	xTaskCreate(Button2_MOTOR, "Button2_MOTOR", 256, NULL, 1, NULL);
	/* create LED1 TASK */
	xTaskCreate(Button1_LED, "Button1_LED", 256, NULL, 1, NULL);
	/* create ADC TASK */
	xTaskCreate(TaskADC1_Channel1, "TaskADC1_Channel1", 256, NULL, 1, NULL);
	/* create BUZZER TASK */
	xTaskCreate(Task_Buzzer, "Task_Buzzer", 256, NULL, 2, NULL);
	/* create TimerCMD_KEY1&KEY2 TASK */
	xTaskCreate(TaskTimercmd, "TaskTimercmd", 256, NULL, 1, NULL);
	/*¶¨Ê±Æ÷×Ô¶¯¼ÓÔØ pdTRUE£¬¼ÓÔØÒ»´Î pdFALSE */
	xMyHandleTimer = xTimerCreate("mytimer",100,pdTRUE,NULL,vCallbackFunction);
	
	/* Start the scheduler. */
	vTaskStartScheduler();
}

首先在主函数中,创建任务,我们一共有以下几个任务 

初始化程序, MOTOR转动  , LED1的亮暗光敏传感器ADC,   蜂鸣器的报警装置,     

定时器开启和关闭的控制,   定时器的开启(守护任务,执行舵机角度的转换),




初始化程序

/*Init progress*/
void Task_Init(void *param)
{
	Key_Init();
	LED_Init();
	Motor_Init();
	OLED_Init();
	PWM_Init();
	Servo_Init();
	AD_Init();
	Buzzer_Init();
	vTaskDelete(NULL);/* Delete myself*/

	while(1)
	{
	}
}

MOTOR转动 

/* °´ÏÂPB11£LMOTOR ËÙ¶ÈÔö¼Ó*/
void Button2_MOTOR(void *param)
{	
	OLED_ShowString(1, 1, "Sp:");
	OLED_ShowString(1, 10, "Ld:");
	OLED_ShowString(2, 1, "NUM:");
	OLED_ShowString(2, 8, "Ang:");
	OLED_ShowString(3, 1, "AD1:");
	while (1)	
	{
		KeyNum = Key_GetNum();
		if(KeyNum == 2)
		{
			Speed += 20;
			if (Speed > 100)
			{
//				xEventGroupSetBits(xEventGroupCalc, (1<<0));
				Speed = -100;
			}
			Motor_SetSpeed(Speed);
			OLED_ShowSignedNum(1, 4, Speed, 3);
			vTaskDelay(1);
		}
		if(Speed >= 100){xEventGroupSetBits(xEventGroupCalc, (1<<0));}
	}
}

  LED1的亮暗

/* °´ÏÂPB1£LLED ÁÁ¶ÈÔö¼Ó */
void Button1_LED(void *param)
{
	while(1)
	{		
		KeyNum = Key_GetNum();
		if(KeyNum == 1)
		{
			Light+=20;
			if (Light > 100)
			{				
				Light = 0;
			}
			PWM_SetCompare1(Light);
			OLED_ShowNum(1, 13, Light, 3);

			vTaskDelay(1);
		}
		if(Light >= 100){xEventGroupSetBits(xEventGroupCalc, (1<<1));}
	}
}

 光敏传感器ADC

/* ADC1 Channel PA1  ¹âÃô´«¸ÐÆ÷*/
void TaskADC1_Channel1(void *param)
{	
	while(1)
	{
		AD1 = AD_GetValue(ADC_Channel_1);
		vTaskDelay(10);
		OLED_ShowNum(3, 5, AD1, 4);
		if(AD1 > 2000)
		{
			xEventGroupSetBits(xEventGroupCalc, (1<<2));
			LED2_ON();
		}
		else if(AD1 >1000)
		{
			LED2_OFF();
		}
	}
	
	
}

蜂鸣器的报警装置 

void Task_Buzzer(void *param)
{
	while(1)
	{
		xEventGroupWaitBits(xEventGroupCalc, (1<<0)|(1<<1)|(1<<2),pdTRUE, pdTRUE,portMAX_DELAY);

//		if(Speed >= 80&& Light >= 80 && AD1 > 1800)
//		{
		Buzzer_ON();
		vTaskDelay(100);
		Buzzer_OFF();
		vTaskDelay(100);
//		}
	}
}

 定时器开启和关闭的控制

void TaskTimercmd(void *param)
{
	while(1)
	{	
		KeyNum = Key_GetNum();
		if(KeyNum == 1)
		{
			/* start Timer*/
			xTimerStart(xMyHandleTimer,0);
		}
		else if(KeyNum == 2)
			/* stop Timer*/
			xTimerStop(xMyHandleTimer,0);
	}
}

 定时器的开启(守护任务,执行舵机角度的转换)

void vCallbackFunction( TimerHandle_t xTimer )
{
	LED2_Turn();
	NUM++;
	OLED_ShowNum(2,5,NUM,2);
	OLED_ShowNum(2, 13, Angle, 3);
	vTaskDelay(1);
	if(NUM >= 2)
	{
		Angle = 60;
	}
	if(NUM >= 4)
	{
		Angle = 90;
	}
	if(NUM >= 6)
	{
		Angle = 120;
	}
	if(NUM >= 8)
	{
		Angle = 180;
	}
	if(NUM >= 9)
	{
		Angle = 0;
		NUM = 0;
	}
	Servo_SetAngle(Angle);
}

涉及的知识点 

FreeRTOS的并发性,优先级情况一样的情况下,各个任务看似在同时运行,其实也不是的,每隔任务执行1s,切换的非常快,给人的感觉就是在同时执行,因此裸机开发不同。主函数中没有while(1),主函数中仅仅进行了任务的创建;

任务与任务,怎么交流呢? ok  队列 ,信号量,互斥量,任务通知和 事件组,互斥量就是二进制信号量的一种,二进制信号量的初始值为0,用的时候需要先give一下,然后下一个在take;互斥量的初始值为1,直接Take,我Take了,我要使用临界资源啦,你们不允许来哈;


还有报警系统 我采用的事件组的形式,比如Task1执行完之后,我给事件组bit0一个标志位, Task2的执行完任务,给bit1一个标志位,在Task3里面,等待这两个任务全部完成,或是其中一个完成 我就开始执行task3里面的程序;如果Task3的优先级比Task1 和 Task2的优先级高,Task3也是要等待前两个任务执行完成奥、

在这里,MOTOR的速度达到100,LED1的亮度达到100,同时LED2也是发亮的,ok 这时候我就开始执行BUZZER啦,开始疯狂的响啊。由于程序的并发执行,嘿嘿,然后你改动一下任意一个,他就不响啦

pdTRUE:AND

pdTRUE:完事之后,清除标志位

portMAX_DELAY:等啊等;如果设置为0,他就会立刻就响


还有一个是关于定时器的创建 开和关 

两个模式欸: 自动加载 和 一次的  我们使用的是自动加载 pdTRUE

创建

开启

关闭 

 

 

守护任务,定时器里面需要执行的程序呀,注意他的优先级在FreeCONfig,h文件中是需要定义的,优先级一定要高于开启定时器的任务的优先级,要不然她无法抢占开启定时器的任务,也就是无法执行守护任务里面的程序代码哈、、、具体的可以看这里13-2_定时器的一般使用 (100ask.net)

 

程序接口配置

 

LED1PA0使用PWM波形驱动TIM2_CH0
MOTORPA2使用PWM波形驱动TIM2_CH2
ADC1光敏传感PA1channel_1 ADC12_IN1
舵机PA6使用PWM波形驱动TIM3_CH1
LED2PA9低电平
BUZZERPA12低电平

NOTE: 在引脚复用表中,一定要注意引脚重复定义,这样你都不知道那里出的问题。

 

还有哈 针对PWM的初始化

 开启内部时钟 开两个也行哈 然后 我定义了PA0 PA2 还有PA6(LED1 MOTOR 舵机)

 总的PWM初始化程序如下:

#include "stm32f10x.h"                  // Device header

void PWM_Init(void)
{
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
	
//	RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
//	GPIO_PinRemapConfig(GPIO_PartialRemap1_TIM2, ENABLE);
//	GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE);
	
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_2|GPIO_Pin_6;		//GPIO_Pin_15;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);
	
	TIM_InternalClockConfig(TIM2);
	TIM_InternalClockConfig(TIM3);

	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
	TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
	TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
	TIM_TimeBaseInitStructure.TIM_Period = 100 - 1;		//ARR
	TIM_TimeBaseInitStructure.TIM_Prescaler = 720 - 1;		//PSC
	TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;
	TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure);
	
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure3;
	TIM_TimeBaseInitStructure3.TIM_ClockDivision = TIM_CKD_DIV1;
	TIM_TimeBaseInitStructure3.TIM_CounterMode = TIM_CounterMode_Up;
	TIM_TimeBaseInitStructure3.TIM_Period = 20000 - 1;		//ARR
	TIM_TimeBaseInitStructure3.TIM_Prescaler = 72 - 1;		//PSC
	TIM_TimeBaseInitStructure3.TIM_RepetitionCounter = 0;
	TIM_TimeBaseInit(TIM3, &TIM_TimeBaseInitStructure3);
	
	TIM_OCInitTypeDef TIM_OCInitStructure;
	TIM_OCStructInit(&TIM_OCInitStructure);
	TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
	TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
	TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
	TIM_OCInitStructure.TIM_Pulse = 0;		//CCR
	
	TIM_OCInitTypeDef TIM_OCInitStructure3;
	TIM_OCStructInit(&TIM_OCInitStructure3);
	TIM_OCInitStructure3.TIM_OCMode = TIM_OCMode_PWM1;
	TIM_OCInitStructure3.TIM_OCPolarity = TIM_OCPolarity_High;
	TIM_OCInitStructure3.TIM_OutputState = TIM_OutputState_Enable;
	TIM_OCInitStructure3.TIM_Pulse = 0;		//CCR
	// Êä³öͨµÀ1
	TIM_OC1Init(TIM2, &TIM_OCInitStructure);
	TIM_OC1Init(TIM3,&TIM_OCInitStructure3);

	// Êä³öͨµÀ2
//	TIM_OC2Init(TIM2,&TIM_OCInitStructure);

	// Êä³öͨµÀ3
	TIM_OC3Init(TIM2, &TIM_OCInitStructure);//TIM2 OC3
	
	TIM_Cmd(TIM2, ENABLE);
	TIM_Cmd(TIM3, ENABLE);

}

/*LED  PA0*/ 
void PWM_SetCompare1(uint16_t Compare)
{
	TIM_SetCompare1(TIM2, Compare);
}

// ÓÖÖØÐÂÑ¡ÔñÁËÒ»¸ö¶¨Ê±Æ÷ TIM3
/*Servo  PA1*/
void PWM_SetCompare2(uint16_t Compare)
{
	TIM_SetCompare1(TIM3, Compare);
}


/*Servo  PA1*/
//void PWM_SetCompare2(uint16_t Compare)
//{
//	TIM_SetCompare2(TIM2, Compare);
//}


/*Motor PA2*/
void PWM_SetCompare3(uint16_t Compare)
{
	TIM_SetCompare3(TIM2, Compare);
}

OK 今天到这里啦 ,freeRTOS其实也不是很明白,哎,我八月10号开始看的,韦东山老师的,7天看完了入门课程;然后八月19号基于STM32F103移植了FreeRTOS系统;20 21两天做完了整个小项目。如有不足,欢迎批评指正哈!

  • 2
    点赞
  • 39
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值