# Project#10 - Diagnoistic Testing # This project uses every electronic block available on the Pico Pal. This is a culmination of all projects so far. The main loop is located... # at the bottom of this code. Feel free to modify as you see fit. From here, you should have the tooks needed to complete your own... # projects. Please make sure to watch the videos on the project page. There is a ton of information there that will help you on your # MicroPython adventure! There is also a list of optional connections, like the microphone and light sensor, and dedicated GPIOs... # such as the heart rate sensor input on GPIO28. import machine # Think of "import" as importing a library. This library allows for us to use GPIOs import utime # This "library" allows for us to tell time if connected to the internet, and use delays like 'utime.sleep(1)' my_list = [] # This is a list that we need to create for later sda=machine.Pin(0) # Setup GPIO pin 0 as the I2C Data line scl=machine.Pin(1) # Setup GPIO pin 1 as the I2C Clock line bytes = 0 # We're going to use this variable to change I2C read variables from HEX to BINARY val = 0 # This variable will also be used for RTC conversion i2c = machine.I2C(0,scl=scl, sda=sda, freq = 400000) # This line sets up I2C communications. cs = machine.Pin(5, machine.Pin.OUT) #Setup the CS (Chip select pin for the audio chip. GPIO5. Set as output. # ASTOP = machine.Pin(6, machine.Pin.IN) #Setup the ASTOP (AUDIO STOP) pint o GPIO 6. Set it as an input. Button = machine.Pin(15, machine.Pin.IN) #Setup the SEL1 button pin to GPIO 15. Set it as an input. Button2 = machine.Pin(14, machine.Pin.IN) #Setup the SEL2 button pin to GPIO 14. Set it as an input. Buzzer = machine.Pin(22, machine.Pin.OUT) #Setup the CS (Chip select pin for the audio chip. GPIO5. Set as output. REDLED = machine.Pin(16, machine.Pin.OUT) #Setup the BLUELED as an output. Connect the blue LED jumper which connects the blue LED to GPIO16 BLUELED = machine.Pin(17, machine.Pin.OUT) #Setup the BLUELED as an output. Connect the blue LED jumper which connects the blue LED to GPIO16 # DIPA = machine.Pin(21, machine.Pin.IN) #Setup DIP Switch Channel-A as an output DIPB = machine.Pin(20, machine.Pin.IN) #Setup DIP Switch Channel-B as an output DIPC = machine.Pin(19, machine.Pin.IN) #Setup DIP Switch Channel-C as an output DIPD = machine.Pin(18, machine.Pin.IN) #Setup DIP Switch Channel-D as an output # LightSensor = machine.ADC(26) Microphone = machine.ADC(27) HeartSensor = machine.ADC(28) cs.value(1) # Set the CS line to 1 (HIGH/3.3v) spi_sck=machine.Pin(2) # Set SPI clock to GPIO pin 2 spi_tx=machine.Pin(3) # Set SPI MASTER OUT to GPIO pin 3 spi_rx=machine.Pin(4) # Set SPI MASTER IN to GPIO pin 4 spi=machine.SPI(0,baudrate=500000,sck=spi_sck,mosi=spi_tx, phase=1, polarity=0) # Setup SPI communications settings utime.sleep(1) # Sleep/Wait for one second hold = '\x00' # 'hold' acts as the pointer for the little buddy talker chip. Load the HEX value of the audio bite that you want to play, then call the playaudio() function. state = 0 conversion = 3.3/(65535) def playaudio(): # This function plays a single sound bite determined by the value in the "hold" integer print("Playing sound bite...") # Print this to the shell global hold # global means that this valiable can be used across functions. cs.value(0) # Clear the cs pin to 0v to activate the audio chip utime.sleep(0.001) # Wait 1ms spi.write('\x98') # '\x98' is the first value that is always sent to the audio chip spi.write(hold) # The HEX value stored in 'hold' will be sent to the audio chip, which will instruct it to play the sound bite in question utime.sleep(0.001) # Wait another 1ms cs.value(1) # Set the cs pin to 5v to end the transaction utime.sleep(0.01) # Wait 10ms while ASTOP.value() == True: #Turn on the red LED for as long as the ASTOP chip signal is high (true). Once this line goes low, the audio bite is done playing. REDLED.value(1) # Turn on the red LED REDLED.value(0) # When the while loop ends, the audio bite has completed, and the LED turns off. print("Done...") def Samplelight(): # This function samples and prints the voltage on the light sensor print("Sampling Light...") # Print this to the shell #print("Light Sensor Value",LightSensor.read_u16()) hold = LightSensor.read_u16() #Read the light sensor 16-bit value (u16) and store it in "hold" hold = hold*conversion # Multiply "hold" by "conversion" to convert the value into a value representative of voltage. print(hold,"v") # If you look above in the code, you'll see that "conversion" equals 3.3v/65535, which is the full scale... # voltage divided by the full 16bit decimal value of 65535. Once done, print the value, followed by "v" def SampleAudio(): print("Sampling Microphone...") # Print this to the shell #print("Audio ADC Value",Microphone.read_u16()/conversion) hold = Microphone.read_u16() # This function works exactly like the Samplelight() function above. hold = hold*conversion print(hold,"v") def NoiseTest(): # This function waits for a loud sound like a clap. This tests the microphone. print("Waiting for noise...") # Print this to the shell global state # "state" has already been definded, but declaring this as a "gloabl" in thsi function means that we can work with it state = 0 # Clear the value in "state" BLUELED.value(1) # Turn on the Blue LED while state == 0: # Loop the following while "state" equals 0 hold = Microphone.read_u16() # Sample the 16-bit microphone ADC value and store the returned value in "hold" hold = hold*conversion # Convert to voltage if(hold > 2): # If the value returned is larger than 2v, then this function will end, as "state" will be changed to 1 state = 1 # Change "State" to one BLUELED.value(0) # Turn the LED off print("Noise detected... Moving on!") # Print this to the shell, and end this function. def Buzz(): # This function turns the buzzer on and off five times. On for 0.25 seconds/250ms, then off for 250ms print("Buzzer on...") # Print this to the shell for i in range(5): # This is a FOR loop set to execute five times Buzzer.value(1) # Turn the buzzer on utime.sleep(0.25) # Wait 250ms Buzzer.value(0) # Turn the buzzer off utime.sleep(0.25) # Wait 250ms print("Buzzer off") # Once the FOR loop ends, so does this function. Print this to the shell def DIPStates(): # This function checks the states of each of the four DIP switches and prints them to the shell print("DIP Switch Status Check:") # Print this to the shell if DIPA.value() == True: # If DIP Channel-A is seeing 5v, then it is turned off. If it sees 0v, then it is turned on. print("DIP Channel-A is OFF...") # If off, Print this to the shell else: print("DIP Channel-A is ON...") # Otherwise, print this to the shell instead. The remainder of this function checks all other channels. if DIPB.value() == True: print("DIP Channel-B is OFF...") else: print("DIP Channel-B is ON...") if DIPC.value() == True: print("DIP Channel-C is OFF...") else: print("DIP Channel-C is ON...") if DIPD.value() == True: print("DIP Channel-D is OFF...") else: print("DIP Channel-D is ON...") ####################################################The following section is all for the RTC def print_date(): # This function has a lot going on, so try to stay with me here. The goal is to read the RTC, and print the date to the shell global address # Set the address variable/integer as a global so that it can be used across all functions address = 0 # Set address to 0 so that when the below function is called, there is a pointer. It will make sense when you see the function. secs = read_i2c() # Call this function to read back the "seconds" value in the RTC and place the value in "secs" to be used later address = 1 # Set address to 1 mins = read_i2c() # Now call the same read_i2c() function again with the address pointer set to 1. Place the result in "mins" address = 2 # Set the address pointer to 2 hours = return_hours_or_months() # For hours, we'll call a different function. This is because the hours and months registers are formtted... # differently than the seconds and minutes registers address = 3 # Set the address pointer to 3 day = read_i2c() # Call the read_i2c() function again and place the result in "day" if day == 1: # This fullowing section changes the value in "day" into a word. day = "Monday" # If day equals 1, then change day into "monday". The rest of this section shoud be self explanitory. elif day == 2: day = "Tuesday" elif day == 3: day = "Wednesday" elif day == 4: day = "Thursday" elif day == 5: day = "Friday" elif day == 6: day = "Saturday" else: # If day equals anything over than 6, then change day to "Sunday" day = "Sunday" address = 4 # Set the address pointer to 4. date = read_i2c() # Call the read_i2c function and place the result in "date" address = 5 # Set the address pointer to 5 month = return_hours_or_months() # Call this function and place the result in "month" if month == 1: # Look familiar? This is another decoder section that changes the value in month into a word. month = "January" elif month == 2: month = "February" elif month == 3: month = "March" elif month == 4: month = "April" elif month == 5: month = "May" elif month == 6: month = "June" elif month == 7: month = "July" elif month == 8: month = "August" elif month == 9: month = "September" elif month == 10: month = "October" elif month == 11: month = "November" else: month = "December" address = 6 # Set the address pointer to 6 year = read_i2c() # Call the read_i2c() function and place the result in year. year+=2000 # Add 2000 to the result. For 2021, the result would only be 21. print(day,"//",month,date,"//",day,"//","Time: ",hours,":",mins,":",secs, " // Year:",year) # Print the date to the shell! # This is the end of this function def new_time(): #My current time is Monday June 14th, 9:10.00 AM. This code writes your time to the RTC. Make changes as needed. i2c.writeto_mem(104, 0, b'\x00') # seconds // 0-60 seconds // Set to 0 seconds i2c.writeto_mem(104, 1, b'\x10') # minutes // minutes = 0-59 // Set to 10 minutes i2c.writeto_mem(104, 2, b'\x09') # hours // hours = 0-23 i2c.writeto_mem(104, 3, b'\x01') # day // 7th day (Sunday) i2c.writeto_mem(104, 4, b'\x14') # date // Month days (0-31) i2c.writeto_mem(104, 5, b'\x06') # month // Months 0-11 i2c.writeto_mem(104, 6, b'\x21') # year // 2021 def bytes_to_int(bytes): result = 0 for b in bytes: result = result + int(b) #print(result) return result def read_i2c(): # This function reads the RTC for time data, and changes it from a byte into a useable integer. #print(i2c.scan()) # This scans and prints out any I2C addresses on the line bytes = i2c.readfrom_mem(104,address,1)# The RTC address is 104. The data address is pointed to by "address" and we want to read "1" byte #utime.sleep(1)# sleep for one second x = bytes_to_int(bytes) # Call the butes_to_int function to turn the read-back value from a byte into an int, and return into x b = [] # Create a new and empty list (b) counter = 0 while(x>0): # while the value in x is more greater than 0 counter+=1 # we'll use this to see how many bits there are in b d=x%2 # Add 2 to x? b.append(d) # add d to the end of the list (b) x=x//2 # b.reverse() # #print("Binary Equivalent is: ") # The following section changes the returned byte into an integer. It was huge pain to get working! #print(b) #print(counter) val = 0 if counter > 0: if b[-1] == 1: val = val + 1 if counter > 1: if b[-2] == 1: val = val + 2 if counter > 2: if b[-3] == 1: val = val + 4 if counter > 3: if b[-4] == 1: val = val + 8 if counter > 4: if b[-5] == 1: val = val + 10 if counter > 5: if b[-6] == 1: val = val + 20 if counter > 6: if b[-7] == 1: val = val + 40 #print(val) return(val) def return_hours_or_months(): #print(i2c.scan()) # This scans and prints out any I2C addresses on the line bytes = i2c.readfrom_mem(104,address,1) # Tell RTC (104) to read back '1' byte of data from data address pointed to by the "address' pointer #utime.sleep(1) # sleep for one second x = bytes_to_int(bytes) # Call the butes_to_int function to turn the read-back value from a byte into an int, and return into x b = [] # Create a new and empty list (b) counter = 0 while(x>0): # while the value in x is more greater than 0 counter+=1 # we'll use this to see how many bits there are in b d=x%2 # Add 2 to x? b.append(d) # add d to the end of the list (b) x=x//2 # b.reverse() # #print("Binary Equivalent is: ") #print(b) #print(counter) # The following section changes the returned byte into an integer. val = 0 if counter > 0: if b[-1] == 1: val = val + 1 if counter > 1: if b[-2] == 1: val = val + 2 if counter > 2: if b[-3] == 1: val = val + 4 if counter > 3: if b[-4] == 1: val = val + 8 if counter > 4: if b[-5] == 1: val = val + 10 #print(val) return(val) ############################################################################################### This is the end of the RTC functions def heartrate(): print("Heart to LED Test") while Button2.value() == True: hold = HeartSensor.read_u16() hold = hold*conversion if hold < 1.5: REDLED.value(1) else: REDLED.value(0) REDLED.value(0) print("Done...") utime.sleep(3) def heartbeataverage(): # This function will average your heart rate and offer a visual representation on the red LED. print("Average your Heartrate. Press Button#1/SW1 to end this sequence") # Print this to the shell state = 0 # Introduce variables state, timer, counter, and hearthold to 0. timer = 0 counter = 0 hearthold = 0 LEDRED.value(0) # Turn the red LED off while state == 0: # Loop the following while state equals 0. We're waiting here for a low voltage. No beat. # This first while loop waits for a "High/heart beat" to end so that we can start fresh with a new beat. hold = HeartSensor.read_u16() # Sample the heart sensor and take an ADC reading. Place the result into hold. hold = hold*conversion # Convert the ADC value into a voltage representation. See previous projects for more info if hold < 1.5: # If the heart sensor voltage is less than 1.5v, then do the following: utime.sleep(0.01) # Sleep for 10ms state = 1 # Set state to 1 to end the while loop, as we've recevived a heart beat # With the above while loop being done, we can now start timing our heart beats while Button.value() == True: # If you press button#1, it will end this sequence quickly and nullify the result. state = 0 # Set state to 0 LEDRED.value(1) # Turn the LED on while state == 0: # Do the following while state equals 0 timer = timer + 1 # Add one to timer. Increment timer by 1. This timer times the frequency of our heart rate. utime.sleep(0.001) # Wait 1ms hold = HeartSensor.read_u16() # Sample the heart rate sensor ADC and place the result into hold hold = hold*conversion # Convert to voltage if hold < 1.5: # If no beat is detected, set state to 1 state = 1 # See above LEDRED.value(0) # Turn the LED off while state == 1: # Loop the following while state is 1 timer = timer + 1 # Add one ti timer utime.sleep(0.001) # Wait 1ms hold = HeartSensor.read_u16() # Sample the heart sensor, place in hold, convert to voltage. hold = hold*conversion # See above if hold > 1.5: # If a heart beat is detected, set state back to 0 state = 0 # State now equals 0 counter = counter + 1 # Add one to counter timer = 60000 / timer # change the value in timer by dividing itself by 60000ms (60 seconds) hearthold = hearthold + timer # Add the new timer value to hearthold if counter == 10: # If counter equals ten, then we've taken ten heart beat samples hearthold = hearthold / 10 # If so, divide the value in hearthold by 10 and we'll get our averaged heartbeat. if hearthold < 200: # Only print to the shell if the value is realistic. 200BPM isn't realistic. If is a false reading. print("Heartrate Average:",hearthold,"BPM") # Print this to the shell else: print("Invalid Measurement...") # If the value was higher than 200, print this to the shell counter = 0 # Reset all variables and start again. timer = 0 hearthold = 0 timer = 0 timer = 0 print("Done...") # Print the following to the shell. while True: # This is the main loop. It will run a diagnostic loop on every electronic block on the board sequentially. print("Running System Diagnostics") # Print this to the shell hold = '\x00' # Set hold (pointer) to have a byte value of of '0', which will play the first sound bite on the LBT chip playaudio() # Call the playaudio function to play the sound bite. Samplelight() # Call the Samplelight() function SampleAudio() # Call the SampleAudio() function NoiseTest() # Call the NoiseTest() function utime.sleep(0.1) # Sleep for 100ms Buzz() # Test the buzzer by calling the Buzz() function DIPStates() # Call the DIPStates() function heartrate() # Call the heartrate() function heartbeataverage() # Average your heart rate by calling the heartbeataverage() function if DIPA.value() == True: # If DIP Switch (A) is ON, set a new time based on the values you've set in the new_time() function new_time() else: # Otherwise, call the print)date() function. print_date() # This is the end of the code, It will now loop back to the top, and re-execute all functions in order.