基于FreeRTOS的智能家居系统
还有哈 针对PWM的初始化开启内部时钟 开两个也行哈 然后 我定义了PA0 PA2 还有PA6(LED1 MOTOR 舵机)
材料
STM32F103C8T8最小开发版,直流电机,舵机,OLED,LED两个,蜂鸣器,光敏传感器,按键两个,面包板 ,若干杜邦线
功能描述
- 按下Key1,电机的速度增加,一共20 40 60 60 100 、 -(20 40 60 60 100)和 0一共11个挡位;按下Key2,LED1的亮度增加,一共20 40 60 80 100 5个挡位;
- 创建了定时器,每隔两秒进行舵机的驱动,30 60 90 180 四个转动方向,舵机转动的同时,也带着电机进行旋转;从而实现了”摇头风扇“。。当然定时器的开启和关门可以使用Key2和Key1进行控制;
- 受光敏传感器的控制,当检测到当前的光线比较暗,LED2可以实现自我开启,模拟傍晚来临,门外路灯开启的情况
- LED显示电机速度信息,LED亮度信息,舵机的角度信息,AD1的光敏转换信息
- 当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)
程序接口配置
LED1 | PA0 | 使用PWM波形驱动 | TIM2_CH0 |
MOTOR | PA2 | 使用PWM波形驱动 | TIM2_CH2 |
ADC1光敏传感 | PA1 | channel_1 | ADC12_IN1 |
舵机 | PA6 | 使用PWM波形驱动 | TIM3_CH1 |
LED2 | PA9 | 低电平 | |
BUZZER | PA12 | 低电平 |
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两天做完了整个小项目。如有不足,欢迎批评指正哈!
更多推荐
所有评论(0)