通過PWM控制液晶屏幕的亮度
一、工程準備
在上一個工程:RT-Thread開發之路(8)— 通過TFTLCD液晶屏幕顯示數據,我們已經完成了LCD的基本顯示,可是我們會發現,LCD屏幕非常的亮,那麼可以降低他的亮度嗎,接下來我們就通過PWM來控制他的亮度。實際上只要控制他的背光引腳LCD_POWER即可。
二、開啓PWM設備
打開board.h
文件,找到PWM的配置處,按照其提示配置:
首先,打開【RT-Thread Settings】,找到PWM設備驅動程序,將其選中,然後保存使之生效
通過查看STM32L431的數據手冊,可以看到,LCD_POWER即PB15引腳,可以由TIM1和TIM15兩個定時器控制,但是TIM1是互補輸出引腳,所以我們選擇TIM15,在board.h的添加TIM15宏定義
#define BSP_USING_PWM15
接下來使用CubeMx生成HAL_TIM_Base_MspInit()和HAL_TIM_MspPostInit()函數,將SPI以及LCD需要的控制引腳設置爲如圖所示:
將HAL_TIM_Base_MspInit()
修改爲HAL_TIM_PWM_MspInit()
後,和HAL_TIM_MspPostInit()
函數複製到board.c裏,這裏後其其給的註釋不一樣,要注意,(可能是還沒來得及修改註釋)
void HAL_TIM_PWM_MspInit(TIM_HandleTypeDef* tim_baseHandle)
{
if(tim_baseHandle->Instance==TIM15)
{
/* USER CODE BEGIN TIM15_MspInit 0 */
/* USER CODE END TIM15_MspInit 0 */
/* TIM15 clock enable */
__HAL_RCC_TIM15_CLK_ENABLE();
/* USER CODE BEGIN TIM15_MspInit 1 */
/* USER CODE END TIM15_MspInit 1 */
}
}
void HAL_TIM_MspPostInit(TIM_HandleTypeDef* timHandle)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
if(timHandle->Instance==TIM15)
{
/* USER CODE BEGIN TIM15_MspPostInit 0 */
/* USER CODE END TIM15_MspPostInit 0 */
__HAL_RCC_GPIOB_CLK_ENABLE();
/**TIM15 GPIO Configuration
PB15 ------> TIM15_CH2
*/
GPIO_InitStruct.Pin = GPIO_PIN_15;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
GPIO_InitStruct.Alternate = GPIO_AF14_TIM15;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
/* USER CODE BEGIN TIM15_MspPostInit 1 */
/* USER CODE END TIM15_MspPostInit 1 */
}
}
然後打開stm32xxxx_hal_config.h
文件,添加#define HAL_TIM_MODULE_ENABLED
的註釋去掉:
因爲配置文件沒有定義PWM15輸出通道,所以我們需要添加一些配置,打開drives/include/config/
目錄下的pwm_config
文件,添加如下代碼,其中.channel
可以採用相或的方式設置多個通道的初始化:channel1->0x01,channel2->0x02,channel3->0x04,channel1->0x08
#ifdef BSP_USING_PWM15
#ifndef PWM15_CONFIG
#define PWM15_CONFIG \
{ \
.tim_handle.Instance = TIM15, \
.name = "pwm15", \
.channel = 0x02 \
}
#endif /* PWM15_CONFIG */
#endif /* BSP_USING_PWM15 */
然後編譯,很好,報錯了,提示找不到TIM17,可是STM32L431RCT6本就沒有TIM17,
這可能是一個bug我們直接將其註釋掉:
下載運行,在msh下輸入list_device,可以看到,pwm15
已經註冊上去了
三、編寫代碼,控制LCD背光
在main.c中,包含頭文件,
#include "drv_lcd.h"
然後設置PWM15 的參數:
#define PWM_DEV_NAME "pwm15" /* PWM設備名稱 */
#define PWM_DEV_CHANNEL 2 /* PWM通道 */
struct rt_device_pwm *pwm_dev; /* PWM設備句柄 */
接下來在main()中寫入如下代碼:
rt_uint32_t period, pulse;
period = 1000000; /* 週期爲0.5ms,單位爲納秒ns */
pulse = 100000; /* PWM脈衝寬度值,單位爲納秒ns */
/* 查找設備 */
pwm_dev = (struct rt_device_pwm *)rt_device_find(PWM_DEV_NAME);
if (pwm_dev == RT_NULL)
{
rt_kprintf("pwm sample run failed! can't find %s device!\n", PWM_DEV_NAME);
return RT_ERROR;
}
/* 設置PWM週期和脈衝寬度默認值 */
rt_pwm_set(pwm_dev, PWM_DEV_CHANNEL, period, pulse);
/* 使能設備 */
rt_pwm_enable(pwm_dev, PWM_DEV_CHANNEL);
還有一點要注意的是,將drv_lcd.c
文件中lcd_gpio_init()
中對LCD_PWR_PIN的初始化註釋掉,不要設置其爲通用推輓輸出了,
然後編譯下載運行,可以觀察到其屏幕暗下來了:
四、優化代碼
我們將lcd的代碼放到一個文件夾裏,新建一個線程,在線程中通過檢測按鍵的按下來調節LCD的亮度,代碼如下:
#include <rtthread.h>
#include <board.h>
#include <rtdevice.h>
#include "drv_lcd.h"
#define KEY1_PIN GET_PIN(B, 2)
#define KEY2_PIN GET_PIN(B, 3)
#define PWM_DEV_NAME "pwm15" /* PWM設備名稱 */
#define PWM_DEV_CHANNEL 2 /* PWM通道 */
struct rt_device_pwm *pwm_dev; /* PWM設備句柄 */
/* 定義一個LCD線程句柄結構體指針 */
static rt_thread_t app_lcd_thread = RT_NULL;
void brightness_ctrl(rt_uint32_t bright)
{
if(bright > 100)
bright = 100;
/* 設置PWM週期和脈衝寬度 */
rt_pwm_set(pwm_dev, PWM_DEV_CHANNEL, 1000000, bright * 10000);
}
static void app_lcd_thread_entry(void *parameter)
{
rt_uint32_t ctrl_value = 10;
static int key_up = 1; /* 按鍵鬆開標誌 */
rt_pin_mode(KEY1_PIN, PIN_MODE_INPUT_PULLUP);
rt_pin_mode(KEY2_PIN, PIN_MODE_INPUT_PULLUP);
/* 查找設備 */
pwm_dev = (struct rt_device_pwm *)rt_device_find(PWM_DEV_NAME);
if (pwm_dev == RT_NULL)
{
rt_kprintf("pwm run failed! can't find %s device!\n", PWM_DEV_NAME);
return ;
}
/* 使能設備 */
rt_pwm_enable(pwm_dev, PWM_DEV_CHANNEL);
brightness_ctrl(ctrl_value);
/* 設置背景色和前景色 */
lcd_set_color(WHITE, BLACK);
/* 在 LCD 上顯示字符 */
lcd_show_string(10, 60, 32, "Hello!");
lcd_show_string(10, 100, 32, "RT-Thread");
/* 在 LCD 上畫線 */
lcd_draw_line(0, 69+16+24+32, 240, 69+16+24+32);
/* 在 LCD 上畫一個同心圓 */
lcd_draw_point(120, 194);
for (int i = 0; i < 46; i += 4)
{
lcd_draw_circle(120, 194, i);
}
lcd_show_string(200, 0, 24, "%3d",ctrl_value);
while (1)
{
/* 檢測按鍵是否按下 */
if (key_up && ((rt_pin_read(KEY1_PIN) == 0) || (rt_pin_read(KEY2_PIN) == 0)) )
{
rt_thread_mdelay(50); /* 延時50ms消抖*/
key_up = 0;
if(rt_pin_read(KEY1_PIN) == 0)
{
rt_kprintf("key1 press \r\n");
if(ctrl_value > 4)
ctrl_value = ctrl_value -5;
brightness_ctrl(ctrl_value);
rt_kprintf("brightness level %d \r\n",ctrl_value);
}
else if(rt_pin_read(KEY2_PIN) == 0)
{
rt_kprintf("key2 press \r\n");
if(ctrl_value < 96)
ctrl_value = ctrl_value +5;
brightness_ctrl(ctrl_value);
rt_kprintf("brightness level %d \r\n",ctrl_value);
}
lcd_show_string(200, 0, 24, "%3d",ctrl_value);
}
else if((rt_pin_read(KEY1_PIN) == 1) && (rt_pin_read(KEY2_PIN) == 1))
{
key_up = 1; /* 按鍵已鬆開 */
}
rt_thread_mdelay(100);
}
}
static int app_lcd_init(void)
{
rt_err_t rt_err;
/* 創建LCD線程*/
app_lcd_thread = rt_thread_create("app_lcd thread",
app_lcd_thread_entry, RT_NULL, 2048, 6, 10);
/* 如果獲得線程控制塊,啓動這個線程 */
if (app_lcd_thread != RT_NULL)
rt_err = rt_thread_startup(app_lcd_thread);
else
rt_kprintf("app_lcd_thread create failure !!! \n");
/* 判斷線程是否啓動成功 */
if( rt_err == RT_EOK)
rt_kprintf("app_lcd_thread startup ok. \n");
else
rt_kprintf("app_lcd_thread startup err. \n");
return rt_err;
}
INIT_APP_EXPORT(app_lcd_init);
可以實現需要的效果