Script is displaying Unicode onto my character LCD - unicode
I am trying to get my Raspberry Pi 3 to display information taken from a MS SQL database onto a 2x16 character LCD. I have a script that gets the string from the database then writes it to a .txt and another that reads the .txt and displays it on the LCD. When it displays, however, it is in Unicode instead of "plain text." Is there a way to convert this so the LCD will display it properly?
I cannot insert a picture, but it is displaying like this: (u'thewordineedhere',)
This is the script I am using to get the string and write to the .txt
import pymssql
conn = pymssql.connect(server='###.##.###.##',port='1433', user='User_Name',
password='Password', database='Database_Name')
cursor = conn.cursor()
cursor.execute('Select Distinct * From Database_Name')
results = cursor.fetchall()
my_file = open("output.txt","w")
for string in results:
print (string)
my_file.write(str(string) +"\n")
my_file.close
conn.commit()
conn.close()
This is the script that reads it and displays on the LCD.
import I2C_LCD_driver
from time import *
f = open('output.txt','r')
data = f.read()
mylcd = I2C_LCD_driver.lcd()
mylcd.lcd_display_string(data, 1)
mylcd.lcd_display_string("", 2)
If necessary I can provide the I2C_LCD_driver.py, /etc/odbc.ini, /etc/odbcinst.ini, and /etc/freetds/freetds.conf scripts as well.
Here is the I2C_LCD_driver.py
# -*- coding: utf-8 -*-
# Original code found at:
# https://gist.github.com/DenisFromHR/cc863375a6e19dce359d
"""
Compiled, mashed and generally mutilated 2014-2015 by Denis Pleic
Made available under GNU GENERAL PUBLIC LICENSE
# Modified Python I2C library for Raspberry Pi
# as found on http://www.recantha.co.uk/blog/?p=4849
# Joined existing 'i2c_lib.py' and 'lcddriver.py' into a single library
# added bits and pieces from various sources
# By DenisFromHR (Denis Pleic)
# 2015-02-10, ver 0.1
"""
# i2c bus (0 -- original Pi, 1 -- Rev 2 Pi)
I2CBUS = 1
# LCD Address
ADDRESS = 0x3F
import smbus
from time import sleep
class i2c_device:
def __init__(self, addr, port=I2CBUS):
self.addr = addr
self.bus = smbus.SMBus(port)
# Write a single command
def write_cmd(self, cmd):
self.bus.write_byte(self.addr, cmd)
sleep(0.0001)
# Write a command and argument
def write_cmd_arg(self, cmd, data):
self.bus.write_byte_data(self.addr, cmd, data)
sleep(0.0001)
# Write a block of data
def write_block_data(self, cmd, data):
self.bus.write_block_data(self.addr, cmd, data)
sleep(0.0001)
# Read a single byte
def read(self):
return self.bus.read_byte(self.addr)
# Read
def read_data(self, cmd):
return self.bus.read_byte_data(self.addr, cmd)
# Read a block of data
def read_block_data(self, cmd):
return self.bus.read_block_data(self.addr, cmd)
# Read a single byte
def read(self):
return self.bus.read_byte(self.addr)
# Read
def read_data(self, cmd):
return self.bus.read_byte_data(self.addr, cmd)
# Read a block of data
def read_block_data(self, cmd):
return self.bus.read_block_data(self.addr, cmd)
# commands
LCD_CLEARDISPLAY = 0x01
LCD_RETURNHOME = 0x02
LCD_ENTRYMODESET = 0x04
LCD_DISPLAYCONTROL = 0x08
LCD_CURSORSHIFT = 0x10
LCD_FUNCTIONSET = 0x20
LCD_SETCGRAMADDR = 0x40
LCD_SETDDRAMADDR = 0x80
# flags for display entry mode
LCD_ENTRYRIGHT = 0x00
LCD_ENTRYLEFT = 0x02
LCD_ENTRYSHIFTINCREMENT = 0x01
LCD_ENTRYSHIFTDECREMENT = 0x00
# flags for display on/off control
LCD_DISPLAYON = 0x04
LCD_DISPLAYOFF = 0x00
LCD_CURSORON = 0x02
LCD_CURSOROFF = 0x00
LCD_BLINKON = 0x01
LCD_BLINKOFF = 0x00
# flags for display/cursor shift
LCD_DISPLAYMOVE = 0x08
LCD_CURSORMOVE = 0x00
LCD_MOVERIGHT = 0x04
LCD_MOVELEFT = 0x00
# flags for function set
LCD_8BITMODE = 0x10
LCD_4BITMODE = 0x00
LCD_2LINE = 0x08
LCD_1LINE = 0x00
LCD_5x10DOTS = 0x04
LCD_5x8DOTS = 0x00
# flags for backlight control
LCD_BACKLIGHT = 0x08
LCD_NOBACKLIGHT = 0x00
En = 0b00000100 # Enable bit
Rw = 0b00000010 # Read/Write bit
Rs = 0b00000001 # Register select bit
class lcd:
#initializes objects and lcd
def __init__(self):
self.lcd_device = i2c_device(ADDRESS)
self.lcd_write(0x03)
self.lcd_write(0x03)
self.lcd_write(0x03)
self.lcd_write(0x02)
self.lcd_write(LCD_FUNCTIONSET | LCD_2LINE | LCD_5x8DOTS | LCD_4BITMODE)
self.lcd_write(LCD_DISPLAYCONTROL | LCD_DISPLAYON)
self.lcd_write(LCD_CLEARDISPLAY)
self.lcd_write(LCD_ENTRYMODESET | LCD_ENTRYLEFT)
sleep(0.2)
# clocks EN to latch command
def lcd_strobe(self, data):
self.lcd_device.write_cmd(data | En | LCD_BACKLIGHT)
sleep(.0005)
self.lcd_device.write_cmd(((data & ~En) | LCD_BACKLIGHT))
sleep(.0001)
def lcd_write_four_bits(self, data):
self.lcd_device.write_cmd(data | LCD_BACKLIGHT)
self.lcd_strobe(data)
# write a command to lcd
def lcd_write(self, cmd, mode=0):
self.lcd_write_four_bits(mode | (cmd & 0xF0))
self.lcd_write_four_bits(mode | ((cmd << 4) & 0xF0))
# write a character to lcd (or character rom) 0x09: backlight | RS=DR<
# works!
def lcd_write_char(self, charvalue, mode=1):
self.lcd_write_four_bits(mode | (charvalue & 0xF0))
self.lcd_write_four_bits(mode | ((charvalue << 4) & 0xF0))
# put string function with optional char positioning
def lcd_display_string(self, string, line=1, pos=0):
if line == 1:
pos_new = pos
elif line == 2:
pos_new = 0x40 + pos
elif line == 3:
pos_new = 0x14 + pos
elif line == 4:
pos_new = 0x54 + pos
self.lcd_write(0x80 + pos_new)
for char in string:
self.lcd_write(ord(char), Rs)
# clear lcd and set to home
def lcd_clear(self):
self.lcd_write(LCD_CLEARDISPLAY)
self.lcd_write(LCD_RETURNHOME)
# define backlight on/off (lcd.backlight(1); off= lcd.backlight(0)
def backlight(self, state): # for state, 1 = on, 0 = off
if state == 1:
self.lcd_device.write_cmd(LCD_BACKLIGHT)
elif state == 0:
self.lcd_device.write_cmd(LCD_NOBACKLIGHT)
# add custom characters (0 - 7)
def lcd_load_custom_chars(self, fontdata):
self.lcd_write(0x40);
for char in fontdata:
for line in char:
self.lcd_write_char(line)
When a row of data is read from the database, it comes back as a row object which can have the individual columns accessed as if it was a list. What you're seeing is the string representation of a row object. You want the first item so you need to use string[0].
I am using Python in VS2017 on Windows, and I used pyodbc instead of pymssql:
import pyodbc
conn_str = (
r"Driver={SQL Server Native Client 11.0};"
r"Server=.\SQLEXPRESS;"
r"Database=testing;"
r"Trusted_Connection=yes;"
)
conn = pyodbc.connect(conn_str)
cursor = conn.cursor()
cursor.execute('Select Distinct Name From Names')
results = cursor.fetchall()
conn.close()
my_file = open(r"C:\temp\output.txt","w")
for string in results:
print (string[0])
my_file.write(string[0] + "\n")
my_file.close()
Notice that I closed the database as soon as possible to keep things clean, I used a full path to the file, and I had to use my_file.close() with the parentheses to make it work.
Related
I2C: difference between I2C Tools and python SMBus2
I am trying to understand the i2c protocol and it's implementation through the python SMBus library and I2C Tools for Linux. Let's look at the following I2C Sequences out of a datasheet: chapter 4.2 for the SFM3003: I can read out the data, if I first initialise a continuous measurement with $i2cset -y 0x28 0x36 0x08 i and then run my python script: from smbus2 import SMBus, i2c_msg import time OFFSET_FLOW = -24576 # [-] SCALEFACTOR_FLOW = 170 # [slm^-1] OFFSET_TEMP = 0 # [-] SCALEFACTOR_TEMP = 200 # [°C^-1] #bus.write_byte_data(0x28, 0x36, 0x08) msg = i2c_msg.read(0x28, 9) bus = SMBus(1) while True: bus.i2c_rdwr(msg) data = list(msg) # JUST SOME CONVERSION FROM HERE ON flow_bytes = data[0:2] flow_bytes_converted = bytes(flow_bytes) flow_raw = int.from_bytes(flow_bytes_converted, byteorder='big', signed=True) print("flow_raw: ", flow_raw) flow = (flow_raw-OFFSET_FLOW)/SCALEFACTOR_FLOW print("flow: ", flow) temp_bytes = data[3:5] temp_bytes_converted = bytes(temp_bytes) temp_raw = int.from_bytes(temp_bytes_converted, byteorder='big', signed=True) print("temp_raw: ", temp_raw) temp = (temp_raw-OFFSET_TEMP)/SCALEFACTOR_TEMP print("temp: ", temp) time.sleep(0.1) If I uncomment the line bus.write_byte_data(0x28, 0x36, 0x08) and try to run the python script without initialisation from the command line($i2cset -y 0x28 0x36 0x08 i), I get an Remote I/O Error and see a NACK on my bus after writing 0x08 to the register 0x36. So how is that command different to what I do with the I2C Linux Tools?
Reading/Writing to LSM6DSOX via SPI from Raspberry Pi
I'm having trouble reading and writing to my Adafruit LSM6DSOX IMU from my Raspberry Pi 4 running Ubuntu 20.04. I need to do it via SPI since I require the bandwidth, but I can only seem to read the WHO_AM_I register successfully. Reading/writing to any other register only returns 0x00. I have verified that I can read data off the IMU from an Arduino via SPI, but if I try to read a register other than 0x0F (the IMU_ID) I get 0x0 as a response. Any insight/ideas what could be causing this would be greatly appreciated! EDIT: It turns out I can read the following registers: 0x0f : 0x6c 0x13 : 0x1c 0x33 : 0x1c 0x53 : 0x1c 0x73 : 0x1c These are all random registers however, and the value 0x1C doesn't seem to correspond with anything. This is my main.py: import LSM6DSOX def main(): imu=LSM6DSOX.LSM6DSOX() imu.initSPI() whoamI=imu.read_reg(0x0F) while(whoamI != imu.LSM6DSOX_ID): imu.ms_sleep(200) print('searching for IMU') whoamI=imu.get_id() print(hex(whoamI)) print('found lsm6dsox IMU') imu.spi.close() imu.spi = None if __name__=="__main__": main() This is an excerpt from my LSM6DSOX.py: def initSPI(self): # Setup communication SPI self.spi = spidev.SpiDev() self.spi.open(0, 0) self.spi.mode=0b11 #mode 3, (mode 0 is also fine) self.spi.max_speed_hz = 500000 return self.spi def read_reg(self, reg, len=1): # Set up message buf = bytearray(len+1) buf[0] = 0b10000000 | reg # MSB bit must be 1 to indicate a read operation. this is OR'd with the register address you want to read resp =self.spi.xfer2(buf) #send (and recieve) data to the imu if len==1: return resp[1] else: return resp[1:] #display recieved data def write_reg(self, reg, data, len=1): # Set up message buf = bytearray(len+1) buf[0] = 0b00000000 | reg # MSB bit must be 0 to indicate a read operation. this is OR'd with the register address you want to read buf[1:] =bytes(data) resp =self.spi.xfer2(buf) #send (and recieve) data to the imu return resp[1:] #display recieved data
Raspberry Pi Pico I2C pins not working (MicroPython)
I have connected an ssd1306 OLED and BME280 to my Pico. Everything works like a charm when connected to Pin 0 (sda) and 1 (scl) i2c pins. But due to my very bad planning, I have to switch to any other i2c pins. Once connected I cannot get it to work. I have changed from i2c = machine.I2C(0, scl=machine.Pin(1), sda=machine.Pin(0),freq=400000) to i2c = machine.I2C(0, scl=machine.Pin(13), sda=machine.Pin(12),freq=400000) and others, but to no avail. Code snippet: import machine import bme280 import time from machine import Pin, I2C, ADC from ssd1306 import SSD1306_I2C i2c = machine.I2C(0, scl=machine.Pin(13), sda=machine.Pin(12),freq=400000) bme = bme280.BME280(i2c=i2c) oled = SSD1306_I2C(128, 64, i2c) Error I'm getting is: Traceback (most recent call last): File "<stdin>", line 9, in <module> File "/lib/bme280.py", line 75, in __init__ OSError: 5 Which is: dig_88_a1 = self.i2c.readfrom_mem(self.address, 0x88, 26) from bme280.py (standard driver) I have performed an i2c scan and it does return correct addresses on the new pins.
So I had a Similar Problem to you I had the ssd1306 OLED and I kept getting \\Traceback (most recent call last): File "<stdin>", line 5, in <module> File "/lib/ssd1306.py", line 110, in __init__ File "/lib/ssd1306.py", line 36, in __init__ File "/lib/ssd1306.py", line 71, in init_display File "/lib/ssd1306.py", line 115, in write_cmd OSError: [Errno 5] EIO Im running the QT PI from addafuit but its a RP2040 chip and I'm running micro python. Anyhow, I pressed the restart button on the board and It magically started working. Just like you, my i2c scan was getting the right address. the code I ended up using that worked for me was from machine import Pin, I2C from ssd1306 import SSD1306_I2C i2c = I2C(0,sda=Pin(24),scl=Pin(25),freq=40000) oled = SSD1306_I2C(128,64,i2c) oled.fill(0) oled.text("Hello",0,0) oled.show() and for the ssd1306 driver, I used # MicroPython SSD1306 OLED driver, I2C and SPI interfaces from micropython import const import framebuf # register definitions SET_CONTRAST = const(0x81) SET_ENTIRE_ON = const(0xA4) SET_NORM_INV = const(0xA6) SET_DISP = const(0xAE) SET_MEM_ADDR = const(0x20) SET_COL_ADDR = const(0x21) SET_PAGE_ADDR = const(0x22) SET_DISP_START_LINE = const(0x40) SET_SEG_REMAP = const(0xA0) SET_MUX_RATIO = const(0xA8) SET_COM_OUT_DIR = const(0xC0) SET_DISP_OFFSET = const(0xD3) SET_COM_PIN_CFG = const(0xDA) SET_DISP_CLK_DIV = const(0xD5) SET_PRECHARGE = const(0xD9) SET_VCOM_DESEL = const(0xDB) SET_CHARGE_PUMP = const(0x8D) # Subclassing FrameBuffer provides support for graphics primitives # http://docs.micropython.org/en/latest/pyboard/library/framebuf.html class SSD1306(framebuf.FrameBuffer): def __init__(self, width, height, external_vcc): self.width = width self.height = height self.external_vcc = external_vcc self.pages = self.height // 8 self.buffer = bytearray(self.pages * self.width) super().__init__(self.buffer, self.width, self.height, framebuf.MONO_VLSB) self.init_display() def init_display(self): for cmd in ( SET_DISP | 0x00, # off # address setting SET_MEM_ADDR, 0x00, # horizontal # resolution and layout SET_DISP_START_LINE | 0x00, SET_SEG_REMAP | 0x01, # column addr 127 mapped to SEG0 SET_MUX_RATIO, self.height - 1, SET_COM_OUT_DIR | 0x08, # scan from COM[N] to COM0 SET_DISP_OFFSET, 0x00, SET_COM_PIN_CFG, 0x02 if self.width > 2 * self.height else 0x12, # timing and driving scheme SET_DISP_CLK_DIV, 0x80, SET_PRECHARGE, 0x22 if self.external_vcc else 0xF1, SET_VCOM_DESEL, 0x30, # 0.83*Vcc # display SET_CONTRAST, 0xFF, # maximum SET_ENTIRE_ON, # output follows RAM contents SET_NORM_INV, # not inverted # charge pump SET_CHARGE_PUMP, 0x10 if self.external_vcc else 0x14, SET_DISP | 0x01, ): # on self.write_cmd(cmd) self.fill(0) self.show() def poweroff(self): self.write_cmd(SET_DISP | 0x00) def poweron(self): self.write_cmd(SET_DISP | 0x01) def contrast(self, contrast): self.write_cmd(SET_CONTRAST) self.write_cmd(contrast) def invert(self, invert): self.write_cmd(SET_NORM_INV | (invert & 1)) def show(self): x0 = 0 x1 = self.width - 1 if self.width == 64: # displays with width of 64 pixels are shifted by 32 x0 += 32 x1 += 32 self.write_cmd(SET_COL_ADDR) self.write_cmd(x0) self.write_cmd(x1) self.write_cmd(SET_PAGE_ADDR) self.write_cmd(0) self.write_cmd(self.pages - 1) self.write_data(self.buffer) class SSD1306_I2C(SSD1306): def __init__(self, width, height, i2c, addr=0x3C, external_vcc=False): self.i2c = i2c self.addr = addr self.temp = bytearray(2) self.write_list = [b"\x40", None] # Co=0, D/C#=1 super().__init__(width, height, external_vcc) def write_cmd(self, cmd): self.temp[0] = 0x80 # Co=1, D/C#=0 self.temp[1] = cmd self.i2c.writeto(self.addr, self.temp) def write_data(self, buf): self.write_list[1] = buf self.i2c.writevto(self.addr, self.write_list) class SSD1306_SPI(SSD1306): def __init__(self, width, height, spi, dc, res, cs, external_vcc=False): self.rate = 10 * 1024 * 1024 dc.init(dc.OUT, value=0) res.init(res.OUT, value=0) cs.init(cs.OUT, value=1) self.spi = spi self.dc = dc self.res = res self.cs = cs import time self.res(1) time.sleep_ms(1) self.res(0) time.sleep_ms(10) self.res(1) super().__init__(width, height, external_vcc) def write_cmd(self, cmd): self.spi.init(baudrate=self.rate, polarity=0, phase=0) self.cs(1) self.dc(0) self.cs(0) self.spi.write(bytearray([cmd])) self.cs(1) def write_data(self, buf): self.spi.init(baudrate=self.rate, polarity=0, phase=0) self.cs(1) self.dc(1) self.cs(0) self.spi.write(buf) self.cs(1) So the only advice and can give to you is to try to press the restart button.
Grove I2C display not working on Raspberry Pi 3B
I only have my RPi 3B and a I²C display, I don't own any GrovePi hat and I want to show some text to the said display. Is there a way to make it work? My display. i2cdetect -y 1 shows this result, meaning the RPi is detecting the I²C display and it should work. But nothing seemed to be showing on the display, except for the full block on the first row. I've tried literally everything on the internet, some library worked (as in throwing no errors) but the display still stays the same, full block on the first row. I've installed python3, smbus, smbus2 and i2c-tools. I've changed the address to 3e. My most recent *.py file. It does write 'LCD printing' yet nothing else works. I don't find a way to change the contrast of the LCD (no potentiometer or whatsoever) #!/usr/bin/python3 import smbus2 as smbus import time # Define some device parameters I2C_ADDR = 0x3e # I2C device address, if any error, change this address to 0x3f LCD_WIDTH = 16 # Maximum characters per line # Define some device constants LCD_CHR = 1 # Mode - Sending data LCD_CMD = 0 # Mode - Sending command LCD_LINE_1 = 0x80 # LCD RAM address for the 1st line LCD_LINE_2 = 0xC0 # LCD RAM address for the 2nd line LCD_LINE_3 = 0x94 # LCD RAM address for the 3rd line LCD_LINE_4 = 0xD4 # LCD RAM address for the 4th line LCD_BACKLIGHT = 0x08 # On ENABLE = 0b00000100 # Enable bit # Timing constants E_PULSE = 0.0005 E_DELAY = 0.0005 # Open I2C interface # bus = smbus.SMBus(0) # Rev 1 Pi uses 0 bus = smbus.SMBus(1) # Rev 2 Pi uses 1 def lcd_init(): # Initialise display lcd_byte(0x33, LCD_CMD) # 110011 Initialise lcd_byte(0x32, LCD_CMD) # 110010 Initialise lcd_byte(0x06, LCD_CMD) # 000110 Cursor move direction lcd_byte(0x0C, LCD_CMD) # 001100 Display On,Cursor Off, Blink Off lcd_byte(0x28, LCD_CMD) # 101000 Data length, number of lines, font size lcd_byte(0x01, LCD_CMD) # 000001 Clear display time.sleep(E_DELAY) def lcd_byte(bits, mode): # Send byte to data pins # bits = the data # mode = 1 for data # 0 for command bits_high = mode | (bits & 0xF0) | LCD_BACKLIGHT bits_low = mode | ((bits << 4) & 0xF0) | LCD_BACKLIGHT # High bits bus.write_byte(I2C_ADDR, bits_high) lcd_toggle_enable(bits_high) # Low bits bus.write_byte(I2C_ADDR, bits_low) lcd_toggle_enable(bits_low) def lcd_toggle_enable(bits): # Toggle enable time.sleep(E_DELAY) bus.write_byte(I2C_ADDR, (bits | ENABLE)) time.sleep(E_PULSE) bus.write_byte(I2C_ADDR, (bits & ~ENABLE)) time.sleep(E_DELAY) def lcd_string(message, line): # Send string to display message = message.ljust(LCD_WIDTH, " ") lcd_byte(line, LCD_CMD) for i in range(LCD_WIDTH): lcd_byte(ord(message[i]), LCD_CHR) if __name__ == '__main__': lcd_init() while True: # Send some test lcd_string("Hello ", LCD_LINE_1) lcd_string(" World", LCD_LINE_2) print('LCD printing!') time.sleep(3)
Data transmission Pi/MCP3008
I have a question regarding data transmisison from a Raspberry Pi to a mcp3008. It is just a theoretical one. When they exchange the bytes does the master send 1 byte and receives 1 byte. Then sends the 2nd byte and receives 2nd byte.. OR does the master send 3 bytes and receives 3 bytes after that. From my understanding it is the first one, am I right?
Adafruit's library for the MCP3008 has your answer. Check out the read_adc() function: def read_adc(self, adc_number): """Read the current value of the specified ADC channel (0-7). The values can range from 0 to 1023 (10-bits). """ assert 0 <= adc_number <= 7, 'ADC number must be a value of 0-7!' # Build a single channel read command. # For example channel zero = 0b11000000 command = 0b11 << 6 # Start bit, single channel read command |= (adc_number & 0x07) << 3 # Channel number (in 3 bits) # Note the bottom 3 bits of command are 0, this is to account for the # extra clock to do the conversion, and the low null bit returned at # the start of the response. resp = self._spi.transfer([command, 0x0, 0x0]) # Parse out the 10 bits of response data and return it. result = (resp[0] & 0x01) << 9 result |= (resp[1] & 0xFF) << 1 result |= (resp[2] & 0x80) >> 7 return result & 0x3FF It appears that it sends a three-byte command (where only one byte is non-zero): resp = self._spi.transfer([command, 0x0, 0x0]) The response is three bytes which contains the packed 10-bit ADC value. resp = self._spi.transfer([command, 0x0, 0x0]) # Parse out the 10 bits of response data and return it. result = (resp[0] & 0x01) << 9 result |= (resp[1] & 0xFF) << 1 result |= (resp[2] & 0x80) >> 7