自制摇摇棒

自制摇摇棒开发总结

最近做了一个摇摇棒,也算是一个小制作吧,原理很简单,制作过程也不是很复杂.

YaoyaobangOnSTM32硬件及软件资料下载


摇摇棒简介

摇摇棒就是一个可以摇动然后显示图案的小制作.利用人眼的视觉暂留现象,显示图案.我制作的摇摇棒使用STM32C8T6微控制器作为主控,使用内部RC震动器(也可外接晶振),采用16个LED灯作为显示部分,采用ams1117作为电源稳压芯片,也可直接不经过稳压芯片直接驱动.软件方面设计为摇动的频率可变,以任意较快频率(可产生视觉暂留现象的频率)晃动都可以产生图像.采用低功耗设计,自动进入待机模式节省电量.待机时功耗低至60μw.

细节

原理

检测频率

使用震动开关检测晃动的频率,震动开关就是在震动的时候能产生高低电平.通过systick定时器和外部中断的配合使用可以达到计算晃动频率的目的.以下是两个主要使用的函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
void HAL_SYSTICK_Callback()//定时器回掉函数
{
yaoyaobangBase.timeCount++;
if(yaoyaobangBase.timeCount>=10000)
{
yaoyaobangBase.timeCount=10000;
PowerManagement();
}

if(yaoyaobangBase.DelayMS!=0)
yaoyaobangBase.DelayMS--;
}

void HAL_GPIO_EXTI_Callback (uint16_t GPIO_Pin)//外部中断回掉函数
{
if(GPIO_Pin==Vibrate)
{
yaoyaobangBase.time=yaoyaobangBase.timeCount;
yaoyaobangBase.timeCount=0;
yaoyaobangBase.state=run;
}
}

LED显示

计算出每晃动一次的时间之后就是控制LED灯显示了.以下是我输出图形的数组

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
const char Image[16*ImageLenth]=
{
1, 1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1,
1, 1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1,
1, 1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1,
1, 1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1,
1, 1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1,
1, 1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1,
1, 1 ,0 ,0 ,0 ,0 ,0 ,0 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1,
1, 0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,1 ,1 ,1 ,1 ,1 ,1,
1, 0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,1 ,1 ,1 ,1 ,1,
1, 0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,1 ,1 ,1 ,1,
1, 0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,1 ,1 ,1,
1, 1 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,1 ,1,
1, 1 ,1 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,1,
1, 1 ,1 ,1 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,1,
1, 1 ,1 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,1,
1, 1 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,1 ,1,
1, 0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,1 ,1 ,1,
1, 0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,1 ,1 ,1 ,1,
1, 0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,1 ,1 ,1 ,1 ,1,
1, 0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,1 ,1 ,1 ,1 ,1 ,1,
1, 1 ,0 ,0 ,0 ,0 ,0 ,0 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1,
1, 1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1,
1, 1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1,
1, 1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1,
1, 1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1,
1, 1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1,
1, 1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1
};

大概能看出来图形吧.1和0就代表着灯的亮和灭,一共16个灯所以是(16X图像长度).当然啦,像我这样保持图像有点原始,更优化的方案是用bit来保存,显示的时候直接把一个字节写进寄存器省去了按位与或非的过程,既节省时间又节省空间.当然甚至还可以利用DMA+定时器做硬件触发链,完全利用硬件输出图像更能加速和降低功耗.说多了,将计算出的晃动时间除以图像长度就得到了每一帧应该输出的时间了,控制LED输出即可.以下是输出部分.

1
2
3
4
5
6
7
8
9
10
11
12
13
14

void ShowImage(const char *this)
{
const char *base=this;
yaoyaobangBase.moment=yaoyaobangBase.time/ImageLenth;
for(char i=0;i<ImageLenth;i++)
{
this=base;
LEDShow((this+16*i));//每一帧的输出
yaoyaobangBase.DelayMS=yaoyaobangBase.moment;
while(yaoyaobangBase.DelayMS!=0);
}
yaoyaobangBase.state=stop;
}

低功耗

低功耗是从设计之初就考虑到的问题,就是不想在我设计出来的东西上加关机键,所以设计就没有加开关,用低功耗的待机模式即可.待机功耗最终降到19μA,还是在预期范围内.实现低功耗主要就是进入低功耗模式以及低功耗唤醒两方面了.先说进入待机模式,现在HAL库功能强大,一句HAL_PWR_EnterSTANDBYMode();就可进入待机模式.不过退出待机模式就需要硬件支持了,PA0管脚的跳变可以触发唤醒,所以我的震动开关用的这个脚,不过最后我放弃了唤醒这个功能,改为用复位按键实现唤醒,主要是震动开关不是特别稳定,误触发的情况比较严重.另外,使用内部RC震动器,工作时主频以较低的8MHz工作灯也有助于降低功耗.

填坑总结

坑1:JTAG管脚复用问题

焊接完成芯片以后测试时发现有几个脚连在了一起,挑开后发现始终GPIOB3GPIOB4脚不受控制.开始以为是脚还连在一起,换芯片后问题依旧.最后发现是JTAG管脚复用问题,这两个脚上电默认功能是JTAG,需要先复用成GPIO,之后操作GPIO才有效,在STM32的HAL库中系统初始化时本来关闭了JTAG的,但是STlink就没法工作,于是我将那一行注释了就造成这样的错误.

坑2:flash容量选错

开始建立工程时芯片型号选择错误,导致flash容量时错误的,虽然烧录进去了,但是执行的时候程序跑飞,差点锁死.CMSIS-DAP使用没有STlink和J-link那么稳定,尤其是解锁或者擦flash的时候.另外建立工程时一定要选择正确型号

坑3:编译优化等级

采用CubeMX建立出来的工程貌似默认的编译优化等级就是最高级,导致最开始的调试结果始终有问题,单步调试时总感觉很奇怪.在开发调试阶段一定要注意编译优化等级,不要开优化,到后期优化时在开高,太高等级有可能无法正常运行的.

坑4:AMS1117功耗问题

AMS1117作为线性稳压电源静态功耗其实不低的,根据我的测算,输入电压6v时静态电流5mA.其实也不是很大,不过需要低功耗场景时这个5mA却十分致命,严重影响续航时间(5mA那么1000mAh的电池只能待机8天).为保证待机时间,我在最后阶段去掉了这个芯片,待机电流迅速降低到19μA,理论上1000mAh的电池应该可以续航7年了.

结束

遇到了坑,填吧,只能记录下来尽量让下次注意.通过这个小制作也更加了解STM32系列了,尤其是HAL库和低功耗设计.不得不说ST的HAL库确实良心,非常好用,层次清晰,抽象程度恰到好处,没有炫技式写法,帮助文档做得也十分贴心,看得出来ST确实用心做了这个库,不像NXP的MCUXpresso,简直难用到爆炸,为炫技而存在,故意复杂化问题.另外配套的CubeMX工具也很好用,帮助建立工程以及初始化等,的确能让开发者直面问题本身而不是花大量时间建立工程,配置各种初始化等.


EOF