New Ticker

News Ticker
Epstien didn't kill himself.
Epstien didn't kill himself.
Epstien didn't kill himself.
Epstien didn't kill himself.

Saturday, August 24, 2024

Coding for ATTiny microprocessor chips

It's better to use an ATTiny microprocessor than an Arduino or Raspberry development board such as the Arduino Nano or the Raspberry Pi Pico. When it comes to chips like the ATTiny13, space is at a premium. This microconroller has only 1K for program storage and 64 bytes for variables. While program memory can be used for storage via progmem, a different programming technique is worthwhile for such small microcontrollers.
The 8-pin chip in the middle of the small breadboard is the ATTiny13A micro-controller. Small but mighty.

This is a C++ Morse Code program creator written in Python.
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Fri Aug 23 20:20:01 2024

@author: zephod beeblebrox
"""

# Morse Code Dictionary
MORSE_CODE_DICT = {
    'A': '.-', 'B': '-...', 'C': '-.-.', 'D': '-..', 'E': '.', 'F': '..-.',
    'G': '--.', 'H': '....', 'I': '..', 'J': '.---', 'K': '-.-', 'L': '.-..',
    'M': '--', 'N': '-.', 'O': '---', 'P': '.--.', 'Q': '--.-', 'R': '.-.',
    'S': '...', 'T': '-', 'U': '..-', 'V': '...-', 'W': '.--', 'X': '-..-',
    'Y': '-.--', 'Z': '--..', '1': '.----', '2': '..---', '3': '...--',
    '4': '....-', '5': '.....', '6': '-....', '7': '--...', '8': '---..',
    '9': '----.', '0': '-----', ', ': '--..--', '.': '.-.-.-', '?': '..--..',
    '/': '-..-.', '-': '-....-', '(': '-.--.', ')': '-.--.-', ' ': '/'
}

def message_to_morse(message):
    # Convert message to uppercase
    message = message.upper()

    for char in message:
        if char == ' ':
            print("    delay(WORD_SPACE - LETTER_SPACE);")
        else:
            morse_char = MORSE_CODE_DICT.get(char, '')
            for i, symbol in enumerate(morse_char):
                if symbol == "-": 
                    print ("    sendDash();") 
                if symbol == ".": 
                    print("    sendDot();")
#                print(symbol)
                if i < len(morse_char) - 1:
                   print("    delay(SYMBOL_SPACE);")
            print("    delay( LETTER_SPACE - SYMBOL_SPACE);")

if __name__ == "__main__":
    # Input message from user
    message = input("//Enter your message: ")

    print("#define DOT_DURATION 50   // Duration of a dot in milliseconds")
    print ("#define DASH_DURATION (3 * DOT_DURATION)   // Duration of a dash")
    print ("#define SYMBOL_SPACE DOT_DURATION   // Space between symbols in the same letter")
    print("#define LETTER_SPACE (3 * DOT_DURATION)   // Space between letters")
    print("#define WORD_SPACE (7 * DOT_DURATION)   // Space between words")
    print("#define MESSAGE_DELAY 30000   // 30-second delay between messages")
    print("#define MORSE_PIN 4   // Define the pin used for Morse code output")
    print("void sendDot() {")
    print("    digitalWrite(MORSE_PIN, HIGH);   // Set the pin high")
    print("    delay(DOT_DURATION);")
    print("    digitalWrite(MORSE_PIN, LOW);   // Set the pin low")
    print("    }")
    print("void sendDash() {")
    print("    digitalWrite(MORSE_PIN, HIGH);   // Set the pin high")
    print("    delay(DASH_DURATION);")
    print("    digitalWrite(MORSE_PIN, LOW);   // Set the pin low")
    print("    }")
    print("void setup() {")
    print("    pinMode(MORSE_PIN, OUTPUT);   // Set the pin as an output")
    print("}")
    print("void loop() {")

    # Convert and print in Morse code format
    message_to_morse(message)
    
    print("    delay(MESSAGE_DELAY);")
    print("}") 

Entering a simple message such as "a b c" produces this output:

 //Enter your message: a b c

#define DOT_DURATION 50   // Duration of a dot in milliseconds

#define DASH_DURATION (3 * DOT_DURATION)   // Duration of a dash

#define SYMBOL_SPACE DOT_DURATION   // Space between symbols in the same letter

#define LETTER_SPACE (3 * DOT_DURATION)   // Space between letters

#define WORD_SPACE (7 * DOT_DURATION)   // Space between words

#define MESSAGE_DELAY 30000   // 30-second delay between messages

#define MORSE_PIN 4   // Define the pin used for Morse code output

void sendDot() {

    digitalWrite(MORSE_PIN, HIGH);   // Set the pin high

    delay(DOT_DURATION);

    digitalWrite(MORSE_PIN, LOW);   // Set the pin low

    }

void sendDash() {

    digitalWrite(MORSE_PIN, HIGH);   // Set the pin high

    delay(DASH_DURATION);

    digitalWrite(MORSE_PIN, LOW);   // Set the pin low

    }

void setup() {

    pinMode(MORSE_PIN, OUTPUT);   // Set the pin as an output

}

void loop() {

    sendDot();

    delay(SYMBOL_SPACE);

    sendDash();

    delay( LETTER_SPACE - SYMBOL_SPACE);

    delay(WORD_SPACE - LETTER_SPACE);

    sendDash();

    delay(SYMBOL_SPACE);

    sendDot();

    delay(SYMBOL_SPACE);

    sendDot();

    delay(SYMBOL_SPACE);

    sendDot();

    delay( LETTER_SPACE - SYMBOL_SPACE);

    delay(WORD_SPACE - LETTER_SPACE);

    sendDash();

    delay(SYMBOL_SPACE);

    sendDot();

    delay(SYMBOL_SPACE);

    sendDash();

    delay(SYMBOL_SPACE);

    sendDot();

    delay( LETTER_SPACE - SYMBOL_SPACE);

    delay(MESSAGE_DELAY);

}

And the Arduino compiler gives this message:

Sketch uses 414 bytes (40%) of program storage space. Maximum is 1024 bytes.

Global variables use 4 bytes (6%) of dynamic memory, leaving 60 bytes for local variables. Maximum is 64 bytes. 

Sunday, July 14, 2024

Reading analogue values on the Pi Pico

Fairly straightforward but take care with the pin positions. It's a case of connecting the centre pin of the potentiometer to the ADC pin, either of the two other pins to vref and the remaining pin to GND. The photo below looks good but the wires are on the wrong side of the board. They should be on the other side.

That was what NOT to do. Instead, let's install the jumpers correctly as below.


Having installed the jumpers it's possible to run the code and twiddle the preset with a jewelers screwdriver. Notice how the value returned from the ADC now changes.


And finally, here's the code: 

import machine
import utime
 
analog_value = machine.ADC(0)
 
while True:
    reading = analog_value.read_u16()     
    print("ADC: ",reading, " binary ", bin(reading), " test ", int(reading/256))
    utime.sleep(0.2)

All very simple and... it works.
 

Sunday, January 14, 2024

Using the IdeaSpark Nano091OLED

 The C++ code for the project is as follows:

#include <U8g2lib.h>

#include <U8x8lib.h>

#include <MUIU8g2.h>

#include<Arduino.h>

#ifdef U8X8_HAVE_HW_SPI

#include <SPI.h>

#endif

U8G2_SSD1306_128X32_UNIVISION_F_SW_I2C u8g2(U8G2_R0, A5, A4, U8X8_PIN_NONE);

void setup() {

  u8g2.begin();

}

void loop() {

  u8g2.clearBuffer();

  u8g2.setFont(u8g2_font_ncenB08_tr);

  u8g2.drawStr(0,10,"Hello, Ideaspark");

  u8g2.drawStr(0,25, "Nano V3 0.91""    OLED");

  u8g2.sendBuffer();

  delay(1000);

  u8g2.clearBuffer();

  u8g2.setFont(u8g2_font_ncenB08_tr);

  u8g2.drawStr(0,10,"BritishTechGuru");

  u8g2.drawStr(0,25, "The hairy dude!");

  u8g2.sendBuffer();

  delay(1000);

}


To use this, you need the latest version of the Arduino IDE (packaged as flatpak). Do not use the version that downloads from the Linux Mint app store. Use Sudo to install it.

Once you have that, install the library U8g2 then set the board to Arduino Nano and the Processor to AT Mega 328P

Then enter the code as shown and run it.


Your expected result will be an alternating display that states 

Hello, Ideaspark

Nano V3 0.91    OLED

then 

BritishTechGuru

The hairy dude!

The display flickers a bit at a delay of 1,000 but at a delay of 100 it's hard to see what is displayed. This is a very handy way of displaying vital statistics from a process without having to include an LED and all the wiring for that in a project.

Saturday, September 17, 2022

Basic Python external components

For those struggling with basic Python and coding, here's a very simple piece of code that might help you a lot.

Set this code as Main.py

#!/usr/bin/env python3

# -*- coding: utf-8 -*-

"""

Created on Sat Sep 17 10:34:38 2022

@author: nobody

"""

import imp

try:

    imp.find_module('externalsubroutine')

    found = True

    print("subroutine exists")

except ImportError:

    found = False

    print("Subroutine is missing")

#from externalsubroutine import Testit

import externalsubroutine

externalsubroutine.Testit()

print("Adding 5 and 6")

print(externalsubroutine.ReturnValue(5,6))

 


Now set this code in a file called "externalsubroutine.py"

#!/usr/bin/env python3

# -*- coding: utf-8 -*-

"""

Created on Sat Sep 17 10:31:47 2022

@author: nobody

"""

#try to code an external subroutine

def Testit():

    print("yeah, that works")

def ReturnValue(num1, num2):

    num3 = num1 + num2

    return num3

   

 When you run the code, your output should look similar to this:

runfile('/home/CERN/projects/external subroutines/mainstuff.py', wdir='/home/CERN/projects/external subroutines')

subroutine exists

yeah, that works

Adding 5 and 6

11


Congratulations - you can now put different batches of code into external library files. 

Sunday, August 7, 2022

How to calculate I2C addresses on a Raspberry Pi using Python

Occasionally when programming on a RP2040 it's necessary to identify the port an I2C address is using. This helps..

import machine

 

sda=machine.Pin(0)

scl=machine.Pin(1)

 

i2c=machine.I2C(0,sda=sda, scl=scl, freq=400000)

 

print('I2C address:')

print(i2c.scan(),' (decimal)')

print(hex(i2c.scan()[0]), ' (hex)') 

Saturday, August 6, 2022

Calculating distances between grid coordinates

 Calculating distances is more challenging than compass directions. There are three methods. One is the geometric method which is accurate enough but needs to be recalculated every 50 miles for real accuracy. Another is the Haversine method which is accurate to within about 10% and which was used for well over a hundred years. The best, however is the Vincenty method which is accurate to within 0.5mm.

Here's code comparing all 3 methods...

from vincenty import vincenty

import math

# Python 3 program for the

# haversine formula

def haversine(lat1, lon1, lat2, lon2):

     

    # distance between latitudes

    # and longitudes

    dLat = (lat2 - lat1) * math.pi / 180.0

    dLon = (lon2 - lon1) * math.pi / 180.0

 

    # convert to radians

    lat1 = (lat1) * math.pi / 180.0

    lat2 = (lat2) * math.pi / 180.0

 

    # apply formulae

    a = (pow(math.sin(dLat / 2), 2) +

         pow(math.sin(dLon / 2), 2) *

             math.cos(lat1) * math.cos(lat2));

    rad = 6371

    c = 2 * math.asin(math.sqrt(a))

    return rad * c

 

# Driver code

if __name__ == "__main__":

    lat1 = 51.5081

    lon1 = 0.0759

    lat2 = 48.8738

    lon2 = -2.2950

     

    print("Haversine distance in miles ",haversine(lat1, lon1,lat2, lon2)/1.6)

    

 

# This code is contributed

# by ChitraNayal


LocationOneV = lon1

LocationTwoV = lon2

LocationOneH = lat1

LocationTwoH = lat2

#My own version of distance created using the flat earth model

    #Distance calculation

DistanceV = (LocationOneV - LocationTwoV) *54.6

DistanceH = (LocationOneH - LocationTwoH) *68.7

DistanceCalc = (DistanceV*DistanceV)+(DistanceH*DistanceH)

ActualDistance = math.sqrt(DistanceCalc)

print("Distance in Miles using flat earth calculation ", ActualDistance)


TowerOfLondon = (51.5081, 0.0759)

ArcDeTriomph = (48.873756, 2.294946)

print("Vincenty miles ", vincenty(TowerOfLondon, ArcDeTriomph , miles=True))


This, of course, required the Vincenty library which is here:

import math


# WGS 84

a = 6378137  # meters

f = 1 / 298.257223563

b = 6356752.314245  # meters; b = (1 - f)a


MILES_PER_KILOMETER = 0.621371


MAX_ITERATIONS = 200

CONVERGENCE_THRESHOLD = 1e-12  # .000,000,000,001



def vincenty_inverse(point1, point2, miles=False):

    """

    Vincenty's formula (inverse method) to calculate the distance (in

    kilometers or miles) between two points on the surface of a spheroid


    Doctests:

    >>> vincenty((0.0, 0.0), (0.0, 0.0))  # coincident points

    0.0

    >>> vincenty((0.0, 0.0), (0.0, 1.0))

    111.319491

    >>> vincenty((0.0, 0.0), (1.0, 0.0))

    110.574389

    >>> vincenty((0.0, 0.0), (0.5, 179.5))  # slow convergence

    19936.288579

    >>> vincenty((0.0, 0.0), (0.5, 179.7))  # failure to converge

    >>> boston = (42.3541165, -71.0693514)

    >>> newyork = (40.7791472, -73.9680804)

    >>> vincenty(boston, newyork)

    298.396057

    >>> vincenty(boston, newyork, miles=True)

    185.414657

    """


    # short-circuit coincident points

    if point1[0] == point2[0] and point1[1] == point2[1]:

        return 0.0


    U1 = math.atan((1 - f) * math.tan(math.radians(point1[0])))

    U2 = math.atan((1 - f) * math.tan(math.radians(point2[0])))

    L = math.radians(point2[1] - point1[1])

    Lambda = L


    sinU1 = math.sin(U1)

    cosU1 = math.cos(U1)

    sinU2 = math.sin(U2)

    cosU2 = math.cos(U2)


    for iteration in range(MAX_ITERATIONS):

        sinLambda = math.sin(Lambda)

        cosLambda = math.cos(Lambda)

        sinSigma = math.sqrt((cosU2 * sinLambda) ** 2 +

                             (cosU1 * sinU2 - sinU1 * cosU2 * cosLambda) ** 2)

        if sinSigma == 0:

            return 0.0  # coincident points

        cosSigma = sinU1 * sinU2 + cosU1 * cosU2 * cosLambda

        sigma = math.atan2(sinSigma, cosSigma)

        sinAlpha = cosU1 * cosU2 * sinLambda / sinSigma

        cosSqAlpha = 1 - sinAlpha ** 2

        try:

            cos2SigmaM = cosSigma - 2 * sinU1 * sinU2 / cosSqAlpha

        except ZeroDivisionError:

            cos2SigmaM = 0

        C = f / 16 * cosSqAlpha * (4 + f * (4 - 3 * cosSqAlpha))

        LambdaPrev = Lambda

        Lambda = L + (1 - C) * f * sinAlpha * (sigma + C * sinSigma *

                                               (cos2SigmaM + C * cosSigma *

                                                (-1 + 2 * cos2SigmaM ** 2)))

        if abs(Lambda - LambdaPrev) < CONVERGENCE_THRESHOLD:

            break  # successful convergence

    else:

        return None  # failure to converge


    uSq = cosSqAlpha * (a ** 2 - b ** 2) / (b ** 2)

    A = 1 + uSq / 16384 * (4096 + uSq * (-768 + uSq * (320 - 175 * uSq)))

    B = uSq / 1024 * (256 + uSq * (-128 + uSq * (74 - 47 * uSq)))

    deltaSigma = B * sinSigma * (cos2SigmaM + B / 4 * (cosSigma *

                 (-1 + 2 * cos2SigmaM ** 2) - B / 6 * cos2SigmaM *

                 (-3 + 4 * sinSigma ** 2) * (-3 + 4 * cos2SigmaM ** 2)))

    s = b * A * (sigma - deltaSigma)


    s /= 1000  # meters to kilometers

    if miles:

        s *= MILES_PER_KILOMETER  # kilometers to miles


    return round(s, 6)


vincenty = vincenty_inverse


if __name__ == '__main__':

    import doctest

    doctest.testmod()


 

Friday, August 5, 2022

Direction given two grid coordinates

 This is the code to calculate a compass bearing given two geographical coordinates.

#!/usr/bin/env python3

# -*- coding: utf-8 -*-

"""

Created on Tue Jul 19 12:04:26 2022

"""

import math

DiameterOfEarth = 7917.5

RadiusOfEarth = 3961


#Assumung two fixed point - just for the sake of making life easy...

#North = positive values. South = negative values

#West = Positive values, East = negative values

LocationOneV = 51.5081

LocationOneH = 0.0759

#Tower of London


LocationTwoV = 48.8738

LocationTwoH = -2.2950

#Arc de Triomph


X = math.cos(LocationTwoV)*math.sin(LocationOneH-LocationTwoH)

Y = (math.cos(LocationOneV)*math.sin(LocationTwoV)-math.sin(LocationOneV)*

    math.cos(LocationTwoV)*math.cos(LocationOneH-LocationTwoH))

Radians = math.atan2(X,Y)  #radians

print("radians ", Radians)

Degrees = math.degrees(Radians)

print ("Degrees", Degrees)

That was pretty easy, wasn't it?