基于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实时操作系统的支持,三个任务可以看作同时运行。便可实时检测各个模块是否有开锁信号。