(Cet article contient quelques erreurs avec les caractères spéciaux à corriger)
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預C, ce projet est fait en C# et a pour but de cr饲 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褥r aux ressources de la carte : Ex, une trackbar permet de contr? l'鴡t de sortie d'une sortie PWM.
Enfin en ce qui concerne le protocole d'飨ange 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 ࠬa pin '12' d'effectuer un pulse 'P' de longueur '1250'ms.
Actuellement, le protocole suivant est impl魥nt頺
'D' : Met la DO (digital output) ࠬa valeur pass饠en param贲e. Dans le cas d'une DO simple, les valeurs support饠sont 0 (鴡t LOW) et 255 (鴡t 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饠doit 괲e scrut饠ou non.
'R' (Rate) : Indique un temps minimum (en ms) en de硠duquel un changement de valeur de l'AI sera ignor鮊 'P' (Pulse) : Indique ࠬa carte de g鮩rer un pulse (passage en 鴡t HIGH puis en LOW), d'une longueur pass饠en param贲e. Cette commande est tr鳠utile pour le controle de servos-moteurs.
'D' : indique un changement d'鴡t de la DI concern饮
'A' : indique un changement de valeur de l'AI concern饮
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 à dire sur ce code, et des optimisations à faire, mais j'ai voulu privilegier la facilité de lecture.
Pascal BUIREY.