NWatch-Alarm闹钟功能实现

文章目录

  • W25Q64初始化
    • SPI初始化
    • W25Q初始化
  • AlARM模块初始化
    • AlARM模块绘制Draw函数
    • AlARM的更新函数
    • AlARM中最重要的函数


W25Q64初始化

W25Q64用来存储用户设置的闹钟值,开机的时候自动读取闹钟记录。

SPI初始化

使用CubeMx自动配置。
在这里插入图片描述

#define SPI1CS_ON	HAL_GPIO_WritePin(GPIOB, GPIO_PIN_11, GPIO_PIN_RESET)
#define SPI1CS_OFF	HAL_GPIO_WritePin(GPIOB, GPIO_PIN_11, GPIO_PIN_SET)static volatile bool gSPI1TxCplt = 0;
static volatile bool gSPI1RxCplt = 0;static void SPI1WaitTxCplt(void)
{while(gSPI1TxCplt == 0);gSPI1TxCplt = 0;
}static void SPI1WaitRxCplt(void)
{while(gSPI1RxCplt == 0);gSPI1RxCplt = 0;
}void HAL_SPI_TxCpltCallback(SPI_HandleTypeDef *hspi)
{if(SPI1 == hspi->Instance){gSPI1TxCplt = 1;}
}void HAL_SPI_RxCpltCallback(SPI_HandleTypeDef *hspi)
{if(SPI1 == hspi->Instance){gSPI1RxCplt = 1;}
}static int SpiWrite(unsigned char *wbuf, unsigned int length){HAL_StatusTypeDef status = HAL_SPI_Transmit_DMA(&hspi1, wbuf, length);if(HAL_OK != status)    return -1;SPI1WaitTxCplt();return length;
}static int SpiRead(unsigned char *rbuf, unsigned int length){HAL_StatusTypeDef status = HAL_SPI_Receive_DMA(&hspi1, rbuf, length);if(HAL_OK != status)    return -1;SPI1WaitRxCplt();return length;
}

W25Q初始化

使用SPI读取W25Q的ID验证通信的正确性

static unsigned int ReadID(void)
{    unsigned char cmd = 0x9F;   // W25X_JedecDeviceIDunsigned char id[3] = {0};SPI1CS_ON;SpiWrite(&cmd,1);SpiRead(id, 3);SPI1CS_OFF;unsigned int ID = (id[0] << 16) | (id[1] << 8) | (id[2]);return ID;
}void W25QInit(void){int ID = ReadID();if(ID != 0xEF4017)return;printf("ID is %d",ID);
}int W25QPageWrite(uint32_t addr,unsigned char *buf,unsigned int length){unsigned char data[4];data[0] = 0x02;data[1] = (addr &0xFF0000)>>16;data[2] = (addr &0x00FF00)>>8;data[3] = (addr &0x0000FF);W25QWriteEnable();SPI1CS_ON;int ret = SpiWrite(data,4);if(ret < 0){SPI1CS_OFF;}ret = SpiWrite(buf,length);if(ret < 0){SPI1CS_OFF;}SPI1CS_OFF;WaitWrite();return (int)length;
}int W25QRead(uint32_t addr,unsigned char *buf,unsigned int length){unsigned char data[4];data[0] = 0x03;data[1] = (addr &0xFF0000)>>16;data[2] = (addr &0x00FF00)>>8;data[3] = (addr &0x0000FF);SPI1CS_ON;int ret = SpiWrite(data,4);if(ret < 0){SPI1CS_OFF;}ret = SpiRead(buf,length);if(ret != length){SPI1CS_OFF;}SPI1CS_OFF;return (int)length;
}void W25QEraseSector(uint32_t addr){unsigned char data[4];data[0] = 0x20;data[1] = (addr &0xFF0000)>>16;data[2] = (addr &0x00FF00)>>8;data[3] = (addr &0x0000FF);W25QWriteEnable();SPI1CS_ON;int ret = SpiWrite(data,4);if(ret < 0){SPI1CS_OFF;}SPI1CS_OFF;WaitWrite();}

AlARM模块初始化

设置闹钟界面的信息

/** 描述:设置闹钟界面的页面加载函数* 参数:无  * 返回值:无	 */
static void AlarmLoader(uint8_t num){if(num < ALARM_COUNT-1){alarm_s alarm2;if(setting.now == SETTING_NOW_NONE || num != Main_Menu.selected)Alarmget(num, &alarm2);elsememcpy(&alarm2, &alarm, sizeof(alarm_s));AddAlarmBasic(num, &alarm2);}addExitOption();
}
/** 描述:设置闹钟界面的确认函数* 参数:无  * 返回值:无	 */
static void AlarmSelect(){bool isExiting = exitSelected();GetMenupre(&alarmMenus);DoAction(isExiting);
}/** 描述:设置闹钟界面的按钮函数等菜单基本信息 * 参数:无  * 返回值:无	 */
void AlarmMenu(void){SetButtonFunc(menuUp, (bool (*)(void))AlarmSelect, menuDown);SetMenuFunc(preOption, AlarmSelect, nextOption,AlarmLoader);SetMenuInfo(ALARM_COUNT,MENU_TYPE_STR,PSTR(STR_ALARMMENU));SetMenuPre(&alarmMenus,AlarmMenu);AnimotionInto(NULL);
}

AlARM模块绘制Draw函数

alarm模块是STR菜单界面,更改界面的值通过状态机的方式逐个改变每个数据的值然后通过确认赋值,改变完所有数据值后保存到外部Flash中。

static void AlarmUp(void){setting.val++;if(setting.val > getMaxValForSetting())setting.val = 0;if(setting.now == SETTING_NOW_HOUR && appConfig.timeMode  == TIMEMODE_12HR && setting.val == 0)setting.val = 1;
}static void AlarmDown(void){setting.val--;if(setting.now == SETTING_NOW_HOUR && appConfig.timeMode  == TIMEMODE_12HR && setting.val == 0)setting.val = 12;uint8_t max = getMaxValForSetting();if(setting.val > max)setting.val = max;
}static void AlarmDraw(void){uint8_t w = 5;uint8_t x;char buff[4];buff[1] = 0x00;switch(setting.now){case SETTING_NOW_EN:x = 6;w = 8;buff[0] = setting.val ? ALARM_SET_CHAR : ALARM_UNSET_CHAR;break;case SETTING_NOW_HOUR:x = 22;w = 16;break;case SETTING_NOW_MIN:x = 46;w = 16;break;case SETTING_NOW_AMPM:x = 62;w = 8;buff[0] = setting.val ? CHAR_PM : CHAR_AM;break;case SETTING_NOW_DAY_MON:case SETTING_NOW_DAY_TUE:case SETTING_NOW_DAY_WED:case SETTING_NOW_DAY_THUR:case SETTING_NOW_DAY_FRI:case SETTING_NOW_DAY_SAT:case SETTING_NOW_DAY_SUN:{uint8_t dow = setting.now - SETTING_NOW_DAY_MON;x = 70 + (8 * dow);w = 8;buff[0] = setting.val ? dowChars[dow] : '-';}break;default:return;}uint8_t y = 8 + ((Main_Menu.selected * 8) - (Main_Menu.scroll * 8));OledClearArea(x, y, w);if(setting.now == SETTING_NOW_HOUR || setting.now == SETTING_NOW_MIN)sprintf(buff, PSTR("%02hhu"), setting.val);OledShowStr(x,y,buff,OLED_8X8);
}static void SelectedAlarm()
{static uint8_t dayBit;static bool wasPM;SetMenuFunc(AlarmUp, AlarmSelect, AlarmDown, AlarmLoader);Main_Menu.func.draw = AlarmDraw;switch(setting.now){case SETTING_NOW_NONE:Alarmget(Main_Menu.selected, &alarm);setting.now = SETTING_NOW_EN;setting.val = alarm.enabled;break;case SETTING_NOW_EN:alarm.enabled = setting.val;setting.now = SETTING_NOW_HOUR;time_s time;time.hour = alarm.hour;time.ampm = CHAR_24;TimeSetMode(&time, appConfig.timeMode);setting.val = time.hour;wasPM = (alarm.hour >= 12);break;case SETTING_NOW_HOUR:{uint8_t hour = setting.val;uint8_t max = appConfig.timeMode == TIMEMODE_12HR ? 12 : 23;if(hour > max)hour = max;if(appConfig.timeMode  == TIMEMODE_12HR){time_s time;time.hour = hour;time.ampm = wasPM ? CHAR_PM : CHAR_AM;TimeSetMode(&time, TIMEMODE_24HR);hour = time.hour;}alarm.hour = hour;setting.now = SETTING_NOW_MIN;setting.val = alarm.min;}break;case SETTING_NOW_MIN:alarm.min = setting.val;if(appConfig.timeMode  == TIMEMODE_12HR){setting.now = SETTING_NOW_AMPM;setting.val = wasPM;}else{setting.now = SETTING_NOW_DAY_MON;setting.val = alarm.mon;}dayBit = 0;break;case SETTING_NOW_AMPM:{time_s time;time.hour = alarm.hour;time.ampm = setting.val ? CHAR_PM : CHAR_AM;TimeSetMode(&time, TIMEMODE_24HR);alarm.hour = time.hour;setting.now = SETTING_NOW_DAY_MON;setting.val = alarm.mon;}break;case SETTING_NOW_DAY_MON:case SETTING_NOW_DAY_TUE:case SETTING_NOW_DAY_WED:case SETTING_NOW_DAY_THUR:case SETTING_NOW_DAY_FRI:case SETTING_NOW_DAY_SAT:case SETTING_NOW_DAY_SUN:if(setting.val)alarm.days |= _BV(dayBit);elsealarm.days &= ~_BV(dayBit);dayBit++;setting.val = (bool)(alarm.days & _BV(dayBit));if(setting.now != SETTING_NOW_DAY_SUN)setting.now++;else{AlarmSave(Main_Menu.selected, &alarm);setting.now = SETTING_NOW_NONE;SetMenuFunc(preOption, AlarmSelect, nextOption,AlarmLoader);Main_Menu.func.draw = NULL;}break;default:break;}
}

AlARM的更新函数

如果当前时间是闹钟设置的时间,则进行相应。改变当前页面绘制函数称为闹钟响后的绘制函数。


void AlarmUpdate(void){bool wasGoingOff = alarmSetOff;bool alarmNow = goingOff();if(alarmSetOff){if(alarmNow){if(wasGoingOff != alarmSetOff){oldDrawFunc = SetDrawFunc(AlarmDraw);oldBtn1Func = SetButtonSignedFunc(BTN1, NULL);oldBtn2Func = SetButtonSignedFunc(BTN2, (bool (*)(void))AlarmStop);oldBtn3Func = SetButtonSignedFunc(BTN3, NULL);BuzzerPlay(tuneAlarm,VOL_ALARM,PRIO_ALARM);}if(!LedFlashing()){static led_t ledFlash = LEDGREEN;ledFlash = (ledFlash == LEDGREEN) ? LEDRED : LEDGREEN;LedFlash(ledFlash, 150);}}elseAlarmStop();}
}static void AlarmDraw(void){if((uint8_t)xTaskGetTickCount() < 128)OledShowImage(16, 16, 32, 32, &MAIN_MUNE[3][0], 0);// Draw timechar buff[8];sprintf(buff, PSTR(TIME_FORMAT_SMALL), timeDate.time.hour, timeDate.time.mins, timeDate.time.ampm);OledShowStr(60, 20,buff,OLED_8X8);// Draw daystrcpy(buff, days[timeDate.date.day]);OledShowStr(68,36,buff,OLED_8X8);}

AlARM中最重要的函数

每次时间或者闹钟响后,更新最近一个闹钟。通过计算本周开始到当前闹钟时间总共过去多少分钟,最少的就是最近一个闹钟。

void GetNextAlarm(void){uint8_t next = NOALARM;uint32_t nextTime = (uint32_t)UINT_MAX;// Make sure time is in 24 hour modetime_s timeNow;timeNow.hour = timeDate.time.hour;timeNow.ampm = timeDate.time.ampm;TimeSetMode(&timeNow, TIMEMODE_24HR);// Now in minutes from start of weekuint32_t now = toMinutes(timeNow.hour, timeDate.time.mins + 1, timeDate.date.day);// Loop through alarmsfor(uint8_t i = 0;i <ALARM_COUNT; i++){// Get alarm dataalarm_s alarm;Alarmget(i, &alarm);// Not enabledif(!alarm.enabled)continue;// Loop through daysfor(uint8_t d = 0;d <7; d++){// Day not enabledif(!AlarmDayEnabled(alarm.days, d))continue;// Alarm time in minutes from start of weekuint32_t alarmTime = toMinutes(alarm.hour, alarm.min, d);// Minutes to alarmint timeTo = alarmTime - now;// Negative result, must mean alarm time is earlier in the week than now, add a weeks timeif(timeTo < 0)timeTo += ((6*1440) + (23*60) + 59); // 10079// Is minutes to alarm less than the last minutes to alarm?if((uint32_t)timeTo < nextTime){// This is our next alarmnextTime = timeTo;next = i;}}}// Set next alarmnextAlarm = next;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/707957.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

3d模型导出简单线条的步骤---模大狮模型网

导出简单线条的3D模型通常涉及以下步骤&#xff1a; 创建线条模型&#xff1a;首先&#xff0c;在您的3D建模软件中创建或导入包含线条的模型。这可以是简单的线框模型&#xff0c;也可以是由线条构成的复杂形状。确保您的模型中只包含您希望导出的线条部分。 选择导出格式&am…

Python的自然语言处理库NLTK介绍

NLTK&#xff08;Natural Language Toolkit&#xff09;简介 NLTK是Python中一个领先的自然语言处理&#xff08;NLP&#xff09;库&#xff0c;它提供了文本处理的基础设施&#xff0c;包括分词&#xff08;tokenization&#xff09;、词性标注&#xff08;part-of-speech tag…

yolov5v7v8目标检测增加计数功能--免费源码

在yolo系列中&#xff0c;很多网友都反馈过想要在目标检测的图片上&#xff0c;显示计数功能。其实官方已经实现了这个功能&#xff0c;只不过没有把相关的参数写到图片上。所以微智启软件工作室出一篇教程&#xff0c;教大家如何把计数的参数打印到图片上。 一、yolov5目标检测…

前端Ajax获取当前外网IP地址并通过腾讯接口解析地理位置

目录 一、获取访问端IP地址 二、可用的IP获取接口 1、韩小韩IP获取接口&#xff1a; 2、ipify API 附3、失败的太平洋接口 三、腾讯位置服务-IP位置查询接口 一、获取访问端IP地址 原计划使用后端HttpServletRequest 获取访问端的IP地址&#xff0c;但在nginx和堡垒机等阻…

峟思科普小(1)型土石坝安全监测设备的基本配置与策略

土石坝&#xff0c;作为水利工程中的重要组成部分&#xff0c;其安全性能直接关系到下游人民的生命财产安全。为了确保土石坝的安全运行&#xff0c;必须对其进行科学有效的安全监测。本文将详细阐述小(1)型土石坝安全监测设备的基本配置与策略。 首先&#xff0c;对于存在渗漏…

JVM运行时数据区——运行时数据区及线程概述

文章目录 1、运行时数据区概述2、线程3、小结 内存是非常重要的系统资源&#xff0c;是硬盘和CPU的中间仓库及桥梁&#xff0c;承载着操作系统和应用程序的实时运行。JVM在程序执行期间把它所管理的内存分为若干个不同的数据区域。这些不同的数据区域可以分为两种类型&#xff…

“智农”-农业一体化管控平台

大棚可视化|设施农业可视化|农业元宇宙|农业数字孪生|大棚物联网|大棚数字孪生|农业一体化管控平台|智慧农业可视化|智农|农业物联网可视化|农业物联网数字孪生|智慧农业|大棚三维可视化|智慧大棚可视化|智慧大棚|农业智慧园区|数字农业|数字大棚|农业大脑|智慧牧业数字孪生|智…

【饮食】如何有效的补充维生素,矿物质?学习笔记(附膳食营养素参考摄入量DRIs)

程序员养生指南之 【饮食】如何有效的补充维生素&#xff0c;矿物质&#xff1f;学习笔记&#xff08;附膳食营养素参考摄入量DRIs&#xff09; 文章目录 一、维生素补充1、需要补充维生素的情况2、食补&#xff1a;缺啥补啥3、补充剂&#xff08;无脑吃&#xff09; 二、膳食营…

Android 跨进程通信aidl及binder机制详解(一)

前言 上文中描述了&#xff0c;什么是绑定服务、以及创建一个绑定服务都可以通过哪些方式&#xff0c;同时说了通过扩展Binder类来创建一个绑定服务&#xff0c;并使用一个例子来说明了客户端与服务端的绑定过程&#xff0c;最后又总结了绑定服务的生命周期与调用过程。由于上…

(unity学习)一些效果的学习

一、学习视频 【Unity教程】零基础带你从小白到超神 二、效果实现 三、问题解决 Unity 点击UI与点击屏幕冲突的解决方案 关于unity UI界面操作与场景内操作不冲突问题

Unity安装与简单设置

安装网址&#xff1a;https://unity.cn 设置语言&#xff1a; 设置安装位置&#xff1a;否则C盘就会爆了 获取一个个人的资格证&#xff1a; 开始安装&#xff1a; 安装完毕。 添加模块&#xff1a;例如简体中文 新建项目&#xff1a; 布局2*3、单栏布局、 设置…

4. client-go 编程式交互

Kubernetes 系统使用 client-go 作为 Go 语言的官方编程式交互客户端库&#xff0c;提供对 Kubernetes API Server 服务的交互访问。Kubernetes 的源码中已经集成了 client-go 的源码&#xff0c;无须单独下载。client-go 源码路径为 vendor/k8s.io/client-go。 开发者经常使用…

前端架构: 脚手架之包管理工具的案例对比及workspace特性的基本使用

Npm WorkSpace 特性 1 &#xff09;使用或不使用包管理工具的对比 vue-cli 这个脚手架使用 Lerna 管理&#xff0c;它的项目显得非常清晰在 vue-cli 中包含很多 package 点开进去&#xff0c;每一个包都有package.json它里面有很多项目&#xff0c;再没有 Lerna 之前去维护和管…

threehit二次注入案例

君衍. 一、环境搭建1、conn.php源码&#xff1a;2、register.php源码3、login.php源码4、index.php源码5、demo.php源码 二、数据库环境搭建1、注意点一2、注意点二报错原因 三、复现过程1、user12、user23、user34、user45、user56、user6-name7、user7-table8、user8-column9…

Python编程实验五:文件的读写操作

目录 一、实验目的与要求 二、实验内容 三、主要程序清单和程序运行结果 第1题 第2题 四、实验结果分析与体会 一、实验目的与要求 &#xff08;1&#xff09;通过本次实验&#xff0c;学生应掌握与文件打开、关闭相关的函数&#xff0c;以及与读写操作相关的常用方法的…

vue中scss样式污染引发的思考

新做了一个项目&#xff0c;就是在登录后&#xff0c;就会产生左侧菜单的按钮颜色不一样。 然后发现样式是从这里传过来的 然后发现是登录页面的css给污染了 就是加了scope就把这个问题解决了 然后想总结一下这个思路&#xff1a;就是如何排查污染样式&#xff0c; 如果出现…

postman测试接口

1、postman测试接口 &#xff08;1&#xff09;首先安装postman 下载地址&#xff1a;Download Postman | Get Started for Free 选择对应版本下载&#xff0c;然后安装即可 &#xff08;2&#xff09;使用postman发送请求 比如以下这个请求例子&#xff1a; 使用postman发…

SpringBoot集成EasyExcel快速人们

目录 1.背景介绍 2.EasyExcel的使用 1.添加依赖 2.相关代码准备 1.实体类 2.ExcelUtil工具类 3.写入控制类 1.背景介绍 EasyExcel 是阿里巴巴开发的一款基于 Java 的专业化 Excel 操作工具&#xff0c;主要用于在 Java 应用程序中快速、高效地读写 Excel 文件。EasyExce…

Git 指令深入浅出【2】—— 分支管理

Git 指令深入浅出【2】—— 分支管理 分支管理1. 常用分支管理指令2. 合并分支合并冲突合并模式 3. 实战演习 分支管理 1. 常用分支管理指令 # 查看本地分支 git branch# 查看远程分支 git branch -r# 查看全部分支 git branch -aHEAD 指向的才是当前的工作分支 # 查看当前分…

开源的 Python 数据分析库Pandas 简介

阅读本文之前请参阅-----如何系统的自学python Pandas 是一个开源的 Python 数据分析库&#xff0c;它提供了高性能、易用的数据结构和数据分析工具。Pandas 特别适合处理表格数据&#xff0c;例如时间序列数据、异构数据等。以下是对 Pandas 的简明扼要的介绍&#xff0c;包括…