├── README.md ├── WebTestClientandServer2 └── WebTestClientandServer2.ino └── buzz_8pwm_to_ppm328 ├── PPM_Encoder.h ├── README.txt └── buzz_8pwm_to_ppm328.ino /README.md: -------------------------------------------------------------------------------- 1 | BuzzsArduinoCode 2 | ================ 3 | 4 | Buzzs collection of Arduino "Scripts", code, samples, and stuff. -------------------------------------------------------------------------------- /WebTestClientandServer2/WebTestClientandServer2.ino: -------------------------------------------------------------------------------- 1 | /* 2 | Web Server AND Web Client - together. using an Arduino Wiznet Ethernet shield. 3 | 4 | A simple web SERVER that shows the value of the analog input pins, and lets you toggle the pin13 LED on and off. :-) 5 | //server web address will look like ( eg) http://192.168.0.253:80/ when submited 6 | AND ALSO: 7 | A simple web CLIENT that does a HTTP request to a different URL on another server on the LAN, and presents you the results. 8 | // open serial monitor and send an 'e' to run the HTTP client and to see what the arduino receives 9 | 10 | Circuit: 11 | * Ethernet shield attached to pins 10, 11, 12, 13 12 | * Analog inputs attached to pins A0 through A5 (optional) 13 | 14 | Bits by David A. Mellis, Tom Igoe and zoomkat. 15 | Assembled and made to work properly by Buzz, Jan 2013. ( davidbuzz@gmail.com ) 16 | 17 | */ 18 | 19 | #include 20 | #include 21 | 22 | // Enter a MAC address and IP address for your controller below. 23 | // The IP address will be dependent on your local network: 24 | byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; 25 | //byte ip[] = { 192,168,0,253 }; 26 | 27 | // fill in an available IP address on your network here, 28 | // for manual configuration: 29 | IPAddress ip(192,168,0,253); 30 | IPAddress gateway( 192, 168, 0, 1 ); // internet access via router 31 | IPAddress subnet( 255, 255, 255, 0 ); //subnet mask 32 | IPAddress remoteserver( 192, 168, 0, 163 ); // a simple web page 33 | 34 | #define IOPIN 13 35 | 36 | // fill in your DNS address here: 37 | //IPAddress myDns(8,8,8,8); 38 | 39 | // Initialize the Ethernet server library 40 | // with the IP address and port you want to use 41 | // (port 80 is default for HTTP): 42 | EthernetServer localserver(80); 43 | 44 | // initialize the library instance: 45 | EthernetClient outgoingclient; 46 | 47 | String readString; 48 | 49 | 50 | //char remoteserver[] = "www.arduino.cc"; 51 | 52 | unsigned long lastConnectionTime = 0; // last time you connected to the server, in milliseconds 53 | boolean lastConnected = false; // state of the connection last time through the main loop 54 | const unsigned long postingInterval = 6*1000; // delay between updates, in milliseconds 55 | 56 | 57 | void setup() 58 | { 59 | // start serial port: 60 | Serial.begin(19200); 61 | // give the ethernet module time to boot up: 62 | delay(1000); 63 | 64 | // start the Ethernet connection using a fixed IP address and DNS server: 65 | //Ethernet.begin(mac, ip, myDns); 66 | Ethernet.begin(mac, ip, gateway, subnet); 67 | 68 | // start the local server too. 69 | localserver.begin(); 70 | 71 | // print the Ethernet board/shield's IP address: 72 | Serial.print("My IP address: "); 73 | Serial.println(Ethernet.localIP()); 74 | 75 | } 76 | 77 | void loop() 78 | { 79 | //Serial.print("."); 80 | 81 | // check for serial input 82 | if (Serial.available() > 0) 83 | { 84 | byte inChar; 85 | inChar = Serial.read(); 86 | if(inChar == 'e') 87 | { 88 | Serial.println("ack, doing http client request! "); 89 | sendGET1(); // call sendGET function 90 | } 91 | } 92 | 93 | // listen for incoming clients 94 | EthernetClient incomingclient = localserver.available(); 95 | if (incomingclient) { 96 | // an http request ends with a blank line 97 | boolean currentLineIsBlank = true; 98 | while (incomingclient.connected()) { 99 | if (incomingclient.available()) { 100 | char c = incomingclient.read(); 101 | //Serial.print(c); // debug to show client data on Serial console. 102 | // if you've gotten to the end of the line (received a newline 103 | // character) and the line is blank, the http request has ended, 104 | // so you can send a reply 105 | 106 | //read char by char HTTP request into 100 byte buffer, toss rest away! 107 | if (readString.length() < 100) { 108 | //store characters to string 109 | readString += c; 110 | } 111 | 112 | if (c == '\n' && currentLineIsBlank) { 113 | // send a standard http response header 114 | incomingclient.println("HTTP/1.1 200 OK"); 115 | incomingclient.println("Content-Type: text/html"); 116 | incomingclient.println(); 117 | 118 | incomingclient.println(""); 119 | incomingclient.println(""); 120 | incomingclient.println("Buzzs simple html page"); 121 | incomingclient.println(""); 122 | incomingclient.println(""); 123 | 124 | // and output the links for the button on/off stuff: 125 | incomingclient.println("

Buzz's Analog data samples:

"); 126 | 127 | 128 | // output the value of each analog input pin 129 | for (int analogChannel = 0; analogChannel < 6; analogChannel++) { 130 | incomingclient.print("analog input "); 131 | incomingclient.print(analogChannel); 132 | incomingclient.print(" is "); 133 | incomingclient.print(analogRead(analogChannel)); 134 | incomingclient.println("
"); 135 | } 136 | 137 | // and output the links for the button on/off stuff: 138 | incomingclient.println("

Buzz's simple Arduino button:

"); 139 | 140 | ///////////////////// control arduino pin 141 | if(readString.indexOf("on") >0)//checks for on 142 | { 143 | digitalWrite(IOPIN, HIGH); // set pin 4 high 144 | Serial.println("Led On"); 145 | } 146 | if(readString.indexOf("off") >0)//checks for off 147 | { 148 | digitalWrite(IOPIN, LOW); // set pin 4 low 149 | Serial.println("Led Off"); 150 | } 151 | 152 | // report to user revised state of pin! 153 | if ( digitalRead(IOPIN) == 0 ) { 154 | incomingclient.println("LED IS OFF. CLICK TO TURN ON"); 155 | } else { 156 | incomingclient.println("LED IS ON, CLICK TO TURN OFF"); 157 | } 158 | //client.println(""); 160 | 161 | incomingclient.println(""); 162 | incomingclient.println(""); 163 | 164 | break; 165 | } 166 | if (c == '\n') { 167 | // you're starting a new line 168 | currentLineIsBlank = true; 169 | } 170 | else if (c != '\r') { 171 | // you've gotten a character on the current line 172 | currentLineIsBlank = false; 173 | } 174 | } 175 | } 176 | // give the web browser time to receive the data 177 | delay(1); 178 | // close the connection: 179 | incomingclient.stop(); 180 | //clearing string for next read 181 | readString=""; 182 | } 183 | 184 | 185 | // Serial.println("END"); 186 | 187 | } 188 | 189 | // now we optionally can do an outgoing client...... 190 | void sendGET1() { 191 | // if there's incoming data from the net connection. 192 | // send it out the serial port. This is for debugging 193 | // purposes only: 194 | 195 | // if there's no net connection, but there was one last time 196 | // through the loop, then stop the outgoingclient: 197 | if (!outgoingclient.connected() && lastConnected) { 198 | Serial.println(); 199 | Serial.println("disconnecting."); 200 | outgoingclient.stop(); 201 | } 202 | 203 | // if you're not connected, and X seconds have passed since 204 | // your last connection, then connect again and send data: 205 | if(!outgoingclient.connected() && (millis() - lastConnectionTime > postingInterval)) { 206 | // Serial.println("pre-connecting!......"); 207 | 208 | // if there's a successful connection: 209 | if (outgoingclient.connect(remoteserver, 80)) { 210 | //Serial.println("connecting..."); 211 | // send the HTTP PUT request: 212 | outgoingclient.println("GET /ard/arduino.txt HTTP/1.0"); // or HTTP/1.1 213 | // outgoingclient.println("Host: www.arduino.cc"); 214 | // outgoingclient.println("User-Agent: arduino-ethernet"); 215 | // outgoingclient.println("Connection: close"); 216 | outgoingclient.println(); 217 | 218 | // note the time that the connection was made: 219 | lastConnectionTime = millis(); 220 | 221 | Serial.println("connected."); 222 | // delay(1); // wait for data 223 | 224 | } 225 | else { 226 | // if you couldn't make a connection: 227 | Serial.println("http connection failed"); 228 | // Serial.println("disconnecting unclean."); 229 | outgoingclient.stop(); 230 | } 231 | } else { 232 | Serial.print("too soon for next http request, please slow them down to wait at least "); 233 | Serial.print(postingInterval/1000); 234 | Serial.println(" secs between them."); 235 | } 236 | 237 | 238 | while(outgoingclient.connected() && !outgoingclient.available()) delay(1); //waits for data 239 | 240 | 241 | // if we were just connectd by the above block we'll have data, check fgor it now! 242 | while (outgoingclient.connected() || outgoingclient.available()) { //connected or data available 243 | char c = outgoingclient.read(); 244 | Serial.print(c); 245 | } 246 | // Serial.println("data done."); 247 | // Serial.println(outgoingclient.connected()); 248 | // Serial.println(outgoingclient.available()); 249 | 250 | 251 | // finally stop the outgoingclient: 252 | if (! outgoingclient.connected() ) { 253 | Serial.println(); 254 | Serial.println("disconnected ok."); 255 | outgoingclient.stop(); 256 | } 257 | 258 | 259 | // store the state of the connection for next time through 260 | // the loop: 261 | lastConnected = outgoingclient.connected(); 262 | 263 | 264 | } 265 | 266 | 267 | -------------------------------------------------------------------------------- /buzz_8pwm_to_ppm328/PPM_Encoder.h: -------------------------------------------------------------------------------- 1 | 2 | // ------------------------------------------------------------- 3 | 4 | #ifndef _PPM_ENCODER_H_ 5 | #define _PPM_ENCODER_H_ 6 | 7 | #include 8 | 9 | // ------------------------------------------------------------- 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | // ------------------------------------------------------------- 16 | // SERVO INPUT FILTERS 17 | // ------------------------------------------------------------- 18 | // Using both filters is not recommended and may reduce servo input resolution 19 | 20 | // #define _AVERAGE_FILTER_ // Average filter to smooth servo input capture jitter 21 | // #define _JITTER_FILTER_ // Cut filter to remove 0,5us servo input capture jitter 22 | // ------------------------------------------------------------- 23 | 24 | #ifndef F_CPU 25 | #define F_CPU 16000000UL 26 | #endif 27 | 28 | #ifndef true 29 | #define true 1 30 | #endif 31 | 32 | #ifndef false 33 | #define false 0 34 | #endif 35 | 36 | //#ifndef bool 37 | //#define bool boolean 38 | //#endif 39 | // 328 does not define PBX but defines an equivalent as PORTBX, comment these lines out if you already have a PB2 defined. 40 | #define PB2 PORTB2 41 | #define PB1 PORTB1 42 | #define PB0 PORTB0 43 | 44 | 45 | // ------------------------------------------------------------- 46 | // SERVO INPUT MODE - !EXPERIMENTAL! 47 | // ------------------------------------------------------------- 48 | 49 | #define SERVO_PWM_MODE 1 // Normal 8 channel servo (pwm) input 50 | 51 | // Servo input mode (jumper (default), pwm, ppm, jeti or spektrum) 52 | volatile uint8_t servo_input_mode = SERVO_PWM_MODE; 53 | // ------------------------------------------------------------- 54 | 55 | // Number of Timer1 ticks in one microsecond 56 | #define ONE_US F_CPU / 8 / 1000 / 1000 57 | 58 | // 400us PPM pre pulse 59 | #define PPM_PRE_PULSE ONE_US * 400 60 | 61 | // ------------------------------------------------------------- 62 | // SERVO LIMIT VALUES 63 | // ------------------------------------------------------------- 64 | 65 | // Servo minimum position 66 | #define PPM_SERVO_MIN ONE_US * 900 - PPM_PRE_PULSE 67 | 68 | // Servo center position 69 | #define PPM_SERVO_CENTER ONE_US * 1500 - PPM_PRE_PULSE 70 | 71 | // Servo maximum position 72 | #define PPM_SERVO_MAX ONE_US * 2100 - PPM_PRE_PULSE 73 | 74 | // Throttle default at power on 75 | #define PPM_THROTTLE_DEFAULT ONE_US * 1100 - PPM_PRE_PULSE 76 | 77 | // Throttle during failsafe 78 | #define PPM_THROTTLE_FAILSAFE ONE_US * 900 - PPM_PRE_PULSE 79 | 80 | // CH5 power on values (mode selection channel) 81 | //#define PPM_CH5_MODE_4 ONE_US * 1555 - PPM_PRE_PULSE 82 | 83 | // ------------------------------------------------------------- 84 | 85 | // Number of servo input channels 86 | #define SERVO_CHANNELS 8 87 | 88 | // PPM period 18.5ms - 26.5ms (54hz - 37Hz) 89 | #define PPM_PERIOD ONE_US * ( 22500 - ( 8 * 1500 ) ) 90 | 91 | // Size of ppm[..] data array ( servo channels * 2 + 2) 92 | #define PPM_ARRAY_MAX 18 93 | 94 | 95 | // Data array for storing ppm (8 channels) pulse widths. 96 | volatile uint16_t ppm[ PPM_ARRAY_MAX ] = 97 | { 98 | PPM_PRE_PULSE, 99 | PPM_SERVO_CENTER, // Channel 1 100 | PPM_PRE_PULSE, 101 | PPM_SERVO_CENTER, // Channel 2 102 | PPM_PRE_PULSE, 103 | PPM_THROTTLE_DEFAULT, // Channel 3 (throttle) 104 | PPM_PRE_PULSE, 105 | PPM_SERVO_CENTER, // Channel 4 106 | PPM_PRE_PULSE, 107 | PPM_SERVO_CENTER, // Channel 5 108 | PPM_PRE_PULSE, 109 | PPM_SERVO_CENTER, // Channel 6 110 | PPM_PRE_PULSE, 111 | PPM_SERVO_CENTER, // Channel 7 112 | PPM_PRE_PULSE, 113 | PPM_SERVO_CENTER, // Channel 8 114 | PPM_PRE_PULSE, 115 | PPM_PERIOD 116 | }; 117 | 118 | 119 | // ------------------------------------------------------------- 120 | // SERVO FAILSAFE VALUES 121 | // ------------------------------------------------------------- 122 | const uint16_t failsafe_ppm[ PPM_ARRAY_MAX ] = 123 | { 124 | PPM_PRE_PULSE, 125 | PPM_SERVO_CENTER, // Channel 1 126 | PPM_PRE_PULSE, 127 | PPM_SERVO_CENTER, // Channel 2 128 | PPM_PRE_PULSE, 129 | PPM_THROTTLE_FAILSAFE, // Channel 3 (throttle) 130 | PPM_PRE_PULSE, 131 | PPM_SERVO_CENTER, // Channel 4 132 | PPM_PRE_PULSE, 133 | PPM_SERVO_CENTER, // Channel 5 134 | PPM_PRE_PULSE, 135 | PPM_SERVO_CENTER, // Channel 6 136 | PPM_PRE_PULSE, 137 | PPM_SERVO_CENTER, // Channel 7 138 | PPM_PRE_PULSE, 139 | PPM_SERVO_CENTER, // Channel 8 140 | PPM_PRE_PULSE, 141 | PPM_PERIOD 142 | }; 143 | // ------------------------------------------------------------- 144 | 145 | 146 | // AVR parameters for ArduPilot MEGA v1.4 PPM Encoder (ATmega328P) 147 | #if defined (__AVR_ATmega328P__) || defined (__AVR_ATmega328__) 148 | 149 | 150 | #define SERVO_DDR DDRD 151 | #define SERVO_PORT PORTD 152 | #define SERVO_INPUT PIND 153 | // PCIE2 PC Interrupt enable 2 is for Arduino Pins (D0-D7), also called PORTD. 154 | #define SERVO_INT_VECTOR PCINT2_vect 155 | 156 | #define SERVO_INT_MASK PCMSK2 157 | #define SERVO_INT_CLEAR_FLAG PCIF2 158 | #define SERVO_INT_ENABLE PCIE2 159 | #define SERVO_TIMER_CNT TCNT1 160 | 161 | #define PPM_DDR DDRB 162 | #define PPM_PORT PORTB 163 | #define PPM_OUTPUT_PIN PB2 164 | #define PPM_INT_VECTOR TIMER1_COMPB_vect 165 | #define PPM_COMPARE OCR1B 166 | #define PPM_COMPARE_FLAG COM1B0 167 | #define PPM_COMPARE_ENABLE OCIE1B 168 | 169 | #else 170 | #error NO SUPPORTED DEVICE FOUND! ( ATmega328/p) 171 | #endif 172 | 173 | // Used to indicate invalid SERVO input signals 174 | //volatile uint8_t servo_input_errors = 0; 175 | 176 | // Used to indicate missing SERVO input signals 177 | volatile bool servo_input_missing = true; 178 | 179 | // Used to indicate if PPM generator is active 180 | volatile bool ppm_generator_active = false; 181 | 182 | // Used to indicate a brownout restart 183 | volatile bool brownout_reset = false; 184 | 185 | // ------------------------------------------------------------------------------ 186 | // PPM GENERATOR START - TOGGLE ON COMPARE INTERRUPT ENABLE 187 | // ------------------------------------------------------------------------------ 188 | // this starts OUTGOING PPM stream on PPM_PORT (PORTB, Arduino D8-D13) at PPM_OUTPUT_PIN (PB2, arduino pin D10) 189 | void ppm_start( void ) 190 | { 191 | // Prevent reenabling an already active PPM generator 192 | if( ppm_generator_active ) return; 193 | 194 | // Store interrupt status and register flags 195 | uint8_t SREG_tmp = SREG; 196 | 197 | // Stop interrupts 198 | cli(); 199 | 200 | 201 | // Make sure initial output state is low 202 | PPM_PORT &= ~(1 << PPM_OUTPUT_PIN); 203 | 204 | // Wait for output pin to settle 205 | //_delay_us( 1 ); 206 | 207 | // Set initial compare toggle to maximum (32ms) to give other parts of the system time to start 208 | SERVO_TIMER_CNT = 0; 209 | PPM_COMPARE = 0xFFFF; 210 | 211 | // Set toggle on compare output 212 | TCCR1A = (1 << PPM_COMPARE_FLAG); 213 | 214 | // Set TIMER1 8x prescaler 215 | TCCR1B = ( 1 << CS11 ); 216 | 217 | // Enable output compare interrupt 218 | TIMSK1 |= (1 << PPM_COMPARE_ENABLE); 219 | 220 | // Indicate that PPM generator is active 221 | ppm_generator_active = true; 222 | 223 | // Restore interrupt status and register flags 224 | SREG = SREG_tmp; 225 | 226 | } 227 | 228 | // ------------------------------------------------------------------------------ 229 | // PPM GENERATOR STOP - TOGGLE ON COMPARE INTERRUPT DISABLE 230 | // ------------------------------------------------------------------------------ 231 | void ppm_stop( void ) 232 | { 233 | // Store interrupt status and register flags 234 | uint8_t SREG_tmp = SREG; 235 | 236 | // Stop interrupts 237 | cli(); 238 | 239 | // Disable output compare interrupt 240 | TIMSK1 &= ~(1 << PPM_COMPARE_ENABLE); 241 | 242 | // Reset TIMER1 registers 243 | TCCR1A = 0; 244 | TCCR1B = 0; 245 | 246 | // Indicate that PPM generator is not active 247 | ppm_generator_active = false; 248 | 249 | // Restore interrupt status and register flags 250 | SREG = SREG_tmp; 251 | 252 | } 253 | 254 | // ------------------------------------------------------------------------------ 255 | // Watchdog Interrupt (interrupt only mode, no reset) 256 | // ------------------------------------------------------------------------------ 257 | ISR( WDT_vect ) // If watchdog is triggered then enable missing signal flag and copy power on or failsafe positions 258 | { 259 | // Use failsafe values if PPM generator is active or if chip has been reset from a brown-out 260 | if ( ppm_generator_active || brownout_reset ) 261 | { 262 | // Copy failsafe values to ppm[..] 263 | for ( uint8_t i = 0; i < PPM_ARRAY_MAX; i++ ) 264 | { 265 | ppm[ i ] = failsafe_ppm[ i ]; 266 | } 267 | 268 | } 269 | 270 | 271 | // Set missing receiver signal flag 272 | servo_input_missing = true; 273 | 274 | // Reset servo input error flag 275 | //servo_input_errors = 0; 276 | 277 | } 278 | // ------------------------------------------------------------------------------ 279 | 280 | 281 | // ------------------------------------------------------------------------------ 282 | // SERVO/PPM INPUT - PIN CHANGE INTERRUPT, for any Arduino pin D0 -> D7 283 | // ------------------------------------------------------------------------------ 284 | ISR( SERVO_INT_VECTOR ) 285 | { 286 | 287 | 288 | // Servo pulse start timing 289 | static uint16_t servo_start[ SERVO_CHANNELS ] = { 0, 0, 0, 0, 0, 0, 0, 0 }; 290 | 291 | 292 | // Missing throttle signal failsafe 293 | static uint8_t throttle_timeout = 0; 294 | 295 | // Servo input pin storage 296 | static uint8_t servo_pins_old = 0; 297 | 298 | // Used to store current servo input pins 299 | uint8_t servo_pins; 300 | 301 | // Read current servo pulse change time 302 | uint16_t servo_time = SERVO_TIMER_CNT; 303 | 304 | 305 | // ------------------------------------------------------------------------------ 306 | // SERVO PWM MODE 307 | // ------------------------------------------------------------------------------ 308 | CHECK_PINS_START: // Start of servo input check 309 | 310 | // Store current servo input pins 311 | servo_pins = SERVO_INPUT; 312 | 313 | // Calculate servo input pin change mask 314 | uint8_t servo_change = servo_pins ^ servo_pins_old; 315 | 316 | // Set initial servo pin and channel 317 | uint8_t servo_pin = 1; 318 | uint8_t servo_channel = 0; 319 | 320 | CHECK_PINS_LOOP: // Input servo pin check loop 321 | 322 | // Check for pin change on current servo channel 323 | if( servo_change & servo_pin ) 324 | { 325 | // if (( servo_pin == 1 ) && ( ppm_generator_active = false) ) ppm_start(); 326 | // if (( servo_pin == 8 ) && ( ppm_generator_active = true) ) ppm_stop(); 327 | // High (raising edge) 328 | if( servo_pins & servo_pin ) 329 | { 330 | servo_start[ servo_channel ] = servo_time; 331 | } 332 | else 333 | { 334 | 335 | // Get servo pulse width 336 | uint16_t servo_width = servo_time - servo_start[ servo_channel ] - PPM_PRE_PULSE; 337 | 338 | // Calculate servo channel position in ppm[..] 339 | uint8_t _ppm_channel = ( servo_channel << 1 ) + 1; 340 | 341 | // Check that servo pulse signal is valid before sending to ppm encoder 342 | if( servo_width > PPM_SERVO_MAX ) goto CHECK_PINS_ERROR; 343 | if( servo_width < PPM_SERVO_MIN ) goto CHECK_PINS_ERROR; 344 | 345 | goto CHECK_PINS_NOERROR; 346 | 347 | CHECK_PINS_ERROR: 348 | 349 | // on width input error, use defailt/failsave value, OR previous value 350 | 351 | // choose the error handling type here! 352 | #define FAILHOLD 1 353 | 354 | #ifdef FAILCENTRE 355 | servo_width = failsafe_ppm[ _ppm_channel ]; // failsafe defaults, most channels centred, throttle lowered. 356 | #endif 357 | 358 | #ifdef FAILHOLD 359 | servo_width = ppm[ _ppm_channel ]; // all channels hold their previous position! 360 | #endif 361 | 362 | CHECK_PINS_NOERROR: 363 | 364 | //Reset throttle failsafe timeout 365 | if( _ppm_channel == 5 ) throttle_timeout = 0; 366 | 367 | #ifdef _AVERAGE_FILTER_ 368 | // Average filter to smooth input jitter 369 | servo_width += ppm[ _ppm_channel ]; 370 | servo_width >>= 1; 371 | #endif 372 | 373 | #ifdef _JITTER_FILTER_ 374 | // 0.5us cut filter to remove input jitter 375 | int16_t ppm_tmp = ppm[ _ppm_channel ] - servo_width; 376 | if( ppm_tmp == 1 ) goto CHECK_PINS_NEXT; 377 | if( ppm_tmp == -1 ) goto CHECK_PINS_NEXT; 378 | #endif 379 | 380 | // Update ppm[..] 381 | ppm[ _ppm_channel ] = servo_width; 382 | } 383 | } 384 | 385 | CHECK_PINS_NEXT: 386 | 387 | // Select next servo pin 388 | servo_pin <<= 1; 389 | 390 | // Select next servo channel 391 | servo_channel++; 392 | 393 | // Check channel and process if needed 394 | if( servo_channel < SERVO_CHANNELS ) goto CHECK_PINS_LOOP; 395 | 396 | goto CHECK_PINS_DONE; 397 | 398 | 399 | // All servo input pins has now been processed 400 | 401 | CHECK_PINS_DONE: 402 | 403 | // Reset Watchdog Timer 404 | wdt_reset(); 405 | 406 | // Set servo input missing flag false to indicate that we have received servo input signals 407 | servo_input_missing = false; 408 | 409 | // Store current servo input pins for next check 410 | servo_pins_old = servo_pins; 411 | 412 | // Start PPM generator if not already running 413 | if( ppm_generator_active == false ) ppm_start(); 414 | 415 | 416 | // Throttle failsafe 417 | if( throttle_timeout++ >= 128 ) 418 | { 419 | // Reset throttle timeout 420 | throttle_timeout = 0; 421 | // Set throttle failsafe value 422 | ppm[ 5 ] = PPM_THROTTLE_FAILSAFE; 423 | } 424 | 425 | //Has servo input changed while processing pins, if so we need to re-check pins 426 | if( servo_pins != SERVO_INPUT ) goto CHECK_PINS_START; 427 | 428 | // Clear interrupt event from already processed pin changes 429 | PCIFR |= (1 << SERVO_INT_CLEAR_FLAG); 430 | } 431 | // ------------------------------------------------------------------------------ 432 | 433 | 434 | // ------------------------------------------------------------------------------ 435 | // PPM OUTPUT - TIMER1 COMPARE INTERRUPT 436 | // ------------------------------------------------------------------------------ 437 | ISR( PPM_INT_VECTOR ) 438 | { 439 | // Current active ppm channel 440 | static uint8_t ppm_channel = PPM_ARRAY_MAX - 1; 441 | 442 | // Update timing for next compare toggle 443 | PPM_COMPARE += ppm[ ppm_channel ]; 444 | 445 | // Select the next ppm channel 446 | if( ++ppm_channel >= PPM_ARRAY_MAX ) 447 | { 448 | ppm_channel = 0; 449 | } 450 | } 451 | // ------------------------------------------------------------------------------ 452 | 453 | // ------------------------------------------------------------------------------ 454 | // PPM READ - INTERRUPT SAFE PPM SERVO CHANNEL READ 455 | // ------------------------------------------------------------------------------ 456 | /* uint16_t ppm_read_channel( uint8_t channel ) 457 | { 458 | // Limit channel to valid value 459 | uint8_t _channel = channel; 460 | if( _channel == 0 ) _channel = 1; 461 | if( _channel > SERVO_CHANNELS ) _channel = SERVO_CHANNELS; 462 | 463 | // Calculate ppm[..] position 464 | uint8_t ppm_index = ( _channel << 1 ) + 1; 465 | 466 | // Read ppm[..] in a non blocking interrupt safe manner 467 | uint16_t ppm_tmp = ppm[ ppm_index ]; 468 | while( ppm_tmp != ppm[ ppm_index ] ) ppm_tmp = ppm[ ppm_index ]; 469 | 470 | // Return as normal servo value 471 | return ppm_tmp + PPM_PRE_PULSE; 472 | } 473 | */ 474 | // ------------------------------------------------------------------------------ 475 | 476 | // ------------------------------------------------------------------------------ 477 | // PPM ENCODER INIT 478 | // ------------------------------------------------------------------------------ 479 | void ppm_encoder_init( void ) 480 | { 481 | 482 | 483 | // SERVO/PPM INPUT PINS 484 | // ------------------------------------------------------------------------------ 485 | // Set all servo input pins to inputs 486 | SERVO_DDR = 0; 487 | 488 | // Activate pullups on all input pins 489 | SERVO_PORT |= 0xFF; 490 | 491 | 492 | // SERVO/PPM INPUT - PIN CHANGE INTERRUPT 493 | // ------------------------------------------------------------------------------ 494 | if( servo_input_mode == SERVO_PWM_MODE ) 495 | { 496 | // Set servo input interrupt pin mask to all 8 servo input channels 497 | SERVO_INT_MASK = 0xFF; 498 | } 499 | 500 | // Enable servo input interrupt 501 | PCICR |= (1 << SERVO_INT_ENABLE); 502 | 503 | // PPM OUTPUT PIN 504 | // ------------------------------------------------------------------------------ 505 | // Set PPM pin to output 506 | PPM_DDR |= (1 << PPM_OUTPUT_PIN); 507 | 508 | // ------------------------------------------------------------------------------ 509 | // Enable watchdog interrupt mode 510 | // ------------------------------------------------------------------------------ 511 | // Disable watchdog 512 | wdt_disable(); 513 | // Reset watchdog timer 514 | wdt_reset(); 515 | // Start timed watchdog setup sequence 516 | WDTCSR |= (1< 26 | #include 27 | 28 | 29 | #define ERROR_THRESHOLD 2 // Number of servo input errors before alerting 30 | #define ERROR_DETECTION_WINDOW 3000 * LOOP_TIMER_10MS // Detection window for error detection (default to 30s) 31 | #define ERROR_CONDITION_DELAY 500 * LOOP_TIMER_10MS // Servo error condition LED delay (LED blinking duration) 32 | 33 | #define PASSTHROUGH_MODE_ENABLED // Comment this line to remove CH8 radio passthrough mode support (hardware failsafe for Arduplane) 34 | #define PASSTHROUGH_CHANNEL 8 * 2 // Channel for passthrough mode selection 35 | #define PASSTHROUGH_CHANNEL_OFF_US ONE_US * 1600 - PPM_PRE_PULSE // Passthrough off threshold 36 | #define PASSTHROUGH_CHANNEL_ON_US ONE_US * 1800 - PPM_PRE_PULSE // Passthrough on threshold 37 | 38 | #define THROTTLE_CHANNEL 3 * 2 // Throttle Channel 39 | #define THROTTLE_CHANNEL_LED_TOGGLE_US ONE_US * 1200 - PPM_PRE_PULSE // Throttle Channel Led toggle threshold 40 | #define LED_LOW_BLINKING_RATE 125 * LOOP_TIMER_10MS // Led blink rate for low throttle position (half period) 41 | 42 | // Timers 43 | 44 | #define TIMER0_10MS 156 // Timer0 ticks for 10 ms duration 45 | #define TIMER1_10MS 20000 // Timer1 ticks for 10 ms duration 46 | #define TIMER2_100MS 1562 // Timer2 ticks for 100 ms duration 47 | #define LOOP_TIMER_10MS 10 // Loop timer ticks for 10 ms duration 48 | 49 | // LED Code 50 | 51 | #define SPACE_SHORT_DURATION 40 * LOOP_TIMER_10MS // Space after short symbol 52 | #define SPACE_LONG_DURATION 75 * LOOP_TIMER_10MS // Space after long symbol 53 | #define SYMBOL_SHORT_DURATION 20 * LOOP_TIMER_10MS // Short symbol duration 54 | #define SYMBOL_LONG_DURATION 100 * LOOP_TIMER_10MS // Long symbol duration 55 | #define INTER_CODE_DURATION 150 * LOOP_TIMER_10MS // Inter code duration 56 | 57 | #define INTER_CODE 0 // Symbols value for coding 58 | #define SHORT_SYMBOL 1 59 | #define LONG_SYMBOL 2 60 | #define SHORT_SPACE 3 61 | #define LONG_SPACE 4 62 | #define LOOP 5 63 | 64 | 65 | 66 | // ------------------------------------------------------------------------------------------------------------------------------------------------------------ 67 | // PPM ENCODER INIT AND AUXILIARY TASKS 68 | // ------------------------------------------------------------------------------------------------------------------------------------------------------------ 69 | 70 | // ------------------------------------------------------------------------------------------------------------------------------------------------------------ 71 | // LOCAL VARIABLES 72 | // ------------------------------------------------------------------------------------------------------------------------------------------------------------ 73 | bool localinit = true; // We are inside init sequence 74 | bool mux_passthrough = false; // Mux passthrough mode status Flag : passthrough is off 75 | uint16_t led_acceleration; // Led acceleration based on throttle stick position 76 | bool servo_error_condition = false; // Servo signal error condition 77 | 78 | static uint16_t servo_error_detection_timer=0; // Servo error detection timer 79 | static uint16_t servo_error_condition_timer=0; // Servo error condition timer 80 | static uint16_t blink_led_timer = 0; // Blink led timer 81 | 82 | #ifdef PASSTHROUGH_MODE_ENABLED 83 | static uint8_t mux_timer = 0; // Mux timer 84 | static uint8_t mux_counter = 0; // Mux counter 85 | static int8_t mux_check = 0; 86 | static uint16_t mux_ppm = 500; 87 | #endif 88 | 89 | static uint16_t led_code_timer = 0; // Blink Code Timer 90 | static uint8_t led_code_symbol = 0; // Blink Code current symbol 91 | 92 | 93 | // ------------------------------------------------------------------------------------------------------------------------------------------------------------ 94 | // LOCAL FUNCTIONS 95 | // ------------------------------------------------------------------------------------------------------------------------------------------------------------ 96 | 97 | // ------------------------------------------------------------------------------ 98 | // Led blinking (non blocking) function 99 | // ------------------------------------------------------------------------------ 100 | 101 | uint8_t blink_led ( uint16_t half_period ) // ( half_period max = 65 s ) 102 | { 103 | 104 | blink_led_timer++; 105 | 106 | if ( blink_led_timer < half_period ) // If half period has not been reached 107 | { 108 | return 0; // Exit timer function and return 0 109 | } 110 | else // half period reached - LED Toggle 111 | { 112 | PPM_PORT ^= ( 1 << PB0 ); // Toggle status LED 113 | blink_led_timer = 0; // Blink led timer reset 114 | 115 | return 1; // half period reached - Exit timer function and return 1 116 | } 117 | 118 | } 119 | 120 | // ------------------------------------------------------------------------------ 121 | // Led code (non blocking) function 122 | // ------------------------------------------------------------------------------ 123 | 124 | void blink_code_led ( uint8_t code ) 125 | { 126 | 127 | const uint8_t coding[2][14] = { 128 | 129 | // PPM_PASSTROUGH_MODE 130 | { INTER_CODE, LONG_SYMBOL, LONG_SPACE, SHORT_SYMBOL, SHORT_SPACE, SHORT_SYMBOL, LOOP }, 131 | 132 | // JETI_MODE 133 | { INTER_CODE, LONG_SYMBOL, LONG_SPACE, SHORT_SYMBOL, SHORT_SPACE, SHORT_SYMBOL, SHORT_SPACE, SHORT_SYMBOL,LOOP } 134 | 135 | }; 136 | 137 | led_code_timer++; 138 | 139 | 140 | switch ( coding [ code - 2 ] [ led_code_symbol ] ) 141 | { 142 | case INTER_CODE: 143 | 144 | if ( led_code_timer < ( INTER_CODE_DURATION ) ) return; 145 | else PPM_PORT |= ( 1 << PB0 ); // Enable status LED 146 | break; 147 | 148 | case LONG_SYMBOL: // Long symbol 149 | 150 | if ( led_code_timer < ( SYMBOL_LONG_DURATION ) ) return; 151 | else PPM_PORT &= ~( 1 << PB0 ); // Disable status LED 152 | break; 153 | 154 | case SHORT_SYMBOL: // Short symbol 155 | 156 | if ( led_code_timer < ( SYMBOL_SHORT_DURATION ) ) return; 157 | else PPM_PORT &= ~( 1 << PB0 ); // Disable status LED 158 | break; 159 | 160 | case SHORT_SPACE: // Short space 161 | 162 | if ( led_code_timer < ( SPACE_SHORT_DURATION ) ) return; 163 | else PPM_PORT |= ( 1 << PB0 ); // Enable status LED 164 | break; 165 | 166 | case LONG_SPACE: // Long space 167 | 168 | if ( led_code_timer < ( SPACE_LONG_DURATION ) ) return; 169 | else PPM_PORT |= ( 1 << PB0 ); // Enable status LED 170 | break; 171 | 172 | case LOOP: // Loop to code start 173 | led_code_symbol = 0; 174 | return; 175 | break; 176 | 177 | } 178 | 179 | led_code_timer = 0; // Code led timer reset 180 | led_code_symbol++; // Next symbol 181 | 182 | return; // LED code function return 183 | 184 | } 185 | 186 | 187 | // ------------------------------------------------------------------------------ 188 | // ppm reading helper - interrupt safe and non blocking function 189 | // ------------------------------------------------------------------------------ 190 | uint16_t ppm_read( uint8_t channel ) 191 | { 192 | uint16_t ppm_tmp = ppm[ channel ]; 193 | while( ppm_tmp != ppm[ channel ] ) ppm_tmp = ppm[ channel ]; 194 | 195 | return ppm_tmp; 196 | } 197 | 198 | // ------------------------------------------------------------------------------------------------------------------------------------------------------------ 199 | // INITIALISATION CODE 200 | // ------------------------------------------------------------------------------------------------------------------------------------------------------------ 201 | 202 | void setup() { 203 | 204 | 205 | // ------------------------------------------------------------------------------ 206 | // Reset Source checkings 207 | // ------------------------------------------------------------------------------ 208 | if (MCUSR & 1) // Power-on Reset 209 | { 210 | MCUSR=0; // Clear MCU Status register 211 | // custom code here 212 | } 213 | else if (MCUSR & 2) // External Reset 214 | { 215 | MCUSR=0; // Clear MCU Status register 216 | // custom code here 217 | } 218 | else if (MCUSR & 4) // Brown-Out Reset 219 | { 220 | MCUSR=0; // Clear MCU Status register 221 | brownout_reset=true; 222 | } 223 | else // Watchdog Reset 224 | { 225 | MCUSR=0; // Clear MCU Status register 226 | // custom code here 227 | } 228 | 229 | 230 | // ------------------------------------------------------------------------------ 231 | // Servo input and PPM generator init 232 | // ------------------------------------------------------------------------------ 233 | ppm_encoder_init(); 234 | 235 | // ------------------------------------------------------------------------------ 236 | // Outputs init 237 | // ------------------------------------------------------------------------------ 238 | PPM_DDR |= ( 1 << PB0 ); // Set LED pin (PB0) to output 239 | PPM_DDR |= ( 1 << PB1 ); // Set MUX pin (PB1) to output 240 | PPM_DDR |= ( 1 << PPM_OUTPUT_PIN ); // Set PPM pin (PPM_OUTPUT_PIN, OC1B) to output 241 | 242 | // ------------------------------------------------------------------------------ 243 | // Timer0 init (normal mode) used for LED control and custom code 244 | // ------------------------------------------------------------------------------ 245 | TCCR0A = 0x00; // Clock source: System Clock 246 | TCCR0B = 0x05; // Set 1024x prescaler - Clock value: 15.625 kHz - 16 ms max time 247 | TCNT0 = 0x00; 248 | OCR0A = 0x00; // OC0x outputs: Disconnected 249 | OCR0B = 0x00; 250 | TIMSK0 = 0x00; // Timer 1 interrupt disable 251 | 252 | // ------------------------------------------------------------------------------ 253 | // Enable global interrupt 254 | // ------------------------------------------------------------------------------ 255 | sei(); // Enable Global interrupt flag 256 | 257 | // ------------------------------------------------------------------------------ 258 | // Disable radio passthrough (mux chip A/B control) 259 | // ------------------------------------------------------------------------------ 260 | PPM_PORT |= ( 1 << PB1 ); // Set PIN B1 to disable Radio passthrough (mux) 261 | 262 | 263 | 264 | 265 | } 266 | 267 | void loop() { 268 | 269 | 270 | // ------------------------------------------------------------------------------------------------------------------------------------------------------------ 271 | // AUXILIARY TASKS 272 | // ------------------------------------------------------------------------------------------------------------------------------------------------------------ 273 | PWM_LOOP: // SERVO_PWM_MODE 274 | while( 1 ) 275 | { 276 | 277 | _delay_us (950); // Slow down while loop 278 | 279 | } // PWM Loop end 280 | 281 | 282 | 283 | 284 | } // main lopo function end 285 | 286 | 287 | 288 | --------------------------------------------------------------------------------