Proteus: 使用STM32CubeMX的LCD1602仿真实验

前言

时不可以苟遇,道不可以虚行。


一、LCD1602介绍

  • LCD1602 是一种工业字符型液晶,能够同时显示 16x0232 个字符。LCD1602液晶显示原理: LCD1602液晶显示的原理是利用液晶的物理特性,通过电压对其显示区域进行控制,有电就有显示,这样即可以显示出图形。1602液晶也叫1602字符型液晶,它是一种专门用来显示字母、数字、符号等的点阵型液晶模块。
  • LCD1602 则是指显示内容为 16 * 2 ,即可以显示两行、每行可以显示 16 个字符的液晶模块。
  • 1、引脚说明:

  • 下图是在 proteus 中的 LCD1602 屏幕的样子,少了两个背光引脚:
  • 引脚 功能
    VSS 地电源
    VDD 接 5 V 电源
    VEE/VL 液晶显示器对比度调整端,接正电源时对比度最弱,接地时对比度最高,对比度过高时会产生“鬼影”,使用时可以通过一个10K的电位器调整对比度。
    RS 指令/数据选择信号,高电平时选择数据寄存器、低电平时选择指令寄存器
    RW 读写信号线,高电平时进行读操作,低电平时进行写操作
    E 使能端,当E端由高电平跳变成低电平时,液晶模块执行命令
    D0~D7 双向数据线,传输信息
    BLA 背光源正极
    BLK 背光源负极
  • 2、指令集


    二、工程建立

    准备:

  • proteus 软件:proteus 8.13
  • STM32CubeMX 软件:6.5
  • Keil MDK
  • 1、新建仿真工程






  • 所需元器件查找:
  • 元器件 符号
    LCD1602 LM016L
    电位器(滑动变阻器) POT
    STM32单片机 STM32F103R6
  • 仿真连线如下图所示:
  • 供电网配置:

  • 2、STM32cubemx新建工程

    1、 选择芯片型号:

    2、时钟配置


    3、引脚输出配置

    4、生成代码

    三、编写代码

  • 在 main.c 中:
  • /* USER CODE BEGIN Includes */
    
    #include  "LCD1602.h"
    
    /* USER CODE END Includes */
    
    /* USER CODE BEGIN 2 */
    
    	LCD_Init();
    	LCD_Puts(0,0,"I am successful.");
    
    /* USER CODE END 2 */
    
  • LCD1602.h:
  • #ifndef __LCD1602_H_
    #define __LCD1602_H_
    
    #include "main.h"
    
    #define _LCD_COLS         16
    #define _LCD_ROWS         2
    
    /*****  GPIOB3  H:data;L:command  ******/
    #define  LCD1602_RS_DATA	   	HAL_GPIO_WritePin(GPIOB,GPIO_PIN_3,GPIO_PIN_SET)		
    #define  LCD1602_RS_CMD			HAL_GPIO_WritePin(GPIOB,GPIO_PIN_3,GPIO_PIN_RESET)
    /*****  GPIOB4  H:read;L:write  ******/
    #define  LCD1602_RW_READ        HAL_GPIO_WritePin(GPIOB,GPIO_PIN_4,GPIO_PIN_SET)
    #define  LCD1602_RW_WRITE       HAL_GPIO_WritePin(GPIOB,GPIO_PIN_4,GPIO_PIN_RESET)
    /*****  GPIOB5    ******/
    #define  LCD1602_E_HIGH         HAL_GPIO_WritePin(GPIOB,GPIO_PIN_5,GPIO_PIN_SET)
    #define  LCD1602_E_LOW          HAL_GPIO_WritePin(GPIOB,GPIO_PIN_5,GPIO_PIN_RESET)
    
    #define  LCD1602_DATA(x)				GPIOB->ODR=(GPIOB->ODR & 0x00ff) | (x<<8)
    
    /* 指令集 */
    #define LCD_CLEARDISPLAY        0x01	//清屏指令
    #define LCD_RETURNHOME          0x02	//地址计数器 AC=0;(此时地址为 0x80) 光标归原点,但是 DDRAM 中断内容不变
    #define LCD_ENTRYMODESET        0x04	//输入模式设置
    #define LCD_DISPLAYCONTROL      0x08	//只开显示
    #define LCD_CURSORSHIFT         0x10	
    #define LCD_FUNCTIONSET         0x20
    #define LCD_SETCGRAMADDR        0x40
    #define LCD_SETDDRAMADDR        0x80
    
    /* 显示入口模式的标志 */
    #define LCD_ENTRYRIGHT          0x00
    #define LCD_ENTRYLEFT           0x02
    #define LCD_ENTRYSHIFTINCREMENT 0x01
    #define LCD_ENTRYSHIFTDECREMENT 0x00
    /* 开关控制标志 */
    #define LCD_DISPLAYON           0x04
    #define LCD_CURSORON            0x02
    #define LCD_BLINKON             0x01
    
    #define LCD_DISPLAYMOVE         0x08
    #define LCD_CURSORMOVE          0x00
    #define LCD_MOVERIGHT           0x04
    #define LCD_MOVELEFT            0x00
    
    #define LCD_8BITMODE            0x10
    #define LCD_4BITMODE            0x00
    #define LCD_2LINE               0x08
    #define LCD_1LINE               0x00
    #define LCD_5x10DOTS            0x04
    #define LCD_5x8DOTS             0x00
    
    typedef struct {
    uint8_t DisplayControl;
    uint8_t DisplayFunction;
    uint8_t DisplayMode;
    uint8_t currentX;
    uint8_t currentY;
    } LCD_Options_t;
    
    void LCD_Init(void);	//屏幕初始化	
    void LCD_DisplayOn(void);	
    void LCD_DisplayOff(void);
    void LCD_Clear(void);	//清屏
    void LCD_Puts(uint8_t x, uint8_t y, char* str);		//显示字符串
    void LCD_BlinkOn(void);
    void LCD_BlinkOff(void);
    void LCD_CursorOn(void);
    void LCD_CursorOff(void);
    void LCD_ScrollLeft(void);
    void LCD_ScrollRight(void);
    void LCD_CreateChar(uint8_t location, uint8_t* data);
    void LCD_PutCustom(uint8_t x, uint8_t y, uint8_t location);
    void LCD_Put(uint8_t Data);
    
    #endif
    
  • LCD1602.c:
  • #incldue “LCD1602.h”
    
    static void LCD_Cmd(uint8_t cmd);
    static void LCD_Data(uint8_t data);
    static void LCD_CursorSet(uint8_t col, uint8_t row);
    static void LCD_EnBlink(void);
    
    
    static LCD_Options_t LCD_Opts;
    
    //us级Delay
    void  LCD_Delay_us(uint16_t  us)
    {
        uint32_t  Div = (SysTick->LOAD+1)/1000;
        uint32_t  StartMicros = HAL_GetTick()*1000 + (1000- SysTick->VAL/Div);
        while((HAL_GetTick()*1000 + (1000-SysTick->VAL/Div)-StartMicros < us));
    }
    //ms级Delay
    void  LCD_Delay_ms(uint8_t  ms)
    {
        HAL_Delay(ms);
    }
    //LCD初始化
    void LCD_Init(void)
    {
      /* Set cursor pointer to beginning for LCD */
        LCD_Opts.currentX = 0;
        LCD_Opts.currentY = 0;
        LCD_Opts.DisplayFunction = LCD_8BITMODE | LCD_5x8DOTS | LCD_1LINE;
        if (_LCD_ROWS > 1)
        LCD_Opts.DisplayFunction |= LCD_2LINE;
      /* Set # lines, font size,8BITMODE,etc. */
        LCD_Cmd(LCD_FUNCTIONSET | LCD_Opts.DisplayFunction);
      /* Turn the display on with no cursor or blinking default */
        LCD_Opts.DisplayControl = LCD_DISPLAYON;
        LCD_DisplayOn();
        /* Default font directions 文字不动,地址自动+1*/
        LCD_Opts.DisplayMode = LCD_ENTRYLEFT | LCD_ENTRYSHIFTDECREMENT;
        LCD_Cmd(LCD_ENTRYMODESET | LCD_Opts.DisplayMode);
        LCD_Clear();
        LCD_Delay_ms(5);
    }
    //清屏
    void LCD_Clear(void)
    {
        LCD_Cmd(LCD_CLEARDISPLAY);
        LCD_Delay_ms(5);
    }
    //显示一个string,支持换行
    void LCD_Puts(uint8_t x, uint8_t y, char* str)
    {
        LCD_CursorSet(x, y);
        while (*str) {
            if (LCD_Opts.currentX >= _LCD_COLS)/*移动到下一行*/ {
                LCD_Opts.currentX = 0;
                LCD_Opts.currentY++;
                LCD_CursorSet(LCD_Opts.currentX, LCD_Opts.currentY);
            }
            if (*str == '\n') /*换行,列对其*/{
                LCD_Opts.currentY++;
                LCD_CursorSet(LCD_Opts.currentX, LCD_Opts.currentY);
            } else if (*str == '\r') /*回车,换行回行首*/{
                LCD_CursorSet(0, LCD_Opts.currentY);
            } else {
                LCD_Data(*str);
                LCD_Opts.currentX++;
            }
            str++;
        }
    }
    
    void LCD_DisplayOn(void)
    {
        LCD_Opts.DisplayControl |= LCD_DISPLAYON;
        LCD_Cmd(LCD_DISPLAYCONTROL | LCD_Opts.DisplayControl);
    }
    
    void LCD_DisplayOff(void)
    {
        LCD_Opts.DisplayControl &= ~LCD_DISPLAYON;
        LCD_Cmd(LCD_DISPLAYCONTROL | LCD_Opts.DisplayControl);
    }
    
    void LCD_BlinkOn(void)
    {
        LCD_Opts.DisplayControl |= LCD_BLINKON;
        LCD_Cmd(LCD_DISPLAYCONTROL | LCD_Opts.DisplayControl);
    }
    
    void LCD_BlinkOff(void)
    {
        LCD_Opts.DisplayControl &= ~LCD_BLINKON;
        LCD_Cmd(LCD_DISPLAYCONTROL | LCD_Opts.DisplayControl);
    }
    
    void LCD_CursorOn(void)
    {
        LCD_Opts.DisplayControl |= LCD_CURSORON;
        LCD_Cmd(LCD_DISPLAYCONTROL | LCD_Opts.DisplayControl);
    }
    
    void LCD_CursorOff(void)
    {
        LCD_Opts.DisplayControl &= ~LCD_CURSORON;
        LCD_Cmd(LCD_DISPLAYCONTROL | LCD_Opts.DisplayControl);
    }
    
    void LCD_ScrollLeft(void)
    {
        LCD_Cmd(LCD_CURSORSHIFT | LCD_DISPLAYMOVE | LCD_MOVELEFT);
    }
    
    void LCD_ScrollRight(void)
    {
        LCD_Cmd(LCD_CURSORSHIFT | LCD_DISPLAYMOVE | LCD_MOVERIGHT);
    }
    
    void LCD_CreateChar(uint8_t location, uint8_t *data)
    {
        uint8_t i;
      /* We have 8 locations available for custom characters */
        location &= 0x07;
        LCD_Cmd(LCD_SETCGRAMADDR | (location << 3));
    
        for (i = 0; i < 8; i++) {
            LCD_Data(data[i]);
        }
    }
    
    void LCD_PutCustom(uint8_t x, uint8_t y, uint8_t location)
    {
        LCD_CursorSet(x, y);
        LCD_Data(location);
    }
    
    static void LCD_EnBlink(void)
    {
        LCD1602_E_HIGH;
        LCD_Delay_us(50);
        LCD1602_E_LOW;
        LCD_Delay_us(50);
    }
    
    static void LCD_Cmd(uint8_t cmd)
    {
        LCD1602_RS_CMD;
        LCD1602_RW_WRITE;
        LCD1602_DATA(cmd);
        LCD_EnBlink();
    }
    
    static void LCD_Data(uint8_t data)
    {
        LCD1602_RS_DATA;
        LCD1602_RW_WRITE;
        LCD1602_DATA(data);
        LCD_EnBlink();
    }
    
    static void LCD_CursorSet(uint8_t col, uint8_t row)
    {
        uint8_t row_offsets[] = {0x00, 0x40, 0x14, 0x54};
        if (row >= _LCD_ROWS)
            row = 0;
        LCD_Opts.currentX = col;
        LCD_Opts.currentY = row;
        LCD_Cmd(LCD_SETDDRAMADDR | (col + row_offsets[row]));
    }
    
    void LCD_Put(uint8_t Data)
    {
        LCD_Data(Data);
    }
    

    四、结果

    物联沃分享整理
    物联沃-IOTWORD物联网 » Proteus: 使用STM32CubeMX的LCD1602仿真实验

    发表评论