Skip to content

Instantly share code, notes, and snippets.

@maxmacstn
Last active January 29, 2021 10:25
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save maxmacstn/8b5c08e5353a8cabb9dfe0ecbf012e1c to your computer and use it in GitHub Desktop.
Save maxmacstn/8b5c08e5353a8cabb9dfe0ecbf012e1c to your computer and use it in GitHub Desktop.
Raspberry Pi Pico internal temperature sensor with LCD 16x2 example.
/**
*
* Raspberry Pi Pico internal temperature sensor with LCD 16x2 example.
*
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
*
* Adapted by MaxMacSTN
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <stdio.h>
#include <string.h>
#include "pico/stdlib.h"
#include "hardware/i2c.h"
#include "hardware/gpio.h"
#include "hardware/adc.h"
#include "pico/binary_info.h"
#include <math.h>
/* Example code to drive a 16x2 LCD panel via a I2C bridge chip (e.g. PCF8574)
NOTE: The panel must be capable of being driven at 3.3v NOT 5v. The Pico
GPIO (and therefor I2C) cannot be used at 5v.
You will need to use a level shifter on the I2C lines if you want to run the
board at 5v.
Connections on Raspberry Pi Pico board, other boards may vary.
GPIO 4 (pin 6)-> SDA on LCD bridge board
GPIO 5 (pin 7)-> SCL on LCD bridge board
3.3v (pin 36) -> VCC on LCD bridge board
GND (pin 38) -> GND on LCD bridge board
*/
// commands
const int LCD_CLEARDISPLAY = 0x01;
const int LCD_RETURNHOME = 0x02;
const int LCD_ENTRYMODESET = 0x04;
const int LCD_DISPLAYCONTROL = 0x08;
const int LCD_CURSORSHIFT = 0x10;
const int LCD_FUNCTIONSET = 0x20;
const int LCD_SETCGRAMADDR = 0x40;
const int LCD_SETDDRAMADDR = 0x80;
// flags for display entry mode
const int LCD_ENTRYSHIFTINCREMENT = 0x01;
const int LCD_ENTRYLEFT = 0x02;
// flags for display and cursor control
const int LCD_BLINKON = 0x01;
const int LCD_CURSORON = 0x02;
const int LCD_DISPLAYON = 0x04;
// flags for display and cursor shift
const int LCD_MOVERIGHT = 0x04;
const int LCD_DISPLAYMOVE = 0x08;
// flags for function set
const int LCD_5x10DOTS = 0x04;
const int LCD_2LINE = 0x08;
const int LCD_8BITMODE = 0x10;
// flag for backlight control
const int LCD_BACKLIGHT = 0x08;
const int LCD_ENABLE_BIT = 0x04;
#define I2C_PORT i2c0
// By default these LCD display drivers are on bus address 0x27
static int addr = 0x27;
// Modes for lcd_send_byte
#define LCD_CHARACTER 1
#define LCD_COMMAND 0
#define MAX_LINES 2
#define MAX_CHARS 16
const uint LED_PIN = PICO_DEFAULT_LED_PIN;
const uint DHT_PIN = 15;
const uint MAX_TIMINGS = 85;
/* Quick helper function for single byte transfers */
void i2c_write_byte(uint8_t val) {
i2c_write_blocking(I2C_PORT, addr, &val, 1, false);
}
void lcd_toggle_enable(uint8_t val) {
// Toggle enable pin on LCD display
// We cannot do this too quickly or things don't work
#define DELAY_US 600
sleep_us(DELAY_US);
i2c_write_byte(val | LCD_ENABLE_BIT);
sleep_us(DELAY_US);
i2c_write_byte(val & ~LCD_ENABLE_BIT);
sleep_us(DELAY_US);
}
// The display is sent a byte as two separate nibble transfers
void lcd_send_byte(uint8_t val, int mode) {
uint8_t high = mode | (val & 0xF0) | LCD_BACKLIGHT;
uint8_t low = mode | ((val << 4) & 0xF0) | LCD_BACKLIGHT;
i2c_write_byte(high);
lcd_toggle_enable(high);
i2c_write_byte(low);
lcd_toggle_enable(low);
}
void lcd_clear(void) {
lcd_send_byte(LCD_CLEARDISPLAY, LCD_COMMAND);
}
// go to location on LCD
void lcd_set_cursor(int line, int position) {
int val = (line == 0) ? 0x80 + position : 0xC0 + position;
lcd_send_byte(val, LCD_COMMAND);
}
static void inline lcd_char(char val) {
lcd_send_byte(val, LCD_CHARACTER);
}
void lcd_string(const char *s) {
while (*s) {
lcd_char(*s++);
}
}
void lcd_init() {
lcd_send_byte(0x03, LCD_COMMAND);
lcd_send_byte(0x03, LCD_COMMAND);
lcd_send_byte(0x03, LCD_COMMAND);
lcd_send_byte(0x02, LCD_COMMAND);
lcd_send_byte(LCD_ENTRYMODESET | LCD_ENTRYLEFT, LCD_COMMAND);
lcd_send_byte(LCD_FUNCTIONSET | LCD_2LINE, LCD_COMMAND);
lcd_send_byte(LCD_DISPLAYCONTROL | LCD_DISPLAYON, LCD_COMMAND);
lcd_clear();
}
int main() {
stdio_init_all();
adc_init();
// Select ADC input 0 (GPIO26)
gpio_set_dir(LED_PIN, GPIO_OUT);
// This example will use I2C0 on GPIO4 (SDA) and GPIO5 (SCL)
i2c_init(I2C_PORT, 100 * 1000);
gpio_set_function(4, GPIO_FUNC_I2C);
gpio_set_function(5, GPIO_FUNC_I2C);
gpio_pull_up(4);
gpio_pull_up(5);
// Make the I2C pins available to picotool
bi_decl( bi_2pins_with_func(4, 5, GPIO_FUNC_I2C));
lcd_init();
while (1) {
const float conversion_factor = 3.3f / (1 << 12);
adc_select_input(4);
uint16_t result = adc_read();
printf("Raw value: 0x%03x, voltage: %f V\n", result, result * conversion_factor);
float reading = result * conversion_factor;
float tempF = 27 - (reading - 0.706)/0.001721;
float tempC = (tempF - 32) * 5/9;
char *message[16];
lcd_set_cursor(0, 0);
lcd_string(" - RPi Pico - ");
lcd_set_cursor(1, 0);
sprintf(message, " Temp: %.1fc ",tempC);
lcd_string(message);
sleep_ms(2000);
}
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment