基于M5StickC Plus的综合应用-电子沙漏
本片文章分享我在硬禾学堂的2022年暑假在家一起练活动,基于M5StickC Plus的电子沙漏项目的流程及效果展示
标签
嵌入式
2022年暑假在家一起练
基于M5StickC Plus的综合应用
反正都一样
更新2022-09-07
524

FqP8UWyvcQIJLopbJtoV7TH8c0FC

项目介绍

这里时我参加硬禾学堂的2022年暑假在家一起练活动的任务总结报告,我所使用的是M5StickC Plus设备完成任务一,电子沙漏

以vscode+arduino的方式,实现在屏幕上确定好需要定时的时间,在点下开始按钮后,并由加速度传感器检测并确定是否经过翻转,在两块led灯板上呈现出电子沙漏的效果,待上一块灯板的所有led灯都熄灭时,即完成了设定时间的计时

流程图

                                                                         Fjx5HfGZqrm2ghc0ukgrzFPaW76P

主要硬件介绍

本次所使用的的设备M5StickC Plus是一个能帮助我么你快速搭建物联网产品的利器

主控为ESP32-PICO-D4模组,具备WIFI功能,方便我们实现联网功能

机身内部集成了丰富的硬件资源,如红外、RTC、麦克风、LED、IMU(本次我做的电子沙漏就用到了这个加速度传感器)、按键、蜂鸣器、PMU,1.14寸屏幕,电池容量为120mAh。可以看得出来,小小的机身里,隐藏着大大的能力,就看我们怎么使用它。

除了上面的M5StickC Plus,实现电子沙漏功能还需要两个以74HC595为驱动芯片的led灯板

FkOPSscGF9Rn7UZUW1cQyZjfXDAVFg-gqwPlC6O3O_nFQ4NHGqB3yEAE

在连线上,虽说有两个灯板,看起来有20个引脚需要连接,M5StickC Plus只有可怜的8个外接引脚,就算加上下面的四个,也才11个外接引脚,似乎没法连接两个led灯板,实则不然,在硬禾学堂的官方介绍上可以看出,将相邻的两块灯板靠近的5个引脚互相连接起来,在程序实现上,在驱动一块led灯板的基础上,连续写入两次地址,再打开时钟引脚,便可以实现用5个引脚同时控制两块led灯板的显示。

主要软件介绍

M5StickC Plus有多种开发环境

1、UIFLOW,官方开发的一种图形化编程平台控制M5StickC PLUS 设备,特点是够简单,够形象。

2、Micropython,一种简单而又快捷的嵌入式设备编程方式,相较于C语言开发, 即使是新手也能够快速上手,开发自己的产品

3、Arduino IDE,即使用C语言的方式进行开发,很常见

我所使用的就是第三种开发方式,但使用的环境为Arduino+vscode的方式开发,因为Arduino的官方IDE真的是一言难尽。

当然,在进行开发前,我们好像需要用arduino ide下载M5StickC PLUS的官方支持包和示例程序的,方便我们快速上手,开发应用

代码实现

因为我们下载了官方的支持包及示例程序,在驱动程序,如屏幕的,按键的使用上,我们就可以借鉴示例程序的。

void setup() {
	M5.begin(); //Init M5StickC Plus.  初始化 M5StickC Plus
	M5.Imu.Init();  //Init IMU.  初始化IMU
	gpio_pulldown_dis(GPIO_NUM_36);
	gpio_pullup_dis(GPIO_NUM_36);

	pinMode(DIN, OUTPUT);
	pinMode(SRCLK, OUTPUT);
	pinMode(RCLK, OUTPUT);

	M5.Lcd.setRotation(1);  //Rotate the screen. 将屏幕旋转
	M5.Lcd.setCursor(0, 0, 4); //set the cursor location.  设置光标位置
	M5.Lcd.println("Time Set:");

	M5.Lcd.setCursor(40, 50,6);
	M5.Lcd.printf("%d",timing_1);
	M5.Lcd.drawRect(30, 40, 45, 57, YELLOW);

	M5.Lcd.setCursor(110, 50,6);
	M5.Lcd.printf("%d",timing_2);
	//M5.Lcd.drawRect(100, 40, 45, 57, YELLOW);

	M5.Lcd.setCursor(170, 100,4);
	M5.Lcd.print("Start");
	//M5.Lcd.drawRect(165, 95, 63, 32, YELLOW);
	
	flash();//刷新一下,免得有上一次的记录
}

这个setup函数为设备的初始化函数,先是对M5这个设备进行了初始化操作,对外界的led灯板IO口进行初始化,配置为输出模式。并在屏幕初始化后,将要显示的内容,两个数字变量,和一个start字符,显示在屏幕上。最后一个flash函数则是对led灯板进行刷新下,防止有上一次数据还残留着。

	M5.update();
	if (M5.BtnA.wasReleased()) {  //If the button A is pressed.  如果按键 A 被按下
		update_dispaly(1);
		button_lock=1;
	}else if (M5.BtnA.wasReleasefor(700)) {  //The button B is pressed for 700ms. 按键 B 按下 700ms,屏幕清空
		update_dispaly(0);
	}
	if (M5.BtnB.wasReleased()) {  //If the button A is pressed.  如果按键 A 被按下
		update_dispaly(2);
	}else if (M5.BtnB.wasReleasefor(2000)) {  //The button B is pressed for 700ms. 按键 B 按下 700ms,屏幕清空
		ESP.restart();
	}

而在主循环中,先是对M5设备进行更新,看其是否进行了按键操作,从而执行相应的流程。我这里用到了两个按键的单击及长按事件,若是触发了A按键单击,长按事件,则进行数字的加减或计时开始确定,若是触发了B按键的单击,长按事件,则是对目标框转移或对设备重启。

 

关于电子沙漏的实现部分,我先来说说,led灯板的刷新函数

void Hc595OneRow(uint8_t R, uint8_t C)
{
	uint16_t cnt;
	SRCLK_0;
	RCLK_0;
	for(cnt=0;cnt<16;cnt++)
	{
		if (cnt<=7)
		{
			if(R & 0x80)
				DIN_1;
			else
				DIN_0;
			R<<=1;
		}else{
			if(C & 0x80)
				DIN_1;
			else
				DIN_0;
			C<<=1;
		}
		SRCLK_1;
		SRCLK_0;
	}	
}

上图是驱动一个LED灯板的程序,主要就是将要显示的led以一行一行,uint8_t的形式传进来,每一个bit代表着这个led是否亮灭

void flash(){
	uint8_t row=0x01;
	for(uint8_t i=0;i<8;i++){
		Hc595OneRow(row,status[15-i]);
		Hc595OneRow(row,status[7-i]);
		RCLK_1;
		RCLK_0;		
		row<<=1;
		vTaskDelay(2);
	}
}

上图则是整个电子沙漏的刷新函数,前两个箭头实现了只用5个引脚使两个led灯板同时刷新,而最下面的延迟函数则是用于防止刷新速度过快导致出现了不该亮的led却微微亮着的情况。

	unsigned long currentMillis = millis();
	if(hourglass_start==0){
		if(currentMillis>next_getahr_time){
			M5.IMU.getAhrsData(&pitch,&roll,&yaw);
			M5.Lcd.setCursor(0, 110,2);
			M5.Lcd.printf(" %5.2f %5.2f %5.2f ", pitch, roll, yaw);
			if(roll>-90&&roll<-70){
				if(button_lock==1){
					hourglass_start=1;
					delay(1000);
				}
			}
			next_getahr_time=currentMillis+100;
		}

上面的代码在点下确定按钮,准备开始计时后,会不断获取加速度传感器的值根据得到的姿态角数据,判断沙漏是否倒置了,若是倒置了,则开始进行电子沙漏的计时工作

而开头的currentMillis这个变量十分的重要,先提前说明。

在电子沙漏的实现过程中,难点在于如何实现一粒粒沙粒之间怎么做到1秒的间隔下落,且沙粒该如何实现一步一步从顶部落到底部的动画效果,关键就一点,如何控制时间间隔的准确性。答案就是上面这个millis()函数,该程序返回的是程序运行以来毫秒数

	}else if(hourglass_start==1){
		fill(timing_1*10+timing_2);
		next_update_time=currentMillis+100;
		next_drop_time=currentMillis+1000;
		hourglass_start=2;
	}else if(hourglass_start==2){
		if(currentMillis>next_update_time){
			update();
			next_update_time=currentMillis+100;
		}
		if(currentMillis>next_drop_time){
			fanzhuan();
			next_drop_time=currentMillis+1000;
		}
		flash();
	}

上面的代码中,当检测到hourglass_start变量置1后,开始给LED灯板填充需要计时的led灯的数量,使用的是fill函数,同时更新了两个变量next_update_time和next_drop_time,这两个在之后都将充当重要的功能。一个是以100ms的时间间隔进行变化,这个update函数就是实现了一粒沙粒一步一步的落到底部的动画效果。另一个箭头是以1000ms的时间间隔进行变化,这个fanzhuan函数则是实现了相邻的两个沙粒之间是1秒的时间间隔。至于其他的时间,我们都是在调用flash函数,对两个led灯板进行刷新操作

当然,update函数跟fanzhuan函数里面是怎么实现的,这就要话大篇幅来说了,如果大家感兴趣的话,可以到这个页面底部,下载源码进行学习。

主要的收获和遇到的困难

通过这次参加活动,我掌握了一些硬件基础知识和驱动方法,开阔了眼界且打开了思路,我感觉非常有成就感。

同时,我在代码编写过程中也遇到了不少困难,刚开始对项目的实现流程掌握不清楚导致学习进度缓慢,特别是电子沙漏的算法实现上有点绕,后来在不断解决问题中不断摸索,虽然遇到了一些问题,我也从处理问题中学到了很多知识。

附件下载
demo.zip
电子沙漏的程序,记得m5stickcplus的库
团队介绍
个人
评论
0 / 100
查看更多
目录
硬禾服务号
关注最新动态
0512-67862536
info@eetree.cn
江苏省苏州市苏州工业园区新平街388号腾飞创新园A2幢815室
苏州硬禾信息科技有限公司
Copyright © 2023 苏州硬禾信息科技有限公司 All Rights Reserved 苏ICP备19040198号