我们用multi_timer+状态机的方式实现了光强读取,文章链接如下:
基于小熊派光强传感器BH1750实践(multi_timer+状态机工程应用)
今天我们再小小的进阶一步,把它和小熊派上的OLED结合起来吧!所谓所见即所得,这才是开发最大的乐趣,在实现这个小项目之前,我们先来了解下小熊派开发板上的这个屏吧,先看下原理图是怎么接的:
如上图所示,根据Datasheet解读下该LCD的控制方式:
LCD_SPI_MOSI、LCD_SPI_CLK这两个管脚是用于建立SPI通信协议用的,传统的SPI都有SPI_MOSI(主设备输出从设备输入)、SPI_MISO(主设备输入从设备输出)、SPI_SCK(SPI的时钟线),那为什么这里没有SPI_MISO呢?
这是由于只需要进行显示,所以模组设计的时候将从机发往主机的数据线进行了隐藏,这个在Datasheet里的66页可以看到相关的说明,由于篇幅限制,这里就不贴出。
原理图管脚用途解析
LCD_WR_RS是芯片的命令/数据控制引脚:
由datasheet得知,当LCD_WR_RS引脚为低电平时,则是写命令状态,当LCD_WR_RS引脚为高电平时,为写数据状态。
LCD_RESET是LCD的复位引脚,模块上电的时候拉低,通常情况下需要将该位置1。
LCD_POWER是LCD的电源引脚,通常情况下给它直接拉高就可以正常点亮工作了。
还有一个非常重要的功能,也就是LCD的片选功能,原理图里已经将片选直接拉低,这样芯片才会被使能。
关于通信协议
对于SPI通信而言,数据是有传输时序的,即时钟相位(CPHA)与时钟极性(CPOL)的组合:CPHA的高低决定串行同步时钟是在第一时钟跳变沿还是第二个时钟跳变沿数据被采集,当CPHL = 0,在第一个跳变沿进行数据采集;CPOL的高低决定串行同步时钟的空闲状态电平,CPOL = 0,为低电平。从图中可以看出,当SCLK第一个下降沿时开始传输数据,一个时钟周期传输8bit数据,使用SPI0,按位传输,高位在前,低位在后。
项目实战
上一节,我们没有用拓展板的这个LED灯,这节我们把这个灯(LED_SW)配置起来,把原来开发板那个灯去掉。
这个灯位于开发板的PB9端口。
我们将在上一个工程的基础上添加SPI相关的配置后直接实现,打开上一节的工程:
1、修改配置为LED_SW灯
2、配置SPI2
3、配置LCD_WR_RS、LCD_RESET、LCD_POWER
4、生成工程、然后移植小熊派LCD例程
包含LCD驱动源代码
将LCD相关文件添加到Keil工程
然后编译完发现有一个错误:
LIGHT_SENSOR_I2C\LIGHT_SENSOR_I2C.axf: Error: L6218E: Undefined symbol SPI2_WriteByte (referred from lcd.o).
意思是在lcd程序文件里没有定义SPI2_WriteByte这个接口。
找到这个错误的地方,添加一个这样的函数,再编译,解决问题。
接下来在main.c中添加头文件:
/* Private includes ----------------------------------------------------------*/ /* USER CODE BEGIN Includes */ #include "lcd.h" #include "HzLib.h" /* USER CODE END Includes */
接下来添加LCD显示逻辑:
/** * @brief The application entry point. * @retval int */ int main(void) { /* USER CODE BEGIN 1 */ char display_buf[20] = {0}; /* USER CODE END 1 */ /* MCU Configuration--------------------------------------------------------*/ /* Reset of all peripherals, Initializes the Flash interface and the Systick. */ HAL_Init(); /* USER CODE BEGIN Init */ /* USER CODE END Init */ /* Configure the system clock */ SystemClock_Config(); /* USER CODE BEGIN SysInit */ /* USER CODE END SysInit */ /* Initialize all configured peripherals */ MX_GPIO_Init(); MX_I2C1_Init(); MX_USART1_UART_Init(); MX_SPI2_Init(); /* USER CODE BEGIN 2 */ /*串口初始化后加这个延时,防止后面的printf打印乱码*/ HAL_Delay(200); LCD_Init(); LCD_Clear(BLACK);//清屏为黑色 LCD_ShowString(5, 10, 240, 32, 32, "BearPi LuxTest");//显示字符串,字体大小32*32 printf("光强读取测试实验\n"); Init_BH750(); timer_init(&lsensor.timer1, lsensor.timeout_cb, 1, 1); timer_start(&lsensor.timer1); /* USER CODE END 2 */ /* Infinite loop */ /* USER CODE BEGIN WHILE */ while (1) { /* USER CODE END WHILE */ /* USER CODE BEGIN 3 */ ReadBH1750(LUX_1_MODE); if(1 == lsensor.Conver_completed) { sprintf(display_buf, "%d%d%d%dLux", lsensor.Lux / 1000 % 100, lsensor.Lux / 100 % 10, lsensor.Lux / 10 % 10, lsensor.Lux % 10); LCD_ShowString(80, 50 + 24 + 32, 240, 32, 32, display_buf); //显示字符串,字体大小32*32 if(lsensor.Lux > LIGHT_SENSOR_THREHOLD) { HAL_GPIO_WritePin(LED_GPIO_Port, LED_Pin, GPIO_PIN_RESET); } else { HAL_GPIO_WritePin(LED_GPIO_Port, LED_Pin, GPIO_PIN_SET); } } timer_loop(); } /* USER CODE END 3 */ }
这里这么来显示的主要原因是由于小熊派提供的例程里打印字符串不带清除功能,所以会有叠加效应,后面有时间解决,如果使用清除局部区域的函数,则会造成屏幕闪烁,体验感很不好。
运行结果
当光强小于设定阈值,则亮灯
当光强大于设定阈值,则灭灯
实际例程下载:
链接:https://pan.baidu.com/s/1D3AgGO_vThTgRn09SeHPIw 提取码:nskm
往期精彩
超轻量级网红软件定时器multi_timer(51+stm32双平台实战)