-
本文会介绍如何使用Lora开发板实现屏幕输出模式(基于STM32L151C8T6芯片)
-
一.看题
-
仔细审题很重要,找出题目最后要我们实现的效果
-
二.理清思路
- 根据题目要求可知,我们最终要实现的效果分为一下几点:
- 1.屏幕按要求显示文字
- 2.按键能够控制箭头上下移动,并且停留在某一位置LED灯能实现相对应的功能
总结:简单来说就两点,但其实实现起来也会遇到很多问题。
- 三.解题步骤
- 首先拿到物联网竞赛工程,对工程进行编译,养成良好的习惯!!
- 显示0错误0警告,说明工程没问题
- 根据题目可知,我们要用到呼吸灯,第一步可以先引入头文件
- 找到呼吸灯.c代码
- 找到它的头文件,并将它复制到main.c中,与main.c头文件放在一起,方便查找
#include "led_light.h"
- 接下来进行一些按键、LED灯的宏定义,便于后续编程,加快速度
#define KEY2 HAL_GPIO_ReadPin(GPIOC,GPIO_PIN_13)
#define KEY3 HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_1)
#define KEY4 HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_5)
#define LED1_ON() HAL_GPIO_WritePin(GPIOA,GPIO_PIN_3,GPIO_PIN_RESET)
#define LED1_OFF() HAL_GPIO_WritePin(GPIOA,GPIO_PIN_3,GPIO_PIN_SET)
#define LED2_ON() HAL_GPIO_WritePin(GPIOB,GPIO_PIN_8,GPIO_PIN_RESET)
#define LED2_OFF() HAL_GPIO_WritePin(GPIOB,GPIO_PIN_8,GPIO_PIN_SET)
- 按键和LED灯所对应的引脚
- KEY2——>PC13
- KEY3——>PB1
- KEY4——>PB5
- LED1——>PA3
- LED2——>PB8
- 因为要显示文字,所以要用到取自模软件,本文用的是PCtoLCD2002
- 取出的文字模放在main.c空白出就行
char liang[32]={0x00,0x04,0x04,0x74,0x54,0x54,0x55,0x56,0x54,0x54,0x54,0x74,0x04,0x04,0x00,0x00,
0x84,0x83,0x41,0x21,0x1D,0x05,0x05,0x05,0x05,0x05,0x7D,0x81,0x81,0x85,0xE3,0x00};
char deng[32]={0x80,0x70,0x00,0xFF,0x20,0x10,0x04,0x04,0x04,0x04,0xFC,0x04,0x04,0x04,0x04,0x00,
0x80,0x60,0x18,0x07,0x08,0x30,0x00,0x00,0x40,0x80,0x7F,0x00,0x00,0x00,0x00,0x00};
char mo[32]={0x10,0x10,0xD0,0xFF,0x90,0x14,0xE4,0xAF,0xA4,0xA4,0xA4,0xAF,0xE4,0x04,0x00,0x00,
0x04,0x03,0x00,0xFF,0x00,0x89,0x4B,0x2A,0x1A,0x0E,0x1A,0x2A,0x4B,0x88,0x80,0x00};
char shi[32]={0x10,0x10,0x90,0x90,0x90,0x90,0x90,0x10,0x10,0xFF,0x10,0x10,0x11,0x16,0x10,0x00,
0x00,0x20,0x60,0x20,0x3F,0x10,0x10,0x10,0x00,0x03,0x0C,0x10,0x20,0x40,0xF8,0x00};
char chang[32]={0x20,0x18,0x08,0xEA,0xAC,0xA8,0xA8,0xAF,0xA8,0xA8,0xAC,0xEA,0x08,0x28,0x18,0x00,
0x00,0x00,0x3E,0x02,0x02,0x02,0x02,0xFF,0x02,0x02,0x12,0x22,0x1E,0x00,0x00,0x00};
char hu[32]={0x00,0xFC,0x04,0x04,0xFC,0x00,0x04,0x14,0x64,0x04,0xFE,0x02,0x43,0x32,0x00,0x00,
0x00,0x0F,0x04,0x04,0x0F,0x00,0x01,0x01,0x41,0x81,0x7F,0x01,0x01,0x01,0x01,0x00};
char xi[32]={0x00,0xFC,0x04,0x04,0xFC,0x02,0x02,0xFE,0x02,0x02,0x62,0x5A,0x46,0xC0,0x00,0x00,
0x00,0x0F,0x04,0x04,0x4F,0x30,0x8E,0x81,0x46,0x28,0x10,0x28,0x46,0x81,0x80,0x00};
char jiao[32]={0x08,0x08,0x88,0x68,0x08,0x08,0x09,0x0E,0x08,0x08,0x88,0x28,0x48,0x88,0x08,0x00,
0x80,0x81,0x40,0x40,0x21,0x22,0x14,0x08,0x14,0x22,0x41,0x40,0x80,0x81,0x80,0x00};
char ti[32]={0x10,0x94,0x54,0x34,0x1F,0x34,0x54,0x80,0x54,0x34,0x1F,0x34,0x54,0x94,0x90,0x00,
0x01,0x00,0x00,0xFF,0x49,0x49,0x49,0x49,0x49,0x49,0x49,0xFF,0x00,0x00,0x00,0x00};
char mie[32]={0x02,0x02,0x82,0x72,0x02,0x02,0x02,0xFE,0x02,0x02,0x82,0x42,0x32,0x02,0x02,0x00,
0x80,0x81,0x40,0x20,0x10,0x0C,0x03,0x00,0x03,0x0C,0x10,0x20,0x40,0x80,0x80,0x00,};
- 接下来开始写函数
- 按照步骤来,我们首先让屏幕能显示文字
- 这里就自定义函数名
- 这个函数的主要功能就是显示文字
/*
函数:void OLED_display_dat()
功能:显示文字
*/
void OLED_display_dat()
{
OLED_ShowCHineseArray(16,0,liang);
OLED_ShowCHineseArray(32,0,deng);
OLED_ShowCHineseArray(48,0,mo);
OLED_ShowCHineseArray(64,0,shi);
OLED_ShowString(0,2,(uint8_t * )"1.");
OLED_ShowCHineseArray(16,2,chang);
OLED_ShowCHineseArray(32,2,liang);
OLED_ShowCHineseArray(48,2,mo);
OLED_ShowCHineseArray(64,2,shi);
OLED_ShowString(0,4,(uint8_t * )"2.");
OLED_ShowCHineseArray(16,4,hu);
OLED_ShowCHineseArray(32,4,xi);
OLED_ShowCHineseArray(48,4,mo);
OLED_ShowCHineseArray(64,4,shi);
OLED_ShowString(0,6,(uint8_t * )"3.");
OLED_ShowCHineseArray(16,6,jiao);
OLED_ShowCHineseArray(32,6,ti);
OLED_ShowCHineseArray(48,6,liang);
OLED_ShowCHineseArray(64,6,mie);
OLED_ShowString(80,2,(uint8_t * )"<");
}
- 下来就是按键控制函数
/*
函数:void KEY_Control()
功能:按键控制
*/
void KEY_Control()
{
if(KEY2==0)
{
HAL_Delay(50);
if(KEY2==0)
{
a--;
if(a==0)
{
OLED_ShowString(80,4,(uint8_t *)" ");
OLED_ShowString(80,2,(uint8_t *)"<");
}
if(a==1)
{
OLED_ShowString(80,6,(uint8_t *)" ");
OLED_ShowString(80,4,(uint8_t *)"<");
}
if(a<0)
{
a=0;
}
while(KEY2==0);
}
}
if(KEY3==0)
{
HAL_Delay(50);
if(KEY3==0)
{
a++;
if(a==1)
{
OLED_ShowString(80,2,(uint8_t *)" ");
OLED_ShowString(80,4,(uint8_t *)"<");
}
if(a==2)
{
OLED_ShowString(80,4,(uint8_t *)" ");
OLED_ShowString(80,6,(uint8_t *)"<");
}
if(a>2)
{
a=2;
}
while(KEY3==0);
}
}
if(KEY4==0)
{
HAL_Delay(50);
if(KEY4==0)
{
b=a;
if(b==0)
{
LED1_ON();
LED2_ON();
}
if(b==2)
{
LED1_ON();
LED2_OFF();
}
}
}
}
- 这里解析一下我自己写的逻辑
- a的逻辑:
- OLED屏幕上到下分成0-7,一共八行,根据显示效果来看,箭头在2-4-6行最美观,也就是看起来是正常的,a的初值为0,按下KEY2箭头向上走我定义为a- -,反之为a+ +,相当于我定义了2-4-6所对应a的值的三种情况
- 明白这一点,就很好办了,简单来说就是当a的值为0时,LED常亮模式,为1时,呼吸模式,为2时,LED交替闪烁模式。
- 你以为到这里这题就做出来了是吗,那就高兴的太早了,当时我也以为这样就可以了,但发现这个程序有bug,就是当我们切换到呼吸模式时,再切换到其他模式时,按键不灵,其实也不是按键不灵,要长按一会才能切换,闪烁模式也是如此。
- 那么怎么解决这个问题呢,其实也很简单,明白程序运行的逻辑就很清楚。
- 程序进入main函数,由这个图就能很清晰的看出,你要执行下一个语句,就必须先执行前面一个语句,简单来说,当你切换到LED闪烁模式时,LED闪烁我们是通过延时函数写的,好了,当你的程序在这个模式下,比如你去按按键,是不是也会受到影响,这里就体现我们前面说按键不灵,其实实质是被延时函数影响了,并不是按键问题。
- 解决的办法就是使用定时器来,我们要知道一点,定时器是板子一上电就会启动的,我自己的理解是定时器也相当于一个子程序,就是它和main函数是同一级别的,并且都能互相影响。明白这些,相信你到这里就大彻大悟了,简单来说就是把我们需要用到延时的逻辑放到定时器里。
- 首先在main函数中找到初始化函数
/**********************************************************************************************
*函数:void Init( void )
*功能:平台初始化
*输入:无
*输出:无
*特殊说明:无
**********************************************************************************************/
void Init() {
// 开发板平台初始化
BoardInitMcu();
BoardInitPeriph();
keys_init();//按键初始化
setTimer2Callback(Time2Handler);
Tim2McuInit(2);//定时器初始化,设置定时中断2ms中断一次
}
- 这里我们需要用到两个定时器,需要再添加Timer3初始化,初始化的方法和Timer2一样,我们直接复制粘贴然后把2改成3即可放在这个函数里即可
setTimer3Callback(Time3Handler);
Tim3McuInit(1250);//定时器初始化,设置定时中断5ms中断一次
Timer2用于呼吸灯亮灭,Timer3用于LED交替闪烁快慢
- 这里解释一下定时器里的时间参数为什么填2和1250
- 根据Timer2定时器的初始化配置的注释
抓取关键字,1ms,相当于你这里参数填的就是跟他1:1的 - 再来看Timer3定时器的初始化配置的注释
- 抓取关键字,0.25,相当于原来的1/4
- 初始化配置好后,右键setTimer3Callback(Time3Handler);进入它的.c里,找到回调函数
- 由于我们要在定时器里写LED呼吸和交替亮灭模式,务必引入头文件,否则会报错
#include "led_light.h"
- 将它放在tim-board.c的头文件里,放在一起方便查找
- 前面我们定义了整型变量b,现在就派上用场啦,这里可能大家会奇怪,为什么不直接用a一个变量还把a的值赋给b,这里我觉得一个变量好是好,可以减少代码量,但我觉得分开来这样思路会更清晰,就不会说一个变量做两件事情,不过如果逻辑很多的话,一定要写注释,不然真的很容易搞混。
- 由于我们定义的b是在main函数里的,所以这里我们不用再定义,只需要声明。
- 接下来就可以在定时器的回调函数里写逻辑啦
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
if(htim->Instance == TIM2)
{
/*TIM2用户中断应用程序请添加在下方空白处*/
//========================》TIM2空白处开始
//Time2Handler();
if (timer2Callback != NULL) {
timer2Callback();
}
if(b==1)
{
breathLed();
}
if(htim->Instance == TIM3)
{
/*TIM3用户中断应用程序请添加在下方空白处*/
//========================》TIM2空白处开始
//Time3Handler();
if (timer3Callback != NULL) {
timer3Callback();
}
if(b==2)
{
HAL_GPIO_TogglePin(GPIOA,GPIO_PIN_3);
if(htim->Instance == TIM3)
{
HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_8);
}
}
}
}
- 最后就是main函数里调用
int main( void )
{
Init();
OLED_Init();
OLED_display_dat();
startLedBreath();
LED1_ON();
LED2_ON();
while( 1 )
{
KEY_Control();
}
}
- 四.功能展示
物联网竞赛--Lora开发板控制显示屏输出
- 五.源代码分享链接
Lora开发板控制显示屏输出