赞
踩
本项目目的在于学习记录和设计讨论,主要设计部分上传至Gitee,像是FreeRTOS和F4基础工程部分的代码没有上传,占用空间。基础框架我用的是正点原子的F4例程,FreeRTOS移植的10.5.1版本。因为不同部分的coding时间不同,所以会有不同风格的注释,读者见谅,哈哈哈哈。
我会尽可能把设计思想描述清楚,这样大家有建议和意见可以私信和我交流,或者在gitee提交,github暂时还没上传。
综合之前写过的一些驱动,在加入实时操作系统后的项目更加符合智能门锁的实际需求。整体涉及到四个任务,分别是处理WIFI信息,识别FRID,OLED屏保和舵机开关门。还有很多辅助功能以后有空再添加。
1、通过WiFi发送开门指令,也可以将指令改为密码发送,不过目前还没有考虑安全传输的问题,所以采用简单的open字符串。
2、通过RC522芯片刷卡开门,目前只实现读取卡号实现开门,读者有兴趣可以自行加入卡内信息读取等内容。
3、键盘密码开门的方式没有写,实现起来应该也不麻烦。
4、OLED在成功开门时会显示欢迎语,分别对应不同的开门方式;空闲时会加载动图,实现屏保功能,动画内容大家可以跑跑看,我只能说我不是小黑子。
5、舵机的话比较简单,通过PWM控制角度,具体的调度方式可以看代码,我都有写注释。
这部分WIFI协议等底层细节没有深究,只是使用模块实现数据发送,并通过串口和单片机通信。具体分析可以看我单独分析的文章:
STM32+esp8266实现单片机与服务器的WiFi通信_基于stm32、esp8266及ov7670的无线图传下位机源码-CSDN博客https://blog.csdn.net/plmm__/article/details/132409339?spm=1001.2014.3001.5502代码大体没有改动,可直接下载移植。
采用临界区保护任务不被打断,将事件置1。
- /**
- * @brief task1:处理esp8266接收到的数据
- * @param pvParameters : 传入参数
- * @retval 无
- */
- void task1(void * pvParameters)
- {
- char *rx_data = NULL;/* 接收缓冲 */
- while(1)
- {
- if(esp8266wifi_rx_sta & 0X8000)//串口2esp收到的信息通过串口1打印
- {
- rx_data = pvPortCalloc(1, 32);/* 接收缓冲 */
-
- taskENTER_CRITICAL();
- {
- esp8266_solve_receive_data(rx_data, esp8266wifi_rx_buf);
- if(!strcmp((const char*)rx_data, "abc123"))
- {
- xEventGroupSetBits(EventGroup_Task, EVENTBIT_0);
- }
- esp8266wifi_rx_sta = 0;
- }
- taskEXIT_CRITICAL();
-
- vPortFree(rx_data);
- }
- vTaskDelay(100);
- }
- }
这部分我也单独写过文章进行分析,增加了几个函数,只识别出卡号,不进行后面的读写操作。
- /*
- * @brief 等待刷卡
- * @param *data:要发送的数据
- * @param ID:要收到数据的ID号
- * @retval result:成功返回MI_OK,其他失败
- */
- uint8_t Wait_RFID_card(void)
- {
- /* 寻卡 */
- return PcdRequest(PICC_REQALL, IC_Type);
- }
-
-
- /*
- * @brief 读卡,返回卡号
- * @param *data:要发送的数据
- * @param ID:要收到数据的ID号
- * @retval result:返回1成功,0则失败
- */
- int8_t GET_card_ID(void)
- {
- /* 防冲撞,读出卡号 */
- if(PcdAnticoll(IC_UID) != MI_OK)
- {
- printf("防冲撞失败,请重试\r\n");
- return -1;
- }
-
- /* 返回卡号 */
- return find_RFID_card();
- }
-
- /**
- * @brief 返回卡号
- * @param *data:要发送的数据
- * @param ID:要收到数据的ID号
- * @retval 成功返回卡号,失败返回 0
- */
- uint8_t find_RFID_card(void)
- {
- uint8_t result = 0;
- for (uint8_t i = 0; i < CARD_NUM; i++)
- {
- for (uint8_t j = 0; j < 4; j++)/* 对比每个字节 */
- {
- if (IC_UID[j] != card_ID[i][j])
- {
- result = 0;
- break;
- }
- result = 1;
- }
-
- if (!result)
- {
- result = 0;
- }
- else/* 在数据库内 */
- {
- return i + 1;
- }
- }
- return 0;
- }
任务2:
- /**
- * @brief task2:处理RFID刷卡认证
- * @param pvParameters : 传入参数
- * @retval 无
- */
- void task2(void * pvParameters)
- {
- int8_t ID;
- while(1)
- {
- if(Wait_RFID_card() == MI_OK)
- {
- // vTaskSuspendAll();
- taskENTER_CRITICAL();
- {
- ID = GET_card_ID();
- if(ID == 0)
- //printf("验证失败, 无效卡\n");
- OLED_ShowString(1, 2, "ERROR card!", 16);
- if(ID > 0)
- {
- //printf("用户 %d, 欢迎回家!\n", ID);
- xEventGroupSetBits(EventGroup_Task, EVENTBIT_1);
- }
- }
- taskEXIT_CRITICAL();
- // (void)xTaskResumeAll();
- }
- vTaskDelay(100);
- }
- }
这部分用到了任务通知和软件定时器,并挂起自身取消屏保刷新,最后采用绝对延时保证刷新时间保持一致。解除挂起由软件定时器的回调函数完成。这部分用到的FreeRTOS内容比较多,都有注释,欢迎读者给予改进建议。
任务三的挂起可以放到其他任务中,考虑到任务三的优先级最低,同时可以提高其他任务的执行效率,所以让任务三完成挂起自身并设置软件定时器。
- /**
- * @brief task3:空闲时OLED屏保,如果发生开门事件,则延时一段时间再刷新OLED
- * @param pvParameters : 传入参数
- * @retval 无
- */
- void task3(void * pvParameters)
- {
- uint8_t i = 0;
- TickType_t pxPreviousWakeTime;
- while(1)
- {
- /* 如果接收到任务通知,把通知值清 0,不阻塞等待 */
- if(ulTaskNotifyTake(pdTRUE, 0))
- {
- /* 设置软件定时器,并挂起自身,超时再唤醒 */
- xTimerStart(Timer1_Task, portMAX_DELAY);
- vTaskSuspend(NULL);/* 挂起自身 */
- }
-
- /* 记录当前时间 */
- pxPreviousWakeTime = xTaskGetTickCount();
-
- /* 屏保显示 */
- OLED_DrawBMP(0, 0, i++, frame_len, frame_width);
- OLED_Refresh_Gram();
- if(i >= page_sum)
- i = 0;
-
- /* 采用绝对延时,保证刷新时间可控 */
- vTaskDelayUntil(&pxPreviousWakeTime, refresh_speed);
- }
- }
-
-
- /* 软件定时器回调函数 */
- void Timer1_Task_Callback(TimerHandle_t xTimer)
- {
- /* 唤醒屏保显示 */
- vTaskResume(task3_handler);
- }
这里采用FreeRTOS的事件标志组,来等待任意一个开门请求,等待时间为最大,就是阻塞等待。然后在屏幕上显示欢迎语,这里使用任务通知来让OLED屏保任务,挂起自身,让欢迎语保持显示一段时间。
- /**
- * @brief task4:舵机开关门
- * @param pvParameters : 传入参数
- * @retval 无
- */
- void task4(void * pvParameters)
- {
- volatile EventBits_t EventValue;
- while(1)
- {
- /* 等待其中一个事件完成,皆可启动舵机 */
- EventValue = xEventGroupWaitBits(EventGroup_Task, EVENTBIT_ALL, pdTRUE, pdFALSE, portMAX_DELAY);
-
- /* 保留欢迎语一段时间,再进行OLED屏保 */
- xTaskNotifyGive(task3_handler);
-
- OLED_Clear();
-
- switch (EventValue)
- {
- case EVENTBIT_0:
- //printf("WIFI开门成功\r\n");
- OLED_ShowString(1, 2, "WIFI open door!", 16);
- break;
- case EVENTBIT_1:
- //printf("刷卡开门成功\r\n");
- OLED_ShowString(1, 2, "RFID open door!", 16);
- break;
- case EVENTBIT_2:
- //printf("密码开门成功\r\n");
- OLED_ShowString(1, 2, "PassWord open door!", 16);
- break;
- }
- OLED_Refresh_Gram();
-
- /* 舵机偏转开门 */
- set_Angle(180);
-
- /* 保持开锁 5秒 */
- vTaskDelay(5000);
-
- /* 舵机偏转锁门 */
- set_Angle(0);
-
- vTaskDelay(10);
- }
- }
其余未上传的代码与具体的板耦合较多,还请读者自行修改,有问题可以和我讨论,我也一起学习。
总体来说项目比较简单,个人能力有限,以后有时间再继续完善,欢迎广大读者朋友私信交流,一起学习提升!
gitee指路:
stm32: 一些stm32模块使用经验记录 - Gitee.comhttps://gitee.com/lrf1125962926/stm32/tree/Housekeeper%2BFreeRTOS/
是不是该收拾一下了
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。