Ho fatto qualche esperimento con LM358 in passato (con risultati deludenti..per colpa mia).
Frugando su Internet ho trovato questo link dove viene indicato l'utilizzo di LM358 con un configurazione che non avevo mai usato
Il testo di riferimento citato nel testo del post non e' piu' disponibile ma sono riuscito a trovare una copia di Ops amps for Everyone a questo link
Con la configurazione sotto riportata il fattore di amplificazione e' data dalla tensione di ingresso per il rapporto tra Rf ed Rg piu' la tensione di alimentazione divisa per due (le due resistenze R di uguale entita' funzionano come un divisore di tensione)
Non avendo un microfono audio o un generato di segnale mi sono adattato a vedere l'amplificazione data da un piezoelettrico. In condizioni non amplificate il segnale massimo registrato e' stato di circa 5/6 unita' sull'ingresso analogico
passandolo per l'amplificatore si vede chiaramente che viene amplificato anche il rumore e l'intesita' del segnale e' passata a qualche centinaio di unita' (ho perso i dettagli delle resistenze che ho usato). Si vede anche che il segnale e' stato spostato al centro dell'asse delle Y (valore di circa 500 con una fondo scale di 1024 a bit 10)
mercoledì 15 giugno 2016
martedì 14 giugno 2016
Crearsi una scatola per GPS Arduino
Quando un progetto di Arduino deve diventare operativo e' necessario costruirsi una scatola che alloggi l'elettronica e gli accessori. In questo post descrivo come ho creato la scatola per il mio GPS Arduino Ublox
Il primo passo fondamentale e' munirsi di distanziali (spacer) per bloccare la scheda elettrica alla scatola
Ne esistono sia in metallo (credo sia ottone) che in nylon. Io ho usato quelli in plastica. Il passo della vite e' da 3 per cui si puo' comprare anche minuteria metallica se la lunghezza delle viti del set non e' idonea
Come scatola ho preso una Gewiss GW 44 007 classificata come IP 55 (ovvero Protezione totale alla penetrazione di corpi solidi.Protezione contro la penetrazione di liquidi da gocce, vapori, spruzzi e getti d'acqua in qualsiasi direzione.)
L'utilizzo di questa scatola ha il vantaggio di avere dei tappi removibili che permettono il passaggio di un cavo USB di programmazione per poi richiudere il tutto senza necessariamente dovere rimuovere il coperchio e le sue viti
Il primo passo fondamentale e' munirsi di distanziali (spacer) per bloccare la scheda elettrica alla scatola
Ne esistono sia in metallo (credo sia ottone) che in nylon. Io ho usato quelli in plastica. Il passo della vite e' da 3 per cui si puo' comprare anche minuteria metallica se la lunghezza delle viti del set non e' idonea
Come scatola ho preso una Gewiss GW 44 007 classificata come IP 55 (ovvero Protezione totale alla penetrazione di corpi solidi.Protezione contro la penetrazione di liquidi da gocce, vapori, spruzzi e getti d'acqua in qualsiasi direzione.)
L'utilizzo di questa scatola ha il vantaggio di avere dei tappi removibili che permettono il passaggio di un cavo USB di programmazione per poi richiudere il tutto senza necessariamente dovere rimuovere il coperchio e le sue viti
Modalita' di programmazione |
Il progetto prevede di montare sul coperchio l'antenna GPS (all'interno) ed il pannello solare (all'esterno)
Montati i distanziali sull'antenna si devono fare i fori sul coperchio...ma come farli precisi?? Un piccolo trucco. Si macchia il distanziale con un pennarello, essendo di nylon l'inchiostro non penetra e basta appoggiare il tutto sul coperchio per ottenere l'impronta di dove forare.La punta del trapano da usare e' quella da 3
Il risultato finale e' questo
Per montare il pannello solare si deve praticare un foro per passare i fili all'interno della scatola e dei distanziali per sostenere il pannello. Visto che il pannello solare era privo di prefori ho usato dei gommini di plastica fermati da una vite a ferro (fare prima un preforo prima di avvitare la vite perche' la plastica e' molto scivolosa e ci vuole un foro guida)
Per fissare il pannello al coperchio e' sufficiente usare una abbondante dose di silicone
Si passa all'interno della scatola. Su Arduino Uno sono stati montati gli spacer (in questo caso hanno trovato posto solo tre spacer su quattro fori perche' il dado di serraggio dello spacer e' troppo grande...non un gran male perche' comunque sul fondo della scatola ci sono dei bordi rialzati che si possono utilizzare come appoggio)
Per trovare il punto giusto di realizzazione dei fori si usa lo stesso metodo precedente
La batteria invece e' stata bloccata con del velcro.
A questo punto si devono mettere insieme i pezzi (scatola e coperchio). Qui l'unica attenzione e' quella di allungare tutti i cavi in modo da rendere agevole. E' anche comodo scegliere un lato di apertura della scatola e di marcarla sulla scatola in modo da aprire sempre dallo stesso verso (questo per non aprire per sbaglio un un lato per cui i cavi vanno in tensione)
lunedì 13 giugno 2016
LCD1602 su PIC DevBoard
Codice, ripreso da un produttore cinese, su come usare LCD1602 con PIC. Compilatore MapLab IDE
main.c
---------------------------------------------
#include <pic.h>
#include "LCD1602.h"
//---------------------------------------
unsigned char str0[]={"Luca "};
unsigned char str1[]={"Innocenti "};
unsigned char str2[]={"debiaonoldcomput"};
unsigned char str3[]={"ers.blogspot.com"};
//---------------------------------------
void main(void)
{
LCD1602_GPIO_Init();
LCD1602_init();
while(1)
{
DisplayListChar(0,0,str0);
DisplayListChar(0,1,str1);
Delay1602_MS(500);
DisplayListChar(0,0,str2);
DisplayListChar(0,1,str3);
Delay1602_MS(500);
}
}
---------------------------------------------
LCD1602.H
---------------------------------------------
#ifndef __LCD1602_H
#define __LCD1602_H
#define E RA3
#define RW RA2
#define RS RA5
#define busy RD7
#define busy_init TRISD7
#define Lcd_Date PORTD
void Delay1602_US(unsigned int t);
void Delay1602_MS(unsigned int t);
void LCD1602_BusyTest(void);
void LCD1602_Write_Instruction(unsigned char combuf);
void LCD1602_Write_data_busy(unsigned char databuf);
void LCD1602_init(void);
void DisplayOneChar(unsigned char X,unsigned char Y,unsigned char DData);
void DisplayListChar(unsigned char X,unsigned char Y,unsigned char *DData);
void LCD1602_GPIO_Init(void);
#endif
---------------------------------------------
1602.c
---------------------------------------------
#include <pic.h>
#include "LCD1602.h"
__CONFIG(HS&WDTDIS&LVPDIS);
void Delay1602_US(unsigned int t)
{
unsigned int k;
for(k=0;k<t;k++);
}
void Delay1602_MS(unsigned int t)
{
while(t--)
Delay1602_US(200);
}
void LCD1602_BusyTest(void)
{
busy_init=1;
RS=0;
RW=1;
E=1;
asm("NOP");
asm("NOP");
while(busy==1);
E=0;
busy_init=0;
}
void LCD1602_Write_Instruction(unsigned char combuf)
{
LCD1602_BusyTest();
RS=0;
RW=0;
E=0;
asm("NOP");
Lcd_Date=combuf;
asm("NOP");
asm("NOP");
E=1;
asm("NOP");
E=0;
}
void LCD1602_Write_data_busy(unsigned char databuf)
{
LCD1602_BusyTest();
RS=1;
RW=0;
E=0;
asm("NOP");
Lcd_Date=databuf;
asm("NOP");
asm("NOP");
E=1;
asm("NOP");
E=0;
}
void LCD1602_init(void)
{
Delay1602_US(1500);
LCD1602_Write_Instruction(0x38);
Delay1602_US(500);
LCD1602_Write_Instruction(0x38);
Delay1602_US(500);
LCD1602_Write_Instruction(0x38);
LCD1602_Write_Instruction(0x38);
LCD1602_Write_Instruction(0x08);
LCD1602_Write_Instruction(0x01);
LCD1602_Write_Instruction(0x06);
LCD1602_Write_Instruction(0x0C);
}
void DisplayOneChar(unsigned char X,unsigned char Y,unsigned char DData)
{
Y&=1;
X&=15;
if(Y)X|=0x40;
X|=0x80;
LCD1602_Write_Instruction(X);
LCD1602_Write_data_busy(DData);
}
void DisplayListChar(unsigned char X,unsigned char Y,unsigned char *DData)
{
unsigned char ListLength=0;
Y&=0x01;
X&=0x0f;
while(X<16)
{
DisplayOneChar(X,Y,DData[ListLength]);
ListLength++;
X++;
}
}
void LCD1602_GPIO_Init(void)
{
ADCON1=0X07;
TRISA=0B11010011;
TRISD=0B00000000;
PORTA=0B00000000;
PORTD=0B00000000;
}
---------------------------------------------
Schema elettrico |
main.c
---------------------------------------------
#include <pic.h>
#include "LCD1602.h"
//---------------------------------------
unsigned char str0[]={"Luca "};
unsigned char str1[]={"Innocenti "};
unsigned char str2[]={"debiaonoldcomput"};
unsigned char str3[]={"ers.blogspot.com"};
//---------------------------------------
void main(void)
{
LCD1602_GPIO_Init();
LCD1602_init();
while(1)
{
DisplayListChar(0,0,str0);
DisplayListChar(0,1,str1);
Delay1602_MS(500);
DisplayListChar(0,0,str2);
DisplayListChar(0,1,str3);
Delay1602_MS(500);
}
}
---------------------------------------------
LCD1602.H
---------------------------------------------
#ifndef __LCD1602_H
#define __LCD1602_H
#define E RA3
#define RW RA2
#define RS RA5
#define busy RD7
#define busy_init TRISD7
#define Lcd_Date PORTD
void Delay1602_US(unsigned int t);
void Delay1602_MS(unsigned int t);
void LCD1602_BusyTest(void);
void LCD1602_Write_Instruction(unsigned char combuf);
void LCD1602_Write_data_busy(unsigned char databuf);
void LCD1602_init(void);
void DisplayOneChar(unsigned char X,unsigned char Y,unsigned char DData);
void DisplayListChar(unsigned char X,unsigned char Y,unsigned char *DData);
void LCD1602_GPIO_Init(void);
#endif
---------------------------------------------
1602.c
---------------------------------------------
#include <pic.h>
#include "LCD1602.h"
__CONFIG(HS&WDTDIS&LVPDIS);
void Delay1602_US(unsigned int t)
{
unsigned int k;
for(k=0;k<t;k++);
}
void Delay1602_MS(unsigned int t)
{
while(t--)
Delay1602_US(200);
}
void LCD1602_BusyTest(void)
{
busy_init=1;
RS=0;
RW=1;
E=1;
asm("NOP");
asm("NOP");
while(busy==1);
E=0;
busy_init=0;
}
void LCD1602_Write_Instruction(unsigned char combuf)
{
LCD1602_BusyTest();
RS=0;
RW=0;
E=0;
asm("NOP");
Lcd_Date=combuf;
asm("NOP");
asm("NOP");
E=1;
asm("NOP");
E=0;
}
void LCD1602_Write_data_busy(unsigned char databuf)
{
LCD1602_BusyTest();
RS=1;
RW=0;
E=0;
asm("NOP");
Lcd_Date=databuf;
asm("NOP");
asm("NOP");
E=1;
asm("NOP");
E=0;
}
void LCD1602_init(void)
{
Delay1602_US(1500);
LCD1602_Write_Instruction(0x38);
Delay1602_US(500);
LCD1602_Write_Instruction(0x38);
Delay1602_US(500);
LCD1602_Write_Instruction(0x38);
LCD1602_Write_Instruction(0x38);
LCD1602_Write_Instruction(0x08);
LCD1602_Write_Instruction(0x01);
LCD1602_Write_Instruction(0x06);
LCD1602_Write_Instruction(0x0C);
}
void DisplayOneChar(unsigned char X,unsigned char Y,unsigned char DData)
{
Y&=1;
X&=15;
if(Y)X|=0x40;
X|=0x80;
LCD1602_Write_Instruction(X);
LCD1602_Write_data_busy(DData);
}
void DisplayListChar(unsigned char X,unsigned char Y,unsigned char *DData)
{
unsigned char ListLength=0;
Y&=0x01;
X&=0x0f;
while(X<16)
{
DisplayOneChar(X,Y,DData[ListLength]);
ListLength++;
X++;
}
}
void LCD1602_GPIO_Init(void)
{
ADCON1=0X07;
TRISA=0B11010011;
TRISD=0B00000000;
PORTA=0B00000000;
PORTD=0B00000000;
}
---------------------------------------------
Emulatori 6502 su Arduino
Andando a giro su Internet ho scoperto che esiste la possibilta' di emulare il glorioso processore MOS 6502 (e la sua variante MOS 6510) su Arduino.
Esistono diversi progetti come quello per il C64, per il VIC 20 ed il KIM-1.
Per emulare il C64 e' necessario utilizzare una Arduino Due a causa della mancanza di memoria della scheda Uno
Una volta caricato il programma (da qui) ci si deve collegare via seriale ma non usando il terminale seriale di Arduino IDE (Minicom e Hyperterminal funzionano, configurazione 9600 8N1). Ci si trova davanti all'interprete BASIC
a parte lo spazio di memoria libera veramente esigua il sistema funziona
Un po' (un bel po') piu' impegnativo e' usare l'emulatore del KIM-1 (funzionante anche su Arduino Uno e reperibile a questo indirizzo) perche' di fatto il sistema si programma direttamente in Linguaggio Macchina (non e' un errore, non si programma in Assembler, si inputa il codice direttamente in LM)
Come nel caso precedente si deve usare un terminale seriale esterno alla IDE di Arduino
La cosa piu' divertente e' pero' dare un'occhiata al file cpu.c dove e' contenuta la divisione della memoria con eventuali programmi caricati come ROM, la traduzione delle istruzioni in Assembler 6502 comprese quelle non documentate e la gestione degli interrupt
Esistono diversi progetti come quello per il C64, per il VIC 20 ed il KIM-1.
Per emulare il C64 e' necessario utilizzare una Arduino Due a causa della mancanza di memoria della scheda Uno
Una volta caricato il programma (da qui) ci si deve collegare via seriale ma non usando il terminale seriale di Arduino IDE (Minicom e Hyperterminal funzionano, configurazione 9600 8N1). Ci si trova davanti all'interprete BASIC
a parte lo spazio di memoria libera veramente esigua il sistema funziona
Un po' (un bel po') piu' impegnativo e' usare l'emulatore del KIM-1 (funzionante anche su Arduino Uno e reperibile a questo indirizzo) perche' di fatto il sistema si programma direttamente in Linguaggio Macchina (non e' un errore, non si programma in Assembler, si inputa il codice direttamente in LM)
Come nel caso precedente si deve usare un terminale seriale esterno alla IDE di Arduino
La cosa piu' divertente e' pero' dare un'occhiata al file cpu.c dove e' contenuta la divisione della memoria con eventuali programmi caricati come ROM, la traduzione delle istruzioni in Assembler 6502 comprese quelle non documentate e la gestione degli interrupt
giovedì 9 giugno 2016
RealTime Operating Systems RTOS per Arduino
Una delle cose belle di Arduino e' che, pur nella sua semplicita', esegue in modo ripetibile e prevedibile un compito...ma in fondo e' uno solo. Se il sistema e' intrappolato, per esempio in un loop infinito, esistono sistemi basati sulla gestione degli interrupt per venire incontro a condizioni non prevedbili, come per esempio la pressione di un tasto da parte dell'utente
Un sistema decisamente piu' evoluto per gestire processi concorrenti su un processore da risorse cosi' ridotte come l'AVR ATMega328 e' quello di usare i sistemi operativi realtime, in breve RTOS (sistema operativo inteso come kernel ed API, non come interfaccia utente)
Con questi software si puo' avere la gestione di thread concorrenti con gestione della priorita' dei task, la gestione di semafori Mutex., binari o counting semaphore per sincronizzare i processi. Una caratteristica fondamentale dei sistemi RTOS e' quello di eseguire un task in un arco temporale (minimo e massimo) ben definito; se dopo il tempo massimo il task non ha finito il compito deve lasciare spazio agli altri task concorrenti. Questa caratteristica e' importante per sistemi robotizzati: per esempio se un automa si muove e contemporaneamente acquisisce dati, i sensori di urto devono avere la priorita' sull'acquisizione e non ci deve essere ritardo tra quando viene lanciato l'allarme di prossimita' e la conseguente azione. Su Linux (sempre che non monti un kernel modificato per essere realtime..la Nasa all'inizio degli anni 2000 aveva creato Flight Linux) puo' succedere che il sistema sia occupata in un task lungo e non rilasci in tempo le risorse per evitare l'urto del robot
Per Arduino esistono sostanzialmente FreeRTOS e ChibiOS
Come documentazione Chibios e' decisamente meglio documentato , FreeRTOS ha un libro a pagamento mentre nel file .zip con il sistema operativo c'e' una cartella con gli esempi ma non relativi ad ATMega.
Un caso pratico in cui si puo' capire il vantaggio di un sistema RTOS della classica programmazione Arduino e' quello in cui si gestisce un flusso seriale ed in maniera indipendente si devono gestire anche l'acquisizione dei sensori
FreeRTOS
Per installare le libreriei di FreeRTOS nella IDE di Arduino e' sufficiente andare nel menu Sketch/Includi libreria/Gestione Librerie e cercare ed installare FreeRTOS. Stranamente non vengono installati degli esempi
ChibiOS
Per installare ChibiOS in Arduino IDE si parte scaricando le librerie da questo link.(esiste un sistema di sviluppo completo costituito da ChibiOS Studio ma e' possibile compilare per ATMega ma solo per ARM STM32) e si pone la sottodirectory /libraries/ChibiOS_AVR presente nel file zip dentro la directory libraries della IDE di Arduino (sotto Windows si trova nella propria C:\Documents and Settings\xxxxx\Documenti\Arduino\libraries\ChibiOS_AVR mentre in Linux e' semplicemente in libraries)
Dal punto di vista di scrittura del codice ci sono diversi similitudini. Prendendo due esempi semplici (riportati piu' in basso). Nella parte di setup vengono dichiarati i task che fanno riferimenti a due funzioni con l'indicazione della priorita'; all'interno della funzione del task sono riportate le azioni di ciascun thread FreeRTOS usa il termine task che corrisponde al thread di Chibios)
Esempio FreeRTOS.
Due Task in cui uno lampeggia un led e l'altro legge i dati da una porta analogica e lo spedisce sulla seriale
---------------------------
#include <Arduino_FreeRTOS.h>
#include <croutine.h>
#include <event_groups.h>
#include <FreeRTOSConfig.h>
#include <FreeRTOSVariant.h>
#include <list.h>
#include <mpu_wrappers.h>
#include <portable.h>
#include <portmacro.h>
#include <projdefs.h>
#include <queue.h>
#include <semphr.h>
#include <StackMacros.h>
#include <task.h>
#include <timers.h>
#include <Arduino_FreeRTOS.h>
// define two tasks for Blink & AnalogRead
void TaskBlink( void *pvParameters );
void TaskAnalogRead( void *pvParameters );
// the setup function runs once when you press reset or power the board
void setup() {
// Now set up two tasks to run independently.
xTaskCreate(
TaskBlink
, (const portCHAR *)"Blink" // A name just for humans
, 128 // Stack size
, NULL
, 2 // priority
, NULL );
xTaskCreate(
TaskAnalogRead
, (const portCHAR *) "AnalogRead"
, 128 // This stack size can be checked & adjusted by reading Highwater
, NULL
, 1 // priority
, NULL );
// Now the task scheduler, which takes over control of scheduling individual tasks, is automatically started.
}
void loop()
{
// Empty. Things are done in Tasks.
}
/*--------------------------------------------------*/
/*---------------------- Tasks ---------------------*/
/*--------------------------------------------------*/
void TaskBlink(void *pvParameters) // This is a task.
{
(void) pvParameters;
// initialize digital pin 13 as an output.
pinMode(13, OUTPUT);
for (;;) // A Task shall never return or exit.
{
digitalWrite(13, HIGH); // turn the LED on (HIGH is the voltage level)
vTaskDelay( 1000 / portTICK_PERIOD_MS ); // wait for one second
digitalWrite(13, LOW); // turn the LED off by making the voltage LOW
vTaskDelay( 1000 / portTICK_PERIOD_MS ); // wait for one second
}
}
void TaskAnalogRead(void *pvParameters) // This is a task.
{
(void) pvParameters;
// initialize serial communication at 9600 bits per second:
Serial.begin(9600);
for (;;)
{
// read the input on analog pin 0:
int sensorValue = analogRead(A0);
// print out the value you read:
Serial.println(sensorValue);
vTaskDelay(1); // one tick delay (15ms) in between reads for stability
}
}
---------------------------
Esempio ChibiOs
Due Task che fanno lampeggiare il led con l'uso di un semaforo per scambiarsi i dati tra i due thread
----------------------------
// Example to demonstrate thread definition, semaphores, and thread sleep.
#include <ChibiOS_AVR.h>
// The LED is attached to pin 13 on Arduino.
const uint8_t LED_PIN = 13;
// Declare a semaphore with an inital counter value of zero.
SEMAPHORE_DECL(sem, 0);
//------------------------------------------------------------------------------
// Thread 1, turn the LED off when signalled by thread 2.
// 64 byte stack beyond task switch and interrupt needs
static THD_WORKING_AREA(waThread1, 64);
static THD_FUNCTION(Thread1, arg) {
while (!chThdShouldTerminateX()) {
// Wait for signal from thread 2.
chSemWait(&sem);
// Turn LED off.
digitalWrite(LED_PIN, LOW);
}
}
//------------------------------------------------------------------------------
// Thread 2, turn the LED on and signal thread 1 to turn the LED off.
// 64 byte stack beyond task switch and interrupt needs
static THD_WORKING_AREA(waThread2, 64);
static THD_FUNCTION(Thread2, arg) {
pinMode(LED_PIN, OUTPUT);
while (1) {
digitalWrite(LED_PIN, HIGH);
// Sleep for 200 milliseconds.
chThdSleepMilliseconds(200);
// Signal thread 1 to turn LED off.
chSemSignal(&sem);
// Sleep for 200 milliseconds.
chThdSleepMilliseconds(200);
}
}
//------------------------------------------------------------------------------
void setup() {
chBegin(chSetup);
// chBegin never returns, main thread continues with mainThread()
while(1) {
}
}
//------------------------------------------------------------------------------
// main thread runs at NORMALPRIO
void chSetup() {
// start blink thread
chThdCreateStatic(waThread1, sizeof(waThread1),
NORMALPRIO + 2, Thread1, NULL);
chThdCreateStatic(waThread2, sizeof(waThread2),
NORMALPRIO + 1, Thread2, NULL);
}
//------------------------------------------------------------------------------
void loop() {
// not used
}
Un sistema decisamente piu' evoluto per gestire processi concorrenti su un processore da risorse cosi' ridotte come l'AVR ATMega328 e' quello di usare i sistemi operativi realtime, in breve RTOS (sistema operativo inteso come kernel ed API, non come interfaccia utente)
Con questi software si puo' avere la gestione di thread concorrenti con gestione della priorita' dei task, la gestione di semafori Mutex., binari o counting semaphore per sincronizzare i processi. Una caratteristica fondamentale dei sistemi RTOS e' quello di eseguire un task in un arco temporale (minimo e massimo) ben definito; se dopo il tempo massimo il task non ha finito il compito deve lasciare spazio agli altri task concorrenti. Questa caratteristica e' importante per sistemi robotizzati: per esempio se un automa si muove e contemporaneamente acquisisce dati, i sensori di urto devono avere la priorita' sull'acquisizione e non ci deve essere ritardo tra quando viene lanciato l'allarme di prossimita' e la conseguente azione. Su Linux (sempre che non monti un kernel modificato per essere realtime..la Nasa all'inizio degli anni 2000 aveva creato Flight Linux) puo' succedere che il sistema sia occupata in un task lungo e non rilasci in tempo le risorse per evitare l'urto del robot
Per Arduino esistono sostanzialmente FreeRTOS e ChibiOS
Come documentazione Chibios e' decisamente meglio documentato , FreeRTOS ha un libro a pagamento mentre nel file .zip con il sistema operativo c'e' una cartella con gli esempi ma non relativi ad ATMega.
Un caso pratico in cui si puo' capire il vantaggio di un sistema RTOS della classica programmazione Arduino e' quello in cui si gestisce un flusso seriale ed in maniera indipendente si devono gestire anche l'acquisizione dei sensori
FreeRTOS
Per installare le libreriei di FreeRTOS nella IDE di Arduino e' sufficiente andare nel menu Sketch/Includi libreria/Gestione Librerie e cercare ed installare FreeRTOS. Stranamente non vengono installati degli esempi
ChibiOS
Per installare ChibiOS in Arduino IDE si parte scaricando le librerie da questo link.(esiste un sistema di sviluppo completo costituito da ChibiOS Studio ma e' possibile compilare per ATMega ma solo per ARM STM32) e si pone la sottodirectory /libraries/ChibiOS_AVR presente nel file zip dentro la directory libraries della IDE di Arduino (sotto Windows si trova nella propria C:\Documents and Settings\xxxxx\Documenti\Arduino\libraries\ChibiOS_AVR mentre in Linux e' semplicemente in libraries)
ChibiOS Studio |
Dal punto di vista di scrittura del codice ci sono diversi similitudini. Prendendo due esempi semplici (riportati piu' in basso). Nella parte di setup vengono dichiarati i task che fanno riferimenti a due funzioni con l'indicazione della priorita'; all'interno della funzione del task sono riportate le azioni di ciascun thread FreeRTOS usa il termine task che corrisponde al thread di Chibios)
Esempio FreeRTOS.
Due Task in cui uno lampeggia un led e l'altro legge i dati da una porta analogica e lo spedisce sulla seriale
---------------------------
#include <Arduino_FreeRTOS.h>
#include <croutine.h>
#include <event_groups.h>
#include <FreeRTOSConfig.h>
#include <FreeRTOSVariant.h>
#include <list.h>
#include <mpu_wrappers.h>
#include <portable.h>
#include <portmacro.h>
#include <projdefs.h>
#include <queue.h>
#include <semphr.h>
#include <StackMacros.h>
#include <task.h>
#include <timers.h>
#include <Arduino_FreeRTOS.h>
// define two tasks for Blink & AnalogRead
void TaskBlink( void *pvParameters );
void TaskAnalogRead( void *pvParameters );
// the setup function runs once when you press reset or power the board
void setup() {
// Now set up two tasks to run independently.
xTaskCreate(
TaskBlink
, (const portCHAR *)"Blink" // A name just for humans
, 128 // Stack size
, NULL
, 2 // priority
, NULL );
xTaskCreate(
TaskAnalogRead
, (const portCHAR *) "AnalogRead"
, 128 // This stack size can be checked & adjusted by reading Highwater
, NULL
, 1 // priority
, NULL );
// Now the task scheduler, which takes over control of scheduling individual tasks, is automatically started.
}
void loop()
{
// Empty. Things are done in Tasks.
}
/*--------------------------------------------------*/
/*---------------------- Tasks ---------------------*/
/*--------------------------------------------------*/
void TaskBlink(void *pvParameters) // This is a task.
{
(void) pvParameters;
// initialize digital pin 13 as an output.
pinMode(13, OUTPUT);
for (;;) // A Task shall never return or exit.
{
digitalWrite(13, HIGH); // turn the LED on (HIGH is the voltage level)
vTaskDelay( 1000 / portTICK_PERIOD_MS ); // wait for one second
digitalWrite(13, LOW); // turn the LED off by making the voltage LOW
vTaskDelay( 1000 / portTICK_PERIOD_MS ); // wait for one second
}
}
void TaskAnalogRead(void *pvParameters) // This is a task.
{
(void) pvParameters;
// initialize serial communication at 9600 bits per second:
Serial.begin(9600);
for (;;)
{
// read the input on analog pin 0:
int sensorValue = analogRead(A0);
// print out the value you read:
Serial.println(sensorValue);
vTaskDelay(1); // one tick delay (15ms) in between reads for stability
}
}
---------------------------
Esempio ChibiOs
Due Task che fanno lampeggiare il led con l'uso di un semaforo per scambiarsi i dati tra i due thread
----------------------------
// Example to demonstrate thread definition, semaphores, and thread sleep.
#include <ChibiOS_AVR.h>
// The LED is attached to pin 13 on Arduino.
const uint8_t LED_PIN = 13;
// Declare a semaphore with an inital counter value of zero.
SEMAPHORE_DECL(sem, 0);
//------------------------------------------------------------------------------
// Thread 1, turn the LED off when signalled by thread 2.
// 64 byte stack beyond task switch and interrupt needs
static THD_WORKING_AREA(waThread1, 64);
static THD_FUNCTION(Thread1, arg) {
while (!chThdShouldTerminateX()) {
// Wait for signal from thread 2.
chSemWait(&sem);
// Turn LED off.
digitalWrite(LED_PIN, LOW);
}
}
//------------------------------------------------------------------------------
// Thread 2, turn the LED on and signal thread 1 to turn the LED off.
// 64 byte stack beyond task switch and interrupt needs
static THD_WORKING_AREA(waThread2, 64);
static THD_FUNCTION(Thread2, arg) {
pinMode(LED_PIN, OUTPUT);
while (1) {
digitalWrite(LED_PIN, HIGH);
// Sleep for 200 milliseconds.
chThdSleepMilliseconds(200);
// Signal thread 1 to turn LED off.
chSemSignal(&sem);
// Sleep for 200 milliseconds.
chThdSleepMilliseconds(200);
}
}
//------------------------------------------------------------------------------
void setup() {
chBegin(chSetup);
// chBegin never returns, main thread continues with mainThread()
while(1) {
}
}
//------------------------------------------------------------------------------
// main thread runs at NORMALPRIO
void chSetup() {
// start blink thread
chThdCreateStatic(waThread1, sizeof(waThread1),
NORMALPRIO + 2, Thread1, NULL);
chThdCreateStatic(waThread2, sizeof(waThread2),
NORMALPRIO + 1, Thread2, NULL);
}
//------------------------------------------------------------------------------
void loop() {
// not used
}
mercoledì 8 giugno 2016
Windows XP e Dropbox (API)
Il prossimo 29 agosto Dropbox terminera' il supporto per il client Windows XP.
Al contrario di come fanno altre ditte, per esempio Google con Chrome, la fine del supporto non indica che non saranno piu' sviluppati aggiornamenti ma che il client terminera' il suo funzionamento (sara' sempre disponibile l'interfaccia web)
Considerando che Dropbox e' di proprieta' Microsoft e che il servizio e' fondamentalmente gratuito non e' da biasimare Microsoft se cerca di piazzare qualche SO nuovo...ma forse una soluzione semplice esiste ed e' quella di usare un client Python usanto le API dell'SDK di Dropbox
Per usare il client Python ci si deve prima registrare su Dropbox Developer, creare una App (la piu' semplice e' App Folder) e generare un Access Token
Successivamente si scaricare l'SDK Python di Dropbox da questo indirizzo https://github.com/dropbox/dropbox-sdk-python installandolo poi con il classico
python setup.py install
a questo si puo' modificare il programma updown.py che permette di sincronizzare una cartella (cosi' come fa il client). Per personalizzare la directory da sincronizzare si deve modificare la rootdir (di default e' Downloads) e la cartella remota di Dropbox.
il progrramma si lancia quindi con la sintassi (il token si deve copiare dalle impostazioni della app)
python updown.py --token xxxxxxxxxxxxxxxxxxxxxxxxxxxxx --yes
(lo yes finale risponde in modo affermativo alle domande in modo da sovrascrivere in modo automatico)
i file sincronizzati non si trovano nella radice di Dropbox ma nella sottodirectory /App/nomedellaApp
Al contrario di come fanno altre ditte, per esempio Google con Chrome, la fine del supporto non indica che non saranno piu' sviluppati aggiornamenti ma che il client terminera' il suo funzionamento (sara' sempre disponibile l'interfaccia web)
Considerando che Dropbox e' di proprieta' Microsoft e che il servizio e' fondamentalmente gratuito non e' da biasimare Microsoft se cerca di piazzare qualche SO nuovo...ma forse una soluzione semplice esiste ed e' quella di usare un client Python usanto le API dell'SDK di Dropbox
Per usare il client Python ci si deve prima registrare su Dropbox Developer, creare una App (la piu' semplice e' App Folder) e generare un Access Token
Successivamente si scaricare l'SDK Python di Dropbox da questo indirizzo https://github.com/dropbox/dropbox-sdk-python installandolo poi con il classico
python setup.py install
a questo si puo' modificare il programma updown.py che permette di sincronizzare una cartella (cosi' come fa il client). Per personalizzare la directory da sincronizzare si deve modificare la rootdir (di default e' Downloads) e la cartella remota di Dropbox.
il progrramma si lancia quindi con la sintassi (il token si deve copiare dalle impostazioni della app)
python updown.py --token xxxxxxxxxxxxxxxxxxxxxxxxxxxxx --yes
(lo yes finale risponde in modo affermativo alle domande in modo da sovrascrivere in modo automatico)
i file sincronizzati non si trovano nella radice di Dropbox ma nella sottodirectory /App/nomedellaApp
Mandelbrot su C64 in Assembler
Frugando su internet ho trovato la versione in Assembler di Mandelbrot per C64 compresa nel progetto Resurrection (sotto cartella Mandelbrot)
Il codice e' ben commentato ed il risultato e' in modalita' testo
Il tempo di calcolo su VICE in emulazione del tempo reale del C64 risulta essere di 90 secondi con 26 iterazioni per punto
Il codice e' compilabile con il crosscompiler ACME e necessita della libreria stdlib
----------------------------------------------------------------
;Mandelbrot test code
!source "../stdlib/stdlib.a"
!to "Mandelbrot.prg", cbm
!sal
!sl "Mandelbrot.map"
!svl "Mandelbrot.lbl"
!cpu 6510
!ct pet
!source "../stdlib/BASICEntry80d.a"
!macro OutputFAC {
jsr $bddd ; Convert FAC#1 to ASCII String. Kills FAC#2
jsr $b487 ; Set Up String
jsr $ab21 ; Output String
}
LDFAC = $bba2
STFAC = $bbd4
SUBFAC = $b850
DIVFAC = $bb0f
CMPFAC = $bc5b
MULFAC = $ba28
ADDFAC = $b867
SETFAC = $b391
!macro LoadFAC .addr {
lda #<.addr
ldy #>.addr
jsr LDFAC
}
!macro StoreFAC .addr {
ldx #<.addr
ldy #>.addr
jsr STFAC
}
!macro SubMemFAC .addr {
lda #<.addr
ldy #>.addr
jsr SUBFAC
}
!macro SubFACMem .addr {
+StoreFAC Temp
+LoadFAC .addr
+SubMemFAC Temp
}
!macro DivMemFAC .addr {
lda #<.addr
ldy #>.addr
jsr DIVFAC
}
!macro DivFACMem .addr {
+StoreFAC Temp
+LoadFAC .addr
+DivMemFAC Temp
}
!macro CmpFACMem .addr {
+StoreFAC Temp
+LoadFAC .addr
+CmpMemFAC Temp
}
!macro CmpMemFAC .addr {
lda #<.addr
ldy #>.addr
jsr CMPFAC
}
!macro MulMemFAC .addr {
lda #<.addr
ldy #>.addr
jsr MULFAC
}
!macro AddMemFAC .addr {
lda #<.addr
ldy #>.addr
jsr ADDFAC
}
!macro SetFAC_Y {
lda #0
jsr SETFAC
}
kMaxIterations = 26
!zn
*=BASICEntry
cld
jsr CINT
; Speed testing for some FP ops. As we can see even some simple operations are very slow
!if 0 {
sei
.tl1
lda #0
sta VIC2BorderColour
+MACROWaitForRaster 64
inc VIC2BorderColour
+LoadFAC xmin
inc VIC2BorderColour
+SubMemFAC xmax
inc VIC2BorderColour
+DivFACMem ScrW
inc VIC2BorderColour
+StoreFAC xs
inc VIC2BorderColour
+MulMemFAC xs
inc VIC2BorderColour
+StoreFAC xs
inc VIC2BorderColour
jmp .tl1
}
; The main Mandelbrot code.
;xs=(xmax-xmin)/40.0;
+LoadFAC xmin
+SubMemFAC xmax
+DivFACMem ScrW
+StoreFAC xs
;ys=(ymax-ymin)/24.0;
+LoadFAC ymin
+SubMemFAC ymax
+DivFACMem ScrH
+StoreFAC ys
;for (y=0;y<24;y++) {
lda #0
sta y
.l1
; for (x=0;x<40;x++) {
lda #0
sta x
.l2
; p=xmin+(x*xs);
ldy x
+SetFAC_Y
+MulMemFAC xs
+AddMemFAC xmin
+StoreFAC p
; q=ymin+(y*ys);
ldy y
+SetFAC_Y
+MulMemFAC ys
+AddMemFAC ymin
+StoreFAC q
; xtemp=0;
; x0=0;
; y0=0;
ldy #0
+SetFAC_Y
+StoreFAC x0
+StoreFAC y0
; i=0;
lda #0
sta i
.while
; while (((x0*x0)+(y0*y0))<4 && ++i<kMaxIterations) {
; i check, first, simple integer check
lda i
cmp #kMaxIterations
bcc .ltkMaxIterations
jmp .escape
.ltkMaxIterations
; mul check
+LoadFAC x0
+MulMemFAC x0
+StoreFAC Temp2
+LoadFAC y0
+MulMemFAC y0
+AddMemFAC Temp2
+CmpFACMem Escape
bcc .lt4
jmp .escape
.lt4
;++i
inc i
; xtemp = (x0*x0) - (y0*y0) + p
+LoadFAC x0
+MulMemFAC x0
+StoreFAC Temp2
+LoadFAC y0
+MulMemFAC y0
+SubMemFAC Temp2
+AddMemFAC p
+StoreFAC xtemp
; y0=(2 * x0 * y0) +q;
+LoadFAC x0
+MulMemFAC y0
+StoreFAC Temp2
ldy #2
+SetFAC_Y
+MulMemFAC Temp2
+AddMemFAC q
+StoreFAC y0
; x0=xtemp;
+LoadFAC xtemp
+StoreFAC x0
; }
jmp .while
.escape
; Range check to adjust for printable characters
lda i
; lsr ; Potential for shit adjustment, change kMaxIterations to accomodate
cmp #26 ; Letters in the alphabet!
bcc .okChar
lda #' '
jmp .rawOut
.okChar
clc
adc #64
.rawOut
jsr CHROUT
; Finish for loops
inc x
lda x
cmp #40
beq .ol2
jmp .l2
.ol2
inc y
lda y
cmp #24 ; MPi: TOOD: Keep the last line clear for an IRQ scrolling message
beq .ol1
jmp .l1
.ol1
.flash
; inc VIC2BorderColour
jmp .flash
; C64 Floating point values
; MPi: TODO: Must update the assembler to create these
xmin !by $82, $a0, $00, $00, $00 ; -2.5
xmax !by $81, $40, $00, $00, $00 ; 1.5
ymin !by $81, $c0, $00, $00, $00 ; -1.5
ymax !by $81, $40, $00, $00, $00 ; 1.5
ScrW !by $86, $20, $00, $00, $00 ; 40
ScrH !by $85, $40, $00, $00, $00 ; 24
Escape !by $83, $00, $00, $00, $00 ; 4
; Float storage
Temp = *
Temp2 = * + 5
xs = * + 10
ys = * + 15
p = * + 20
q = * + 25
xtemp = * + 30
x0 = * + 35
y0 = * + 40
; Bytes
x = * + 45
y = * + 46
i = * + 47
Il codice e' ben commentato ed il risultato e' in modalita' testo
Il tempo di calcolo su VICE in emulazione del tempo reale del C64 risulta essere di 90 secondi con 26 iterazioni per punto
Il codice e' compilabile con il crosscompiler ACME e necessita della libreria stdlib
----------------------------------------------------------------
;Mandelbrot test code
!source "../stdlib/stdlib.a"
!to "Mandelbrot.prg", cbm
!sal
!sl "Mandelbrot.map"
!svl "Mandelbrot.lbl"
!cpu 6510
!ct pet
!source "../stdlib/BASICEntry80d.a"
!macro OutputFAC {
jsr $bddd ; Convert FAC#1 to ASCII String. Kills FAC#2
jsr $b487 ; Set Up String
jsr $ab21 ; Output String
}
LDFAC = $bba2
STFAC = $bbd4
SUBFAC = $b850
DIVFAC = $bb0f
CMPFAC = $bc5b
MULFAC = $ba28
ADDFAC = $b867
SETFAC = $b391
!macro LoadFAC .addr {
lda #<.addr
ldy #>.addr
jsr LDFAC
}
!macro StoreFAC .addr {
ldx #<.addr
ldy #>.addr
jsr STFAC
}
!macro SubMemFAC .addr {
lda #<.addr
ldy #>.addr
jsr SUBFAC
}
!macro SubFACMem .addr {
+StoreFAC Temp
+LoadFAC .addr
+SubMemFAC Temp
}
!macro DivMemFAC .addr {
lda #<.addr
ldy #>.addr
jsr DIVFAC
}
!macro DivFACMem .addr {
+StoreFAC Temp
+LoadFAC .addr
+DivMemFAC Temp
}
!macro CmpFACMem .addr {
+StoreFAC Temp
+LoadFAC .addr
+CmpMemFAC Temp
}
!macro CmpMemFAC .addr {
lda #<.addr
ldy #>.addr
jsr CMPFAC
}
!macro MulMemFAC .addr {
lda #<.addr
ldy #>.addr
jsr MULFAC
}
!macro AddMemFAC .addr {
lda #<.addr
ldy #>.addr
jsr ADDFAC
}
!macro SetFAC_Y {
lda #0
jsr SETFAC
}
kMaxIterations = 26
!zn
*=BASICEntry
cld
jsr CINT
; Speed testing for some FP ops. As we can see even some simple operations are very slow
!if 0 {
sei
.tl1
lda #0
sta VIC2BorderColour
+MACROWaitForRaster 64
inc VIC2BorderColour
+LoadFAC xmin
inc VIC2BorderColour
+SubMemFAC xmax
inc VIC2BorderColour
+DivFACMem ScrW
inc VIC2BorderColour
+StoreFAC xs
inc VIC2BorderColour
+MulMemFAC xs
inc VIC2BorderColour
+StoreFAC xs
inc VIC2BorderColour
jmp .tl1
}
; The main Mandelbrot code.
;xs=(xmax-xmin)/40.0;
+LoadFAC xmin
+SubMemFAC xmax
+DivFACMem ScrW
+StoreFAC xs
;ys=(ymax-ymin)/24.0;
+LoadFAC ymin
+SubMemFAC ymax
+DivFACMem ScrH
+StoreFAC ys
;for (y=0;y<24;y++) {
lda #0
sta y
.l1
; for (x=0;x<40;x++) {
lda #0
sta x
.l2
; p=xmin+(x*xs);
ldy x
+SetFAC_Y
+MulMemFAC xs
+AddMemFAC xmin
+StoreFAC p
; q=ymin+(y*ys);
ldy y
+SetFAC_Y
+MulMemFAC ys
+AddMemFAC ymin
+StoreFAC q
; xtemp=0;
; x0=0;
; y0=0;
ldy #0
+SetFAC_Y
+StoreFAC x0
+StoreFAC y0
; i=0;
lda #0
sta i
.while
; while (((x0*x0)+(y0*y0))<4 && ++i<kMaxIterations) {
; i check, first, simple integer check
lda i
cmp #kMaxIterations
bcc .ltkMaxIterations
jmp .escape
.ltkMaxIterations
; mul check
+LoadFAC x0
+MulMemFAC x0
+StoreFAC Temp2
+LoadFAC y0
+MulMemFAC y0
+AddMemFAC Temp2
+CmpFACMem Escape
bcc .lt4
jmp .escape
.lt4
;++i
inc i
; xtemp = (x0*x0) - (y0*y0) + p
+LoadFAC x0
+MulMemFAC x0
+StoreFAC Temp2
+LoadFAC y0
+MulMemFAC y0
+SubMemFAC Temp2
+AddMemFAC p
+StoreFAC xtemp
; y0=(2 * x0 * y0) +q;
+LoadFAC x0
+MulMemFAC y0
+StoreFAC Temp2
ldy #2
+SetFAC_Y
+MulMemFAC Temp2
+AddMemFAC q
+StoreFAC y0
; x0=xtemp;
+LoadFAC xtemp
+StoreFAC x0
; }
jmp .while
.escape
; Range check to adjust for printable characters
lda i
; lsr ; Potential for shit adjustment, change kMaxIterations to accomodate
cmp #26 ; Letters in the alphabet!
bcc .okChar
lda #' '
jmp .rawOut
.okChar
clc
adc #64
.rawOut
jsr CHROUT
; Finish for loops
inc x
lda x
cmp #40
beq .ol2
jmp .l2
.ol2
inc y
lda y
cmp #24 ; MPi: TOOD: Keep the last line clear for an IRQ scrolling message
beq .ol1
jmp .l1
.ol1
.flash
; inc VIC2BorderColour
jmp .flash
; C64 Floating point values
; MPi: TODO: Must update the assembler to create these
xmin !by $82, $a0, $00, $00, $00 ; -2.5
xmax !by $81, $40, $00, $00, $00 ; 1.5
ymin !by $81, $c0, $00, $00, $00 ; -1.5
ymax !by $81, $40, $00, $00, $00 ; 1.5
ScrW !by $86, $20, $00, $00, $00 ; 40
ScrH !by $85, $40, $00, $00, $00 ; 24
Escape !by $83, $00, $00, $00, $00 ; 4
; Float storage
Temp = *
Temp2 = * + 5
xs = * + 10
ys = * + 15
p = * + 20
q = * + 25
xtemp = * + 30
x0 = * + 35
y0 = * + 40
; Bytes
x = * + 45
y = * + 46
i = * + 47
----------------------------------------------------------------
Iscriviti a:
Post (Atom)
Debugger integrato ESP32S3
Aggiornamento In realta' il Jtag USB funziona anche sui moduli cinesi Il problema risiede nell'ID USB della porta Jtag. Nel modulo...
-
In questo post viene indicato come creare uno scatterplot dinamico basato da dati ripresi da un file csv (nel dettaglio il file csv e' c...
-
La scheda ESP32-2432S028R monta un Esp Dev Module con uno schermo TFT a driver ILI9341 di 320x240 pixels 16 bit colore.Il sito di riferiment...
-
Questo post e' a seguito di quanto gia' visto nella precedente prova Lo scopo e' sempre il solito: creare un sistema che permet...