Archive for the ‘programmering’ Category

Enkelt elektronikprojekt

19/10/2022

Jag har två drontyper som jag regelbundet flyger med. DJI:s Phantom samt Yuneec Typhoon. Dronerna är rätt likvärdiga ur flygsynvinkel och kamerornas kvalitet är mycket lika. Det finns dock en betydande skillnad mellan dronfamiljerna.

Dji använder intelligenta batterier d.v.s. laddningslogiken finns i själva batteriet. Batteriet kan alltså helt autonomt följa med sin egen användning vilket är viktigt då man använder moderna LitiumPolymer (LiPo) batterier. Ett LiPo batteri tycker inte om att vara tomt men det skadas också på sikt av att vara fulladdat. Egenskaperna hos ett felbehandlat batteri förändras bl.a. så att batteriets inre motstånd stiger vilket ur dronens synvinkel syns som höjd batteritemperatur under flygningen och kortare flygtid. Dji:s batterier laddar själja ur sig till ca. 60% laddningsnivå inom några dagar om batteriet inte används efter laddning.

Yuneecs batterier är inte intelligenta d.v.s. hela underhållsansvaret faller på användaren. Det är på mitt asnsvar att se till att batterier då de lagras har en laddningsgrad kring 60% för att livslängden skall bli så lång som möjligt. Ett hjälpmedel som jag har för detta ändamål är en intelligent laddare (inte Yuneecs laddare) som har olika program för laddning, urladdning och underhållsladdning. Det jag har saknat är ett enkelt sätt att mäta batteriernas inre motstånd och det är detta denna artikel kommer att handla om.

Då ett batteri belastas kommer det att ske ett inre spänningsfall i batteriet d.v.s. den spänning man ser över batteriets poler kommer att sjunka vilket betyder att t.e.x. en drons varningssystem för låg batterispänning slår på allt tidigare ju högre det inre motståndet blir. Om dronen vid flygning behöver t.e.x. 2A ström kommer ett inre motstånd på 70 milliohm att sänka batteriets spänning med 0,14 V vilket motsvarar flera minuters flygning.

När skall jag kasta ett batteri

Ett batteri är slut då flygtiden blir för kort samt då batteriet eventuellt börja uppföra sig konstigt d.v.s. det kan efter någon minuts flygning ge en batterivarning som tvingar fram en plötslig påtvingad landning för att undvika krasch. Ett sätt att se när ett batteri börjar nå slutet av sitt liv är att mäta det inre motståndet samt naturligtvis ibland mäta den effektiva flygtiden med ett batteri.

Mätning av det inre motståndet

Bilden visar, i form av ett kretsschema, ett batteri som belastas över ett motstånd. För att kunna beräkna det inre motståndet måste vi mäta batteriets spänning obelastat (i vila) samt spänningen då batteriet är belastat. Vi vill också undvika lång urladdning innan vi mäter det belastade batteriets spänning eftersom belastningen också medför att spänningen sjunker till följd av att batteriet laddas ur.

Mätning av batteriets spänning med voltmätaren (V) obelastat då switchen är öppen och belastat då batteriet urladdas genom lastmotståndet Rl.

Då batteriet är obelastat så går det nästan ingen ström genom batteriet, endast en mycket liten läckström går genom voltmätaren kanske 1 uA. Detta betyder att den spänning voltmätaren mäter är batteriets spänning eftersom spänningsfallet över Ri är ungefär lika med noll.

Då man sluter switchen SW kommer batteriet att laddas ur med en ström som beroende av batterityp är mellan 1 och 1.5 A. Batteriets inre motstånd kommer då att leda till ett spänningsfall inne i batteriet med storleken strömmen*inre_motståndet eller Ui=I*Ri . I prktiken kan man se detta så att spänningen sjunker då batteriet laddas ur.

Då batteriet är obelastat är den mätta spänningen:

Vb = det obelastade batteriets polspänning

Då batteriet belastas mäter vi en spänning:

(1) Vl = Vb – I*Ri

Där:

I = strömmen genom lastmotståndet som vi i mitt fall vet att det är 10 ohm

Rl = lastmotståndet 10 ohm

Ri = batteriets okända inre motstånd

Vb = det obelastade batteriets spänning.

Strömmen kan vi beräkna ur den mätta spänningen med last:

(2) I = Vl/Rl

Vi kan lösa Ri ur ekvation (1) och får då:

(3) Ri = (Vb-Vl)/I

Vi byter ut I ekvation (3) mot I taget ur (2) och får då:

(4) Ri = Rl * (Vb-Vl)/Vl

Vi ser alltså att vi helt änkelt gör två spänningsmätningar den första med obelastat batteri och den andra med ett belastat batteri och därefter lägger vi in värdet i (4) tillsammans med det kända vädet på Rl=10 ohm. Lätt som en plätt där inget kan gå fel eller hur?

En Arduino Uno är ett billigt litet mikroprocessorkort med en trevlig utvecklingsomgivning. Processorn har en AD-konverter (voltmätare) med upplösningen 10 bitar d.v.s. mätområdet 0 … 5V delas in i 1024 spänningssteg. Den enklaste mätaren kunde således byggas utgående från en Arduino Uno kopplad till ett 5V relä som styr mätning av obelastat respektive belastat batteri.

Jag skrev ett litet program som gjorde ovanstående mätningar med hjälp av Uno:s AD-konverter. Resultatet blev negativa värden på den inre resistansen. Hur kan jag få negativa värden på den inre resistansen? Då vi tittar på ekvation (4) så ser vi att spänningen med last då måste vara större än det obelastade batteriets polspänning! Hur är detta möjligt?

Uno:s AD-konverter tar sin referensspänning från processorkortets 5V matningsspänning. Ett relä drar rätt mycket ström d.v.s. när relät aktiveras d.v.s. SW är slutet kommer hela processorkortets spänning att sjunka till ca. 4,5V. Plötsligt blev referensspänningen 4,5 i stället för 5V och resultatet är att det ryms 1024 spänningssteg i 0…4,5V i stället för 0…5V d.v.s. steglängden minskar och då processorn mäter det belastade batteriets spänning tror den sig mäta en spänning som är större än det obelastade batteriets spänning.

Lösningen som samtidigt testar diagnosen var att mata relät med ett separat spänningsaggregat. Processorns spänning hålls bättre konstant och felen minskar radikalt.

Nu dyker följande problem upp. Mätningar av riktiga batterier tyder på att upplösningen d.v.s. den precision vi kan uppnå vid mätningen blir av storleksorningen 10 milliOhm vilket är nästan 25% av det inre motståndet i ett typiskt batteri. En enkel kontroll visar vad detta problem beror på.

Antag att inspänningen till AD-konvertern är något över halva maxspänningen t.ex. 3.5 volt vilket motsvarar ett mätvärde på 716 enheter av 1024. Antag nu att Vb och Vl skiljer med endast en enhet och att lastmotståndet är 10 ohm. Det minsta resistansvärdet vi då kan mäta får vi genom att beräkna:

Ri = 10*(716-715)/715 = 14 milliohm … inte bra!

Slutsatsen blev att mätaren måste få en bättre AD-konverter. Ett alternativ kunde ha varit att gå över till en ARM-baserad ”BluePill” processor som erbjuder en 12-bitars AD-konverter d.v.s. med samma uppställning som för Uno och omkompilering av programkoden kunde jag få fyra gånger bättre upplösning d.v.s. ungefär 3.5 milliOhm vilket är betydligt bättre. Ett annat alternativ hittade jag i miljonlådan i form av ett litet kretskort som jag nångång skaffade för ett annat projekt. Kretsen ADS1115 erbjuder en fyrkanalig 16-bitars AD-konverter som kontrolleras över en seriebus I2C. Genom att använda ADS1115 kunde jag fortsätta att använda Arduino Uno men mäta spänningar med god precision. Voltmätaren ADS1115 marknadsförs som 16-bitars men i praktiken är det en 15-bitars konverter då jag mäter positiva spänningar. 15 bitar ger 32768 spänningssteg d.v.s. 32 ggr bättre än Uno.

Mätprogrammet går på 60-rader vilket väl ryms i en Arduino Uno som erbjuder 32k minne för program (en Commodore 64 från ungefär 1980 hade ungefär den här kapaciteten). Programmet använder ett färdigt bibliotek för kontroll av ADS1115 vilket gör programmeringen mycket enklare …

// Name= resistance_ADS1115
// Lars Silen 2022
// This is free source code. Feel free to copy and modify.

#include "Arduino.h"
#include "ADS1115-Driver.h"

#define Rly 6
uint16_t V_battery;
uint16_t V_load;
float R;
float loadResistance=10.1;

ADS1115 ads1115 = ADS1115(ADS1115_I2C_ADDR_GND);

uint16_t readValue(uint8_t input) {
  ads1115.setMultiplexer(input);
  ads1115.startSingleConvertion();

  delayMicroseconds(25); // The ADS1115 needs to wake up from sleep mode and usually it takes 25 uS to do that

  while (ads1115.getOperationalStatus() == 0);

  return ads1115.readConvertedValue();
}

void setup() {
  Serial.begin(9600);
  ads1115.reset();
  ads1115.setDeviceMode(ADS1115_MODE_SINGLE);
  ads1115.setDataRate(ADS1115_DR_250_SPS);
  ads1115.setPga(ADS1115_PGA_6_144);  // +/- 6.144 V
  ads1115.setMultiplexer(ADS1115_MUX_AIN0_GND);
  pinMode(Rly, OUTPUT);
}

void loop() {
    Serial.println("Program to measure the internal resistance of 3s and 4s Yuneec LiPo batteries");
    Serial.println("Ensure there is a very good contact to the battery.");
    Serial.println("Keep your finger on the battery side connector!");
    delay(1000);
    digitalWrite(Rly,LOW);  // Measure battery voltage
    delay(100);
    uint16_t V_battery = readValue(ADS1115_MUX_AIN0_GND);   
    Serial.print("V_battery: ");
    Serial.println(V_battery);
    Serial.println("Switch load to ON");
    digitalWrite(Rly,HIGH);  // Measure load voltage, switch load ON
    delay(10);
    uint16_t V_load = readValue(ADS1115_MUX_AIN0_GND);
    digitalWrite(Rly,LOW);
    Serial.print("V_load: ");
    Serial.println(V_load);
    R = (loadResistance*(V_battery-V_load)/V_load)*1000.0;
    Serial.print("Internal resdistance milliohm:");
    Serial.println(R,0);
    Serial.println();
    Serial.println();
    delay(5000);
}

Det färdiga mätsystemet visas i bilden nedan. Den alternativa plattformen ”Blue Pill” är det lilla processorkortet som ligger på det silverfärgade lilla nätaggregatet som används för att driva reläet. ”Blue Pill” används inte utan finns endast med som illustration. Blue Pill är sannolikt 10 ggr kraftfullare än en Arduino Uno. Både en Uno och Blue Pill kostar sannolikt kring en tia. En Arduino Uno, Mega eller Due är dock mycket lättare att komma igång med eftersom de har skräddarsytts för Arduino utvecklingsomgivningen.

Den färdiga mätaren. Batteriet kopplas till de två banan-honkontakterna. Lastmotståndet är den guldfärgade komponenten. Motståndet är 10 ohm och effekttåligheten 50W.

Programmet körs från Arduino IDE så att utskrift sker till ”Serial monitor”. Det vore enkelt att ansluta en LCD-skärm på vilken resultatet kunde visas. Att lägga till en skärm och på detta sätt göra mätaren oberoende av en PC lämnas som övningsuppgift till läsaren!

Ett gammalt batteri har mätts. Det inre motståndet har närstan fördubblats jämfört med ett färskt batteri. Notera att batteriet har tre celler d.v.s. den inre resistansen är ungefär 24 milliOhm per cell. I ett färskt batteri är motsvarande värde ungefär 14 milliOhm per cell.

Antik datorteknik: Att skriva program på svenska

04/02/2022

Detta är en artikel i serien ”Antik datateknik”.

Jag kommer i denna artikel att visa hur jag enkelt kan skapa en svenskspråkig variant av programmeringsspråket C, språket kallar jag sv och kompilatorn blir då csv. Notera att avsikten med denna övning är att illustrera hur enkelt det vore att erbjuda en nationell nybörejarplattform för unga programmerare. För att verifiera programspråket sv skriver jag ett program som läser in en textsträng och sänder resultatet som morsekod. Morsekoden visas också i textform. Följande steg blir att undersöka vilka förändringar jag behöver göra i koden för att programmet skall fungera på min emulerade minidator PDP11/70 som kör en gammal BSD Unix 2.11 från början av 1990-talet. Unix utvecklades i tiden på minidatorn PDP11 som klarade av att hatera flera användare på olika terminaler allt detta på en maskin med 4 MB (4 miljoner byte) minne. En modern hemdator har typiskt 2000 gånger mera minne … eller ännu mer.

Kompilering av ett program skrivet i sv görs på någon sekund. Jag kompilerar morsesändaren smorse.sv dock utan filtyp eftersom mitt kompileringsskript förenklas en aning om jag inte behöver kontrollera filtypen utan kan anta att användaren vet vad hen gör.

./csv smorse
Källkod:smorse.sv
Översättaren är definierad i swe.lex
Kompilerar översätteren swe.lex till c-kod
Kompilerar lex analysatorn till körbar maskinkod: sv
Översätter sv-programmet smorse.sv till c-kod: smorse.c
C-kod finns nu i smorse.c
Kompilerar nu till körbar maskinkod!
The executable is: smorse.run

Jag kan nu köra programmet med smorse.run

Notera att morsesändningen i ljudfilen är en annan än på skärmen ovan. En utmaning för lyssnare är att bena ut vad som sänts!

Texten nedan visar hur ”kompilatorn” för språket sv är konstruerad. Jag skriver därefter programmet smorse i språket sv för att verifiera att kompileringen fungerar. Notera att programmet på min Linux-dator genererar hörbar morsekod. PDP11 har inte ljudstöd varför jag tänker generera ett simulerat magnetband som huvuddatorn kan sända som ljud.

En elev som lär sig att programmera kommer att stöta på flera samtidiga utmaningar. Vid programmering dyker det upp nya begrepp såsom ”variabel”, ”fil”, ”adress” och många andra begrepp som inte är bekanta från vardagslivet. Eleven lär sig också ett nytt språk, mycket enkelt dock, som beskriver logiken i programmet. Det språk som ligger under de flesta programmeringsspråk idag är engelska. Om vi börjar undervisa tex. en 10-12 årig elev programmering så kan engelskan som sådan vara ett visst problem som kan göra det svårare för eleven att komma över den första tröskeln in i programmeringens värld.

En enkel lösning på problemet programmering på ett främmande språk är naturligtvis att vi i inledningsaskedet skulle låta eleverna programmera på svenska/finska/norska/estniska för att därefter då grunderna finns gå över till engelska som idag är en de facto standard.

Skulle programmering på t.ex. svenska kräva våldsamma ekonomiska resurser? Är inte utveckling av ett nytt programmeringsspråk samt kompilator för det ”nya” språket extremt dyrt? Svaret är att en enkel tvåstegskompilator kan skrivas i ungefär hundra rader kod … inte dyrt alltså!

Om någon läsare är intresserad av att experimentera med språket sv eller modifiera det för något annat språk så kan det löna sig att ta kontakt via en kommentar så skickar jag alla filerna som ett paket med epost. Jag gör inte dessa förfrågningar synliga. Programlistningar på vebben tenderar att vara opålitliga vilket kan leda till onödig felsökning om man kopierar koden direkt från skärmen.

Språket ”sv” samt kompilatorn ”csv”

Min emulerade PDP11/70 minidator kör idag på mitt arbetsbord och jag måste således hitta på något vettigt leksaksprojekt. Jag kör BSD Unix v2.11 på PDP11:an vilket betyder att jag har tillgång till i princip samma programmeringsverktyg som på min huvuddator d.v.s. en kompilator för språket ”c” (kompilatorn heter cc) samt verktyget lex (lex har jag använt mycket sällan).

Ett trevligt miniprojekt kunde då vara att skapa ett svenskt programmeringsspråk som strukturellt är identiskt med programmeringsspråket ”c” under Unix/Linux. Tanken är att det skall vara möjligt att koda helt i ”sv” eller koda i en hybridmiljö där det är möjligt att använda ”c” direkt utan att programmets funktion påverkas. Tanken är att översätta ”sv” till normalt ”c” som därefter kompileras till maskinspråk som vilket normalt c-program som helst.

Fördelen med att använda c som mellanliggande språk är naturligtvis at jag inte behöver skriva den egentliga kompilatorn och maskinkodsgeneratorn (jag har för många år sedan skrivit ett komplett programmeringsspråk ”sil=simple language). Problemet är alltså att skriva en översättare från
språket sv till språket c.

Unix ger tillgång till två klassiska verktyg för att skapa kompilatorer
lex (lexical analyzer) och yacc (yacc=yet another compiler compiler). Jag har aldrig tidigare aktivt använt någondera. Programmet ”lex” kan enkelt sköta översättningen från sv till c d.v.s. jag behöver inte yacc eftersom min kompilator redan finns under förutsättning att det program lex producerar förmår att skapa kompilerbar c-kod.

Jag definierar ett antal ”REGLER” i lex som beskriver hur t.ex. ett nyckelord, en kommentar, en textsträng o.s.v. definieras. Då en regel passar in på källtexten skriver mitt genererade analysatorprogram ut motsvarande element för språket c.

Då jag skriver min översättare från sv till c i lex blir programmets längd ungefär hundra rader kod d.v.s. programmet är väldigt litet och överskådligt. Mitt sv-språk är i detta skede ett subset av språket c men redan i nedanstående form kan man skriva riktiga program i sv. Språket kan enkelt utvidgas genom att modifiera filen swe.lex. Då jag använder lex för att kompilera min definition av sv blir resultatet ett c-program som heter lex.yy.c . Jag kompilerar därefter lex.yy.c till ett körbart program sv som sköter översättningen av en källkodsfil i sv till motsvarande c-program.

Lex-program för översättning av sv till c

Filen swe.lex kan enkelt modofieras så att en större del av c-språket stöds. Notera att jag har skrivit swe.lex så att resulterande c-filen som ett sv-program översätts till har exakt samma antal rader som källkoden i sv. Detta betyder att då jag kompilerar mitt sv program så stämmer radnumren för felmeddelanden för både sv och c.

Min definition av sv-språket ser ut på följande sätt:

%{
/* A lexical analyzer for the computer language "sv". This is a simple translation */
/* of the "c" language into swedish. The corresponding "compiler" translates a */
/* sv-source into c-language that can be compiled using an ordinary c-compiler */
/* need this for the call to atof() below */
#include <math.h>
/* need this for printf(), fopen() and stdin below */
#include <stdio.h>
%}
WHITESPACE [ \t\n]+
DIGIT	  [0-9]
ID	  [a-zA-Z][a-zA-Z0-9]*
CHAR	  [a-zåäö][A-ZÅÄÖ][0-9][\ ][!?][\n]
COMMENT	  \/\/.*[\n]
STR1	  \".[\\]*\"
APP	  [\"]
LPAR	  [(]
RPAR	  [)]
LWAV	  [{]
RWAV	  [}]
TERMINATOR [;]
EXCL	  [!]
AE	  [Ä]
ae        [ä]
Aring	  [Å]
aring	  [å]

COMMA	  [,]

%%
{DIGIT}+		printf("%d",atoi(yytext));
{DIGIT}+"."{DIGIT}*	printf("%s", yytext);
{STR1}			printf("%s",yytext);
{LPAR}			printf("%s",yytext);
{RPAR}			printf("%s",yytext);
{LWAV}			printf("%s",yytext);
{RWAV}			printf("%s",yytext);
{EXCL}			printf("!");
{COMMA}			printf(",");
#inkludera		printf("#include");
#definiera		printf("#define");
program			printf("\nmain");
funktion		printf(" ");
resultat		printf("return ");
alternativ		printf("switch");
valt			printf("case ");
bryt			printf("break");
om			printf("if ");
medan			printf("while");
upprepa			printf("for");
annars			printf("else ");
skrivf			printf("printf");
skrivr			printf("printf");
fskrivf			printf("fprintf");
hämtarad		printf("getline");
hämta			printf("get");
sätt			printf("put");
läs			printf("read");
läsrd			printf("readln");
dröj			printf("delay");
heltal			printf("int ");
tecken			printf("char ");
byte			printf("byte ");
sanningsvärde		printf("boolean ");
register		printf("int");
bitmask			printf("int");
likamed			printf("==");
mindre_än		printf("<");
mindre_än_eller_likamed	printf("<=");
större_än		printf(">");
större_än_eller_likamed	printf(">=");
och			printf("&&");
binär_och		printf("&");
and			printf("&");
or			printf("|");
xor			printf("^");		
binär_exclusiv_och	printf("^\n");
vflytta			printf("<<");
hflytta			printf(">>");
storlek_t		printf("size_t");
\<\<			printf("<<");
\>\>			printf(">>");
=			printf("=");
\<			printf("<");
\>			printf(">");
\.			printf(".");
\&\&			printf("&&");
\&			printf("&");		
{ID}			printf("%s", yytext);
{TERMINATOR}		printf("%s",yytext);
{COMMENT}		printf("%s",yytext);
{WHITESPACE}		printf("%s",yytext);

"+"|"-"|"*"|"/"	printf("%s", yytext);
"{"[^}\n]*"}"	        /* eat up one-line comments */
%%
int main(int argc, char *argv[])
{
		++argv, --argc;	/* skip over program name */
		if (argc > 0)
			yyin = fopen(argv[0], "r");
		else
		yyin = stdin;
		yylex();
		return(0);
}

Verifiering av språket ”sv”

Ett enkelt sätt att visa att det nya språket ”fungerar” är naturligtvis att skriva ett riktigt program i
programspråket sv. Jag byggde för kanske tjugo år sedan några led-ficklampor med några barnhemsbarn där vi använde en liten mikroprocessor som programmerades i mitt språk ”sil” (simple language) för Microchips processor 16F84. Ficklamporna programmerades så att de olika barnens ficklampor kunde blinka ägarens namn i morsekod.

Nedan visar jag hur man kan skriva ett program i språket sv som läser in en textrad från användaren och
”sänder” texten som morsekod till skärmen men också som morseljud via datorns högtalare. Jag kommer att flytta programmet till PDP11 och något modifiera det så att PDP11 som saknar högtalare i stället skickar ett magnetband till huvuddatorn för sändning, detta beskrivs eventuellt i en senare artikel.

Morsesändare skriven i sv

En morseöversättare gör man enklast så att man tabellerar tecknen ”A-Z”, ”a-z” samt siffrorna 0-9 samt deras motsvarande teckenkoder. För en specifik bokstav vill vi alltså ha en översättarfunktion skrivMorse() av ungefär följande typ (ti=’*’ och taa=’-‘):

heltal skrivMorse(tecken c){
heltal i;
tecken morse[16];
alternativ (c){
valt ‘a’: strcpy(morse, ”-”); bryt;

valt ‘b’: strcpy(morse,”-”); bryt;
valt ‘c’: strcpy(morse,”–”); bryt;
valt ‘d’: strcpy(morse,”-”); bryt;
valt ‘e’: strcpy(morse,”*”); bryt;

}

skrivf(”Morsekod:%s\n”,morse);

Som indata till vår funktion ”skrivMorse” ges ett tecken/en bokstav ”c” vid anrop till funktionen. Resultatet av översättningen finns efter exekvering nu i variabeln ”morse”. Jag antar att funktionen är ganska läslig även för personer som inte kan programmera. Nyckelordet ”bryt” betyder att rätt alternativ hittades och exekveringen fortsätter vid ”skrivf(…). Om vi vill översätta bokstaven ”s” till morse så anropar vi vår funktion med:

skrivMorse(‘s’);

Resultatet skulle bli Morsekod:***

Vi börjar vårt egentliga program med att låta programmet be om en text att sända samt läsa in en textrad som innehåller texten. Funktionen skrivf() skriver ut text som kan formatteras för heltal, flyttal etc. Vi kan göra detta med:

skrivf(”Skriv text att sända som morse:”);
l=hämtaRad(&line,&len,stdin);

Kommandot ”hämtaRad” använder biblioteksfunktionen ”getline” som finns definierad i biblioteket stdio.h. Vi måste då komma ihåg att deklarera att vi använder biblioteket stdio.h . Vi inkluderar ett standardbibliotek med:

#inkludera <stdio.h>

Vårt program har nu ungefär följande utseende och det utför inte ännu något vettigt :

#inkludera <stdio.h>

#inkludera <stdlib.h>

#inkludera <string.h>

heltal skrivMorse(tecken c){
heltal i;
char morse[16];
alternativ (c){
valt ‘a’: strcpy(morse, ”-”); bryt;
valt ‘b’: strcpy(morse,”-**”); bryt;
… fler definitioner av morsekoder …
}
}

heltal program(){
heltal l=0;
storlek_t len=0;
tecken *rad=NULL;
skrivf(”Skriv text att sända som morse:”);
l=hämtarad(&rad,&len,stdin);
// Skriv ut den lästa raden för att verifiera att inläsningen lyckades
skrivf(”Inläst rad:%s\n”,rad);
}

Variablerna l, len och *rad behövs för anropet till hämtarad().

Då vi skriver in vår text som skall skickas så vill vi gärna hantera texten ordvis d.v.s. vi skickar ett ord i taget och genererar en standardiserad paus mellan orden. För att splittra up vår textsträng i separata ord inkluderar vi biblioteket string (#inkludera <string.h> se ovan). String-biblioteket har en användbar funktion strtok() som splittrar upp den text vi ger som funktionsparameter i en tabell med separata textsträngar (ordsträngar) separerade med mellanslag ‘ ‘. Råtexten bryts alltså vid mellanslag. Jag splittrar upp den ingående råtexten genast då jag deklarerar ordtabellen som jag kallar ett_ord:

tecken *ett_ord = strtok(rad,” ”);

Om jag har matat in texten ”Lasse skickar morse” så kommer ett_ord efter anrop att innehålla textsträngar som jag kommer åt med:

ett_ord[0] = ”Lasse”
ett_ord[1] = ”skickar”
ett_ord[2] = ”morse”

Vi kan nu skriva en ny funktion som vi kallar skicka_text_som_ord(”någon text …”) .

heltal skicka_text_som_ord(tecken rad[]){
heltal i;
tecken *ett_ord = strtok(rad,” ”);
medan (ett_ord != NULL){
skrivf(”Ord=%s\n”,ett_ord);
upprepa(i=0; i<strlen(ett_ord);i++){
// Skriv ett tecken i nuvarande ord
skrivMorse(ett_ord[i]);
system(teckenpaus);
skrivf(”\n”);
}
skrivf(”\n”);
ett_ord = strtok(NULL, ” ”);
}
}

Efter att vi splittrade upp råtexten i ord så tar vi ett ord i taget och splittrar upp det i bokstäver som skickas för konvertering till morse.

Vi går igenom alla orden i vår råtext med:

medan (ett_ord != NULL){
skrivf(”Ord=%s\n”,ett_ord);

}

Motsvarande konstruktion i språket c är ”while(ett_ord != NULL){ … }” .
Vi skickar vidare orden för sändning så länge som ett_ord inte är tomt (NULL).

Vi lägger nu till en slinga för att skicka iväg varje ord bokstav för bokstav för översättning till morse och sändning. Slingan har följande utseende:

upprepa(i=0; i<strlen(ett_ord);i++){
  // Skriv ett tecken i nuvarande ord
  skrivMorse(ett_ord[i]);
  system(teckenpaus);
  skrivf("\n");
}

Vi använder konstruktionen ”upprepa” som motsvarar c-språkets ”for” slinga.
Slingan går igenom ordsträngen ett_ord bokstav för bokstav tills vi har nått den fulla längden på strängen ett_ord.

Slingan stegar alltså igenom ett_ord på följande sätt:

i=0 ett_ord[i] = ‘L’ som skickas till skrivMorse(‘L’)
i=1 ett_ord[i] = ‘a’ som skickas till skrivMorse(‘a’)
i=2 ett_ord[i] = ‘s’ som skickas till skrivMorse(‘s’)
i=3 ett_ord[i] = ‘s’ som skickas till skrivMorse(‘s’)
i=4 ett_ord[i] = ‘e’ som skickas till skrivMorse(‘e’)

Efter att vi har skickat ett helt ord så håller vi paus genom att anropa operativsystemets funktion sleep.

Vi låter systemet sova i 0.7 sekunder mellan ord. Sovtiden mellan bokstäver är 0.1 sekunder.

Vi spelar upp ”tit” och ”taa” under Linux så att jag med hjälp av programmet ”Audacity” genererade en ton med frekvensen 880 Hz. Från denna ton klippte jag två stumpar 0.1 repektive 0.3 sekunder långa som jag sparade som ljudfilerna 0_1.wav samt 0_3.wav . Jag kan spela upp en wavfil under Linux med hjälp av programmet ”aplay”.

Programmet i dess helhet (under linux i detta skede) har då följande utseende:

// Morse
// Programspråket "sv" är språket "c" med svenska kommando-ord.
// Språket översätts till standard "c" som sedan kompileras till maskinspråk
// för att köras.
// Språket "sv" är egentligen ett experiment med Unixverktyget "lex" som 
// har konstruerats för att känna igen ord och strukturer i en text.
// Strukturer som hittas skulle normalt skickas vidare till programmet "yacc"
// (yet another compiler compiler = en annan kompilator kompilator).
// Eftersom jag översätter språket "sv" till "c" så behöver jag inte
// någon kompilator eftersom denna redan finns och likaså behöver jag inte
// någon kodgenerator som skulle generera maskinspråk eftersom även den redan
// finns. Notera att jag kan använda c-språk direkt om motsvarande
// sv-konstruktion inte har definierats.
// Notera att endast en delmängd av SV-C har skrivits. 
// Vill man ha en mera fullständig 
// motsvarighet så måste filen swe.lex utvidgas med nya nyckelord.
// Jag kör för närvarande en emulerad minidator PDP11/70 från 1970-talet.
// Operativsystemet är BSD Unix 2.11.
// Detta är ett experiment i att skriva ett enkelt svenskt 
// programmeringsspråk som är körbart på denna urgamla dator.   
// 
// Lars Silen 2022
// Detta är öppen källkod som fritt får distribueras
// Författaren tar inget ansvar för eventuella fel i genererad kod 

#inkludera <stdio.h>
#inkludera <stdlib.h>
#inkludera <string.h>

// Definiera tidslängden på olika element i Morse 
tecken teckenpaus[] = "sleep 0.1";
tecken ordpaus[] = "sleep 0.7";

heltal skrivMorse(tecken c){
  heltal i;
  char morse[16];
  alternativ (c){
    valt 'a': strcpy(morse, "*-"); bryt;
    valt 'b': strcpy(morse,"-***"); bryt;
    valt 'c': strcpy(morse,"-*-*"); bryt;
    valt 'd': strcpy(morse,"-**"); bryt;
    valt 'e': strcpy(morse,"*"); bryt;
    valt 'f': strcpy(morse,"**-*"); bryt;
    valt 'g': strcpy(morse,"--*"); bryt;
    valt 'h': strcpy(morse,"****"); bryt;
    valt 'i': strcpy(morse,"**"); bryt;
    valt 'j': strcpy(morse,"*---"); bryt;
    valt 'k': strcpy(morse,"-*-"); bryt;
    valt 'l': strcpy(morse,"*-**"); bryt;
    valt 'm': strcpy(morse,"--"); bryt;
    valt 'n': strcpy(morse,"-*"); bryt;
    valt 'o': strcpy(morse,"---"); bryt;
    valt 'p': strcpy(morse,"*--*"); bryt;
    valt 'q': strcpy(morse,"--*-"); bryt;
    valt 'r': strcpy(morse,"*-*"); bryt;
    valt 's': strcpy(morse,"***"); bryt;
    valt 't': strcpy(morse,"-"); bryt;
    valt 'u': strcpy(morse,"**-"); bryt;
    valt 'v': strcpy(morse,"***-"); bryt;
    valt 'w': strcpy(morse,"*--"); bryt;
    valt 'x': strcpy(morse,"-**-"); bryt;
    valt 'y': strcpy(morse,"-*--"); bryt;
    valt 'z': strcpy(morse,"--**"); bryt;
    // Lägg till ÅÄÖ här om du behöver dem

    valt 'A': strcpy(morse, "*-"); bryt;
    valt 'B': strcpy(morse,"-***"); bryt;
    valt 'C': strcpy(morse,"-*-*"); bryt;
    valt 'D': strcpy(morse,"-**"); bryt;
    valt 'E': strcpy(morse,"*"); bryt;
    valt 'F': strcpy(morse,"**-*"); bryt;
    valt 'G': strcpy(morse,"--*"); bryt;
    valt 'H': strcpy(morse,"****"); bryt;
    valt 'I': strcpy(morse,"**"); bryt;
    valt 'J': strcpy(morse,"*---"); bryt;
    valt 'K': strcpy(morse,"-*-"); bryt;
    valt 'L': strcpy(morse,"*-**"); bryt;
    valt 'M': strcpy(morse,"--"); bryt;
    valt 'N': strcpy(morse,"-*"); bryt;
    valt 'O': strcpy(morse,"---"); bryt;
    valt 'P': strcpy(morse,"*--*"); bryt;
    valt 'Q': strcpy(morse,"--*-"); bryt;
    valt 'R': strcpy(morse,"*-*"); bryt;
    valt 'S': strcpy(morse,"***"); bryt;
    valt 'T': strcpy(morse,"-"); bryt;
    valt 'U': strcpy(morse,"**-"); bryt;
    valt 'V': strcpy(morse,"***-"); bryt;
    valt 'W': strcpy(morse,"*--"); bryt;
    valt 'X': strcpy(morse,"-**-"); bryt;
    valt 'Y': strcpy(morse,"-*--"); bryt;
    valt 'Z': strcpy(morse,"--**"); bryt;
    // Lägg till åäö här om du behöver dem

    valt '1': strcpy(morse,"*----"); bryt;
    valt '2': strcpy(morse,"**---"); bryt;
    valt '3': strcpy(morse,"***--"); bryt;
    valt '4': strcpy(morse,"****-"); bryt;
    valt '5': strcpy(morse,"*****"); bryt;
    valt '6': strcpy(morse,"-****"); bryt;
    valt '7': strcpy(morse,"--***"); bryt;
    valt '8': strcpy(morse,"---**"); bryt;
    valt '9': strcpy(morse,"----*"); bryt;
    valt '0': strcpy(morse,"-----"); bryt;
    // Lägg till skiljetecken etc här
  }

  // Skriv bokstaven som sänds (finns som variabelparametern "c" vid anropet)
  skrivf("%c  ",c);
  skrivf("%s  ",morse);
  // Generera ljud 
  upprepa(i=0; i<strlen(morse);i++){
    om (morse[i] == '*'){
       skrivf("ti ");
       system("aplay -q 0_1.wav >/dev/null");
    } annars {
       skrivf("taa ");
       system("aplay -q 0_3.wav >/dev/null");
    } 
    // skrivf("\n");
  } 
}

heltal skicka_text_som_ord(tecken rad[]){
  heltal i;
  tecken *ett_ord = strtok(rad," ");
  medan (ett_ord != NULL){
    skrivf("Ord=%s\n",ett_ord);
    upprepa(i=0; i<strlen(ett_ord);i++){
      // Skriv ett tecken i nuvarande ord
      skrivMorse(ett_ord[i]);
      system(teckenpaus);
      skrivf("\n");
    }
    skrivf("\n");
    ett_ord = strtok(NULL, " ");
  }  
}

heltal program(){
  heltal l=0;
  storlek_t len=0;
  tecken *rad=NULL;
  skrivf("Skriv text att sända som morse:");
  l=hämtarad(&rad,&len,stdin);
  skicka_text_som_ord(rad);
}

Den genererade c-koden är strukturellt identisk med sv-programmets kod d.v.s. vi gör en ord för ord översättning. Detta betyder att c-kompilatorn ger felmeddelanden som pekar till rätt rad också i sv källkoden. Min editor bör naturligtvis konfigureras så att den visar radnummer för att felsökning skall vara effektiv.

Översättaren bör sannolikt expanderas med ytterligare c-konstruktioner. Det är oklart i hur hög utsträckning det är värt att översätta funktioner i bibliotek men exemplet ”hämtaRad” visar att detta naturligtvis är möjligt. Det är naturligtvis också möjligt att översätta namnen på standardbiblioteken på samma sätt men knappast vettigt eftersom målet är att eleven också bekantar sig med c-språket och dess bibliotek.

Oversättarprogram komplett:

#!/bin/bash
# Name=csv
# Detta är en kompilator för programspråket "sv" som är en svensk översätytning av språket "c".
# Språket "sv" kan enkelt utvidgas genom att modifiera filen "swe.lex".
# Användning: ./csv program           
#             Notera att källkoden antas vara program.sv .
#             Resultatet blir det körbara programmet program.run
#
# En textfil som är en översättning till språket "c" genereras som program.c .
# Lars Silen 2022
# Detta är fri källkod som fritt får användas och modifieras på egen risk.

echo "Källkod:"$1.sv
echo "Översättaren är definierad i swe.lex"
echo "Kompilerar översätteren swe.lex till c-kod"
lex swe.lex
echo "Kompilerar lex analysatorn till körbar maskinkod: sv"
gcc lex.yy.c -ll -o sv
echo "Översätter sv-programmet " $1.sv " till c-kod: " $1.c
./sv $1.sv >$1.c
echo "C-kod finns nu i " $1.c
echo "Kompilerar nu till körbar maskinkod!"
gcc $1.c -o $1.run
echo "The executable is:" $1.run

Notera att skriptet kompilerar om swe.lex varje gång. Användaren kan alltså enkelt lägga till
nya definitioner som blir en del av språket. Om användaren uppfattar att språkdefinitionen är stabil så kan man naturligtvis lämna bort raderna lex swe.lex samt gcc lex.yy.c -ll -o sv , tidsvinsten blir dock marginell.

Antik datorteknik, flytta filer över nätet

11/01/2022

I föregående inlägg visade jag hur jag kan använda en simulerad magnetbandstation för att flytta filer mellan min PDP11/70 och den Raspberry Pi som kör emuleringen. Systemet är något omständligt men det fungerar i princip till belåtenhet. Systemet kunde t.ex. användas till att flytta över källkoden till en lite trevligare editor till PDP11 och därefter kompilera den. Resultatet skulle vara en lite bekvämare arbetsmiljö.

Jag kan utan problem köra min PDP11 också från min ”huvuddator” d.v.s. bordsdatorn. Jag ansluter via SSH d.v.s. en krypterad dataförbindelse till Raspberry Pi och använder samma fönster till att logga in mig på PDP11. Detta betyder att jag kan jobba vid min stora bildskärm med ett ensamt terminalfönster in till PDP11. Om jag vill flytta data direkt från huvuddatorn till PDP11 utan att behöva logga in på Raspberry Pi för att fixa magnetbandet, hur gör jag då?

Det faktum att jag kan koppla upp mig till PDP11 via en SSH förbindelse till Raspberry Pi betyder självklart att jag har en fungerande nätverksförbindelse. Jag kan också kontrollera om min PDP11 syns på nätverket med hjälp av verktyget ”ping”:

ping 192.168.0.xxx

där 192.168.0.xxx är PDP11:ns IP-adress. PDP11 har en egen IP-adress trots att den kör ”inom” Raspberry Pi d.v.s. all dess IP trafik routas via Raspberry Pi. Om PDP11 svarar på en ping så betyder detta att nätverksförbindelsen i princip fungerar. PDP11 känner till kommandot ftp d.v.s. det borde vara möjligt att flytta filer direkt mellan huvuddatorn och PDP11 utan att Raspberry Pi behöver delta i operationen. En intressant detalj är att jag inte kan pinga PDP11 från Raspberry Pi d.v.s. det kort på vilket både Raspberry Pi och PDP11 kör. Däremot kan jag pinga PDP11 från min bordsdator som sitter på samma nätverk som Raspberry Pi. Problemet går att åtgärda men så långt har jag inte ännu hunnit.

En ftp server på min huvuddator

Jag började med att installera en ftp server på min huvuddator. Det finns ett antal varianter för Linux och jag valde att installera en server som heter VSFTPD. Jag kör Linux Mint som stöder denna ftp-server. Installationen gick behändigt med:

sudo apt update

Detta kommando uppdaterar Linux Mint katalog över tillgängliga applikationer.

sudo apt install -y vsftpd

Installation av ftp-servern från kommandoraden. Jag kunde likaväl ha använt ett grafiskt verktyg.

Konfiguration av servern görs i filen /etc/vsftpd.conf

sudo nano /etc/vsftpd.conf

Det lönar sig att googla på vsftpd om man behöver information om konfigurationen. Jag måste installera och konfigurera som superuser ”root” eftersom jag installerar vsftpd för alla användare på maskinen och konfigurationsfilerna i /etc är skrivskyddade eftersom jag inte vill att en eventuell besökare skall kunna gå in och konfigurera min maskin. För att jag skall kunna flytta filer från måste jag åtminstone editera /etc/vsftpd.conf så att jag tillåter skrivning till min katalog på deNeb. Detta kan jag göra genom att sätta write_enable=YES . Denna modifikation behövs om jag vill flytta filer från PDP11 till deNeb.

Flytta filer till/från PDP11

Min PDP11 representerar tidsperioden 1970 till slutet av 1990-talet. I praktiken betyder detta att de programverktyg jag har tillgång till kör i en textterminal inte i ett modernt grafiskt fönster som på min huvuddator. Det visar sig dock att man mycket bekvämt kan flytta filer mellan datorer direkt från kommandoraden på PDP11 utan att detta egentligen är komplicerat.

PTF-inloggning till min huvuddator från PDP11

Jag kopplar upp till min huvuddator ”deNeb” från PDP11. Situationen är intressant genom att det terminalfönster i vilket PDP11 kör finns på deNeb men är kopplad över en ssh-förbindelse. PDP11 kör alltså på Raspberry Pi men terminalfönstret finns på deNeb vilket man kan se i fönstrets rubrik.

Jag jobbar alltså i PDP11 och lägger upp en ftp-förbindelse till deNeb. Steg för steg gör jag:

ftp deNeb

Jag ger mitt användarnamn och password till deNeb för att släppas in i maskinen. Inloggningen är avklarad då jag får svaret ”230 Login successful”.

ftp>

Datorn kommer visa ftp> på varje rad för att indikera att jag har en aktiv ftp-förbindelse. I kommandona nedan är denna indikator bortlämnad. tex. följande kommando nedan kommer att i terminalen vara: ftp>cd Prog/PDP11 men användaren skriver endast cd Prog/PDP11 .

Jag ger nu ett kommando till ftp-servern att jag vill flytta mig till katalogen Prog/PDP11 på datorn deNeb från vilken jag vill hämta en textfil.

cd Prog/PDP11

Svaret blir ”250 Directory successfully changed”. Jag listar nu innehållet (ls) i katalogen dit jag flyttade mig på deNeb.

ls

Katalogen innehåller endast en fil med namnet deNeb.txt. Jag kan nu flytta filen från deNeb till PDP11 där jag kör mitt ftp-program med kommandor ”get”.

get deNeb.txt

… 226 Transfer complete.

Jag har nu flyttat filen till PDP11 och jag kan undersöka vad jag fick. Först går jag ut ur PDP11 med kommandot ctrl-D.

cat deNeb.txt
Resultatet blir:

This text document is moved from the Linux computer ”deNeb” to the emulated PDP11.

Filens innehåll är korrekt. Vi kan ladda in filen i texteditorn ”vi” och göra en liten förändring. Vi ändrar texten till: This text document is moved from PDP11 to ”deNeb”. Jag byter namn på filen till PDP11.txt så att jag kan verifiera att jag faktiskt har flyttat filen tillbaka till PDP11.

Vi kan nu flytta den modifierade filen tillbaka till deNeb genom att på nytt starta ftp på PDP11. Vi flyttar oss till katalogen Prog/PDP11 och använder ”put” för att flytta filen från PDP11 till deNeb.

Jag kan kontrollera vad jag har i min lokala katalog på PDP11 inifrån ftp-programmet genom att ge normala UNIX-kommandon som inleds med ”!”.

!ls
hello hello.c

På PDP11 har jag endast två filer i min arbetskatalog d.v.s. ett ”Hello world!” c-program och samma program i kompilerad körbar form.

Jag flyttar filen PDP11.txt till deNeb med ftpkommandot put PDP11.txt . Jag kan nu i ett annat terminalfönster kontrollera att filen faktiskt levererades korrekt.

Efter kommandot på PDP11 ser vi att vi har fått en ny fil på deNeb d.v.s. överflyttning i båda riktningarna lyckas utan problem.

Det är igen intressant att se hur jag utan större problem kan kommunicera mellan min huvuddator deNeb och en 30 år gammal UNIX. Det finns klara fördelar av att operativsystemen är nära besläktade. Jag tror inte att det hade varit riktigt lika enkelt att idag försöka sätta upp en förbindelse mellan PDP11 och t.ex. Windows 3.1 från 1992 …

Att ladda program på en PDP11

05/01/2022

1970-talets datorer var ofta försedda med en frontpanel med mängder av strömbrytare samt blinkande lampor. Frontpanelen var inte kosmetisk utan tanken var att användaren började med att knappa in en handfull maskininstruktioner i maskinens minne, instruktioner vars uppgift var att ladda in ett större mera avancerat laddarprogram från t.ex. hålremsa. Från hålremsa kunde man ladda in ett enkelt operativsystem eller t.ex. en Basic tolk som kunde användas till att skriva riktiga program. Det var teoretiskt, inte praktiskt, möjligt att knappa in t.ex hela tolken via frontpanelen men chansen att man gjorde något fel var så stor att det inte var något alternativ. En användbar Basic krävde någonstans mellan 4000 och 8000 instruktioner d.v.s. kanske 15000 strömbrytare måste flippas utan fel för att det skulle fungera.

Bilden är tagen från: https://obsolescence.wixsite.com/obsolescence/pidp-11-overview

Man använde oftast hålremsa för att ladda program. Hålremsa är som namnet säger en ungefär 25 mm bred pappersremsa ofta många meter lång med hål stansade tvärs över remsan. Varje stansad hålrad representerade ett tecken i binär form. Det själv inmatade programmets uppgift var alltså att läsa av hålkombinationer från en hålremsläsare och successivt mata in resultatet i minnet. Då hela remsan hade lästs matade man in en startadress från frontpanelen och tryckte på ”kör”.

En hålremsläsare är enkel att bygga själv men att bygga en hålremsstans kräver redan en del mekaniskt kunnande men inte oöverkomligt sådant. Jag tittade lite på möjligheten att bygga upp hålremsan på A4-papper i form av t.ex. en JPG bild. Man kunde då t.ex. i stället för att stansa hålremsa skriva ut program eller data i hexadecimal form, papper som kunde mappas in och sedan läsas av PDP11 via en simulerad hålkortsläsare som skulle använda OCR (Optical Code Recognition) för att återskapa innehållet i binär form för laddning till PDP11. Jag skrev på skoj ett program som dumpade data till printer i ett standardiserat format och använde därefter programmet Tesseract för att återskapa mina data. Programmet Tesseract fungerar mycket väl då man låter det läsa text skrivet på ett språk för vilket Tesseract tränats. Resultatet blev inte speciellt bra då programmet skulle läsa i princip slumpmässiga data. Felkorrigeringen bygger tydligen åtminstone delvis på att den inlästa texten matchas mot ordlistor/meningar/grammatik så att enstaka fel elimineras. Då programmet inte kunde matcha inlästa data mot en språklig databank dök det upp förvånande mycket fel kanske 1-5% av de inlästa tecknen blev fel d.v.s. systemet fungerar inte utan hjälp av mera avancerad felkontroll. Här uppfattade jag att jag hamnade i en återvändsgränd och lät bli att gå vidare.

Av en slump hittade jag efter en del googlande ett enkelt alternativ till att ladda in program till PDP11. Vi har alla sett video/film från gårdagens data center där det finns kylskåpsstora databanspelare som kontinuerligt körs/stoppas/snabbspolas. Databanspelarna var länge det huvudsakliga mediet på vilket data kunde lagras. En svindyr hårskiva rymde kanske 5 Mbyte medan ett magnetband hade nästan oändlig kapacitet sett ur den tidens perspektiv. Magnetbandets nackdel var att man då man skulle ladda in ett program måste man hitta bandet, korrekt mata in bandet i bandstationen och därefter ange vilket ”block” man ville läsa. Systemet var långsamt men blixtsnabbt jämfört med andra system t.ex. hålremsa.

Det visade sig att det fanns en fungerande simulerad bandstation som fungerar på följande sätt:

Jag skapar en katalog /home/pi/bsdtapes på Raspberry Pi där emulatorn körs. Om jag lagrar ett simulerat magnetband tq0tape.tap i denna katalog så kan jag på PDP11 som på den gamla goda tiden aktivera bandstationen och läsa bandet.

För att aktivera bandstationen i PDP11 måste man i BSD 2.11 startfilen definiera att en bandstation finns tillgänglig.

cd /opt/pidp11/systems/211bsd

Gör en kopia på initialiseringsfilen boot.ini:

sudo cp boot.ini boot.ini.backup

Editera boot.ini så att det efter set tq enabled kommer en ny rad:

attach tq0 /home/pi/bsdtapes/tq0tape.tap

Då PDP11 BSD 2.11 startar så vet systemet var det hittar bandet för bandstationen.

Processen beskrivs nedan:

Att läsa program/data från magnetband

Om jag vill flytta data eller program till PDP11 så måste jag först skapa ett läsbart magnetband d.v.s. en fil som binärt ser ut som de data vi får ut från magnetstationen.

Vi börjar med att putsa bort eventuella gamla magnetband i katalogen. Jag har en underkatalog i vilken jag sparar mina magnetband.

sudo rm tq0tape.tap tq0tape.tar

Antag att jag vill flytta en fil minFil.txt till PDP11. Jag börjar med att komprimera/packa ihop filen till en tar-fil. Filändelsen tar står för tape archive! Systemet används fortfarande i Unix/Linux maskiner även om det är många år sedan man hade en riktig bandstation att jobba mot. Resultatet blir helt enkelt en datafil.

tar cvf tq0tape.tar minFil.txt

Vi har nu ett bandarkiv tq0tape.tar som innehåller filen minFil.txt. Filen är inte ännu läsbar av PDP11 utan vi måste skriva om arkivfilen till ett simulerat magnetband. Vi gör detta med hjälp av ett enkelt Perlprogram tapadd.pl och resultatet blir en fil tq0tape.tap .

./tapadd.pl tq0tape.tar tq0tape.tap

Jag kan nu läsa bandet från PDP11 på följande sätt under förutsättning att jag har lagt till bandstationen till 211BSD :

Starta PDP11/70 under simh. Det verkar vara nödvändigt att starta om 211BSD mellan olika band. Jag har inte analyserat vad detta beror på … kanske i framtiden. Logga in på PDP11 och gå till den katalog dit du vill ha dina data. Spola tillbaka magnetbandet och läs innehållet i form av en tar-fil.:

mt rewind
tar xv

Resultatet blir att de filer som fanns på bandet lagras under dut usprungliga namnet i arbetskatalogen. Systemet fungerar förvånande bra.

Att flytta data från PDP11 via magnetband

Systemet är i princip detsamma som det ovan beskrivna men i omvänd ordning. Vi börjar med att skapa ett bandarkiv som skrivs direkt till ”magnetbandet” utan att gå över en lokal fil. Systemet är alltså:

Spola tillbaka bandet.

mt rewind

Vi antar att vi vill flytta hela arbetskatalogen till Raspberry Pi. Vi ”tarrar” då ihop hela katalogen och lägger resultatet på bandet:

tar cv .

Notera att punkten efter tar cv betyder den aktuella katalogens innehåll. Jag kunde byta ut punkten mot t.ex. hello.c varvid endast filen hello.c skulle skrivas till band.

Det vi tarrade ihop finns nu på ”magnetband” i filen tq0tape.tap på Raspberry Pi (detta kallas magi)! Vi kan nu läsa bandet på raspberry pi med hjälp av hjälp programmet tapcat.pl . Vi börjar med att konvertera magnetbandet till ett normalt Unix bandarkiv:

./tapcat.pl tq0tapes.tap > tq0tapes.tar

Vi skapade nu ett Unix bandarkiv tq0tape.tar i arbetskatalogen. Bandarkivet kan nu öppnas med:

tar xvf tq0tapes.tar

Efter detta tar kommando finns hela arkivets innehåll i arbetskatalogen där kommandot kördes.

Slutkommentar

Det är rätt intressant att jag kan använda Unixens ”tar” verktyg på en maskin från 1970-talet. Alternativt kan man säga att det är rätt fantastiskt att 1970-talets programverktyg som skapades för att hantera data-/programarkiv på magnetband fortfarande används aktivt idag trots att forntidens bandstationer har försvunnit helt och man hittar dem endast på olika tekniska muséer.

Jag kan nu hämta ett ”magnetband” d.v.s. kopiera en magnetbandsfil från min underkatalog mytapes till filen tq0tapes.tap och därefter ladda innehållet på PDP11.

Ett ännu enklare sätt att överföra filer är att använda ftp (file transfer protocol) d.v.s. vi använder nätverket för överföring utan att ha något behov av att någon bandstation på vägen. Mera om ftp i nästa artikel.

Länkar

Filtransfer via magnetband: https://github.com/rricharz/pidp11-2.11bsd/blob/master/Tape.pdf

Program tagna från https://github.com/rricharz/pidp11-2.11bsd/

Programmet tapadd.pl:

#!/usr/bin/perl -w
use strict;
if(@ARGV != 1) {
print STDERR ”Usage: $0 <filename>\n”;
exit(1);
}
add_file($ARGV[0], 512);
end_file();
end_file();
sub end_file {
print ”\x00\x00\x00\x00”;
}
sub add_file {
my($filename, $blocksize) = @_;
my($block, $bytes_read, $length);
open(FILE, $filename) || die(”Can’t open $filename: $!”);
while($bytes_read = read(FILE, $block, $blocksize)) {
if($bytes_read < $blocksize) {
$block .= ”\x00” x ($blocksize – $bytes_read);
$bytes_read = $blocksize;
}
$length = pack(”V”, $bytes_read);
print $length, $block, $length;
}
close(FILE);
}

Programmet tapcat.pl:

#!/usr/bin/perl -w
use strict;
use vars qw($filename $filenum);
if(@ARGV != 2) {
printf STDERR ”Usage: $0 <tape file> <file number>\n”;
exit(1);
}
$filename = $ARGV[0];
$filenum = $ARGV[1];
open(INPUT, $filename) || die(”Can’t open $filename: $!”);
while($filenum–) {
readfile(0);
}
readfile(1);
exit(0);
sub readfile {
my($print) = @_;
my($block);
while(defined($block = readblock())) {
if($print) {
print $block;
}
}
}
sub readblock {
my($blocksize, $bs2, $block);
read(INPUT, $blocksize, 4);
$blocksize = unpack(”V”, $blocksize);
return undef unless $blocksize;
read(INPUT, $block, $blocksize);
read(INPUT, $bs2, 4);
$bs2 = unpack(”V”, $bs2);
$blocksize == $bs2 || die(”Invalid tape format”);
return $block;

}

Att köra en PDP11 dator från 1970-talet

05/01/2022

Jag har under en tid bekantat mig med en emulerad/simulerad PDP11 minidator från mitten av 1970-talet. PDP11 datorn var mycket populär innan IBM PC:n slog igenom och i praktiken sopade bort konkurrenterna mot slutet av 1980-talet då minidatorn PDP11 redan hade kring tjugo år på nacken. Konstruktionen kom att kopieras på olika håll bl.a. tillverkade man kopior i Sovjetunionen t.ex. Electronica 60 som jag tittade på i slutet av 1980-talet som alternativ för kontroll av mätsystem för export till Sovjetunionen. Jag jobbade aldrig med en rysk dator eftersom det visade sig att vi kunde kringgå exportrestriktionerna genom att byta ut en HP 9836 dator baserad på Motorola 68000 processor, som omfattades av amerikanska restriktioner, mot en standad 8 MHz långsam första generationens PC 8088. Jag kommer inte ihåg vilken tillverkares PC vi använde men detta är inte viktigt eftersom de olika PC:na var lika som bär. Lösningen var säkerligen bra eftersom Electronica 60 torde ha haft en hel del problem med pålitligheten. Det skulle dock ha varit roligt att ha fått konkret erfarenhet av dåtidens PDP11.

Den PDP11 jag skriver om är en emulerad PDP11/70 från ungefär 1975 som hörde till den tidsperiodens tungviktare använd som laboratoriepersondator. Datorn kunde köra UNIX och den orkade med flera användare eftersom en PDP11/70 med max minne på 4 MByte kunde stöda flera samtidiga användare. Användarna har under 2.11BSD Unix tillgång till något mer än 300 kByte minne vilket på den tiden var mycket. En PC som lanserades ett antal år senare kunde ha 64 kB – 256 kB (-640kB) för användare och operativsystem. Eftersom det normalt inte fanns något grafiskt användargränssnitt så var minnesbehovet litet och det gick att skriva stora program i 300 kByte. Dagens persondatorers behov av ett stort minne 2000-4000 ggr större än PDP11:ns är en följd av den mycket sofistikerade grafiken som kräver väldigt mycket minne utan att egentligen ge annat mervärde än bling bling. Samma kommentar gäller själva processorn som klockades på några megaherz. Moderna datorer kör med en klocka som tickar igen kanske 1000 ggr snabbare. Det intressanta är dock att då man håller sig till en text-terminal och använder kommandoraden så känns maskinen väldigt OK.

Hur emuleras en antik dator

Redan på slutet av 1960-talet d.v.s. för mer än 50 år sedan skrevs den första emulatorn MIMIC som bl.a. användes för testning och utveckling av nya datorkonstruktioner. 1993 startades projektet simH för att bevara minnet av ålderdomlig hårdvara och program. Den första generationens hårdvara höll snabbt på att försvinna och mängder av data som lagrats på magnetband riskerade att förstöras tex. 1960-talets data från månprojektet. Programmet simH emulerar en mängd gamla datorer bl.a.:

  • Data General Nova, Eclipse
  • Digital Equipment Corporation PDP-1, PDP-4, PDP-7, PDP-8, PDP-9, PDP-10, PDP-11, PDP-15 (and UC15), VAX11/780, VAX3900
  • GRI Corporation GRI-909, GRI-99
  • IBM 1401, 1620, 7090/7094, System 3
  • Interdata (Perkin-Elmer) 16b and 32b systems
  • Hewlett-Packard 2114, 2115, 2116, 2100, 21MX, 1000, 3000
  • Honeywell H316/H516
  • MITS Altair 8800, 8080 only
  • Royal-Mcbee LGP-30, LGP-21
  • Scientific Data Systems SDS 940
  • Xerox Data Systems Sigma 32b systems

Listan är inte fullständig.

Det är intressant att konkret se hur extremt mycket mera processorkapacitet vi har tillgång till idag, nästan gratis, än för femtio år sedan. En PDP11/70 kostade med fullt utbyggt minne mer än en högklassig ny personbil medan min på en Raspberry Pi emulerad PDP11/70 med maximalt minne en mängd operativsystem etc. kostar kanske 50E (500 SEK). Min emulerade maskin kör dessutom ungefär dubbelt snabbare än orginalet. Min Raspberry Pi har en kapacitet där RAM-minnet är 1000 ggr större än orginalet. Massminnet (skivminnet) är kanske 10000 ggr större och processorns hastighet är kanske 1200 ggr högre än orginalets. Ordlängden i PDP11 var 16 bitar medan en Raspberry Pi kör med ordlängden 64 bitar d.v.s. 4 ggr längre. Totalt kan man eventuellt säga att dagens lilla Raspberry Pi, beroende på vilken applikation man betraktar har en kapacitet som är mellan 1000 och 1000000 ggr högre än 1970-talets PDP11. Sannolikt ligger sanningen närmare 1000000 ggr än 1000 ggr …

Hello world

Min PiDP11/70 minidator i form av en modern mikrodator av typen Raspberry Pi model 3B. Notera att jag inte kör på den snabbaste varianten av Raspberry Pi. Valet av maskin att emulera PDP11 på gjordes utgående från vad jag råkade ha i miljonlådan … Raspberry Pi ligger på en fusklapp med kommandon man behöver för att använda den klassiska Unixeditorn ”vi” beskriven nedan.

Ett första test av en okänd dator och ifrågavarande dators programvara är ofta att skriva ett mycket kort program, kompilera det och sedan köra det. Sekvensen testar på ett allmänt plan att själva maskinen är någorlunda vettigt konfigurerad, det finns en fungerande text editor, kompilator (eller t.ex. basic tolk) samt förbindelse till bildskärm och tangentbord fungerar.

Jag har kört BSD Unix version 2.11 på min PiDP11. Alla någorlunda färska Unixvarianter är skrivna i programspråket ”c” och motsvarande kompilator heter cc (c compiler). I ett system som kör Unix brukar det alltid finnas en text editor som heter ”vi”. Editorn ”vi” är urgammal men förvånande kraftfull om användaren känner till den. Utmärkande för vi är att den är modal d.v.s. den har en kommandomod och en insättningsmod. I kommandomoden kan man med kursortangenterna och via andra tangentbordskommandon flytta sig i texten, ta bort text, söka text, byta ut text etc. Då man vill skriva text går man in i insättningsmod med kommandot ”i”. Då man vill tillbaka till kommandomoden så trycker man på ”ESC” tangenten.

Man sparar texten med kommandot ESC :w .

Man kommer ut ur programmet med kommandot ESC :q .

Avslutning så att texten sparas kan göras med kombinationen ESC :wq .

Att tvinga stängning av programmet kan man göra med ESC :q! .

Många Unixanvändare uppfattar att det enda ”vi” kommando man behöver känna till är ESC :q eftersom ingen människa med förståndet i behåll vill göra något annat än att snabbt ta sig ur editorn.

Terminalfänster från min bordsdator deNeb över nätet ner till PDP11/70. Programmet hello.c i listningen är skrivet med vi-editorn beskriven ovan.

Vi startar vi-editorn med kommandot ”vi hello.c” och kan då studera själva programmet som innehåller två utskriftskommandon som skriver ut textraderna

Hello world!
Another line!

Vi kompilerar programmet till körbar form d.v.s. maskinspråk med kommandot:

cc hello.c -o hello

Programmet körs med kommandot:

./hello

Och resultatet blir:

Kompilering av programmet hello.c . Vi ger tilläggsinformationen -o hello åt kompilatorn för att lagra resultatet i den körbara filen ”hello”. Standardnamnet på resultatet av compileringen skulle ha varit a.out vilket blir onödigt kryptiskt. Det körbara programmet körs därefter med kommandot ./hello . Orsaken till att jag skriver ./ före hello är att jag säger åt systemet att jag vill köra det program ”hello” som finns i den katalog i vilken jag befinner mig för tillfället. En Unix maskin brukar konfigureras så att man inte av misstag kör program i den katalog där man jobbar.

Jag nämnde ovan att många moderna Unixanvändare anser att det enda vi-commando man behöver känna till är ESC :q så att man med äran i behåll kan ta sig ut ur editorn. Problemet blir då hur jag skall skriva program om jag inte vill använda vi. Alternativet i 211BSD Unix på min PDP11/70 är editorn ”jove” som jag personligen har samma relation till som ”vi” d.v.s. jag vill ut ur den så snabbt som möjligt. Lösningen är naturligtvis att sätta upp kommunikation mellan min normala bordsdator eller laptop rill min PDP11 och då använda en modern editor i den moderna maskinen för att sedan flytta över program för kompilering på PDP11. Olika processer för att flytta över data mellan maskinerna presenteras i nästa avsnitt.

Arkeologi, urgammal musik

11/12/2021

Min goda vän Anders skickade mig en urgammal datafil Windows/DOS(?) sannolikt från början av 1990-talet. Filen innehåller noterna till låten Vandalen skriven av Anders Backman och Marcus Blomberg. Problemet var att ingendera upphovsmannen längre hade noterna till låten och programmet som hade använts för att skriva ner låten hade försvunnit för många år sedan vid någon dator/Windows(?) uppgradering. Anders undrade om jag hade något hjälpmedel för att lista ut vad filen innehöll eventuellt så att man kunde pussla ut hur låten gick.

Jag plockade fram en såkallad HexEditor i detta fall programmet GHex för Linux. En hexeditor klarar av att läsa godtyckliga filtyper och programmet visar två kolumner data. Den vänstra kolumnen är hexadecimala koder (siffror) och den högra kolumnen visar alla tecken som kan tolkas som text inne i filens data massa. Den högra kolumnen är alltså det läsbara som finns rad för rad i den vänstra kolumnen. Att läsa en okänd fil med en hexeditor kan ibland ge någon pekare till vilket program som i forntiden sparade filen, programmets version etc.

Då jag skrollade ner genom filen så hittade jag faktiskt lite text. Texten ingick i ett textblock i notbladet och texten var:

Bilden visar en liten del av HexEditorns skärm. Siffrorna till vänster antyder var den breda breda hexadecimala kolumnen är och visar endast den smala högra kolumnen med läsbar text. I texten fanns också namnet på de två kompositörerna Anders Backman och Marcus Blomberg. Jag putsade bort data som kunde vara känsliga om de sprids på nätet.

Eftersom filen inte innehöll enkelt igenkännbara symboler för t.ex. notvärden så blev följande steg att bena ut vilket program som eventuellt kunde ha använts för att skriva filen. Anders gissade att det eventuellt kunde ha varit ett finskt program musikantti skrivet för Soundblaster musikkortet. Anders hittade ett urgammalt tomt skivfodral som dock innehöll namnen på programmets upphovsmän. Googling på upphovsmännen gav en länk till ett gratisprogram/shareware musician som jag laddade ner och körde i DOS-emulator på min Linuxmaskin. Programmet körde men det kände inte igen filen Vandalen.mus och exempelfilerna som kom med programmet hade filtypen .NOT . Jag testade med att byta namn på Anders fil från Vandalen.mus till Vandalen.not . Samma problem kvarstod d.v.s. filtypen okänd.

Jag trodde att jag i något sammanhang hade stött på en konvertering av musik notskriftsfiler där en filtyp kunde ha varit .mus . Kunde filen eventuellt ha skapats av programmet Encore? Svar: Sannolikt inte, Encore använder filtypen .ENC .

Tid för nästa idékläckningssession. Kunde det eventuellt finnas något konversionsprogram som t.ex. kunde konvertera filtypen MUS till Encores ENC? Googling hittade ett konversionsprogram som påstod sig kunna konvertera MUS och ENC till MIDI. Då jag tittade på sidan länken pekade till så hittade jag:

We can convert MusicTime Deluxe .MUS and Encore .ENC files to a format that can be opened in other score programs or DAW/MIDI sequencer.

Ok, nu vet jag alltså eventuellt namnet på det program som har använts för notskrivningen?

Ett samtal till Anders gav som resultat att MusicTime lät bekant och att det faktiskt kunde vara det program som i början av 1990-talet hade använts vid notskrivningen.

Lite mera googlande gav en länk till en plats där jag kunde ladda ner MusicTime version 4 som en testversion. Sagt och gjort. Jag tog ner testversionen och installerade den under Windows-emulatorn under Linux. Uppackning och installation gick problemfritt och programmet startade utan några större problem. Jag flyttade Anders fil Vandalen.mus till windows emulatorns Ducuments katalog och lyckades öppna den. Filen var något skadad men fullt läslig!

Man kan tydligt se att det finns något fontproblem som beror på att jag kör under Linux och inte på en riktig Windowsinstallation. Problemet skulle med säkerhet ha gått att åtgärda genom att installera de saknade fonterna.

Min lösning var att skicka bilden till Anders som får knacka ner melodin i programmet MuseScore som vi nuförtiden använder. Fontproblemet gör att ackordanalysen försvann men antagligen kan Marcus enkelt återskapa den.

Resultatet var lyckat. Filen var i coma och höll på att glida över i bitparadiset men efter en nära döden upplevelse så återföddes filen. Det gäller nu att skriva ut en kopia som mappas in som en fysisk referens. Sannolikt kommer MuseScore att utvecklas vidare under många år varför den nya kopia Anders knackar ner nog torde vara läslig i några årtionden i framtiden.

Bananrepubliken USA?

25/09/2021

Jag har med stort intresse följt rapporteringen av auditeringen av valet i Maricopa/Arizona i USA. Eftersom jag inte har kopplingar till USA så blir antagligen den intressantaste aspekten att se hur man kommer att rapportera om detta i Europa. Kommer våra media att förbigå allt med tystnad eller kommer vi att få en hederlig rapportering?

Valmaskinens loggfiler putsades dagen innan den första ytliga kontrollen gjordes i mars. Det verkar klart att maskinen har varit i kontakt med internet via WiFi trots att tillverkaren påstår att detta inte är möjligt. Maskinen har alltså helt klart varit kopplad till Internet vilket en valmaskin absolut inte får vara.

Alla användare har använt samma password. Detta är problematiskt eftersom det då inte går att identifiera vem som gjort förändringar på maskinen ochg dess loggfiler eftersom en relativt stor grupp människor har kunnat logga in som godtycklig användare.

Videon nedan visar (på engelska) presentationen av resultaten. Det är intressant att se hur spinndoktorerna redan arbetar på högtryck för att släta över resultatet. Jag önskar mina läsare intressanta nästan tre timmar att lyssna på rapporten.

Kanske ”Banarepubliken” i rubriken är lite väl elakt då man trots allt har lyckats göra en audit … detta görs inte i en bananrepublik. Den stora frågan är om ens det här materialet leder någonstans?

Diskussion on valfusk i Arizona

30/11/2020

Det här är igen ett inlägg avsett att visa vad som diskuteras i USA och således sätta en viss press på våra egna media att ge en balanserad bild av situationen i USA idag. Notera att jag inte tar ställning för eller emot någondera kandidaten. Notera också att enligt Amerikansk lag så har president inte ännu valts eftersom elektorerna inte ännu har samlats för att avge sina röster.

Som en positiv respons tycker jag mig eventuellt se en något mera balanserad rapportering i Hufvudsstadsbladet. Hbl har publicerat åtminstone två korta notiser som visar att det kan finnas problem i valprocessen. Om detta är något nytt som håller i sig så visar detta att det eventuellt har haft effekt att lägga ut information av nedanstående typ på min blogg och naturligtvis samtidigt direkt via epost informara Hbl om detta. Dela gärna inläggen för att sätta press på nordiska media.

Diskussionen nedan är lång men innehåller mängder av mycket intressant information. videon börjar vid ungefär -5 minuter d.v.s. det lönar sig att rulla lite framåt för att spara tid.

Reparation av en Pentax K5 kamera

27/11/2020

Pentax har i många år byggt fina systemkameror som ofta har varit vattentäta/väderskyddade. Statusmässigt ligger Pentax antagligen lite i skuggan av Nikon och Canon samt engefär jämbördigt med Sony. Pentax sägs ha en mycket pålitlig användargrupp som sägs bestå främst av äldre män som använde Pentax i sin ungdom. Pentax var en av de stora tekniska innovatörerna på 1960-70-talet dock så att Nikon på det professionella området körde förbi.

I likhet med alla moderna systemkameror så monteras objektiv via en snabbfattning, bajonett. Den av Pentax utvecklade K-bajonetten har använts på licens av flera andra tillverkare vilket betyder att man har tillgång till mängder av högklassig optik på den begagnade marknaden ofta för en spottstyver.

Min Pentax K5 stomme fick plötsligt ett fel. Den tryck-knapp som frigör objektivet lossnade och försvann. Kameran är helt användbar men för att byta objektiv behövdes en liten bit tex. pianotråd som man kunde använda för att trycka ner ett frigöringslås. Inte bekvämt och allt annat än vattentätt.

Jag vet att somliga Pentaxägare har fått reservdel gratis via Pentax men det har varit oklart vilka vägar detta har skett. Då jag googlade kring detta stötte jag på nedanstående länk:

https://www.thingiverse.com/thing:1731720

Länken går till en 3D-utskriven frigöringstangent. Eftersom jag har en egen 3D-skrivare så var det naturligt att testa om det här kunde vara en lösning.

Den 3D-utskrivna nya tangenten har en axel som är mycket tunn. Detta är oftast ett stort problem vid utskrift. Utskriften av en tunn spets går så snabbt att plasten inte hinner stelna mellan plastlagren vilket leder till att komponenten ändrar form och sjunker ihop. Lösningen på detta är väldigt enkel. Om man har något annat storre objekt som man kan skriva ut samtidigt så lönar det sig att göra detta. Det större föremålet ger tid för det lilla att svalna vilket höjer kvaliteten. Ett annat lika enkelt alternativ är att i stället för att skriva ut endast ett enda litet föremål så skriver man ut, i mitt fall nio st. Efter utskrift väljer man det exemplar som blev bäst.

Frigöringsknappen för objektivet syns nere yngeför vid kl. 7 strax vänster om objektivet. Den utskrivna delen är redan på plats då jag glömde att ta en bild av situationen före den nya komponenten monterades.

Notera hur jag skrev ut 9 st nya tryck-knappar av vilka jag använde endast en.

Belysningen råkar framhäva den sandpapprade sidan av den nya frigöringsknappen. I normal belysning reagerar man inte på att delen är 3D-utskriven och inte orginal.

Lyckat ”hack”! Det är alltid trevligt då man lyckas förlänga livet på en teknisk mojäng som har ett litet men mycket störande fel. Nu blir det naturligtvis intressant att se hur länge den nya delen håller.

Trevlig WiFi kamera

18/11/2020

En digitalkamera, t.o.m. en högkvalitativ sådan kostar idag ingenting eftersom man tillverkar någon miljard per år för montering i främst mobiltelefoner. Eftersom kameror massproduceras så kommer det alltid att finnas ett överskott som bl.a. kan användas av tekniskt intresserade amatörer.

Jag stötte för en tid sedan på ESP32-CAM som bygger på en ESP32 mikroprocessor med kameramodulen OV2640. Hela paketet kostar $6.99 och inklusive transport kostade paketet ungefär 10 Euro (100 SEK).

ESP32-kortet har storleken ca. 40×25 mm. Trådarna som är kopplade till kortet är strömförsörjning via USB samt serielinje för att kunna följa med vad som händer på kortet. Serieförbindelsen behövs inte i ett senare skede och strömförsörjningen kommer att skötas med laddningsbara batterier.

Vad innehåller paketet?

Processorn är en ESP32 med dubbla kärnor, 512 kByte SRAM och 4 MByte pseudostatiskt RAM. Processorn kör på en klockfrekvens upp till 240 MHz och har alla vanliga anslutningar för periferienheter SPI, I2C, serielinje etc. samt inbyggd WiFi alltså trådlöst nätverk utan extra komponenter. En enkel utvecklingsomgivning som finns för Linux, Windows och MacOS är Arduino IDE. För att skriva program för ESP32 behövs en IDE version som är någorlunda ny, jag kör 1.8.13.

Hur lägger jag in webbservern för kameran om den inte finns från början?

Hämta Arduino IDE för ditt operativsystem. Googla ”Arduino IDE xxxxc” där xxxx är ditt operativsystem.

Starta Arduino IDE och lägg till kortfamiljen ESP32 via File/Preferences

Nere i fönstret finns ett fält för Additional Boards Manager URLs .

Klistra in https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json

Tryck på OK.

Gå därefter till Tools/Board/Board Manager . Skriv ESP32 i fältet Filter your Search. Board managern visar vad den hittar (esp32) klicka på Install varvid systemet automatiskt laddar ner de hjälpprogram, drivrutiner, bibliotek och exempel man behöver. Om man tidigare har laddat ner hjälprutiner för ESP32 så meddelar Board manager status: Installed för paketet.

Hämta kameraprogrammet i File/Examples/ESP32/Camera/CameraWebServer . Programkoden öppnas automatiskt i fönstret.

För att programmera ESP32 behöver jag en USB till Serial konversionsmodul som kostar några Euro. Moderna datorer saknar en konventionell serieport varför det behövs en USB-modul som skapar en serieport via USB-porten. Jag beställde en ”USB To TTL FT232RL FTDI Serial Adapter Converter Module For Arduino 3.3V 5V Mini” tillsammans med ESP32-CAM modulen.

Spänningen i USB seriemodulen väljs via en jumper (bygel) till antingen 3.3 V eller 5V. Väljer man 3.3V måste stiftet VCC på USB modulen kopplas till 3.3V på ESP32. Om man väljer 5V kopplas VCC i stället till 5V på ESP32. Det är viktigt att inte klanta och koppla 5V till 3.3V på ESP32 eftersom detta kan leda till att man släpper ut rök. Som känt fungerar all elektronik på rök eftersom elektronik tenderar att sluta fungera om man släpper ut röken.

USB-modulens RX kopplas till UOT på ESP32 och på motsvarande sätt kopplas TX på USB-modulen till UOR på ESP32. Notera att Transmit (sänd) på ena sidan alltid kopplas till Receive (mottag) på andra sidan och tvärtom.

Koppla GND på USB-modulen till GND på ESP32.

För programmering kopplas ytterligare IO0 till GND på ESP32. Byglingen av IO0 till jord signalerar Arduino IDE att uppladdning av program till ESP32 önskas. Då man vill köra ett uppladdat program kopplar man bort denna bygel.

Koppla i USB till datorn där Arduino IDE är aktivt. Kontrollera i Tools/Port att en serieport t.ex. /dev/ttyUSB0 under Linux har detekterats. Kontrollera samtidigt att Upload speed är satt till t.ex. 9212000 bit/sekund (kör man på lägre hastighet kan uppladdningen bli besvärande långsam). Sätt Tools/Partitition Scheme är satt till Huge APP . Glömmer man att organisera minnet till Huge App så kommer kompileringen att misslyckas.

Vi kan nu försöka kompilera exempelprogrammet via Sketch/Verify/Compile. Kompileringen gick inte igenom för mig vid första försöket eftersom en pythonmodul <serial> inte hittades. Det gick att identifiera problemet genom att felet låg i ett program med typen .py medan språket som används under Arduino IDE normalt är C/C++.Notera att felet inte låg i ESP32 vebbserverprogrammet utan det var ett hjälpprogram från ESP32 som behövde modulen. Felet avhjälptes genom att ladda in serial:

sudo apt install python-serial

Modifiera därefter programkoden så att du lägger in WiFi SSID samt password. Dessutom måste man välja kameramodell. I mitt fall fungerar alternativet:

#define CAMERA_MODEL_AI_THINKER

Man väljer kameramodell genom att ta bort kommentaren före ifrågavarande #define. En kommentar börjar med ”//”.

Nu gick kompileringen igenom och programmet kan laddas upp till ESP32. Tryck på Reset på ESP32, en mycket liten trycktangent bredvid 3.3V anslutningen. Välj nu Sketch/Upload och om allt går korrekt så börjar programmet laddas upp (tid kanske 30-60 sekunder beroende på vilken uppladdningshastighet man valt). Då uppladdningen har lyckats kopplar man ur programmeringsbygeln IO0-GND för att köra programmet.

Starta Tools/serial Monitoroch kontrollera att hastigheten är vettig t.ex. 115200. Tryck på ESP32 Reset varefter ESP bör skriva diverse text till monitorn. I texten hittar vi den IP adress som ESP32 har fått via det lokala WiFi nätverket.

Vi öppnar nu en vebbläsare (jag använder Firefox) och lägger in den IP-adress vi fick oss tilldelad och som vi grävde fram åt oss från texten på monitorskärmen. I mitt fall fick jag adressen http://192.168.10.42/. Notera att den angivna adressen ovan inte är verklig och den kommer inte att fungera i ditt fall.

Ett fönster med kamerakontroller på vänster sida öppnas i vebbläsaren. Längst ner finns kontrollerna Get still, Start stream . Tryck på Start Stream varvid ESP32 börjar sända video över WiFi till datorn. Det är nu möjligt att via kontrollerna ändra ljushet/mörkhet, kontrast, upplösning etc. Fritt fram att experimentera.

Följande steg?

Följande steg blir att planera och skriva ut ett lämpligt skal samt förse ESP32 med ett laddningsbart batteripaket så att jag kan hänga systemet på fågelbordet och avslöja våra stora (vitsvanshjortar 😉 ) småfåglar som länsar fågelbordet på nolltid.

Källor:

Det finns en hel del artiklar på engelska om hur ESP32 skall kopplas för programutveckling. Nedan enast ett exempel. Vid problem lönar det sig oftast att Google på den felkod man får. Det finns oftast någon annan som har stött på samma problem och en lösning kan ofta hittas direkt.


Pointman's

A lagrange point in life

THE HOCKEY SCHTICK

Lars Silén: Reflex och Spegling

NoTricksZone

Lars Silén: Reflex och Spegling

Big Picture News, Informed Analysis

Canadian journalist Donna Laframboise. Former National Post & Toronto Star columnist, past vice president of the Canadian Civil Liberties Association.

JoNova

Lars Silén: Reflex och Spegling

Climate Audit

by Steve McIntyre

Musings from the Chiefio

Techno bits and mind pleasers

Bishop Hill

Lars Silén: Reflex och Spegling

Watts Up With That?

The world's most viewed site on global warming and climate change

TED Blog

The TED Blog shares news about TED Talks and TED Conferences.

Larsil2009's Blog

Lars Silén: Reflex och Spegling

%d bloggare gillar detta: