STM32 CubeIDE 4线驱动LCD1602

1、LCD1602简介

  LCD1602是指显示的内容为16X2,即可以显示两行,每行16个字符液晶模块(显示字符和数字),能显示的字符数是32,LCD1602内置了字库。带ASCII码字库,不能显示中文。

1.1、引脚介绍

LCD1602有16条引脚,还有14条引脚的,与16脚的相比缺少了背光电源A(15脚)和地线K(16脚)。

在这里插入图片描述

1.2 、LCD1602 基本时序操作

RS:RS为寄存器选择,高电平1选择数据寄存器,低电平0时选择指令寄存器。
R/W:R/W为读写信号线,高电平1时进行读操作,低电平0时进行写操作
EN:EN端为使能端,写操作时,下降沿使能。读操作时,E高电平有效

读状态。输入RS=0,RW=1,E=高脉冲。输出:D0—D7为状态字。

读数据。输入RS=1,RW=1,E=高脉冲。输出:D0—D7为数据。

写命令。输入RS=0,RW=0,E=高脉冲。输出:无。

写数据。输入RS=1,RW=0,E=高脉冲。输出:无。

2、LCD1602 显示

  使用高4位数据线的接法,即4线并行模式(不同于8线并行模式操作),D0~D3这4个口悬空,据传输只需要通过D4-D7。翻译移植项目,来源https://controllerstech.com/interface-lcd-16x2-with-stm32-without-i2c/

LCD1602与STM32引脚连接:

LCD1602 MCU
D4 PA4
D5 PA5
D6 PA6
D7 PA7
RS PA1
RW PA2
EN PA3

2.1 、建立工程文件

打开调试引脚
在这里插入图片描述
开启外部时钟:
在这里插入图片描述
配置时钟树:
在这里插入图片描述
开启定时器1,定时间仅仅就为了定时,可以任意选择:
在这里插入图片描述
选择管脚:
在这里插入图片描述

2.2、程序移植

创建文件 LCD1602.c 和LCD1602.h 头文件。
在这里插入图片描述
LCD1602.h 头文件内容

#ifndef INC_LCD1602_H_
#define INC_LCD1602_H_


void lcd_init (void);   // initialize lcd

void lcd_send_cmd (char cmd);  // send command to the lcd

void lcd_send_data (char data);  // send data to the lcd

void lcd_send_string (char *str);  // send string to the lcd

void lcd_put_cur(int row, int col);  // put cursor at the entered position row (0 or 1), col (0-15);

void lcd_clear (void);

LCD1602.c 文件内容:

#include <LCD1602.h>

#include "stm32f1xx_hal.h"

/*********** Define the LCD PINS below ****************/

#define RS_Pin GPIO_PIN_1
#define RS_GPIO_Port GPIOA
#define RW_Pin GPIO_PIN_2
#define RW_GPIO_Port GPIOA
#define EN_Pin GPIO_PIN_3
#define EN_GPIO_Port GPIOA
#define D4_Pin GPIO_PIN_4
#define D4_GPIO_Port GPIOA
#define D5_Pin GPIO_PIN_5
#define D5_GPIO_Port GPIOA
#define D6_Pin GPIO_PIN_6
#define D6_GPIO_Port GPIOA
#define D7_Pin GPIO_PIN_7
#define D7_GPIO_Port GPIOA

/****************** define the timer handler below  **************/
#define timer htim1


extern TIM_HandleTypeDef timer;
void delay (uint16_t us)
{
    
    
	__HAL_TIM_SET_COUNTER(&timer, 0);
	while (__HAL_TIM_GET_COUNTER(&timer) < us);
}

/****************************************************************************************************************************************************************/

void send_to_lcd (char data, int rs)
{
    
    
	HAL_GPIO_WritePin(RS_GPIO_Port, RS_Pin, rs);  // rs = 1 for data, rs=0 for command

	/* write the data to the respective pin */
	HAL_GPIO_WritePin(D7_GPIO_Port, D7_Pin, ((data>>3)&0x01));
	HAL_GPIO_WritePin(D6_GPIO_Port, D6_Pin, ((data>>2)&0x01));
	HAL_GPIO_WritePin(D5_GPIO_Port, D5_Pin, ((data>>1)&0x01));
	HAL_GPIO_WritePin(D4_GPIO_Port, D4_Pin, ((data>>0)&0x01));

	/* Toggle EN PIN to send the data
	 * if the HCLK > 100 MHz, use the  20 us delay
	 * if the LCD still doesn't work, increase the delay to 50, 80 or 100..
	 */
	HAL_GPIO_WritePin(EN_GPIO_Port, EN_Pin, 1);
	delay (20);
	HAL_GPIO_WritePin(EN_GPIO_Port, EN_Pin, 0);
	delay (20);
}

void lcd_send_cmd (char cmd)
{
    
    
    char datatosend;

    /* send upper nibble first */
    datatosend = ((cmd>>4)&0x0f);
    send_to_lcd(datatosend,0);  // RS must be 0 while sending command

    /* send Lower Nibble */
    datatosend = ((cmd)&0x0f);
	send_to_lcd(datatosend, 0);
}

void lcd_send_data (char data)
{
    
    
	char datatosend;

	/* send higher nibble */
	datatosend = ((data>>4)&0x0f);
	send_to_lcd(datatosend, 1);  // rs =1 for sending data

	/* send Lower nibble */
	datatosend = ((data)&0x0f);
	send_to_lcd(datatosend, 1);
}

void lcd_clear (void)
{
    
    
	lcd_send_cmd(0x01);
	HAL_Delay(2);
}

void lcd_put_cur(int row, int col)
{
    
    
    switch (row)
    {
    
    
        case 0:
            col |= 0x80;
            break;
        case 1:
            col |= 0xC0;
            break;
    }

    lcd_send_cmd (col);
}


void lcd_init (void)
{
    
    
	// 4 bit initialisation
	HAL_Delay(50);  // wait for >40ms
	lcd_send_cmd (0x30);
	HAL_Delay(5);  // wait for >4.1ms
	lcd_send_cmd (0x30);
	HAL_Delay(1);  // wait for >100us
	lcd_send_cmd (0x30);
	HAL_Delay(10);
	lcd_send_cmd (0x20);  // 4bit mode
	HAL_Delay(10);

  // dislay initialisation
	lcd_send_cmd (0x28); // Function set --> DL=0 (4 bit mode), N = 1 (2 line display) F = 0 (5x8 characters)
	HAL_Delay(1);
	lcd_send_cmd (0x08); //Display on/off control --> D=0,C=0, B=0  ---> display off
	HAL_Delay(1);
	lcd_send_cmd (0x01);  // clear display
	HAL_Delay(1);
	HAL_Delay(1);
	lcd_send_cmd (0x06); //Entry mode set --> I/D = 1 (increment cursor) & S = 0 (no shift)
	HAL_Delay(1);
	lcd_send_cmd (0x0C); //Display on/off control --> D = 1, C and B = 0. (Cursor and blink, last two bits)
}

void lcd_send_string (char *str)
{
    
    
	while (*str) lcd_send_data (*str++);
}

在main.c 文件里面添加修改:
在这里插入图片描述

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "LCD1602.h"

/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
int row=0;
int col=0;
/* USER CODE END PTD */

开启定时器LCD初始化:
在这里插入图片描述

 /* USER CODE BEGIN 2 */
  HAL_TIM_Base_Start(&htim1);//开启定时器

      lcd_init ();
      lcd_put_cur(0, 0);
      lcd_send_string("HELLO ");
      lcd_send_string("WORLD ");
      lcd_send_string("FROM");

      lcd_put_cur(1, 0);
      lcd_send_string("CONTROLLERS TECH");
      HAL_Delay(3000);
      lcd_clear();
  /* USER CODE END 2 */

循环输出字符:
在这里插入图片描述

 /* Infinite loop */
  /* USER CODE BEGIN WHILE */
    //循环输出字符
  while (1)
  {
    
    
	  for (int i=0;i<128;i++)
	 	  {
    
    
	 		  lcd_put_cur(row, col);

	 		  lcd_send_data(i+48);

	 		  col++;

	 		  if (col > 15) {
    
    row++; col = 0;}
	 		  if (row > 1) row=0;

	 		  HAL_Delay(250);
	 	  }
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */

在这里插入图片描述

2.3、可能出现的错误

  在使用的过程中要注意一点,看自己手里的LCD1602是仅仅5V驱动还是支持3.3V驱动。背光,根据自己的需求选择合适的电压,背光可以接电位器调节,或者使用STM32 DAC产生电压进行控制。

猜你喜欢

转载自blog.csdn.net/weixin_45488643/article/details/108222308