pre-alpha ArtBus AVR four-channel h-bridge driver code

Submitted by Ed_B on Mon, 10/19/2009 - 12:45

Printer-friendly versionPrinter-friendly version

Here is the first pre-alpha draft of the ArtBus four-channel H-bridge driver code for the AVR chip. It's in the Arduino dialect. The functional part is mostly copy and paste from the PIC code for the first ArtBus board. That code was for the PIC16F690 using the CCS compiler. The AVR code is made to be edited and compiled using a raw makefile, stand-alone text editor, and shell terminal window, and without using the Arduino development tool (only the libraries). There's a bunch of junk from the PIC code still in here, plus a lot of basic functionality is missing. It's pretty gross, but it runs.

The html formatting below was done by using the export to html function in the Kate editor, then pasting that html from a Firefox window into the drupal editor.

 

// makefile_AB02.cpp 
/*
avr_makefile_demo.cpp 

Ed Bennett 10-19-09 
This is a .cpp file which compiles against the arduino libraries, ver 0013, without the .pde extension.
The makefile is hacked from the arduino playground makefile for use with your own code editor. The makefile
builds and burns the program with the avrispmkii by typing "make". The makefile can also burn the fuses by
typing "make fuses". Do this on a new chip. The .cpp program file is like a normal MCU C program except that init() must be called to start up the wiring code. (1) make an empty folder with the same name as your .cpp file will have, like "my_mcu_prog_v1" (2) copy the makefile into the folder and change it so that TARGET = my_mcu_prog_v1 SAVE THE FILE (3) in the new folder, create, copy, or open your .cpp program file like "my_mcu_prog_v1.cpp" in an editor like textedit or Smultron (4) open a terminal window in the my_mcu_prog_v1 folder (5) edit your code (6) type make in the terminal to build 'n burn (7) goto (5) Note: avrdude coughs up an error at the end of the burn: "Verify error - unable to read lfuse properly. Programmer may not be reliable." The error seems harmless. Its origin is unknown. */ // makefile_AB02.cpp #include "WProgram.h" #include <avr/io.h> #include <avr/wdt.h> #include <ctype.h> #define ADDR_LED 8 // my address is valid LED Arduino pin 8 AVR pin 14 #define ERROR_LED PIN_A1 // there was an error LED - 'F690 pin 18 #define RXTX_SWITCH PIN_C4 // line controls data direction on the // RS-485 transciever chip // errors - values add. A get OVERFLOW, 1 and a UNDERFLOW, 2 // together would cause error_last to have the value 3 #define OVERFLOW 0b00000001 // get overflow flag (1) #define UNDERFLOW 0b00000010 // get underflow flag (2) #define TIMEOUT_FLG 0b00000100 // ser in timeout flag (4) #define BAD_CMD 0b00001000 // invalid command (8) #define BAD_VAL 0b00010000 // bad param value (16) #define FAST_COM 1 // 115200 baud #define SLOW_COM 0 // 19200 baud // top level states #define WAITING 0 #define CHK_ADDR 1 #define RECV_CMD 2 #define RECV_PARM 3 #define RUNNING_CMD 4 #define PAUSED 5 #define SPACE 0x20 int MyBug_1_pwm(void); int MyBug_1_analog(void); int getInt(int *converted); char myAddr = 'A'; // default values char myGroup = 'Z'; int state; int errByte; int ledPin = 8; // LED connected to digital pin 14 //int pwmPin = 9; // Promiscous listen to bus during idle. Wait for "Attention" character (!). int waitForAttention(void){ while(Serial.read() != '!'); return 1; } int process_cmd(char cmd){ /* test strings: !Ap4 9; !Ap4 128; !Ap4 255; */ switch(cmd){ case 'a': MyBug_1_analog(); return WAITING; case 'p': MyBug_1_pwm(); return WAITING; break; case 'q': //x break; case 'g': //x break; case 'h': return PAUSED; break; case 'w': //x break; case 'x': Serial.println("foo"); break; case 'y': //x break; case 'z': // This is an Atmel hack for rebooting. WDTCSR = _BV(WDE); wdt_reset(); wdt_enable(WDTO_30MS); while (1); // DIE! case ';': // sometimes these slip through break; default: errByte &= BAD_CMD; Serial.print("bad cmd in switch"); //Serial.println(cmd); break; } } // PWM channel numbers are 1-6, but 5 and 6 are last resorts int MyBug_1_pwm(){ int pwmChan; int pwmVal; int AB_chan; if(!(getInt(&AB_chan))){ Serial.println("Bad get pwmChan MyBug"); return 0; } // convert ArtBus pin names to arduino pin names switch (AB_chan){ case 1: pwmChan = 3; // AVR pin # 5 break; case 2: pwmChan = 5; // AVR pin # 11 break; case 3: pwmChan = 6; // AVR pin # 12 break; case 4: pwmChan = 9; // AVR pin # 15 break; case 5: pwmChan = 10; // AVR pin # 16 -- ALSO SPI/ICSP PIN! USE CARE! break; case 6: pwmChan = 11; // AVR pin # 17 -- ALSO SPI/ICSP PIN! USE CARE! break; default: //error = badparm; Serial.print("unknown chan "); Serial.println(AB_chan); break; } if(!(getInt(&pwmVal))){ Serial.println("Bad get pwmVal 2 @ MyBug"); return 0; } analogWrite(pwmChan, pwmVal); } int MyBug_1_analog(){ int anaChan; int anaVal; int AB_chan; if(!(getInt(&AB_chan))){ Serial.println("Bad get pwmChan MyBug"); return 0; } /* // convert ArtBus pin names to arduino pin names switch (AB_chan){ case 1: pwmChan = 3; // AVR pin # 5 break; case 2: pwmChan = 5; // AVR pin # 11 break; case 3: pwmChan = 6; // AVR pin # 12 break; case 4: pwmChan = 9; // AVR pin # 15 break; case 5: pwmChan = 10; // AVR pin # 16 -- ALSO SPI/ICSP PIN! USE CARE! break; case 6: pwmChan = 11; // AVR pin # 17 -- ALSO SPI/ICSP PIN! USE CARE! break; default: //error = badparm; Serial.print("unknown chan "); Serial.println(AB_chan); break; } */ /* if(!(getInt(&anaVal))){ Serial.println("Bad get anaVal @ MyBug"); return 0; } */ anaVal = analogRead(AB_chan); Serial.println(anaVal); } // --------------------------------------------------- // when we are expecting data, a timeout means an error char getExpectedData(){ char val; long time; long timeout; timeout=time=millis(); // start counting milliseconds // try getting serial data for 1 to 2 milliseconds (it will vary) while(time - timeout < 2){ if(Serial.available()){ val = Serial.read(); return val; } time=millis(); } //Serial.println("serial timeout @ getExpected"); return 0; // while loop expired before data arrived (error) } int getChar(char *ascVal) { // returns success char asciival; // scratchpad variable asciival = getExpectedData(); //Serial.print("getChar = "); //Serial.println(asciival); if (isascii(asciival)){ // null would be bogus here *ascVal = asciival; //Serial.print("asciival @ getChar "); //Serial.println(asciival); return 1; } // Serial.println("no char @ getChar"); return 0; // failed from timeout } int getInt(int *converted) { // returns success char asciival; char stringarray[6]; int i = 0; int tries = 0; // fill the character array for conversion to an int do { asciival = getExpectedData(); if (asciival){ // null would be bogus here if ((asciival == '\n') || (asciival == '\r')) continue; stringarray[i] = asciival; i++; }else{ //Serial.println("do-while @ getInt()"); return 0; // failed from bad char } }while((isdigit(asciival)) && (i<=5)); // 5-char string + \0 -- do-while //Serial.print("asciival @274 .."); //Serial.print(asciival); //Serial.println(".."); if (asciival == ';' || asciival == ' ') { // delimiter is last member of array // add end of array marker for stringiness stringarray[i] = 0; //overwrite delimiter with null to make string *converted = atoi(stringarray); //didn't check for legit ascii //Serial.print("converted @ getInt "); //Serial.println(*converted); return 1; }else{ Serial.println("bad convert @ getInt()"); return 0; } } void blinkADDR_LED() { digitalWrite(ADDR_LED, HIGH); delay(250); digitalWrite(ADDR_LED, LOW); delay(250); } void greet(void){ char n; n = (myAddr - 'A') * 3; // ~30 millis per letter of the alphabet delay(n*10); // so each unit prints at a different time blinkADDR_LED(); blinkADDR_LED(); blinkADDR_LED(); Serial.print("\n\rHi from "); Serial.print(myAddr); Serial.println("! I'm a PWM bug. (rev 0.090316) \n\r"); } // ----------------------------------------------------------------------------- int main(void){ char val; /* After a software reset, "!Az;" the watchdog timer remains running and must be disabled to keep out of an endless reset loop. The MCU Status Register is cleared first (it likes it that way) so that the watchdog timer can then be disabled. The WDT is only used here as a way to reboot the chip. */ MCUSR = 0; wdt_disable(); init(); Serial.begin(115200); pinMode(ADDR_LED, OUTPUT); pinMode(9,OUTPUT); greet(); state = WAITING; while(1){ switch(state){ case WAITING: //Serial.println("now waiting"); waitForAttention(); // ENTIRE PROGRAM BLOCKS HERE val = getExpectedData(); if(val){ state = CHK_ADDR; }else{ //Serial.println("can't leave WAITING"); state = WAITING; } break; case CHK_ADDR: if(myAddr == val){ state = RUNNING_CMD; digitalWrite(ADDR_LED, HIGH); // hi. }else{ state = WAITING; digitalWrite(ADDR_LED, LOW); } break; case RUNNING_CMD: if(getChar(&val)){ state = process_cmd(val); // returns WAITING }else{ //Serial.println("bad get in STATE RUNNING_CMD"); state = WAITING; } break; default: //Serial.println("default state"); state = WAITING; } } }