提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
文章目录
前言。
作品是基于STM32F411CUE6芯片,制作的一个智能手表的项目。目前整个项目用到了ADC按键,按键中断,五个定时器,分别对应呼吸灯的输出,马达的输出,三个定时中断。
一、开机界面的描述
视频拍的不好,动图效果就更差,只能画一个这样的图来说明。
1.最左面三个中文汉字的显示
2.横杠,横杠,大于号的功能描述和实现方法
第二行方格除了第一排汉字以外的三个图形,我实现的效果是第一秒第一个横杠出现,第二秒第一个横杆消失,第二个横杠出现,以此类推,到最后面就从头再来。
关于部分的实现方式是通过一个一秒定时器,对OLED屏幕对应的地方擦除,写入。
代码部分:
switch(c)
{
case 0 : oled_dis_str24(2,16,"-"); c++; break;
case 1 : OLED_clear_START_1(); c++; break;
case 2 : oled_dis_str24(2,32,"-"); c++; break;
case 3 : OLED_clear_START_2(); c++; break;
case 4 : oled_dis_str24(2,48,">"); c++; break;
case 5 : OLED_clear_START_3(); c++; break;
case 6 : c=0; break;
}
特别需要注意的是,因为中断函数其实也是单片机不断运行的一个局部函数,那么这个如果要实现C++变量正常加减并且不卡主函数运行的功能需要对变量C修饰静态变量,还是不明白请移步局部静态变量相关知识。
3.进度条的描述和实现
进度条没什么描述的,我就直接说一些实现遇到的难处和方法。首先进度条是需要自己掌握开机时间的,因为这个项目的开机其实是一个主函数延时产生的一个假开机,所以,进度条的时间需要自己把握。我通过串口的时间戳来把握了进度条的时间问题。
还有一个难处就是没有合适的时间中断来让他1%的加载,所以需要占用一个额外的定时器来实现这个功能
代码部分
void TIM1_UP_TIM10_IRQHandler(void)
{
static int load;
if(TIM10->SR & (1<<0))
{
TIM10->SR &= ~(1<<0);
//紧急事件
if(flag_time_10 ==1)
{
oled_dis_pic(6,4+load,16,3,load_p);
load = load+4;
}
}
关于代码的解释: flag_time是为了节省定时器而用的,不希望这个定时器只有开机的时候才能用,而且这个开机的功能只在开机的时候才用到,所以自己制作一个标志位,让它只在开机的时候用这个功能。
oled_dis_pic是一个封装好的oled屏幕传递函数,第一个参数是页数,第二个参数是行数,第四个和第五个参数是图片的长和宽,最后一个参数是图片数据数组的一个地址(这里的图片便是涂黑三行)。这个函数实现的功能就是定时器第一次进入中断,从第四行开始涂黑三行,第二次进入中断,从第八行开始涂黑三行。
4.动图的实现
因为上面的的功能都是用定时器中断进入的,那么动图的实现就用主函数的for函数和延时函数来卡住它实现
代码部分:
for(j=0 ;j<1;j++)
{
int i =0;//不可改动,图片帧数
for(i = 0;i < 7;i++)
{
oled_dis_pic(0,64,64,64,pic[i]);
delay(50);
}
}
5.关于电动机的转动和PWM呼吸灯的实现
电机的转动需要一个定时器的PWM功能,灯也需要一个,但是如果需要实现呼吸灯的话,在不卡主函数的情况下,就格外需要一个定时器加入进来改变CCR寄存器的值。
代码部分:
if(flag_time_1 == 1)
{
if(j<1000)
{
i+=10;
j+=10;
TIM3->CCR2 = i;
//printf("%d %d\r\n",i,j);
}
else
{
i-=10;
TIM3->CCR2 = i;
j+=10;
//printf("%d %d\r\n",i,j);
}
if(j>=2000)
{
j=0;
}
}
二、界面一:时间显示的实现
1.RTC:real time clock(真实时间时钟)
关于RTC使用等信息,本文不多赘述。主要只介绍在主函数中可以通过更新时间寄存器来不断的使定时器中断响应读取STM32内RTC信息的方法。这种方法可以使整个系统的运行更为流畅。非常推荐。
三、界面二:灯相关的控制功能
先说实现的功能,进入该页面后,指示部分会闪烁。我们用到的按键是通过ADC检测的五方向按钮(具体实现功能在本文中不过多赘述),五个方向分别为上下左右和中间。当刚进入页面的时候,按上或者下都会移动指示部分,在灯亮度和灯速度之间来回切换(灯速度指呼吸灯的速度)。在指示部分指向灯速度或者灯亮度的时候,按下中间,便会分别进入各自的<0>部分,也就是循环内闪烁部分。进入这个部分时,0会闪烁表示可以按左右进行选择灯的亮度或者呼吸灯的速度,于此同时动图会根据目前的灯亮度的情况进行切换。
1.指示部分
指示部分在这个页面是用一个定时器完成成,因为没有定时器符合它的工作时间,比如动图的工作时间必须在人眼识别不到的情况下,而指示部闪的太快会可能会导致看不见或者没那么舒服,所以我这里用了一个独立的定时器完成这个工作。
工作的实现是通过指定位置的擦除和指定位置的写入实现的
代码部分
if(flag_time_9 == 2)
{
static uint8_t count_9_2 = 0;
if(count_9_2 == 0)
{
count_9_2++;
if(flag_time_9_2_set==0)
{
oled_dis_16(0,48,"<");
}
else if(flag_time_9_2_set==1)
{
oled_dis_16(4,48,"<");
}
}
2.闪烁内循环部分
该部分借鉴的是C++的一个登陆系统,是B站的一个黑马程序员教的。为了让按键总体的左右功能用于控制0变成1的功能而不会翻译的功能,就需要实现这个功能的时候不走主函数的查询循环,而是走我实现这样的功能的一个小循环。(当然如果整个代码的主框架不一样,也许不需要用这种方式,代码只有更好没有最好。)
实现部分是通过中间按键的中断进入的,只要程序目前是在这个页面,并且接收都中间按键的中断,便进入相应的while循环里面。
代码实现:
中断函数部分:
if((interrupt_2_set==1)&&(flag_time_9_2_set==0)) //灯亮度
{
flash_2 = 1;
}
if((interrupt_2_set==1)&&(flag_time_9_2_set==1)) //灯速度
{
flash_2 = 2;
}
}
主函数部分:
//闪烁和控制
if(flash_2 == 1)
{
while(1)
{
key_2 = get_KEY_number();
if(key_2==1)
{
break;
}
else if(key_2==2)
{
break;
}
else if(key_2==3)
{
show--;
}
else if(key_2==4)
{
show++;
}
if(show>4)
{
show = 0;
}
OLED_clear_2_1_flash();
delay(100);
//闪烁多少
show_page_2_1(show);
set_light(show);
delay(100);
}
TIM3->CCR2= 0;
}
else if(flash_2 == 2)
{
while(1)
{
key_2 = get_KEY_number();
if(key_2==1)
{
break;
}
else if(key_2==2)
{
break;
}
else if(key_2==3)
{
show--;
}
else if(key_2==4)
{
show++;
}
if(show>4)
{
show = 0;
}
OLED_clear_2_2_flash();
delay(100);
show_page_2_2(show);
flag_time_1 = 1;
set_speed(show);
delay(100);
}
flag_time_1 = 0;
TIM3->CCR2= 0;
}
flash_2 = 0;
delay(100);
}
相关的函数和自己设计的标志位,建议通过整个工程查看。
3.动图部分
动图部分设置相应的标志位,检查整个程序运行的程度,通过标志位来让图显示即可,如果显示的不是动图也就不需要启用一个定时器来让图动起来
代码部分:
主函数在上面参考
调用函数:
void set_speed_pic(uint8_t light)
{
switch(light)
{
case 0 : delay_TIM10_IT_Init(100); break;
case 1 : delay_TIM10_IT_Init(50); break;
case 2 : delay_TIM10_IT_Init(25); break;
case 3 : delay_TIM10_IT_Init(17); break;
case 4 : delay_TIM10_IT_Init(10); break;
}
}
中断函数:
if(flag_time_10 == 2)
{
static uint8_t TIM10_2_1 = 0;
TIM10_2_1++;
oled_dis_pic(0,64,64,64,pic[TIM10_2_1]);
if(TIM10_2_1>5)
{
TIM10_2_1 =0 ;
}
}
值得一提的是,呼吸灯变换速度的实现,完全靠的是硬件,影子寄存器的实现,只能说666。
总结
关于整个工程目前遇到的一个影响整个工程质量的问题是如果发送数据给OLED屏幕过快的话,很可能会导致OLED屏幕乱码,需要对这个方面留点小心眼。
视频请移步到B站观看:https://www.bilibili.com/video/BV1wv4y1m7Xg/
关于整个工程代码:链接:https://pan.baidu.com/s/1wLzfx38t0ZWbsXt9Z_E-OQ?pwd=8888
提取码:8888