基于STM32和freeRTOS智能门锁设计方案

基于STM32和freeRTOS智能门锁设计方案

前言

​ 项目基于STM32单片机为MCU,通过UART,SPI和蓝牙模块,RC522模块连接,MCU采用freeRTOS实时操作系统,门锁方案实现了蓝牙开锁,键盘密码,刷卡无线射频识别开锁。

正文

蓝牙,射频,键盘分别使用3个任务函数进行数据处理,使用STM32F103 demo,将freeRTOS驱动文件导入。定义好任务属性,句柄以及任务调度函数。

//任务优先级
#define START_TASK_PRIO			1
//任务堆栈大小
#define START_STK_SIZE 			256
//任务句柄
TaskHandle_t StartTask_Handler;
//任务函数
void start_task(void *pvParameters);

//任务优先级
#define INTERRUPT_TASK_PRIO		2
//任务堆栈大小
#define INTERRUPT_STK_SIZE 		256
//任务句柄
TaskHandle_t INTERRUPTTask_Handler;
TaskHandle_t KEYTask_Handler;
TaskHandle_t RC522Task_Handler;

//任务函数
void key_task(void *p_arg);
void interrupt_task(void *p_arg);
void RC522_task(void *p_arg);

主函数部分初始化各个模块,创建开始任务。准备开始任务调度。

int main(void)
{
    delay_init();	    	 //延时函数初始化
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //设置NVIC中断分组2:2位抢占优先级,2位响应优先级
    uart_init(115200);	 //串口初始化为115200
    uart2_init(9600);	 //串口2初始化为115200
	uart3_init(9600);	 //串口2初始化为115200
    LED_Init();			
    KEY_Init();
    LCD_Init();
    InitRc522();				//初始化射频卡模块
    PcdReset();				//复位RC522
    delay_ms(2);
    PcdAntennaOn();		//开启天线发射
    LCD_Clear(WHITE);
    POINT_COLOR=BLACK;
    LCD_ShowString(30,40,210,24,24,"RC522 - ww");
    //创建开始任务
    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();           //进入临界区
    xTaskCreate((TaskFunction_t )key_task,  			//任务函数
                (const char*    )"key_task", 			//任务名称
                (uint16_t       )INTERRUPT_STK_SIZE,		//任务堆栈大小
                (void*          )NULL,						//传递给任务函数的参数
                (UBaseType_t    )INTERRUPT_TASK_PRIO,		//任务优先级
                (TaskHandle_t*  )&INTERRUPTTask_Handler); 	//任务句柄
    xTaskCreate((TaskFunction_t )interrupt_task,  			//任务函数
                (const char*    )"interrupt_task", 			//任务名称
                (uint16_t       )INTERRUPT_STK_SIZE,		//任务堆栈大小
                (void*          )NULL,						//传递给任务函数的参数
                (UBaseType_t    )INTERRUPT_TASK_PRIO,		//任务优先级
                (TaskHandle_t*  )&INTERRUPTTask_Handler); 	//任务句柄
    xTaskCreate((TaskFunction_t )RC522_task,  			//任务函数
                (const char*    )"RC522_task", 			//任务名称
                (uint16_t       )INTERRUPT_STK_SIZE,		//任务堆栈大小
                (void*          )NULL,						//传递给任务函数的参数
                (UBaseType_t    )INTERRUPT_TASK_PRIO,		//任务优先级
                (TaskHandle_t*  )&INTERRUPTTask_Handler); 	//任务句柄
    vTaskDelete(StartTask_Handler); //删除开始任务
    taskEXIT_CRITICAL();            //退出临界区
}

下面是各个外设的任务调度函数,首先键盘开锁,采用34的12键键盘,占用STM32 7个IO口,3个输出模式,4个输入模式,通过输入模式的IO检测高低电平判断按键是否按下。如果按下则通过get_pwd()保存该键值,依次将输入的密码保存在数组里面,当按下号键时将输入的密码和正确密码对比,如果一样则开锁成功。

u8 i = 0;
u8 Passwd[6] = {1,2,3,4,5,6};
u8 ascci_Passwd[6] = {49,50,51,52,53,54};
u8 Input_pwd[128] = {0};
u8 buf[4] = {0x00,0x01,0x0B,0x11};

void get_pwd(u8 pwd)
{
    Input_pwd[i] = pwd;
    i++;
}
void key_task(void *pvParameters)
{
    u8 j,i=0;
    u8 t=0;
    while(1)
    {
        t=KEY_Scan(0);		//得到键值
        switch(t)
        {
        case 1:
            printf("1");
					
            GPIO_SetBits(GPIOB,GPIO_Pin_8);
			delay_ms(15);
			GPIO_ResetBits(GPIOB,GPIO_Pin_8);
            get_pwd(1);
            break;
        case 2:
            	printf("2");
			GPIO_SetBits(GPIOB,GPIO_Pin_8);
			delay_ms(15);
			GPIO_ResetBits(GPIOB,GPIO_Pin_8);
            get_pwd(2);
            break;
        case 3:
            	printf("3");
			GPIO_SetBits(GPIOB,GPIO_Pin_8);
			delay_ms(15);
			GPIO_ResetBits(GPIOB,GPIO_Pin_8);
            get_pwd(3);

            break;
        case 4:
            //	printf("4");
			GPIO_SetBits(GPIOB,GPIO_Pin_8);
			delay_ms(15);
			GPIO_ResetBits(GPIOB,GPIO_Pin_8);
            get_pwd(4);

            break;
        case 5:
            //	printf("5");
			GPIO_SetBits(GPIOB,GPIO_Pin_8);
			delay_ms(15);
			GPIO_ResetBits(GPIOB,GPIO_Pin_8);
            get_pwd(5);

            break;
        case 6:
			GPIO_SetBits(GPIOB,GPIO_Pin_8);
			delay_ms(15);
			GPIO_ResetBits(GPIOB,GPIO_Pin_8);
            get_pwd(6);
				

            break;
        case 7:
			GPIO_SetBits(GPIOB,GPIO_Pin_8);
			delay_ms(15);
			GPIO_ResetBits(GPIOB,GPIO_Pin_8);
            get_pwd(7);

            break;
        case 8:
			GPIO_SetBits(GPIOB,GPIO_Pin_8);
			delay_ms(15);
			GPIO_ResetBits(GPIOB,GPIO_Pin_8);
            get_pwd(8);

            break;
        case 9:
			GPIO_SetBits(GPIOB,GPIO_Pin_8);
			delay_ms(15);
			GPIO_ResetBits(GPIOB,GPIO_Pin_8);
            get_pwd(9);

            break;
        case 10:
			GPIO_SetBits(GPIOB,GPIO_Pin_8);
			delay_ms(15);
			GPIO_ResetBits(GPIOB,GPIO_Pin_8);
            memset(Input_pwd,0,sizeof(Input_pwd));
            i = 0;
            GPIO_SetBits(GPIOE,GPIO_Pin_3);
            delay_ms(3000);
            GPIO_ResetBits(GPIOE,GPIO_Pin_3);
            printf("关门");
            break;
        case 11:
			GPIO_SetBits(GPIOB,GPIO_Pin_8);
			delay_ms(15);
			GPIO_ResetBits(GPIOB,GPIO_Pin_8);
            get_pwd(0);

            break;
        case 12:
			GPIO_SetBits(GPIOB,GPIO_Pin_8);
			delay_ms(15);
			GPIO_ResetBits(GPIOB,GPIO_Pin_8);
            for(j = 0; j < 6; j++)
            {
                printf("%d",Input_pwd[j]);
            }
            if(!memcmp(Input_pwd,Passwd,6))
            {
                printf(" The password is correct! Unlocking successful");
                GPIO_SetBits(GPIOE,GPIO_Pin_2);
                delay_ms(3000);
                GPIO_ResetBits(GPIOE,GPIO_Pin_2);
				
				for(i = 0; i < 4 ; i++)
					{
						while(USART_GetFlagStatus(USART3,USART_FLAG_TC) == RESET)
							;
						USART_SendData(USART3,buf[i]);		//向串口1发送数据包
					}		
//		GPIO_ResetBits(GPIOB,GPIO_Pin_8);
            }
            else
            {
                printf("The password is not correct !please input again");
            }
            break;
      	    default:
            delay_ms(10);
        }
    }
}

key.c

u8 KEY_Scan(u8 mode)
{
	static u8 key0_up=1;//按键按松开标志
	static u8 key1_up=1;//按键按松开标志
	static u8 key2_up=1;//按键按松开标志
	static u8 key3_up=1;//按键按松开标志
	static u8 key4_up=1;//按键按松开标志
	static u8 key5_up=1;//按键按松开标志
	static u8 key6_up=1;//按键按松开标志
	static u8 key7_up=1;//按键按松开标志
	static u8 key8_up=1;//按键按松开标志
	static u8 key9_up=1;//按键按松开标志
//	static u8 keyA_up=1;//按键按松开标志
//	static u8 keyB_up=1;//按键按松开标志
//	static u8 keyC_up=1;//按键按松开标志
//	static u8 keyD_up=1;//按键按松开标志
	static u8 keyX_up=1;//按键按松开标志
	static u8 keyJ_up=1;//按键按松开标志
	
	if(mode)
	{
		key0_up=1;
        key1_up=1;
		key2_up=1;
        key3_up=1;
        key4_up=1;
        key5_up=1;
        key6_up=1;
        key7_up=1;
        key8_up=1;
        key9_up=1;
//        keyA_up=1;
//        keyB_up=1;
//        keyC_up=1;
//        keyD_up=1;
        keyX_up=1;
        keyJ_up=1;	
	}
	
    //第一行
	Hang_00_L;//把第一行输出低电平
	Hang_01_H;
	Hang_02_H;
	Hang_03_H;
		if(key1_up&&Lie_00_V==0)
		{    
		   delay_ms(20); //延时20秒,软件消抖
			
		   key1_up=0;
		   if(Lie_00_V==0) //如果第一列是低电平,说明有键被按下,如果没有直接退出if语句
		   {
			  return 1;
		   }
		}else if(Lie_00_V==1)key1_up=1;
	 
		if(key2_up&&Lie_01_V==0)//如果第二列是低电平,
		{    
		   delay_ms(20);//延时20秒,软件消抖
		   key2_up=0;
		   if(Lie_01_V==0)//如果第二列是低电平,说明有键被按下,如果没有直接退出if语句
		   {
			  return 2; 
		   }
		}else if(Lie_01_V==1)key2_up=1;
	 
		if(key3_up&&Lie_02_V==0)
		{    
		   delay_ms(1);
		   key3_up=0;
		   if(Lie_02_V==0)
		   {
			  return 3;
		   }
		}else if(Lie_02_V==1)key3_up=1;
	 
//		if(keyA_up&&Lie_03_V==0)//如果第四列是低电平
//		{    
//		   delay_ms(20);
//		   keyA_up=0;
//		   if(Lie_03_V==0)//如果第四列是低电平,说明有键被按下,如果没有直接退出if语句
//		   {
//			  return 10;
//		   }
//		}else if(Lie_03_V==1)
//		keyA_up=1;
 
	//第二行
	Hang_00_H;
	Hang_01_L;//把第二行拉低
	Hang_02_H;
	Hang_03_H;
		if(key4_up&&Lie_00_V==0)//如果第一列是低电平
		{    
		   delay_ms(1);
		   key4_up=0;
		   if(Lie_00_V==0)//说明有键被按下,如果没有直接退出if语句
		   {
				return 4;
		   }
		}else if(Lie_00_V==1)key4_up=1;
		 
		if(key5_up&&Lie_01_V==0)
		{    
		   delay_ms(1);
		   key5_up=0;
		   if(Lie_01_V==0)
		   {
		       return 5;
		   }
		}else if(Lie_01_V==1)key5_up=1;
		 
		if(key6_up&&Lie_02_V==0)
		{    
		   delay_ms(1);
		   key6_up=0;
		   if(Lie_02_V==0)
		   {
			   return 6;
		   }
		}else if(Lie_02_V==1)key6_up=1;
		 
//		if(keyB_up&&Lie_03_V==0)
//		{    
//		   delay_ms(1);
//		   keyB_up=0;
//		   if(Lie_03_V==0)
//		   {
//		       return 11;  
//		   }
//		}else if(Lie_03_V==1)keyB_up=1;
 
	//第三行
	Hang_00_H;
	Hang_01_H;
	Hang_02_L;//把第三行置低
	Hang_03_H;
		if(key7_up&&Lie_00_V==0) //如果第一列是低电平
		{    
		   delay_ms(1);//延时20秒
		   key7_up=0;
		   if(Lie_00_V==0)//说明有键被按下,如果没有直接退出if语句
		   {
			   return 7;
		   }
		}else if(Lie_00_V==1)key7_up=1;
		 
		if(key8_up&&Lie_01_V==0)
		{    
		   delay_ms(1);
		   key8_up=0;
		   if(Lie_01_V==0)
		   {
		       return 8;
		   }
		}else if(Lie_01_V==1)key8_up=1;
		 
		if(key9_up&&Lie_02_V==0)
		{    
		   delay_ms(1);
		   key9_up=0;
		   if(Lie_02_V==0)
		   {
		       return 9;
		   }
		}else if(Lie_02_V==1)key9_up=1;
		 
//		if(keyC_up&&Lie_03_V==0)
//		{    
//		   delay_ms(1);
//		   keyC_up=0;
//		   if(Lie_03_V==0)
//		   {
//		       return 12; 
//		   }
//		}else if(Lie_03_V==1)keyC_up=1;
 
	//第四行
	Hang_00_H;
	Hang_01_H;
	Hang_02_H;
	Hang_03_L;//把第四行置低
		if(keyX_up&&Lie_00_V==0)//如果第一列是低电平
		{    
		   delay_ms(1);
		   keyX_up=0;
		   if(Lie_00_V==0)//说明有键被按下,如果没有直接退出if语句
		   {
		       return 10;
		   }
		}else if(Lie_00_V==1)keyX_up=1;
		 
		if(key0_up&&Lie_01_V==0)
		{    
		   delay_ms(10);
		   key0_up=0;
		   if(Lie_01_V==0)
		   {
		       return 11;
		   }
		}else if(Lie_01_V==1)key0_up=1;
		 
		if(keyJ_up&&Lie_02_V==0)//如果第三列是低电平
		{    
		   delay_ms(1);
		   keyJ_up=0;
		   if(Lie_02_V==0)//说明有键被按下,如果没有直接退出if语句
		   {
		       return 12;
		   }
		}else if(Lie_02_V==1)keyJ_up=1;
		 
//		if(keyD_up&&Lie_03_V==0)
//		{    
//		//   delay_ms(1);
//		   keyD_up=0;
//		   if(Lie_03_V==0)
//		   {
//		       return 13;
//		   }
//		}else if(Lie_03_V==1)keyD_up=1;
		
		return 0;
}


key.h

#ifndef __KEY_H
#define __KEY_H	 
#include "sys.h"

#define Hang_00_L  GPIO_ResetBits(GPIOB, GPIO_Pin_6)//行00
#define Hang_00_H  GPIO_SetBits(GPIOB, GPIO_Pin_6)
#define Hang_01_L  GPIO_ResetBits(GPIOG, GPIO_Pin_13)//行01
#define Hang_01_H  GPIO_SetBits(GPIOG, GPIO_Pin_13)
#define Hang_02_L  GPIO_ResetBits(GPIOG, GPIO_Pin_14)//行02
#define Hang_02_H  GPIO_SetBits(GPIOG, GPIO_Pin_14)
#define Hang_03_L  GPIO_ResetBits(GPIOG, GPIO_Pin_15)//行03
#define Hang_03_H  GPIO_SetBits(GPIOG, GPIO_Pin_15)
#define Lie_00_V GPIO_ReadInputDataBit(GPIOG,GPIO_Pin_9)//列00
#define Lie_01_V GPIO_ReadInputDataBit(GPIOG,GPIO_Pin_10)//列01
#define Lie_02_V GPIO_ReadInputDataBit(GPIOG,GPIO_Pin_11)//列02
#define Lie_03_V GPIO_ReadInputDataBit(GPIOG,GPIO_Pin_14)//列03

void KEY_Init(void);//IO初始化
u8 KEY_Scan(u8);  	//按键扫描函数					    
#endif

蓝牙模块通过串口连接,当串口收到数据时进行密码比对。

void interrupt_task(void *pvParameters)
{
    u8 j;
    while(1)
    {
        if(USART2_RX_STA )
        {
            delay_ms(10);
            for(j = 0; j < 6; j++)
            {
                printf("%d",USART2_RX_BUF[j]);
            }
            if(!memcmp(USART2_RX_BUF,ascci_Passwd,6))
            {
                printf("The password is correct! Unlocking successful");
                GPIO_SetBits(GPIOE,GPIO_Pin_2);
                delay_ms(3000);
                GPIO_ResetBits(GPIOE,GPIO_Pin_2);
            }
            USART2_RX_STA=0;
        }
        delay_ms(1000);
        LED1 = !LED1;

    }
}

RC522刷卡无线射频识别模块通过SPI接口和STM32连接。

void RC522_task(void *p_arg)
{
    u8 i;
    u8  status=MI_ERR;
    while(1)
    {
        PcdAntennaOn();		//开启天线发射
        status=PcdRequest(0x52,Temp);寻卡,输出为卡类型----
        if (status != MI_OK)
        {
            PcdReset();
            PcdAntennaOff();
            PcdAntennaOn();
            continue;

        }

        if(status==OK)      //寻卡成功
        {
            LCD_ShowString(30,70,210,24,24,"PcdRequest OK");
            status=MI_ERR;
            status = PcdAnticoll(UID); 
            if(status==MI_OK)
            {
                for(i=0; i<4; i++)
                {
                    printf("%d ",UID[i]);
                }
                status=MI_ERR;
                status=PcdSelect(UID);
            }
            if(status==OK)  //选卡成功
            {
                // LCD_Clear(WHITE);
                POINT_COLOR=BLACK;
                LCD_ShowString(30,100,210,24,24,"Select SUCCESS");
                if(UID[0]==39&&UID[1]==100&&UID[2]==142&&UID[3]==95)
                {
                    LCD_ShowString(30,130,210,24,24,"RIGHT");
                    printf("The password is correct! Unlocking successful");
                    GPIO_SetBits(GPIOE,GPIO_Pin_2);
                    delay_ms(3000);
                    GPIO_ResetBits(GPIOE,GPIO_Pin_2);
                }
                else
                    LCD_ShowString(30,130,210,24,24,"ERROR");

                delay_ms(5000);
            }
            delay_ms(5000);
            continue;
        }
        else
        {
            //printf("检测超时,未检测到消费卡!!!\r\n");
            LCD_ShowString(30,70,210,24,24,"检测超时,未检测到消费卡");
            PcdAntennaOff();  //关闭天线
        }
    }
}

程序由freeRTOS实时操作系统的支持,三个任务可以看作同时运行。便可实时检测各个模块是否有开锁信号。

你可能感兴趣的:(stm32,freertos,蓝牙,驱动程序,物联网)