stm32cubeide驱动LCD1602显示屏

2023-11-14

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’是不能换行的。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

stm32cubeide驱动LCD1602显示屏 的相关文章

  • 一分钟带你快速认识S参数

    S 参数是SI与RF领域工程师必备的基础知识 大家很容易从网络或书本上找到S Y Z参数的说明 但即使如此 在相关领域打滚多年的人 仍然可能还是会被一些问题困扰着 你懂S参数吗 不懂的话 那么请继续往下看 S参数简介 S参数 也就是散射参数

随机推荐

  • GitLab的使用 和 Git 、 Github、Gitlab的区别

    一 git github gitlab的区别 百度相关内容得到的理解 二 git最基本作用 版本控制 三 有集成了git的GIT安装包 github和gitlab都使用git该版本控制系统 来实现对代码的管理 所以 原先怎么用git操作gi
  • obs窗口捕获不到ppt白屏_如何用obs进行电脑直播,学会这篇,直播不再难

    很多人想在头条或者西瓜视频直播 除了用手机直播外 还可以用电脑进行直播 只要用obs进行简单设置即可达到要求 可以直播ppt 直播ps等 1 下载并安装好obs软件 点击文件 设置 在设置的窗口中 找到输出 一般输出的设置默认就好 无需更改
  • 微信浮窗是不是服务器保存,微信浮窗,真能解决小程序留存难题吗?

    小程序浮窗 到底有多大能量 作者丨Suvi 上个月 微信更新了7 0 5版本 对浮窗功能做了全新升级 支持最多同时添加5个项目 不含QQ音乐 并首次支持添加小程序 新版浮窗一上线 便被寄予厚望 各方将之解读为挽救公众号阅读量 提高小程序留存
  • 【8】测试用例设计-边界值法

    对于软件来说 错误经常发生在输入或输出值的关键点 边界值分析法是对软件的输入或输出边界进行测试的一种方法 它的所有测试用例都是在等价类的边界处设计 边界值分析需要选择一个或多个元素 以便等价类的每个边界都经过一次测试 与仅仅关注输入条件 输
  • QT+CUDA混合编程BUG(一)

    QT CUDA混合编程BUG 一 在QT中进行CUDA编程 CUDA库与其他外部库冲突 debug失败 问题描述 在QT中进行CUDA编程 单独使用CUDA编程时并未出现难以解决的问题 但当我讲CUDA处理的部分 加入已搭建完毕一项较大的Q
  • LeetCode第 292 题:Nim游戏(C++)

    292 Nim 游戏 力扣 LeetCode 剩下4块的时候 如果轮到你 那么你必输 先简单推一下 如果第n块的时候轮到你 n 5 必胜 拿1块 n 6 必胜 拿2块 n 7 必胜 拿3块 n 8 必败 无论我拿几块 对方都可以将我逼到4的
  • 基于Lasagne实现限制玻尔兹曼机(RBM)

    RBM理论部分大家看懂这个图片就差不多了 Lasagne写代码首先要确定层与层 RBM 正向反向过程可以分别当作一个层 权值矩阵互为转置即可 代码 coding utf 8 data format is bc01 written by Ph
  • 【Shell编程】Shell中Bash变量-用户自定义变量

    目录 系列文章 Bash变量 用户自定义变量 变量的命名规则 变量分类 本地变量 实例 系列文章 Shell编程 Shell基本概述与脚本执行方式 Shell编程 Shell中Bash基本功能 Bash变量 用户自定义变量 变量的命名规则
  • 前端跨域解决方案

    目录 同源政策 跨域 常见的跨域场景 跨域解决方案 1 JSONP跨域 1 原生JS实现 2 jquery Ajax实现 3 Vue axios实现 后端node js代码 2 跨域资源共享 CORS 1 简单请求 2 非简单请求 3 CO
  • 满载大模型技能干货的AI Day活动全新来袭

    AI大模型时代 创造力才是第一生产力 满载大模型技能干货的AI Day主题活动全新来袭 丰富有趣的Workshop即将空降你的学校 帮助大家掌握前沿技能 拓展技术视野 迈进AIGC的大门 打造属于你的AI应用 满足不同阶段的学习实践需求 无
  • AD10软件打不开,停留在开机界面上

    解决办法 把AD10的缓存文件都删掉 C Users Administrator AppData Roaming Altium下的文件都删掉
  • 二分图最大完美匹配

    嗯 想不通 就是二分之后的点 寻找左边的点和右边的点的保证两条边的顶点不相同的最大边数 匈牙利算法 O mn 左边寻找和右边相邻的边 如果右边还没有和左边进行连线 那么匹配成功 如果右边已经进行连线 那么考虑左边是否能更改连线 换一个右边
  • Qt总结——菜单隐藏

    我们在使用QMenu的时候经常会在其中添加子菜单以及action QMenu中的隐藏禁用的操作是针对action的 所以直接操作action是没有问题的可以想要的效果 但是menu不行 因为不是action类型的 QAction actio
  • 元组:(tuple)

    1 元组 tuple tuple 相比较列表list 元组和列表都是一种有序集合 0 2 3 5 9 第一个元素即是第一个存入的元素 按照存放顺序存储 元组的访问 格式 元组名 下标 tuple4 1 2 3 4 5 print tuple
  • python从视频信息中提取音频,只用了三行代码...

    在做多媒体素材的时候 往往需要从视频中提取音频信息 在python中提供了moviepy这个非标准库 可以很快的帮助我们完成这个操作 算上导入moviepy非标准库的操作只需要三行代码完成 喜欢记得收藏 关注 点赞 1 单文件处理 将mov
  • Java 性能优化的 50 个细节

    前言 在JAVA程序中 性能问题的大部分原因并不在于JAVA语言 而是程序本身 养成良好的编码习惯非常重要 能够显著地提升程序性能 1 尽量在合适的场合使用单例 使用单例可以减轻加载的负担 缩短加载的时间 提高加载的效率 但并不是所有地方都
  • MySQL 表的 添加、更新与删除数据

    添加数据 为表中的所有 部分字段 添加数据 可以添加部分 也可以全部添加 INSERT INTO 表名称 字段名 VALUES 数据类型对应的 值 指定的字段 或 全部字段添加的数据 INSERT INTO 表名称 SET 字段名 值 同时
  • 用python实现时间序列自相关图(acf)、偏自相关图(pacf)

    自相关图是一个平面二维坐标悬垂线图 横坐标表示延迟阶数 纵坐标表示自相关系数 偏自相关图跟自相关图类似 横坐标表示延迟阶数 纵坐标表示偏自相关系数 自相关图与偏自相关图的python代码实现 from statsmodels graphic
  • 一个对象赋予另一个对象

    它的两个对象 n1 和n2 是在 main 里创建的 每个对象中的i 值都赋予了一个不 同的值 随后 将 n2 赋给n1 而且 n1 发生改变 当给n1 i赋值时 n2 i也会随着改变 这是由于无论n1 还是n2 都包含了相同的句柄 它指向
  • stm32cubeide驱动LCD1602显示屏

    STM32驱动LCD1602 硬件连接关系 STM32CUBEIDE设置 代码 项目设置 最后运行 硬件连接关系 LCD1602 STM32 VCC VCC GND GND VO VCC 滑动变阻 RS PB1 RW PB2 BOOT1 E