Ce projet a pour but de faciliter la cr�ation d'applications permettant de contr�ler une carte arduino depuis un PC, via le cable usb. Pour cela, ce projet comporte trois parties :
Un programme tourne en boucle sur la carte Arduino. Ce programme fait en permanence 3 choses :
Cot� PC, ce projet est fait en C# et a pour but de cr�er des composants .net permettant de faire facilement des applications utilisant l'arduino. Le composant fondamental du projet est ArduinoCtrl. Ce composant permet de faire le lien entre l'application et la carte. Plusieurs controles permettent d'acc�der aux ressources de la carte : Ex, une trackbar permet de contr�ler l'�tat de sortie d'une sortie PWM.
Enfin en ce qui concerne le protocole d'�change entre les deux parties, il s'agit d'un protocole simple sur le principe suivant : un message "O/P/V" indique un ordre 'O', concerne la pin 'P', avec la valeur 'V'. Un exemple : P/12/1250 indique � la pin '12' d'effectuer un pulse 'P' de longueur '1250'ms.
Actuellement, le protocole suivant est impl�ment� :
'D' : Met la DO (digital output) � la valeur pass�e en param�tre. Dans le cas d'une DO simple, les valeurs support�e sont 0 (�tat LOW) et 255 (�tat HIGH). Dans le cas d'un DO PWM, toutes les valeurs entre 0 et 255 sont valables.
'S' (Set) : Indique le changer le mode d'une DIO.
'M' (Mesure) : Indique si l'AI concern�e doit �tre scrut�e ou non.
'R' (Rate) : Indique un temps minimum (en ms) en de�a duquel un changement de valeur de l'AI sera ignor�.
'P' (Pulse) : Indique � la carte de g�n�rer un pulse (passage en �tat HIGH puis en LOW), d'une longueur pass�e en param�tre. Cette commande est tr�s utile pour le controle de servos-moteurs.
'D' : indique un changement d'�tat de la DI concern�e.
'A' : indique un changement de valeur de l'AI concern�e.
Voici le code embarqu� :
/*
* UsbControl
* by Pascal BUIREY
*
* embedded software to communicate with monitoring software
* messages are in the following format :
* arduino => PC
* 1/N/V A/N/V Send the Analog value V read from pin N
* 2/N/V D/N/V Send the Digital value V read from pin N
* 64/N/V Send return value V for initialisation on device N
* 65/N/V Send the byte V read on SPI Device #N
*
* PC => arduino
* 0/N/V S/N/V Set the pinmode for the specified pin 0=ignore, 1=INPUT, 2=OUTPUT
* 1/N/V M/N/V set the Measure pin for INPUT (1) or ignore(0);
* 2/N/V D/N/V write the value V on digital pin N 0=LOW, 255=HIGH.
* 99/N/V T/N/V activate/deactivate traces
* intermediate values are possible for PWM digital IOs.
*
* SPI commands :
* 6/N/V : Declare SPI device N is ignored V=SPI Id (0-3);
* 60/N/V :setup SPI Device #N Chip Select pin = V;
* 61/N/V :setup SPI Device #N Clock pin = V;
* 62/N/V :setup SPI Device #N MISO pin = V;
* 63/N/V :setup SPI Device #N MOSI pin = V;
* 64/N/V :initialize SPI Device (pins must be setup)
* 65/N/V :on SPI Device #N, write the byte V
*
*/
//SPI opcodes
#define WREN 6
#define WRDI 4
#define RDSR 5
#define WRSR 1
#define READ 3
#define WRITE 2
class SPIDevice {
private :
byte clr;
public:
short MOSIPin; //Master Out Slave In
short MISOPin; //Master In Slave Out
short ClockPin; //Clock
short ChipSelectPin; //CS Chip Select
SPIDevice() {
MOSIPin = -1;
MISOPin = -1;
ClockPin = -1;
ChipSelectPin = -1;
}
byte SPI_Init() {
short ret_val=0;
//verify that pins have been setup
if ((MOSIPin==-1)||
(MISOPin == -1)||
(ClockPin == -1)||
(ChipSelectPin == -1)) {
return 0;
}
//Setup SPI Pins
pinMode(MOSIPin, OUTPUT);
pinMode(MISOPin, INPUT);
pinMode(ClockPin,OUTPUT);
pinMode(ChipSelectPin,OUTPUT);
digitalWrite(ChipSelectPin,HIGH); //disable device
//Setup SPI Protocol
// SPCR = 01010000
//interrupt disabled,spi enabled,msb 1st,master,clk low when idle,
//sample on leading edge of clk,system clock/4 rate (fastest)
SPCR = (1<<SPE)|(1<<MSTR);
clr=SPSR;
clr=SPDR;
delay(10);
return(1);
}
// transfer Data to/from SPI Device
char spi_transfert(volatile char data)
{
SPDR = data; // Start the transmission
while (!(SPSR & (1<<SPIF))) // Wait for the end of the transmission
{
};
return SPDR; // return the received byte
}
char spi_write(char c) {
spi_transfert(c);
}
char spi_read() {
return spi_transfert(0XFF);
}
~SPIDevice() {
}
};
/*pin modes stored as an array of bytes 0=ignore 1=input, 2=output*/
byte diPinMode[14];
byte aiPinMode[6];
int dioPinValues[14];
int aiPinValues[6];
int aiRefreshRate[6];
unsigned long aiLastRefresh[6];
//support up to 4 SPI devices
SPIDevice *SPIDevices[4];
/*incoming message from monitoring*/
/*maximum message size*/
char sIncomingMsg[255];
/*current index of received chars*/
int iCurrentMsgIdx;
boolean bMsgComplete;
boolean bTraceOn;
void Trace(char* text) {
if (bTraceOn) {
Serial.print("TRACE : ");
Serial.println(text);
}
}
/*sendToMonitoring*/
/*send data for monitoring software*/
/*pinType = 'D' for digitals or 'A' for analogs*/
void sendToMonitoring(char pinType,byte pinNumber,unsigned int value) {
Serial.print(pinType);
Serial.print("/");
Serial.print(pinNumber,DEC);
Serial.print("/");
Serial.println(value,DEC);
}
void check4DIOChanges() {
/*pins 0 and 1 are used for serial communication*/
for (int i=2;i<14;i++) {
/*if this is not an output pin*/
if (diPinMode[i]==1) {
int newval = digitalRead(i);
/*if the value for that pin as changed*/
if (newval!=dioPinValues[i]) {
/*send the new value to monitoring software*/
sendToMonitoring('D',i,newval);
/*store the new value*/
dioPinValues[i]=newval;
}
}
}
}
void check4AIChanges() {
for (int i=0;i<6;i++) {
if (aiPinMode[i]==1) {
unsigned long curTime = millis();
if ((aiLastRefresh[i]+aiRefreshRate[i])<curTime) {
aiLastRefresh[i]=curTime;
int newval = analogRead(i);
/*if the value for that pin as changed*/
if (newval!=aiPinValues[i]) {
/*send the new value to monitoring software*/
sendToMonitoring('A',i,newval);
/*store the new value*/
aiPinValues[i]=newval;
}
}
}
}
}
/*parse the incoming message and perform corresponding action*/
void parseIncomingMsg(char *msg) {
int pinNumber = 0;
int value=0;
int idx=0;
/*get the pin number*/
/* for debug*/
Trace("Parsing ");
Trace(msg);
//read the Command...
while (msg[idx]!='/') {
idx++;
}
idx++;
while (msg[idx]!='/') {
pinNumber=pinNumber*10+msg[idx]-'0';
idx++;
}
idx++;
//for debug only
/*get the value*/
while (msg[idx]!='\0') {
if ((msg[idx]>='0')&&(msg[idx]<='9')) {
value=value*10+msg[idx]-'0';
}
idx++;
}
switch(msg[0]) {
/*incoming order to output on a DIO */
case '?' : {
Serial.println("Arduino");
}
case 'D' : {
if((value == 255)||(value==0)) {
if (value==255) {
digitalWrite(pinNumber,HIGH);
}
if (value==0) {
digitalWrite(pinNumber,LOW);
}
}else{
analogWrite(pinNumber,value);
}
};break;
/*incoming ordre for changing pinmode*/
case 'S' : {
/*ignored pin*/
if (value==0) {
diPinMode[pinNumber]=0;
}
/*set pin for reading*/
if (value==1) {
pinMode(pinNumber,INPUT);
diPinMode[pinNumber]=1;
}
/*set pin for writing*/
if (value==2) {
pinMode(pinNumber,OUTPUT);
diPinMode[pinNumber]=2;
Trace("Pin set");
}
};break;
case 'M' : {
if (value ==0) {
aiPinMode[pinNumber]=0;
}
if (value == 1) {
aiPinMode[pinNumber]=1;
}
};break;
case 'R' : {
aiRefreshRate[pinNumber]=value;
}
case 'P' : { /*P = Pulse value = pulse length (milliseconds)*/
if (value !=0) {
if (diPinMode[pinNumber]==2) {
digitalWrite(pinNumber,HIGH);
delayMicroseconds(value);
digitalWrite(pinNumber,LOW);
}
}
};break;
case 'T' : { /*T = activate(1)/deactivate(0) traces*/
bTraceOn=(value==1);
Trace("Trace mode set");
};break;
/*default : wrong message*/
default : {
//for debug only
Trace("Error parsing message : ");
Trace(msg);
};break;
}
Trace("Processed ok");
}
void check4IncomingMsg() {
/*if com is Ok ?*/
int nbBytes =Serial.available();
if (nbBytes>0) {
char msg[nbBytes+1];
/*read incoming bytes*/
char c='\0';
int i=0;
for (i=0;(i<nbBytes)&&(c!=10);i++) {
c = Serial.read();
msg[i]=c;
}
/*10 indicates the end of a message*/
if (c==10) {
//msg[i]='\0';
bMsgComplete=true;
}
/*add read bytes to current message*/
for (int j=0;j<i;j++) {
sIncomingMsg[iCurrentMsgIdx] = msg[j];
iCurrentMsgIdx++;
}
if (bMsgComplete) {
sIncomingMsg[iCurrentMsgIdx]='\0';
// for debug only
Trace("Received");
Trace(sIncomingMsg);
parseIncomingMsg(sIncomingMsg);
/*message treated, reset the buffer*/
bMsgComplete=false;
iCurrentMsgIdx=0;
}
}
}
void setup()
{
// begin the serial communication
Serial.begin(19200);
bMsgComplete=false;
iCurrentMsgIdx=0;
/*Init all pins to INPUT, and their values to 0*/
/*pins 0 and 1 are used in serial communication*/
for (int i=2;i<14;i++) {
diPinMode[i]=0;
dioPinValues[i]=0;
pinMode(i,INPUT);
}
/*init ai pins values*/
for (int i=0;i<6;i++) {
aiPinMode[i]=0;
aiPinValues[i]=0;
/*refresh every second by default*/
aiRefreshRate[i]=1000;
aiLastRefresh[i]=millis();
}
}
void loop()
{
/*check for changes on AI and DIO. If changes happen, send them to monitoring*/
check4DIOChanges();
check4AIChanges();
/*check for message coming from monitoring*/
//delay(100);
check4IncomingMsg();
}
Il y a surement pas mal � redire sur ce code, et des optimisations � faire, mais j'ai voulu privilegier la facilit� de lecture.
Pascal BUIREY.