174 lines
		
	
	
		
			4.8 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			174 lines
		
	
	
		
			4.8 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /**
 | |
|  * Copyright (c) 2021 Raspberry Pi (Trading) Ltd.
 | |
|  *
 | |
|  * SPDX-License-Identifier: BSD-3-Clause
 | |
|  */
 | |
| 
 | |
| /* Example code to drive a 16x2 LCD panel via an Adafruit TTL LCD "backpack"
 | |
| 
 | |
|    Optionally, the backpack can be connected the VBUS (pin 40) at 5V if
 | |
|    the Pico in question is powered by USB for greater brightness.
 | |
|    
 | |
|    If this is done, then no other connections should be made to the backpack apart
 | |
|    from those listed below as the backpack's logic levels will change.
 | |
| 
 | |
|    Connections on Raspberry Pi Pico board, other boards may vary.
 | |
| 
 | |
|    GPIO 8 (pin 11)-> RX on backpack
 | |
|    3.3v (pin 36) -> 3.3v on backpack
 | |
|    GND (pin 38)  -> GND on backpack
 | |
| */
 | |
| 
 | |
| #include <stdio.h>
 | |
| #include <math.h>
 | |
| #include "pico/stdlib.h"
 | |
| #include "pico/binary_info.h"
 | |
| #include "hardware/uart.h"
 | |
| 
 | |
|  // leave uart0 free for stdio
 | |
| #define UART_ID uart1
 | |
| #define BAUD_RATE 9600
 | |
| #define UART_TX_PIN 8
 | |
| #define LCD_WIDTH 16
 | |
| #define LCD_HEIGHT 2
 | |
| 
 | |
| // basic commands
 | |
| #define LCD_DISPLAY_ON 0x42
 | |
| #define LCD_DISPLAY_OFF 0x46
 | |
| #define LCD_SET_BRIGHTNESS 0x99
 | |
| #define LCD_SET_CONTRAST 0x50
 | |
| #define LCD_AUTOSCROLL_ON 0x51
 | |
| #define LCD_AUTOSCROLL_OFF 0x52
 | |
| #define LCD_CLEAR_SCREEN 0x58
 | |
| #define LCD_SET_SPLASH 0x40
 | |
| 
 | |
| // cursor commands
 | |
| #define LCD_SET_CURSOR_POS 0x47
 | |
| #define LCD_CURSOR_HOME 0x48
 | |
| #define LCD_CURSOR_BACK 0x4C
 | |
| #define LCD_CURSOR_FORWARD 0x4D
 | |
| #define LCD_UNDERLINE_CURSOR_ON 0x4A
 | |
| #define LCD_UNDERLINE_CURSOR_OFF 0x4B
 | |
| #define LCD_BLOCK_CURSOR_ON 0x53
 | |
| #define LCD_BLOCK_CURSOR_OFF 0x54
 | |
| 
 | |
| // rgb commands
 | |
| #define LCD_SET_BACKLIGHT_COLOR 0xD0
 | |
| #define LCD_SET_DISPLAY_SIZE 0xD1
 | |
| 
 | |
| // change to 0 if display is not RGB capable
 | |
| #define LCD_IS_RGB 1
 | |
| 
 | |
| void lcd_write(uint8_t cmd, uint8_t* buf, uint8_t buflen) {
 | |
|     // all commands are prefixed with 0xFE
 | |
|     const uint8_t pre = 0xFE;
 | |
|     uart_write_blocking(UART_ID, &pre, 1);
 | |
|     uart_write_blocking(UART_ID, &cmd, 1);
 | |
|     uart_write_blocking(UART_ID, buf, buflen);
 | |
|     sleep_ms(10); // give the display some time
 | |
| }
 | |
| 
 | |
| void lcd_set_size(uint8_t w, uint8_t h) {
 | |
|     // sets the dimensions of the display
 | |
|     uint8_t buf[] = { w, h };
 | |
|     lcd_write(LCD_SET_DISPLAY_SIZE, buf, 2);
 | |
| }
 | |
| 
 | |
| void lcd_set_contrast(uint8_t contrast) {
 | |
|     // sets the display contrast
 | |
|     lcd_write(LCD_SET_CONTRAST, &contrast, 1);
 | |
| }
 | |
| 
 | |
| void lcd_set_brightness(uint8_t brightness) {
 | |
|     // sets the backlight brightness
 | |
|     lcd_write(LCD_SET_BRIGHTNESS, &brightness, 1);
 | |
| }
 | |
| 
 | |
| void lcd_set_cursor(bool is_on) {
 | |
|     // set is_on to true if we want the blinking block and underline cursor to show
 | |
|     if (is_on) {
 | |
|         lcd_write(LCD_BLOCK_CURSOR_ON, NULL, 0);
 | |
|         lcd_write(LCD_UNDERLINE_CURSOR_ON, NULL, 0);
 | |
|     } else {
 | |
|         lcd_write(LCD_BLOCK_CURSOR_OFF, NULL, 0);
 | |
|         lcd_write(LCD_UNDERLINE_CURSOR_OFF, NULL, 0);
 | |
|     }
 | |
| }
 | |
| 
 | |
| void lcd_set_backlight(bool is_on) {
 | |
|     // turn the backlight on (true) or off (false)
 | |
|     if (is_on) {
 | |
|         lcd_write(LCD_DISPLAY_ON, (uint8_t *) 0, 1);
 | |
|     } else {
 | |
|         lcd_write(LCD_DISPLAY_OFF, NULL, 0);
 | |
|     }
 | |
| }
 | |
| 
 | |
| void lcd_clear() {
 | |
|     // clear the contents of the display
 | |
|     lcd_write(LCD_CLEAR_SCREEN, NULL, 0);
 | |
| }
 | |
| 
 | |
| void lcd_cursor_reset() {
 | |
|     // reset the cursor to (1, 1)
 | |
|     lcd_write(LCD_CURSOR_HOME, NULL, 0);
 | |
| }
 | |
| 
 | |
| #if LCD_IS_RGB
 | |
| void lcd_set_backlight_color(uint8_t r, uint8_t g, uint8_t b) {
 | |
|     // only supported on RGB displays!
 | |
|     uint8_t buf[] = { r, g, b };
 | |
|     lcd_write(LCD_SET_BACKLIGHT_COLOR, buf, 3);
 | |
| }
 | |
| #endif
 | |
| 
 | |
| void lcd_init() {
 | |
|     lcd_set_backlight(true);
 | |
|     lcd_set_size(LCD_WIDTH, LCD_HEIGHT);
 | |
|     lcd_set_contrast(155);
 | |
|     lcd_set_brightness(255);
 | |
|     lcd_set_cursor(false);
 | |
| }
 | |
| 
 | |
| int main() {
 | |
|     stdio_init_all();
 | |
|     uart_init(UART_ID, BAUD_RATE);
 | |
|     uart_set_translate_crlf(UART_ID, false);
 | |
|     gpio_set_function(UART_TX_PIN, GPIO_FUNC_UART);
 | |
| 
 | |
|     bi_decl(bi_1pin_with_func(UART_TX_PIN, GPIO_FUNC_UART));
 | |
| 
 | |
|     lcd_init();
 | |
| 
 | |
|     // define startup sequence and save to EEPROM
 | |
|     // no more or less than 32 chars, if not enough, fill remaining ones with spaces
 | |
|     uint8_t splash_buf[] = "Hello LCD, from Pi Towers!      ";
 | |
|     lcd_write(LCD_SET_SPLASH, splash_buf, LCD_WIDTH * LCD_HEIGHT);
 | |
| 
 | |
|     lcd_cursor_reset();
 | |
|     lcd_clear();
 | |
| 
 | |
| #if LCD_IS_RGB
 | |
|     uint8_t i = 0; // it's ok if this overflows and wraps, we're using sin
 | |
|     const float frequency = 0.1f;
 | |
|     float red, green, blue;
 | |
| #endif
 | |
| 
 | |
|     while (1) {
 | |
|         // send any chars from stdio straight to the backpack
 | |
|         char c = getchar();
 | |
|         // any bytes not followed by 0xFE (the special command) are interpreted
 | |
|         // as text to be displayed on the backpack, so we just send the char
 | |
|         // down the UART byte pipe!
 | |
|         if (c < 128) uart_putc_raw(UART_ID, c); // skip extra non-ASCII chars
 | |
| #if LCD_IS_RGB
 | |
|         // change the display color on keypress, rainbow style!
 | |
|         red = sin(frequency * i + 0) * 127 + 128;
 | |
|         green = sin(frequency * i + 2) * 127 + 128;
 | |
|         blue = sin(frequency * i + 4) * 127 + 128;
 | |
|         lcd_set_backlight_color(red, green, blue);
 | |
|         i++;
 | |
| #endif
 | |
|     }
 | |
| }
 |