RT-Thread開發之路(9)— 通過PWM控制液晶屏幕的亮度

通過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);

可以實現需要的效果
在這裏插入圖片描述
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章