stm32cubeide驱动LCD1602显示屏

STM32驱动LCD1602

  • 硬件连接关系
  • STM32CUBEIDE设置
  • 代码
  • 项目设置
  • 最后运行

硬件连接关系

LCD1602 STM32
VCC VCC
GND GND
VO VCC-滑动变阻
RS PB1
RW PB2(BOOT1)
E PB0
D0 ~ D7 PB8 ~ PB15
A PA8
K PA11

这是普中科技的C51开发板,送了一个stm32f103c6的小核心板,C51开发板上有个LCD1602的接口就直接使用了。

STM32CUBEIDE设置

  • System Core -> RCC -> HSE -> Crystal/Ceramic Resonator
  • System Core -> RCC -> LSE -> Crystal/Ceramic Resonator
  • System Core -> SYS -> Debug -> Serial Wire
  • Connectivity -> USART1 -> Mode -> Asynchronous(Baud Rate: 115200Bits/S, Word Length: 8Bits)
  • PA8:GPIO_Output, GPIO output level: High, GPIO Mode: Output Push Pull
  • PA11:GPIO_Output, GPIO output level: Low, GPIO Mode: Output Push Pull
  • PB0:GPIO_Output, GPIO output level: Low, GPIO Mode: Output Push Pull, User Label: LCD_EN
  • PB1:GPIO_Output, GPIO output level: Low, GPIO Mode: Output Push Pull, User Label: LCD_RS
  • PB2:GPIO_Output, GPIO output level: Low, GPIO Mode: Output Push Pull, User Label: LCD_RW
  • PB8:GPIO_Output, GPIO output level: Low, GPIO Mode: Output Open Drain
  • PB9:GPIO_Output, GPIO output level: Low, GPIO Mode: Output Open Drain
  • PB10:GPIO_Output, GPIO output level: Low, GPIO Mode: Output Open Drain
  • PB11:GPIO_Output, GPIO output level: Low, GPIO Mode: Output Open Drain
  • PB12:GPIO_Output, GPIO output level: Low, GPIO Mode: Output Open Drain
  • PB13:GPIO_Output, GPIO output level: Low, GPIO Mode: Output Open Drain
  • PB14:GPIO_Output, GPIO output level: Low, GPIO Mode: Output Open Drain
  • PB15:GPIO_Output, GPIO output level: Low, GPIO Mode: Output Open Drain
  • 设置时钟并保存

前面4行是设置晶振、JWD口、和UART调试信息。PA8,PA11是背光的控制口,设置推挽输出。PB0,PB1,PB2分别是LCD使能、LCD RS、LCD RW口,设置推挽输出。P8 ~ P15是数据输出和输入,因为输出同时要检测LCD是否忙,所以要读状态,需要设置为开漏输出。这里用的是8线输出方式。

代码

  1. Core->Inc文件夹下建立新的头文件"lcd1602.h"
#ifndef INC_LCD1602_H_
#define INC_LCD1602_H_

#include "main.h"

// 片选、读/写、数据/命令
#define LCD_CMD  	HAL_GPIO_WritePin(LCD_RS_GPIO_Port, LCD_RS_Pin, GPIO_PIN_RESET)
#define LCD_DATA  HAL_GPIO_WritePin(LCD_RS_GPIO_Port, LCD_RS_Pin, GPIO_PIN_SET)
#define LCD_EN_HIGH		HAL_GPIO_WritePin(LCD_EN_GPIO_Port, LCD_EN_Pin, GPIO_PIN_SET)
#define LCD_EN_LOWER 	HAL_GPIO_WritePin(LCD_EN_GPIO_Port, LCD_EN_Pin, GPIO_PIN_RESET)
#define LCD_WRITE	HAL_GPIO_WritePin(LCD_RW_GPIO_Port, LCD_RW_Pin, GPIO_PIN_RESET)
#define LCD_READ		HAL_GPIO_WritePin(LCD_RW_GPIO_Port, LCD_RW_Pin, GPIO_PIN_SET)

void lcd_init(void);
void lcd_wait_ready(void);
void lcd_write_cmd(unsigned char cmd);
void lcd_write_data(unsigned char data);
void lcd_set_cursor(unsigned char x, unsigned char y);
void lcd_area_clear(unsigned char x, unsigned char y, unsigned char len);
void lcd_full_clear(void);
void lcd_show_string(unsigned char x, unsigned char y, unsigned char *data);
void write_data(unsigned char data);

#endif /* INC_LCD1602_H_ */
  1. Core/Src下面建立"lcd1602.c"
#include "main.h"
#include "stdio.h"
#include "lcd1602.h"


void lcd_init(void){
	lcd_write_cmd(0x38);			// 16 * 2 显示 , 5 * 7 点阵, 8位接口
	lcd_wait_ready();
	lcd_write_cmd(0X0c);			// 显示器开,光标关闭
	lcd_wait_ready();
	lcd_write_cmd(0x06);			// 文字不动,地址自动加
	lcd_wait_ready();
	lcd_write_cmd(0x01);			// 清屏
	lcd_wait_ready();
	printf("Init OK \r\n");
}

void lcd_wait_ready(void){
	unsigned char status;

	write_data(0xff);
	LCD_CMD;						// CMD
	LCD_READ;						// Read

	do{
		LCD_EN_HIGH;					// 下降沿
		status = HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_15);
		LCD_EN_LOWER;
	}while(status == 1);
}

void lcd_write_cmd(unsigned char cmd){
	lcd_wait_ready();
	LCD_CMD;
	LCD_WRITE;
	write_data(cmd);
	LCD_EN_HIGH;
	LCD_EN_LOWER;
	lcd_wait_ready();
}

void lcd_write_data(unsigned char data){
	lcd_wait_ready();
	LCD_DATA;
	LCD_WRITE;
	write_data(data);
	LCD_EN_HIGH;
	LCD_EN_LOWER;
	lcd_wait_ready();
}

void lcd_set_cursor(unsigned char x, unsigned char y){
	unsigned char addr = 0;
	// Row : y , Col : x
	lcd_wait_ready();

	// 从输入的屏幕计算显示RAM
	if(y == 0){
		addr = 0x00 + x;
	}
	else{
		addr = 0x40 + x;
	}
	lcd_write_cmd(addr | 0x80);
}

void lcd_area_clear(unsigned char x, unsigned char y, unsigned char len){
	lcd_set_cursor(x, y);
	while(len--){
		lcd_wait_ready();
		lcd_write_data(' ');
	}
}

void lcd_full_clear(void){
	lcd_write_cmd(0x01);
}

void lcd_show_string(unsigned char x, unsigned char y, unsigned char *data){
	lcd_set_cursor(x, y);
	while(*data != '\0'){
		lcd_wait_ready();
		lcd_write_data(*data++);
	}
}

void write_data(unsigned char data){
//  这里直接控制的ODR寄存器,更方便。第一行清除原来的PB高8位,第二行写新数据
	GPIOB->ODR &= 0x00FF;
	GPIOB->ODR |= (data << 8);
}
  1. main.c中加入代码
#include "stdio.h"
#include "lcd1602.h"


// 只是为了printf显示到串口信息中
#ifdef __GNUC__
        #define PUTCHAR_PROTOTYPE  int __io_putchar(int ch)
#else
        #define PUTCHAR_PROTOTYPE  int fputc(int ch, FILE *stream)
#endif
PUTCHAR_PROTOTYPE
{
        HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 0xffff);
        return ch;
}
//

// 以下代码加入main函数中
  unsigned char *str = (unsigned char *)"Hello everyone";
  unsigned char *welcome = (unsigned char *)"Welcome to my world";
  // 开背光
  HAL_GPIO_WritePin(GPIOA, GPIO_PIN_8, GPIO_PIN_SET);
  HAL_GPIO_WritePin(GPIOA, GPIO_PIN_11, GPIO_PIN_RESET);
  lcd_init();
  HAL_Delay(10);
  //尝试读LCD状态。status1要显示非0才是闲状态。如果一直读到1,可能是BOOT1接地了
  write_data(0xff);
  LCD_CMD;
  LCD_READ;
  LCD_EN_HIGH;
  printf("Get status1: %d \r\n", HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_15));
  printf("Get status2: 0x%04X \r\n", (uint16_t)GPIOB->ODR);
  printf("Get status2: 0x%04X \r\n", (uint16_t)GPIOB->IDR);
  LCD_EN_LOWER;
  lcd_show_string(0, 0, str);
  lcd_show_string(0, 1, welcome);
  HAL_Delay(5);
  while (1)
  {
	  HAL_Delay(1000);
	  lcd_write_cmd(0x18);             //屏幕右移
   //

项目设置

Project -> Properties -> C/C++ Build -> Setting -> MCU Setting -> Runtime Libray :Standard C。这个是用于printf显示用的。后面的两个也可以选上,用于显示小数
Project -> Properties -> C/C++ Build -> Setting -> MCU Post Build outputs -> Convert to intel Hex file 选中可以编译生成.HEX文件

最后的运行

  • 因为我使用的是普中的板子,普中给的资料里面有一个UART烧写工具"普中ISP",这个工具烧写还是比较好用的,但烧写要BOOT0,BOOT1都接GND。而且只能烧写.HEX文件,所以我才会生成HEX文件
  • 烧写完成后一定要记得拔下BOOT1的短接帽,因为工程中使用到PB2接口,默认这个PB2和BOOT1是同一个接口,我程序写好后怎么都不能读取到LCD状态lcd_wait_ready()死循环。花了一天时间才找到原因。
  • CSDN上很多程序都没有lcd_wait_ready(),直接使用自己写的延迟代替。自己写来玩是可以用,但毕竟不是完美方法,要想lcd_wait_ready()正常必须要记得BOOT1不能接地,PB8 ~ PB15要设置为开漏输出。
  • 如果有问题可以使用Printf()显示变量信息,也可以使用Jlink调试。printf()要想能换行只用在字符串结束时加上’\r\n’就可以了。只加’\n’是不能换行的。

你可能感兴趣的:(stm32,HAL库,LCD1602)