esp开发与应用(1602液晶显示屏)
【 声明:版权所有,欢迎转载,请勿用于商业用途。 联系信箱:feixiaoxing @163.com】
模块当中,有的是比较简单的,比如说蜂鸣器,尤其是有源蜂鸣器。大家可以把它想象成是一个gpio输出的喇叭,通电就有声音,没通电就没有声音。整个模块也就三个pin,一个是电源,一个是地,还有一个就是gpio控制开关。所以蜂鸣器不复杂。但相比较而言,还有一些模块,会稍微复杂一点,比如说1602液晶屏幕。过去的1602屏幕占用的pin比较多,但是后来出了一个PCF8574芯片,这就方便多了。相当于这是一个i2c接口的芯片,我们只要对PCF8574进行控制,就可以让PCF8574控制屏幕,最终让1602屏幕显示文字和符号了。
1、找到esp32的i2c口
在esp32上面,默认第一个i2c口就是gpio22和gpio21,前者是scl,后者是sda。
2、找到电源部分
这里需要注意的部分,就是输入电压。一般esp32上面有两个电压,一个是5v,一个是3.3v。5v就是直接usb传进来的电压,3.3v也是5v转的电压。但对于1602模块呢,它需要5v的电压,所以这部分还是要找到5v的电压入口。
3、连接好esp32模块和1602模块
连接的时候采用的是母对母的杜邦线,这部分不复杂,但是要细心一点。
4、编写代码
编写代码这部分,如之前所说,还是用ai来写比较好。我们需要告诉ai的是,当前使用的i2c是第一个,gpio用的是22和21,1602的驱动芯片就是PCF8574,然后希望它编写一个简单的输出小程序。这样不出意外的话,ai就可以帮助我们生成代码。有条件的,可以vs code上直接购买ai插件生成代码。如果不行,用deepseek生成后,拷贝粘贴过来,也是可以的。
#include <stdio.h> #include <string.h> #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "driver/i2c.h" // I2C configuration #define I2C_MASTER_SCL_IO 22 // SCL pin #define I2C_MASTER_SDA_IO 21 // SDA pin #define I2C_MASTER_NUM I2C_NUM_0 // I2C port number #define I2C_MASTER_FREQ_HZ 100000 // I2C frequency // PCF8574 I2C address (common: 0x27 or 0x3F) #define PCF8574_ADDR 0x27 // PCF8574 pin definitions (connected to 1602 LCD) #define LCD_RS 0x01 // P0 #define LCD_RW 0x02 // P1 #define LCD_EN 0x04 // P2 #define LCD_BACKLIGHT 0x08 // P3 #define LCD_D4 0x10 // P4 #define LCD_D5 0x20 // P5 #define LCD_D6 0x40 // P6 #define LCD_D7 0x80 // P7 // LCD commands #define LCD_CLEAR 0x01 #define LCD_HOME 0x02 #define LCD_ENTRY_MODE 0x04 #define LCD_DISPLAY_CTRL 0x08 #define LCD_CURSOR_SHIFT 0x10 #define LCD_FUNCTION_SET 0x20 #define LCD_CGRAM_ADDR 0x40 #define LCD_DDRAM_ADDR 0x80 // I2C write byte to PCF8574 static esp_err_t i2c_write_byte(uint8_t data) { i2c_cmd_handle_t cmd = i2c_cmd_link_create(); i2c_master_start(cmd); i2c_master_write_byte(cmd, (PCF8574_ADDR << 1) | I2C_MASTER_WRITE, true); i2c_master_write_byte(cmd, data, true); i2c_master_stop(cmd); esp_err_t ret = i2c_master_cmd_begin(I2C_MASTER_NUM, cmd, 1000 / portTICK_PERIOD_MS); i2c_cmd_link_delete(cmd); return ret; } // Send LCD command void lcd_send_cmd(uint8_t cmd) { uint8_t high_nibble = (cmd & 0xF0) | LCD_BACKLIGHT; // High nibble + backlight uint8_t low_nibble = ((cmd << 4) & 0xF0) | LCD_BACKLIGHT; // Low nibble + backlight // Send high nibble i2c_write_byte(high_nibble); i2c_write_byte(high_nibble | LCD_EN); // EN=1 vTaskDelay(1 / portTICK_PERIOD_MS); i2c_write_byte(high_nibble & ~LCD_EN); // EN=0 // Send low nibble i2c_write_byte(low_nibble); i2c_write_byte(low_nibble | LCD_EN); // EN=1 vTaskDelay(1 / portTICK_PERIOD_MS); i2c_write_byte(low_nibble & ~LCD_EN); // EN=0 } // Send LCD data void lcd_send_data(uint8_t data) { uint8_t high_nibble = (data & 0xF0) | LCD_RS | LCD_BACKLIGHT; // RS=1 uint8_t low_nibble = ((data << 4) & 0xF0) | LCD_RS | LCD_BACKLIGHT; // Send high nibble i2c_write_byte(high_nibble); i2c_write_byte(high_nibble | LCD_EN); vTaskDelay(1 / portTICK_PERIOD_MS); i2c_write_byte(high_nibble & ~LCD_EN); // Send low nibble i2c_write_byte(low_nibble); i2c_write_byte(low_nibble | LCD_EN); vTaskDelay(1 / portTICK_PERIOD_MS); i2c_write_byte(low_nibble & ~LCD_EN); } // Initialize LCD void lcd_init(void) { vTaskDelay(50 / portTICK_PERIOD_MS); // 4-bit mode initialization sequence lcd_send_cmd(0x33); vTaskDelay(5 / portTICK_PERIOD_MS); lcd_send_cmd(0x32); vTaskDelay(5 / portTICK_PERIOD_MS); // Function set: 4-bit, 2-line, 5x8 lcd_send_cmd(LCD_FUNCTION_SET | 0x08 | 0x00); vTaskDelay(5 / portTICK_PERIOD_MS); // Display control: display on, cursor off lcd_send_cmd(LCD_DISPLAY_CTRL | 0x04); vTaskDelay(5 / portTICK_PERIOD_MS); // Clear display lcd_send_cmd(LCD_CLEAR); vTaskDelay(20 / portTICK_PERIOD_MS); // Entry mode: cursor move right lcd_send_cmd(LCD_ENTRY_MODE | 0x02); vTaskDelay(5 / portTICK_PERIOD_MS); } // Set cursor position void lcd_set_cursor(uint8_t row, uint8_t col) { uint8_t addr = (row == 0) ? 0x00 : 0x40; lcd_send_cmd(LCD_DDRAM_ADDR | (addr + col)); } // Print string to LCD void lcd_print(const char *str) { while (*str) { lcd_send_data(*str++); } } // Initialize I2C void i2c_init(void) { i2c_config_t conf = { .mode = I2C_MODE_MASTER, .sda_io_num = I2C_MASTER_SDA_IO, .scl_io_num = I2C_MASTER_SCL_IO, .sda_pullup_en = GPIO_PULLUP_ENABLE, .scl_pullup_en = GPIO_PULLUP_ENABLE, .master.clk_speed = I2C_MASTER_FREQ_HZ, }; i2c_param_config(I2C_MASTER_NUM, &conf); i2c_driver_install(I2C_MASTER_NUM, conf.mode, 0, 0, 0); } void app_main(void) { printf("1602 LCD I2C Driver (PCF8574)\n"); printf("SCL: GPIO%d, SDA: GPIO%d\n", I2C_MASTER_SCL_IO, I2C_MASTER_SDA_IO); printf("PCF8574 Address: 0x%02X\n", PCF8574_ADDR); // Initialize I2C i2c_init(); // Initialize LCD lcd_init(); // Display Hello, World! lcd_set_cursor(0, 0); lcd_print("Hello,"); lcd_set_cursor(1, 0); lcd_print("Fei ning ning!"); printf("LCD display complete!\n"); while (1) { vTaskDelay(1000 / portTICK_PERIOD_MS); } }5、编译查看代码
代码输出后,首先编译一下。不能编译的代码价值不大。其次就是简单看一下流程,有没有i2c初始化、PCF8574初始化、发命令、发数据、显示数据这些动作。如果没有问题的话,就可以烧入显示了。不出意外,就可以看到屏幕的显示了。
6、调整电位器
实际显示的时候,字体的显示效果不一定好,即字体和背景的对比度可能不是很好。好在模块上面有一个明显的电位器。说是电位器,其实就是一个可调电阻,找一个十字起,微调一下即可。
