16-channel multiplexer & python - python

Update 4/5/22
Equipment: ESP8266 board, CD74HC4067 16-Channel Multiplexer
Code Platform: micropython using Thonny on RPi transmitting over USB cable.
Project Goal: 16 individual photo-resistors to trigger individual LEDs or Relays.
Code:
Opening Line...
from machine import Pin, ADC
from time import sleep_ms
s0 = Pin(16, Pin.OUT) # assigns s0 on multiplexer to D0 pin on ESP8266
s1 = Pin(5, Pin.OUT) # D1
s2 = Pin(4, Pin.OUT) # D2
s3 = Pin(2, Pin.OUT) # D4
SIG_pin = ADC(0) # assigns SIG on multiplexer to A0 pin on ESP8266
to test the code, I ran
val = Sig_pin.read()
print(val)
and I get a value which reflects an output... i'm not sure from which of the (16) channels. If i comment 3 out of 4 of the s# pins, I get a change in value as expected... but again, I'm not sure which channel from the active pin.
I have thought about it and I can create a binary directory to use for the channels.
mux = [{0b0000},{0b0001},{0b0010},{0b0011}],[{0b0100},{0b0101},{0b0110},{0b0111}],[{0b1000},{0b1001},{0b1010},{0b1011}],[{0b1100},{0b1101},{0b1110},{0b1111}]
In arduino, i could use digitalWrite(pin,channel) to call for a specific channel, but how can I do this in python?
and then how can I get the Sig_pin to read that specific pin & channel?

Solved the problem. I was overthinking the process way too much.
ch1 = (s0.value(0), s1.value(0), s2.value(0), s3.value(0))
val = Sig_pin.read()
print(val)
Setting each of the s# pins to a high low state gives me my binary combination.

Related

Using python to read 8-bit ADC outputs into a Raspberry Pi 4?

I'm using python to read in values from a high-speed 8-bit ADC (the ADS7885 linked here) and convert them into voltages using the SPI0 ports on a Raspberry Pi 4. At this point, I do receive values from the ADC on the Raspberry Pi, but the values I am reading in are not at all accurate. I was hoping someone might be able to help me out with my code so that I can accurately read values from the ADC at a sampling rate of 48mHz and convert them into voltages?
I think the problem might have to do with the number of clock cycles it takes before the ADC can read/convert valid data? The datasheet says that this specific ADC requires 16 SCLK cycles before it is able to begin converting valid data, but I'm not sure how to enforce this in my code.
I followed sample code for a 10-bit ADC that uses the Spidev python module, but I'm open to any other code solutions. This is what I'm currently running:
spi404 = spidev.SpiDev(0, 0)
def read_adc404(adc_ch, vref = 5):
msg = 0b11
msg = ((msg << 1) + 0) << 3
msg = (msg, 0b000000)
reply = spi404.xfer2(msg)
adc = 0
for n in reply:
adc = (adc << 6) + n
adc = adc >> 2
voltage = (vref * adc) / 256
return voltage
Any tips or help would be greatly appreciated!!

ESP8266 rshell repl freezes

I wanted to define some pin variables before experimenting with a seven-segment 4-digit display which is connected to my ESP8266. On the interpreter, the following lines of code work fine, and they do not raise any errors:
from machine import Pin
OUT = Pin.OUT
Whenever I try to define a pin variable using the machine.Pin class, the entire repl freezes:
a = Pin(1, OUT)
It would just hang there:
I have tried this on two separate ESP8266 boards, so it is unlikely that the problem has to do with the board being poorly soldered...
This is my current setup:
These are the variables and pin numbers that I intend to use:
from machine import Pin
OUT = Pin.OUT
a = Pin(1, OUT)
b = Pin(3, OUT)
c = Pin(15, OUT)
d = Pin(13, OUT)
e = Pin(12, OUT)
f = Pin(14, OUT)
g = Pin(2, OUT)
dec = Pin(0, OUT)
digit1 = Pin(4, OUT)
digit2 = Pin(5, OUT)
digit3 = Pin(16, OUT)
digit4 = Pin(10, OUT)
I have searched around and have not found anything that matches my case. Perhaps both of the boards that I have tried have bad soldering?
My setup is inspired by this video.
Something that I found odd about his setup was that every single pin was configured for digital output. Are ground pins unnecessary with this setup?
UPDATE (Yes, while writing this post):
I have changed my code to the following:
from machine import Pin
OUT = Pin.OUT
digit1 = Pin(4, OUT)
digit1.on()
digit2 = Pin(5, OUT)
digit2.on()
digit3 = Pin(16, OUT)
digit3.on()
digit4 = Pin(10, OUT)
digit4.on()
Digits 1 to 3 seem to load fine, but when I get to digit4, I get the following output:
ets Jan 8 2013,rst cause:4, boot mode:(3,6)
wdt reset
load 0x40100000, len 31088, room 16
tail 0
chksum 0x44
load 0x3ffe8000, len 1028, room 8
tail 12
chksum 0x1e
ho 0 tail 12 room 4
load 0x3ffe8410, len 824, room 12
tail 12
chksum 0x89
csum 0x89
���2�n��s��N|�$l$l`c��|{��l�N��N�d ��r�l�l2�$`��s�p��l�l`��{�p���� l`rl���c ���c#��c|l#���B|����l$b��N�2Nn� �$N� ��$�� $l����l`�n� ����Bll����2"��l�crls$r�o�� � ��o����"�����#��
MicroPython v1.12 on 2019-12-20; ESP module with ESP8266
Type "help()" for more information.
>>>
As noted in the comments, pins 1 & 3 are tx0, rx0 used for serial communication, so not usable during serial transmission. Pins 6-11 are used for flash communication so are not usable at all. See the pin allocation table here...
https://tttapa.github.io/ESP8266/Chap04%20-%20Microcontroller.html

Not able to read valid voltage input in raspberry pi with PCF8591

I try to read voltage input came form machine via PCF8591 in Raspberry-pi using I2C communication but printing some another value.
Also could you please suggest me for I want to get machine input voltage if voltage is dropped it should interrupt a function which method should I use?
Connection between PCF8591-> Raspberry Pi
SDL -> SDL on Rpi
SCL -> SCL on Rpi
VCC -> 3.3v on Rpi even tried 5.0v
GND -> GND on Rpi
Connection machine to PCF8591
5v -> AIN1 on PCF8591
GND -> GND Rpi
import smbus
import time
address = 0x48
A0 = 0x40
A1 = 0x41
A2 = 0x42
A3 = 0x43
bus = smbus.SMBus(1)
while True:
bus.read_byte_data(address,A1)
value = bus.read_byte_data(address, A1)
print("AOUT: %1.03f" %(value*3.3/255))
time.sleep(0.2)
Showing output like this
AOUT: 2.756
To get the correct value, you have to read the value twice. The first read tells the chip to do a new measurement and return meanwhile the current value in the register (which is not the correct value). On the second read you get the correct value:
import smbus
import time
address = 0x48
A0 = 0x40
A1 = 0x41
A2 = 0x42
A3 = 0x43
bus = smbus.SMBus(1)
while True:
bus.read_byte_data(address, A1) # do the measurement but ignore the value
value = bus.read_byte_data(address, A1) # get the correct value
#print(value)
print("AOUT: %1.03f" %(value*3.3/255))
time.sleep(0.2)

SPIDEV on raspberry pi for TI DAC8568 not behaving as expected

I have a Texas Instruments DAC8568 in their BOOST breakout board package. The DAC8568 is an 8 channel, 16bit DAC with SPI interface. The BOOST package has headers to connect it to my raspberry pi, and it has LEDs connected to the output voltage so you can easily check to see if your code is doing what you think it does. Links to the BOOST package and datasheet of the DAC8568 are in my python code below.
I have the package wired to the raspberry Pi with the 3.3V supply, the 5V supply (needed for LEDs), and ground. The DACs SCLK goes to Pi SCLK, DAC /SYNC (which is really chip select) goes to Pi CE1, DAC /LDAC goes to Pi Gnd, and DAC MOSI goes to Pi MOSI. I do not wire the DACs /CLR, but I can physically hook it to ground to reset the chip if I need to.
I believe my wiring is good, because I can light the LEDs with either a python script or from the terminal using: sudo echo -ne "\xXX\xXX\xXX\xXX" > /dev/spidev0.1
I learned the terminal trick from this video: https://www.youtube.com/watch?v=iwzXh2V1SP4
My problem though is that the LEDs are not lighting as I would expect them to according to the data sheet. I should be lighting A, but instead I light B. I should light B but instead I light D, etc. I have tried to make sense of it all and can dim the LEDs and turn on new ones, but never in the way I would really expect it to work according to the datasheet.
Below is my python script. In the comments I mentioned where in the datasheet I am looking for the bits to send. I am very new to working with analog components and am not a EE, so maybe I am not doing the timing correctly, or making some other silly error. Perhaps someone can look at the datasheet and see my error without having to actually have the chip in hand. Thanks for the help!
# -*- coding: utf-8 -*-
"""
Created on Sat Jul 8 16:33:05 2017
#author: pi
for texas instruments BOOST DAC8568
for BOOST schematic showing LEDs http://www.ti.com/tool/boost-dac8568
for DAC8568 datasheet: http://www.ti.com/product/dac8568
"""
import spidev
import time
spi = spidev.SpiDev() #create spi object
spi.open(0,1) #open spi port 0, device (CS) 1
#spi.bits_per_word = 8 does not seem to matter
#spi.max_speed_hz = 50000000 #does not seem to matter
#you have to power the DAC, you can write to the buffer and later power on if you like
power_up = spi.xfer2([0x04, 0x00, 0x00, 0xFF]) #p.37 Table11 in datasheet: powers all DACS
voltage_write = spi.xfer2([0x00, 0x0F, 0xFF, 0xFF ]) #p.35 Table11 in datasheet supposed write A--but lights B
voltage_write = spi.xfer2([0x00, 0x1F, 0xFF, 0xFF ]) #supposed write B--but lights D
voltage_write = spi.xfer2([0x00, 0x2F, 0xFF, 0xFF ]) #supposed write C--but lights F
voltage_write = spi.xfer2([0x00, 0x3F, 0xFF, 0xFF ]) #supposed write D--but lights H
voltage_write = spi.xfer2([0x00, 0x4F, 0xFF, 0xFF ]) #supposed write E--but does nothing
spi.close()
Note for future readers, the power up needs to power on the internal reference which is
power_up = spi.xfer2([0x08, 0x00, 0x00, 0xFF]) #(p.37 datasheet
Comment: the bits are shifted. ... how ... compensate for the shift or eliminate the shift?
This could be the case, if the SPIDIV.mode is not in sync with the DAC.
DAC Datasheet Page 6/7:
This input is the frame synchronization signal for the input data.
When SYNC goes low, it enables the input shiftregister,
and data are sampled on subsequent SYNC falling clock edges.
The DAC output updates following the 32nd clock.
Reference: Clock polarity and phase
According to the above and the Timing Diagram I come to the conclusion that SPDIV.mode == 2
is the right.
Check the actual SPDIV.mode
Change to SPDIV.mode = 2
I can confirm your used Values by reading Table 11 Page 35.
Write to Input Register - DAC Channel X
My Example set Feature Bits = 0
3 2 1
10987654321098765432109876543210
RXXXCCCCAAAADDDDDDDDDDDDDDDDFFFF
A = 32-bit[00000000000011111111111111110000]:0xffff0 ('0x00', '0x0f', '0xff', '0xf0')
3 2 1
10987654321098765432109876543210
RXXXCCCCAAAADDDDDDDDDDDDDDDDFFFF
B = 32-bit[00000000000111111111111111110000]:0x1ffff0 ('0x00', '0x1f', '0xff', '0xf0')
Page 33:
DB31(MSB) is the first bit that is loaded into the DAC shift register and must be always set to '0'.
The wireing seems straight forward and simple, but worth to doublecheck.
Code Snippet from testing:
def writeDAC(command, address, data, feature=0x0):
address = ord(address) - ord('A')
b1 = command
b2 = address << 4 | data >> 12 # 4 address Bits and 4 MSB data Bits
b3 = data >> 4 # middle 8 Bits of data
b4 = 0xF0 & (data << 4) >> 8 | feature # 4 data Bits and feature Bits
voltage_write = spi.xfer2([b1, b2, b3, b4])
# Usage:
# Write Command=0 Channel=B Data=0xFFFF Default Features=0x0
writeDAC(0, 'B', 0xFFFF)

Python set Parallel Port data pins high/low

I am wondering how to set the data pins on a parallel port high and low. I believe I could use PyParallel for this, but I am unsure how to set a specific pin.
Thanks!
You're talking about a software-hardware interface here. They are usually set low and high by assigning a 1-byte value to a register. A parallel port has 8 pins for data to travel across. In a low level language like C, C++, there would be a register, lets call it 'A', somewhere holding 8 bits corresponding to the 8 pins of data. So for example:
Assuming resgister A is setup like pins: [7,6,5,4,3,2,1,0]
C-like pseudocode
A=0x00 // all pins are set low
A=0xFF // all pins are high
A=0xF0 // Pins 0:3 are low, Pins 4:7 are high
This idea follows through with PyParallel
import parallel
p = parallel.Parallel() # open LPT1
p.setData(0x55) #<--- this is your bread and butter here
p.setData is the function you're interested in. 0x55 converted to binary is
0b01010101
-or-
[L H L H L H L H]
So now you can set the data to a certain byte, but how would I sent a bunch of data... lets say 3 bytes 0x00, 0x01, 0x02? Well you need to watch the ack line for when the receiving machine has confirmed receipt of whatever was just sent.
A naive implementation:
data=[0x00, 0x01, 0x02]
while data:
onebyte=data.pop()
p.setDataStrobe('low') #signal that we're sending data
p.setData(onebyte)
while p.getInAcknowledge() == 'high': #wait for this line to go 'low'
# to indicate an ACK
pass #we're waiting for it to acknowledge...
p.setDataStrobe('high')#Ok, we're done sending that byte.
Ok, that doesn't directly answer your question. Lets say i ONLY want to set pin 5 high or low. Maybe I have an LED on that pin. Then you just need a bit of binary operations.
portState = 0b01100000 #Somehow the parallel port has this currently set
newportState = portState | 0b00010000#<-- this is called a bitmask
print newportState
>>> 0b011*1*0000
Now lets clear that bit...
newportState = 0b01110000
clearedPin5 = newportState & 11101111
print clearedPin5
>>> 0b011*0*0000
If these binary operations are foreign, I recommend this excellent tutorial over on avrfreaks. I would become intimate with them before progressing further. Embedded software concepts like these are full of bitmasks and bitshifting.
I've made this function to control the pins individually (code derived from here and here):
def setPin(pin,value):
if(pin==1):
p.setDataStrobe(value)
elif(pin>=2 and pin<=9):
pin = pin-2
if(value==0):
# clear the bit
p.setData(p.getData() & (255 - pow(2, pin)))
else:
#set the bit
p.setData(p.getData() | pow(2, pin))
elif(pin==14):
p.setAutoFeed(value)
elif(pin==16):
p.setInitOut(value)
elif(pin==17):
p.setSelect(value)
else:
raise(ValueError("invalid pin number"))

Categories