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

基于STM32和freeRTOS智能门锁设计方案 前言 ? 项目基于STM32单片机为MCU,通过UART,SPI和蓝牙模块,RC522模块连接,MCU采用freeRTOS实时操作系统,门锁方案实现了蓝牙开锁,键盘密码,刷卡无线射频识别开锁。
正文 蓝牙,射频,键盘分别使用3个任务函数进行数据处理,使用STM32F103 demo,将freeRTOS驱动文件导入。定义好任务属性,句柄以及任务调度函数。

//任务优先级 #define START_TASK_PRIO1 //任务堆栈大小 #define START_STK_SIZE256 //任务句柄 TaskHandle_t StartTask_Handler; //任务函数 void start_task(void *pvParameters); //任务优先级 #define INTERRUPT_TASK_PRIO2 //任务堆栈大小 #define INTERRUPT_STK_SIZE256 //任务句柄 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);

【stm32|基于STM32和freeRTOS智能门锁设计方案】主函数部分初始化各个模块,创建开始任务。准备开始任务调度。
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_LGPIO_ResetBits(GPIOB, GPIO_Pin_6)//行00 #define Hang_00_HGPIO_SetBits(GPIOB, GPIO_Pin_6) #define Hang_01_LGPIO_ResetBits(GPIOG, GPIO_Pin_13)//行01 #define Hang_01_HGPIO_SetBits(GPIOG, GPIO_Pin_13) #define Hang_02_LGPIO_ResetBits(GPIOG, GPIO_Pin_14)//行02 #define Hang_02_HGPIO_SetBits(GPIOG, GPIO_Pin_14) #define Hang_03_LGPIO_ResetBits(GPIOG, GPIO_Pin_15)//行03 #define Hang_03_HGPIO_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)//列03void 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; u8status=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实时操作系统的支持,三个任务可以看作同时运行。便可实时检测各个模块是否有开锁信号。

    推荐阅读