banner left Boxtec Banner
Platzhalter BoxtecProdukteForumShopKontaktPlaygroundn/aJobs
 

ChipKit Boards (PIC32 chips von Microchip)

Allgemeines zu ChipKit

Wenn man sich die Produktpalette von Microchip anschaut, wird man als erstes von der Vielfalt der über 800 Typen erschlagen. Dabei war es beim Arduino so überschaubar:

  • UNO mit dem ATmega328
  • MEGA mit dem ATmega2560
  • ATtinys
  • und den Due hat man sich vorgenommen, mal anzuschauen ;-)

Bei den PIC Prozessoren von Microchip hat man eine ähnliche Vorauswahl gemacht und das Ganze unter dem Projekt chipKIT ins Leben gerufen. Dabei hat man sich beim IDE direkt beim Arduino bedient und das zu chipKIT passende IDE heißt MPIDE. Die Software gibt es auf der [http://chipkit.org|Projektseite]] als Download.

Um mit dem chipKIT vertraut zu werden, möchte ich erst einmal mit dem einfachen Selbstbau beginnen. Der dabei verwendete Chip ist der PIC32MX250F128B, der das gleiche 28-pin Gehäuse hat wie der ATmega328. Seine Parameter sind:

  • 32 bit Architektur
  • 40 MHz
  • 128 kB Flash Memory
  • 32 kB RAM
  • USB 2.0 on board (kein FTDI Chip nötig)

Die Pinbelegung ist hier wiedergegeben:

Durch die eingebaute Unterstützung von USB 2.0 ist mit wenigen Bauteilen eine lauffähige Breadboardversion erstellt. Man benötigt

  • Breadboard USB Adapter
  • 4 100nF Keramikkondensatoren
  • 4 10 kOhm Widerstände
  • 1 150 Ohm Widerstand (Strombegrenzung für die LED)
  • 1 LED
  • 1 10 uF Tantal Kondensator
  • 2 Taster
  • 1 3.3V Spannungsregler (Transistorgehäuse TO-92)
  • 8 MHz Quarz
  • 2 33 pF Keramikkondensatoren

Der Chip hat einen internen Quarz, so dass der externe Quarz nicht unbedingt nötig ist. Er wird aber in allen Beschreibungen empfohlen. Für die beiden Kondensatoren am Quarz habe ich Werte von 22, 33, 36 pF gefunden. Ein Aufbau mit 33 pF läuft problemlos. Der Chip kann bei BoxTec gekauft werden und ist ab Werk mit dem chipKit Bootloader geflasht. Im MPIDE verwende ich als Board das Digilent chipKIT DP32 welches diesen Chip einsetzt. Der Aufbau ist überschaubar und hier abgebildet:

Eine detaillierte Aufbauanleitung findet man hier. Statt dem dort angegebenen Fubarino Board wie gesagt das DP32 board auswählen, da der Fubarino einen anderen Chip verwendet. Hier noch der Schaltplan:

Mir hat der Aufbau viel Spass bereitet und mir gefällt die Einfachheit des Boards. Es liegt also nahe, dass man ein eigenes Board analog zum Helvetino aufbaut.

Der HelvePic32

Das BoxTec ChipKit Board

Die Designvorgaben für das Board sind folgende:

  • alles PTH, also Durchsteckmontage, keine SMD, so dass das Board auch von Kindern gelötet werden kann
  • Herausführung der verwendbaren Pins zur Seite, alle Pins stehen auf 0.1” Rastermaß
  • Gleiche Pinauslegung auf beiden Seiten, so dass Module zwischen den Seiten gewechselt werden können
  • die Pinreihen sind so weit vom Rand entfernt, dass gewinkelte Stiftleisten eine Auflage haben
  • Die Boardgröße entspricht dem Rastermaß der Camdenboss Hutschienenhalterungen (72x42mm)
  • USB Mini Gehäuse, da Microgehäuse zu störanfällig sind
  • I2C und SPI werden getrennt herausgeführt
  • PicKit Pins herausgeführt für die direkte Programmierung des Chips
  • automatische Selektion der Spannungsquelle
  • 8 MHz externes Quarz, Chip läuft auf 40 MHz und ist damit kompatibel zum ChipKit-DP32

Die finale Version V1.0 der Umsetzung dieser Vorgaben sieht dann so aus:

  • Rechts und links sind je eine Stiftleiste mit 12 Pins, 8 davon sind GPIO Pins, die jeweils letzten Pins sind Reset, 3.3V, 5V und GND. Mit den letzten vier Pins hat man alle Spannungen zur Hand und kann damit auch problemlos Levelshifter versorgen, wenn man mit der 5V- Welt arbeitet.
  • Am oberen USB Port befindet sich eine Stiftleiste mit allen USB Pins. Die GPIO-Pins RB10 und RB11 sind nicht zur Seite herausgeführt, da sie mit D+ und D- belegt sind. Hier kann man sie aber dennoch abgreifen
  • Neben den USB Pins befinden sich RX/TX der beiden UARTs des Chips, UART2 ist 5V tolerant
  • Direkt am Quarz können die Pins RA2 and RA3 abgegriffen werden, sofern man den Chip ohne Quarz betreibt
  • Neben dem Reset Taster befinden sich die SPI Anschlüsse in der gewohnten ICSP-Anordnung. (Der Chip kann hierüber nicht programmiert werden)
  • Neben dem Program Taster befidnen sich zwei Jumper, mit denen die SDA und SCL Leitung über 4.7kOhm auf Plus gehoben werden (pull-up), wenn gewünscht.
  • Darunter liegt der I2C Bus
  • Daneben die Programmier-Pins für den PicKit Programmierer. Das Dreieck muss mit dem Programmierer ausgerichtet werden (Pin-1)

Das Bild gibt die Belegung der einzelnen GPIO Pins wieder und die entsprechende Pinnummer des DP32 bootloaders.

Tests und Anwendungsbeispiele

Sketch Upload

Der HelvePic32 schaltet nicht automatisch in den Bootloader Modus, sondern vor einem Upload eines Sketches muss dieser durch Drücken der Program- und Reset-Taste in den Bootloadermodus schalten. Dabei ist es wichtig, dass erst die Program-Taste gedrückt wird und dann Reset. Man erkennt den Bootloader daran, dass ein serieller Port erscheint, der dann vom IDE verwendet werden kann.

PinMap

Für den HelvePic32 wird die Boardeinstellung ChipKitDP32 verwendet, da dieses Board von Digilent den gleichen Chip verwendet. Leider sind die Pins auf unserem HelvePic32 etwas anders angeordnet, so dass wir ein Array verwenden, das die Pinnummer umsetzt. Dieses Array besteht aus zwei Vektoren, welche die jeweils linke (Index 0) oder die rechte (Index 1) Seite widerspiegeln:

const uint8_t LEFT=0;
const uint8_t RIGHT=1;
uint8_t nP[2][8] = {{0,17, 9,10,11,12,13,14},{18,17, 1, 2, 3, 6, 7, 8}}; // pins of version 1.0 using DP32 board definitions

Die Definition der ersten beiden Konstanten ist optional, macht den Code aber lesbarer. Die LED ist auf der rechten Seite an Pin 2 angeschlossen, kann also über

nP[RIGHT][2]

angesprochen werden.

Man sieht in der Liste der Pins, dass der Pin 17 auf beiden Seiten angegeben ist. Das hängt damit zusammen, dass der Pin 17 der Programmierpin ist. Da auf beiden Seiten 8 Pins, zusammen also 16 Pins zur Verfügung stehen, der Chip aber nur 15 nutzbare Pins bietet, lag es nahe, den Programmierpin auf beiden Seiten an der gleichen Stelle anzubieten. Über den zusätzlich verfügbaren Reset-Pin kann so das Board von einem Wing sowohl resettet als auch in Bootloadermodus verbracht werden. Außer den beiden Pinleisten gibt es noch weitere Pins, die hier dargestellt sind:

  • Direkt an der USB Buchse sind die Pins der USB Buchse herausgeführt. Damit sind auch die beiden Pins verfügbar, welche mit D+ und D- verbunden sind.
  • Direkt daneben liegen die Pins für die beiden UARTs.
  • Unten links sind die Pins des SPI Busses in der beim Arduino üblichen Anordnung zu finden.
  • Neben dem Quarz sind die beiden Pins herausgeführt, welche mit dem Quarz verbunden sind
  • Unten Rechts sind zwei pull-up Widerstände (4.7 kΩ) über Jumper erreichbar, welche bei Bedarf dem I2C-Bus dienen.
  • Ganz unten sind die Pins zur Programmierung über den PicKit3 Adapter und daneben
  • die I2C Pins

In guter Tradition ist der erste Test eines Boards der, die User-LED zum blinken zu bringen. Beim HelvePic32 gibt es da zwei Möglichkeiten:

1) Traditionell digitalWrite()

const uint8_t LEFT=0;
const uint8_t RIGHT=1;
uint8_t nP[2][8] = {{0,17, 9,10,11,12,13,14},{18,17, 1, 2, 3, 6, 7, 8}}; // pins of version 1.0 using DP32 board definitions
 
void setup()
{
	pinMode(nP[RIGHT][2],OUTPUT);
}
 
void loop()
{
	digitalWrite(nP[RIGHT][2], HIGH);
	delay(250);
	digitalWrite(nP[RIGHT][2], LOW);
	delay(250);
}

2) Register Manipulation

Hier bedienen wir uns eines Tricks, den wir uns in der UTFT Library abgeschaut haben. Statt das Register und die zugehörige Bitmask selbst zusammen zu suchen, kann man eine entsprechende Routine aufrufen, die einem das Portregister als auch die passende Bitmask zu einem Pin ausrechnet. Das funktioniert übrigens auch beim Arduino… Zusätzlich zum Pin-Array definieren wir ein Pointerarray pP, welches auf die Portregister zeigt und ein Bitmaskarray bP, welches die Bitmask speichert. Der nachfolgende Code verwendet dann zwei Pre-Prozessor Macros um das jeweilige Bit zu setzen (sbi) oder zu löschen (cbi). Der Code prüft auch die Architektur, so dass der Code auch auf einem Arduino laufen kann.

#define cbi(reg, bitmask) *reg &= ~bitmask
#define sbi(reg, bitmask) *reg |= bitmask
const uint8_t LEFT=0;
const uint8_t RIGHT=1;
uint8_t nP[2][8] = {{0,17, 9,10,11,12,13,14},{18,17, 1, 2, 3, 6, 7, 8}}; // pins of version 1.0 using DP32 board definitions
 
#if defined(__AVR__)
volatile uint8_t *pP[2][8];
uint8_t           bP[2][8];
#elif defined(__PIC32MX__)
volatile uint32_t *pP[2][8];
uint32_t           bP[2][8];
#endif
 
void _IO_Init() {
	for (uint8_t i=0; i<2; i++){
		for (uint8_t j=0; j<8; j++){
			pP[i][j] = portOutputRegister(digitalPinToPort(nP[i][j]));
			bP[i][j] = digitalPinToBitMask(nP[i][j]);
		}
	}
}
 
void setup()
{
	_IO_Init();
	for (uint8_t i=0; i<8; i++){
		pinMode(nP[RIGHT][i],OUTPUT);
	}
}
 
void loop()
{
	sbi(pP[RIGHT][2], bP[RIGHT][2]);
	delay(500);
	cbi(pP[RIGHT][2], bP[RIGHT][2]);
	delay(100);
}

(zur Unterscheidung sind die Delays unterschiedlich gewählt)

Was ist der Unterschied?

Das nachfolgende Bild zeigt erst das Setzen des Pins auf HIGH mit digitalWrite gefolgt von einem Aufruf zu digitalWrite, um den Pin auf LOW zu setzen. Danach die gleiche Aktion mit sbi und cbi:

Man sieht, dass mit digitalWrite der kürzeste Puls 1.2 μs lang ist, mit sbi/cbi nur 140 nS, also um einen Faktor 8-10 schneller.

Serielle Schnittstelle

Als nächstes testen wir die serielle Schnittstelle. Deren hat es drei:

  1. Serial.begin(9600) : die normale serielle Schnittstelle via der USB-Schnittstelle. Nach einem Reset braucht diese etwa eine Sekunde um bereit zu sein
  2. Serial0.begin(9600) : UART1 auf dem Board
  3. Serial1.begin(9600) : UART2 auf dem Board

Der Code ist entsprechend einfach:

void setup() {
	Serial.begin(9600);
	Serial0.begin(9600);
	Serial1.begin(9600);
}
 
void loop() {
  Serial.println("Hello World 1");
  Serial0.println("Hello World 2 UART1");
  Serial1.println("Hello World 3 UART2");
  delay(1000);
}

Mit diesem Code sieht man in drei Terminalfenstern die unterschiedlichen Ausgaben. Die hier verwendete Baudrate von 9600 kann natürlich gegen höhere Baudraten ausgetauscht werden. Als Verbindung habe ich zwei FOCA Breakout verwendet. Man beachte, dass RX des FOCA an TX des Boards geht sowie TX des FOCA an RX des Boards.

Mit diesem Setup ist es möglich, eine serielle Kommunikation unabhängig vom USB Anschluss aufzubauen, z.B mit einem Bluetooth Adapter.

Servo

Spätestens jetzt ist es an der Zeit etwas Bewegung an das Board zu bringen: Der Anschluss eines Servos. Dazu bietet es sich an, gleich die SoftPWMServo Bibliothek zu verwenden. Damit ist es möglich, jeden IO Pin zur Steuerung des Servos zu verwenden.

Der zugehörige Code ist entsprechend einfach:

const uint8_t LEFT=0;
const uint8_t RIGHT=1;
uint8_t nP[2][8] = {{0,17, 9,10,11,12,13,14	},{18,17, 1, 2, 3, 6, 7, 8	}}; // pins of version 1.0 using DP32 board definitions
 
#include <SoftPWMServo.h> 
 
int pos = 0;         // variable to store the servo position, in microseconds
const int pin = nP[RIGHT][3];  // Choose _any_ pin number on your board, i.e. pin 3, right side
 
void setup() 
{ 
} 
 
void loop() 
{ 
  for(pos = 1000; pos < 2000; pos += 10)  // goes from 1ms to 2ms
  {                                       // in steps of 10us
    SoftPWMServoServoWrite(pin, pos);     // tell servo to go to position in variable 'pos' 
    delay(25);                            // waits 25ms for the servo to reach the position 
  } 
} 

Auffällig ist, wie glatt und fließend der Servo sich bewegt.

16 x 2 LCD Anzeige

Als nächstes wollen wir eine Anzeige an den HelvePic32 anschließen. Wie beim Arduino bietet sich hier eine zweizeilige LCD-Anzeige an. Da ChipKit das Ziel hat, den Code weitestgehend gleich zum Arduino zu halten, gibt es auch hier die Bibliothek LiquidCrystal und der Code ist identisch zum Arudino Code, hier “Hello World”. Der Anschluss ist dementsprechend sehr ähnlich:

Und der Code bedarf nur der Pin-Definition von oben. Die #define Anweisungen dienen nur der Lesbarkeit:

/*
 Code based on: LiquidCrystal Library - Hello World
 
 Library originally added 18 Apr 2008 by David A. Mellis
 library modified 5 Jul 2009 by Limor Fried (http://www.ladyada.net)
 example added 9 Jul 2009 by Tom Igoe
 modified 22 Nov 2010 by Tom Igoe
 modified for HelvePic32 30 Dec 2014 by Mathias Wilhelm
 This example code is in the public domain.
 */
const uint8_t LEFT=0;
const uint8_t RIGHT=1;
uint8_t nP[2][8] = {{0,17, 9,10,11,12,13,14},{18,17, 1, 2, 3, 6, 7, 8}}; // pins of version 1.0 using DP32 bootloader
 
#define RS nP[RIGHT][0]
#define EN nP[RIGHT][1]
#define D4 nP[RIGHT][2]
#define D5 nP[RIGHT][3]
#define D6 nP[RIGHT][4]
#define D7 nP[RIGHT][5]
 
#include <LiquidCrystal.h>
LiquidCrystal lcd(RS, EN, D4, D5, D6, D7);
 
void setup() {
  lcd.begin(16, 2);
  lcd.print("hello, world!");
}
 
void loop() {
  lcd.setCursor(0, 1);
  lcd.print(millis()/1000);
}

Noch ein Tipp: Der Poti, der über V0 den Kontrast einstellt muss bei 3.3V fast ganz aufgedreht werden. Als Poti habe ich 10kOhm verwendet. Bei einem 5kOhm Poti blieb das LCD dunkel, was mich einige Stunden der Fehlersuche gekostet hat. Die LCD Hintergrundbeleuchtung auf den LCD-pins 15 und 16 ist nicht angeschlossen, da für das Beispiel unwichtig.

Analog Input

Der PIC32MX250F128B hat 9 analoge Input Pins, welche als A0 … A8 vordefiniert sind. Der Einfachheit des Codes zu Liebe bleiben wir bei der Notation mit dem oben eingeführten Pin-Arrays. Dazu schliessen wir ein Potentiometer (10 kOhm) an GND und 3.3V an. Den Mittenabgriff geben wir auf der linken Seite auf den Pin 2, den ersten analogen Input dieser Seite (siehe Diagramm oben).Das Auslesen des analogen Inputs geht wie beim Arduino:

/*
 Code based on Analog Input
 Created by David Cuartielles
 Modified 4 Sep 2010 by Tom Igoe
 modified 31 Dec 2014 by Mathias Wilhelm
 This example code is in the public domain.
 http://arduino.cc/en/Tutorial/AnalogInput
 */
 
const uint8_t LEFT=0;
const uint8_t RIGHT=1;
uint8_t nP[2][8] = {{0,17, 9,10,11,12,13,14},{18,17, 1, 2, 3, 6, 7, 8}}; // pins of version 1.0 using DP32 bootloader
 
int sensorPin = nP[LEFT][2];    // select the input pin for the potentiometer
int ledPin = nP[RIGHT][2];      // select the pin for the LED
int sensorValue = 0;  		// variable to store the value coming from the sensor
 
void setup() {
  pinMode(ledPin, OUTPUT);  
}
 
void loop() {
  sensorValue = analogRead(sensorPin);    
  digitalWrite(ledPin, HIGH);  
  delay(sensorValue);          
  digitalWrite(ledPin, LOW);   
  delay(sensorValue);                  
}

Es bietet sich natürlich an, diesen Sketch mit dem Servo Sketch zu verbinden und den Servo über den Poti zu steuern:

/*
 Control a Servo via a poti
 Created  31 Dec 2014 by Mathias Wilhelm
 */
 
const uint8_t LEFT=0;
const uint8_t RIGHT=1;
uint8_t nP[2][8] = {{0,17, 9,10,11,12,13,14},{18,17, 1, 2, 3, 6, 7, 8}}; // pins of version 1.0 using DP32 bootloader
 
#include <SoftPWMServo.h> 
 
int pos = 0;     			    // variable to store the servo position, in microseconds
const int pin = nP[RIGHT][4];	// Choose _any_ pin number on your board
int sensorPin = nP[LEFT][2];    // select the input pin for the potentiometer
int ledPin = nP[RIGHT][2];      // select the pin for the LED
int sensorValue = 0;  			// variable to store the value coming from the sensor
 
void setup() {
  pinMode(ledPin, OUTPUT);  
}
 
void loop() {
  sensorValue = analogRead(sensorPin); 
  pos = map(sensorValue,0, 1023, 1000, 2000);
  SoftPWMServoServoWrite(pin, pos);
  delay(25);
}

Step Motor

Statt eines Servos kann man auch einen Schrittmotor anschließen. Für den Test verwenden wir den weit verbreiteten 28BYJ-48 in der 5V Ausführung und den günstigen ULN2003 Treiber:

Da die Anschlusskabel oft variieren, ist die Motorbeschaltung auch gezeichnet. Der Code kann ohne Veränderung vom Arduino übernommen werden:

/* 
	Based on Stepper exemple V1.01 11/30/2013 by terry@yourduino.com 
	*/
#define LEFT 0
#define RIGHT 1
uint8_t nP[2][8] = {{0,17, 9,10,11,12,13,14},{18,17, 1, 2, 3, 6, 7, 8}}; // pins of version 1.0 using DP32 bootloader
 
#include <AccelStepper.h>
#define FULLSTEP 4
#define HALFSTEP 8
// motor pins
#define motorPin1  nP[RIGHT][3]     // Blue   - 28BYJ48 pin 1
#define motorPin2  nP[RIGHT][2]     // Pink   - 28BYJ48 pin 2
#define motorPin3  nP[RIGHT][1]     // Yellow - 28BYJ48 pin 3
#define motorPin4  nP[RIGHT][0]     // Orange - 28BYJ48 pin 4
			            // Red    - 28BYJ48 pin 5 (VCC)
// NOTE: The sequence 1-3-2-4 is required for proper sequencing of 28BYJ48
AccelStepper stepper1(HALFSTEP, motorPin1, motorPin3, motorPin2, motorPin4);
 
void setup()
{
  stepper1.setMaxSpeed(1000.0);
  stepper1.setAcceleration(50.0);
  stepper1.setSpeed(200);
  stepper1.moveTo(2048);  // 1 revolution   
}
 
void loop()
{
  //Change direction at the limits
  if (stepper1.distanceToGo() == 0) stepper1.moveTo(-stepper1.currentPosition());
  stepper1.run();
}

Warnung: Ein Schrittmotor zieht recht viel Strom, so dass die USB Versorgung gegebenenfalls durch eine stärkere Stromversorgung ersetzt werden muss. Der ULN2003 kann auch 12V schalten.

Servo Detailsteuerung

Wenn man sich die PWM Signale der normalen Servo Bibliothek anschaut, sieht man, dass die Puls-weite zwischen ca. 500 μs und 2300 μs variiert. Das bedeutet, dass man mit Hilfe der SoftPWMServo Bibliothek die Position eines Servos in Zehntel-Grad ansteuern kann. Da die Bibliothek aber in der Voreinstellung die Puls-weite auf 2 ms begrenzt, muss man diese Werte anpassen. Der zugehörige Code sieht so aus:

const uint8_t LEFT=0;
const uint8_t RIGHT=1;
uint8_t nP[2][8] = {{	0,17, 9,10,11,12,13,14},{18,17, 1, 2, 3, 6, 7, 8}};
const int Smax=1800;
const int Smin=500;
 
#include <SoftPWMServo.h> 
 
int pos = 0;         
const int pin = nP[RIGHT][7];  // Choose _any_ pin number on your board
 
void setup() 
{
	SoftPWMServoInit();
	SoftPWMServoSetFrameTime(100000); // 2500 us are 100000 tics for 40 MHz CPU!
	SoftPWMServoSetServoFrames(8);    // 8 frames make 20 ms wavelength
} 
 
void loop()
{ 
	for (pos=0; pos <= 1800; pos+=2) // use deci-degree in 0.2 degree steps
	{
		SetServoPos_decidegree(pos);
		delay(5);
	}
	for (pos=0; pos <= 1800; pos+=2) // use deci-degree in 0.2 degree steps
	{
		SetServoPos_decidegree(1800-pos);
		delay(5);
	}
	for (pos=0; pos <= 180; pos++) // use degree in 1 degree steps
	{
		SetServoPos_degree(pos);
		delay(25);
	}
	for (pos=0; pos <= 180; pos++) // use degree in 1 degree steps
	{
		SetServoPos_degree(180-pos);
		delay(25);
	}
	SetServoPos_degree(90);
	delay(1000);
	SetServoPos_degree(180);
	delay(1000);
	SetServoPos_degree(0);
	delay(1000);
}
 
void SetServoPos_degree(int degree)
{
	SoftPWMServoServoWrite(pin, 10*degree+Smin); 
}
 
void SetServoPos_decidegree(int decidegree)
{
	SoftPWMServoServoWrite(pin, decidegree+Smin); 
}

Der Code fährt einmal den Servo von 0 bis 180 Grad in 0.2 Grad Schritten und dann wieder zurück, danach die gleiche Aktion aber in Gradschritten. Zum Schluss werden die Positionen 90°, 180° und 0° für je eine Sekunde angefahren.

Grafik LCD mit SPI (320x240 Pixel TFT)

Richtig interessant wird es für mich, wenn ich mit dem Mikrocontroller ein farbiges LCD ansteuern kann. Hier gibt es eine Reihe von günstigen TFT und hier sei das 2.2” TFT mit 320×240 Pixeln Auflösung beschrieben, welches über SPI angesprochen wird:

Um das TFT anzusteueren brauchen wir die UTFT Bibliothek von Henning Karlsen. Diese Bibliothek ist sowohl für Arduino als auch für ChipKit geschrieben. Leider hat Henning keinen PIC32MX250F128B Prozessor zum testen gehabt, wesshalb der Code im Original nicht funktioniert. Mit einigen leichten Änderungen läuft dieser aber problemlos mit unserem HelvePic32. Die modifizierte Bibliothek kann man hier herunterladen.

Als Test kann man das UTFT Beispiel für UTFT_Demo_320x240_Serial mit folgender Pindefinitionen verwenden:

const uint8_t LEFT=0;
const uint8_t RIGHT=1;
 
uint8_t nP[2][8] = {{ 0,17, 9,10,11,12,13,14},{18,17, 1, 2, 3, 6, 7, 8}};
 
const uint8_t TFT_CS  = nP[RIGHT][7];
const uint8_t TFT_RST = nP[RIGHT][6];
const uint8_t TFT_RS  = nP[RIGHT][5];
const uint8_t TFT_SDA = nP[RIGHT][4];
const uint8_t TFT_SCL = nP[RIGHT][3];
 
#include <UTFT.h>
// Declare which fonts we will be using
extern uint8_t SmallFont[];
 
// Usage: myGLCD(<model code>, SDA, SCL, CS, RST[, RS]);
// Serial 2.2" TFT 320x240
UTFT myGLCD(TFT22SHLD, TFT_SDA, TFT_SCL, TFT_CS, TFT_RST, TFT_RS); 

Neopixel

Bei den Anwendungsbeispielen darf natürlich nicht die Anbindung der beliebten NeoPixel fehlen. Die beim Arduino verwendete Bibliothek kann dabei nicht benutzt werden, da diese auf den Atmel-Chip ausgelegt ist und Maschinencode dieses Prozessors verwendet. Andererseits gibt es eine Bibliothek, welche für chipKit geschrieben wurde und mit den Standard-Boards funktioniert. Da der HelvePic32 aber mit einer anderen Taktfrequenz arbeitet, musst der Code leicht angepasst werden. DIe Neopixel Strips können an jeden Pin angeschlossen werden. Es gelten die gleichen Regeln bezüglich der Stromversorgung. 30 Pixel liefen problemlos mit der Stromversorgung des Boards.

Die Bibliothek wurde so angepasst, dass die Funktionsaufrufe der Adafruit Bibliothek verwendbar sind. Es muss also nur die Einbindung der Bibliothek und der Generierung des Objekts geändert werden:

#include <ChipKitPixel.h>
 
ChipKitPixel strip1(30, nP[RIGHT][6], GRB);
ChipKitPixel strip2(8, nP[RIGHT][7], GRB);

Bei beiden Strip bitte beachten, dass die Datenleitung an DIN angeschlossen ist (Daher ist der Stick von der Rückseite her gezeigt)

LED Wings

Beim HelvePic32 gibt es nicht primär Shields sondern Winds, welche zur Seite hin angeschlossen werden. Shields sind derzeit in der Entwicklung. Aufgrund dieser Wings sind die Stiftleisten an der Seite rotations-symmetrisch, so dass ein Wing an beide Seiten angeschlossen werden kann. ALs ersten Wing bietet es sich an, jeden Pin mit einer LED gegen GND mit Widerstand zu versorgen:

Im Betrieb werden dabei vier LED auffallen:

  • die LED np[LEFT][7] blinkt, wenn der PIC im bootloader modus ist
  • die LED nP[LEFT][6] leuchtet, wenn der Sketch geladen wird
  • die LED nP[RIGHT][3] und nP[RIGHT][4] leuchten, wenn der I2C Bus mit pull-up Widerständen versehen sit und wenn Aktivität auf dem Bus herrscht.

Es hat sich gezeigt, dass ein Wing auf der linken Seite sehr hilfreich ist, wenn die Pins nicht gebraucht werden. Der LED-Wing kann im Betrieb abgezogen und aufgesteckt werden.

I2C Bus

Über den I2C Bus kann man sehr elegant Module anbauen. Um dies zu veranschaulichen, sind in diesem Beispiel drei I2C Module angeschlossen:

  • Adafruit 8×8 Mini Matrix (Adresse 0x72)
  • Adafruit 14-Segemnt AlphaNum Anzeigt (Adresse 0x70)
  • 128×64 OLED mit SSD1306 (Adresse 0x3c)

Beim I2C ist die Adresse des Moduls am wichtigsten. Um zu sehen, ob man das Modul richtig angweschlossen hat, kann man den Code i2cscanner verwenden (identisch zum Arduino code bis auf den Aufruf der wire Unterroutine twi_writeTo)

/**
 * I2CScanner.pde -- I2C bus scanner for Arduino
 * based on the work of 2009, Tod E. Kurt, http://todbot.com/blog/
 */
#include "Wire.h"
extern "C" { 
#include "utility/twi.h"  // from Wire library, so we can do bus scanning
}
 
int devfnd=0;
void scanI2CBus(byte from_addr, byte to_addr, 
void(*callback)(byte address, byte result) ) 
{
  byte rc;
  byte data = 0; // not used, just an address to feed to twi_writeTo()
  for( byte addr = from_addr; addr <= to_addr; addr++ ) {
//    rc = twi_writeTo(addr, &data, 0, 1, true); // last argument: send stop at the end
    rc = twi_writeTo(addr, &data, 0, 1); // last argument: send stop at the end
    callback( addr, rc );
  }
}
 
void scanFunc( byte addr, byte result ) {
  char str[40];
  sprintf(str,"addr: %3d 0x%02x",addr,addr);
  Serial.print(str);
  Serial.print( (result==0) ? " DEV!":"     ");
  Serial.print( (addr%5) ? "\t":"\n\r");
  if (!result) devfnd++;
}
 
 
byte start_address = 16;
byte end_address = 123;
 
// standard Arduino setup()
void setup()
{
  Wire.begin();
  pinMode(1,OUTPUT);
  Serial.begin(9600);
  delay(2000);
  Serial.println("\nI2CScanner ready!");
}
 
// standard Arduino loop()
void loop() 
{
  Serial.print("starting scanning of I2C bus from ");
  Serial.print(start_address,DEC);
  Serial.print(" to ");
  Serial.print(end_address,DEC);
  Serial.println("...");
  devfnd=0;
  // start the scan, will call "scanFunc()" on result from each address
  scanI2CBus( start_address, end_address, scanFunc );
  Serial.println("\ndone");
  Serial.print("I2C devices found: ");
  Serial.println(devfnd);
  for (int i=0;i<devfnd; i++){
    digitalWrite(1,HIGH);
    delay(250);
    digitalWrite(1,LOW);
    delay(250);
  }
  delay(5000);
}

Im Serial Monitor zeigen sich die Module an den erhofften Adressen:

starting scanning of I2C bus from 16 to 123...
addr:  16 0x10          addr:  17 0x11          addr:  18 0x12          addr:  19 0x13          addr:  20 0x14
addr:  21 0x15          addr:  22 0x16          addr:  23 0x17          addr:  24 0x18          addr:  25 0x19
addr:  26 0x1a          addr:  27 0x1b          addr:  28 0x1c          addr:  29 0x1d          addr:  30 0x1e
addr:  31 0x1f          addr:  32 0x20          addr:  33 0x21          addr:  34 0x22          addr:  35 0x23
addr:  36 0x24          addr:  37 0x25          addr:  38 0x26          addr:  39 0x27          addr:  40 0x28
addr:  41 0x29          addr:  42 0x2a          addr:  43 0x2b          addr:  44 0x2c          addr:  45 0x2d
addr:  46 0x2e          addr:  47 0x2f          addr:  48 0x30          addr:  49 0x31          addr:  50 0x32
addr:  51 0x33          addr:  52 0x34          addr:  53 0x35          addr:  54 0x36          addr:  55 0x37
addr:  56 0x38          addr:  57 0x39          addr:  58 0x3a          addr:  59 0x3b          addr:  60 0x3c DEV!
addr:  61 0x3d          addr:  62 0x3e          addr:  63 0x3f          addr:  64 0x40          addr:  65 0x41
addr:  66 0x42          addr:  67 0x43          addr:  68 0x44          addr:  69 0x45          addr:  70 0x46
addr:  71 0x47          addr:  72 0x48          addr:  73 0x49          addr:  74 0x4a          addr:  75 0x4b
addr:  76 0x4c          addr:  77 0x4d          addr:  78 0x4e          addr:  79 0x4f          addr:  80 0x50
addr:  81 0x51          addr:  82 0x52          addr:  83 0x53          addr:  84 0x54          addr:  85 0x55
addr:  86 0x56          addr:  87 0x57          addr:  88 0x58          addr:  89 0x59          addr:  90 0x5a
addr:  91 0x5b          addr:  92 0x5c          addr:  93 0x5d          addr:  94 0x5e          addr:  95 0x5f
addr:  96 0x60          addr:  97 0x61          addr:  98 0x62          addr:  99 0x63          addr: 100 0x64
addr: 101 0x65          addr: 102 0x66          addr: 103 0x67          addr: 104 0x68          addr: 105 0x69
addr: 106 0x6a          addr: 107 0x6b          addr: 108 0x6c          addr: 109 0x6d          addr: 110 0x6e
addr: 111 0x6f          addr: 112 0x70 DEV!     addr: 113 0x71          addr: 114 0x72 DEV!     addr: 115 0x73
addr: 116 0x74          addr: 117 0x75          addr: 118 0x76          addr: 119 0x77          addr: 120 0x78
addr: 121 0x79          addr: 122 0x7a          addr: 123 0x7b
                                                                        done
I2C devices found: 3

Zur Ansteuerung der Module können die Adafruit Bibliotheken fast unverändert verwendet werden. Lediglich beim Code für das 14-Segment Modul musste der Aufruf von pgm_read_word entfernt werden, da PIC32 kein PROGMEM kennt.

Ausblick

Bau von “Wings”, welche an die Seite angesteckt werden:

  • I2C Bus Wing
  • Motor Wing (4 Motoren oder 2 Stepper)
  • Servo Wing (8 Servos, der Chip kann theoretisch bis zu 85 Servos steuern)
  • Prototyping

Eagle Dateien

Eagle Quellendateien

… wird fortgesetzt …

 
chipkit/start.txt · Last modified: 2015/01/24 21:34 by mathiasw
 
 

zum Seitenanfang

Letzte Aktualisierung: © boxtec internet appliances · the better security products