📄 rc_mk1.2.1_rx.c
字号:
// RX/** * \file main.c * \brief Firmware for the CYRF6936 based RC system Receiver. * \author Duncan Law * \version receiver/main.c V1.0 * * \log. * \ 01/12/08 v1 of firmware complete. * \ 01/01/09 Restructure of main loop. Now pauses to wait for incoming transmission. * \ 01/01/09 syncronises timer0 according to Controller's timer0 displayed in incoming packet. * * * License: See documentation. */#include "main.h"#include <avr/eeprom.h>#include </usr/avr/include/compat/deprecated.h>#define NOP asm("nop");#define F_CPU 8000000 // 8MHz processor#define CYCLES_PER_US ((F_CPU+500000)/1000000) // cpu cycles per microsecondint main(){ // timer0 setup for system clock. TCCR0A = 0x00; TCCR0B = 0x05; // timer0 prescaler = 1024 TCNT0 = 0x00; // set timer0 to 0x00. // timer1 setup for servo control TCCR1A = _BV(COM1A1) // set OC1A/B at TOP | _BV(COM1B1) // clear OC1A/B when match | _BV(COM1C1) | _BV(WGM11); // mode 14 (fast PWM, clear TCNT1 on match ICR1) TCCR1B = _BV(WGM13) | _BV(WGM12) | _BV(CS11); // timer uses main system clock with 1/8 prescale ICR1 = 20000; // used for TOP, makes for 50 hz PWM OCR1A = 1500; // servo at center OCR1B = 1500; // servo at center OCR1C = 1000; // servo at low (ESC off) DDRB = _BV(PB5) | _BV(PB6) // have to set up pins as outputs | _BV(PB7); // have to set up pins as outputs // timer3 setup for servo control TCCR3A = _BV(COM3A1) // set OC1A/B at TOP | _BV(COM3B1) // clear OC1A/B when match | _BV(COM3C1) | _BV(WGM31); // mode 14 (fast PWM, clear TCNT1 on match ICR1) TCCR3B = _BV(WGM33) | _BV(WGM32) | _BV(CS31); // timer uses main system clock with 1/8 prescale ICR3 = 20000; // used for TOP, makes for 50 hz PWM OCR3A = 1500; // servo at center OCR3B = 1500; // servo at center OCR3C = 1500; // servo at center DDRE = _BV(PE3) | _BV(PE4) // have to set up pins as outputs | _BV(PE5); // have to set up pins as outputs // set the baud rate of the UART uartSetUp(19200); UARTout(0x00); UARTout(0x00); UARTout(0x00); UARTout(0x00); // setup SPI bus and RF module. InitialiseRF(); short int timeout = 0; short int i; // loop through data bytes. unsigned char data[16], data_debounce[16]; unsigned char servo_multiplier = 1; // multipler for all chanels float servo_multiplier_1 = 1; // multiplier for different channels float servo_multiplier_2 = 1; uint16_t trimA_addr = 0x0000; uint16_t trimB_addr = 0x0002; uint16_t trimA = eeprom_read_word(&trimA_addr); uint16_t trimB = eeprom_read_word(&trimB_addr); short int newdata=0; unsigned char tmp, tmp2, tmp3, TXcount, count; unsigned char chan_num=0, PWM_count_error=0, PWM_count_consecutive_error_max=0; short int PWM_count=0, PWM_count_consecutive_error=0, PacketTX_result=0, PacketTX_debounce; unsigned char timeL = 0; unsigned char timeH = 0; short int PWM_count_total = 0, time_int = 0; TCNT0 = 0x00; // set timer0 to 0x00. while (1) // Loop forever { while(0){ if ((!(SpiByteRead(0x05) & (1<<7))) && (!(SpiByteRead(0x07) & (1<<6)))){ SpiByteWrite(0x05,0x80); //RX_GO } } //while(TCNT0 < 0x01){ // Transmitter is reading controller now so this end free to do stuff. //} //UARTout_hex(SpiByteRead(0x00)); // put RF module in receive mode: SpiByteWrite(0x05,0x80); //RX_GO newdata=0; // wait for incoming packet. while((!newdata) && (TCNT0 < 0x95)){ tmp= SpiByteRead(0x07); if (!(SpiByteRead(0x05))){ tmp2= SpiByteRead(0x08); if ((tmp & (1<<1)) && (!((tmp) & (1<<0)))){ SpiByteWrite(0x07,0x80); for (i=0; i<16; i++){ //read data. data[i] = SpiByteRead(0x21); } TCNT0 = data[4] -4 ; // syncronise clocks newdata=1; //UARTout('A'); UARTout(0x0A); } else { newdata=0; /*UARTout('B'); UARTout_hex(tmp); UARTout(','); UARTout_hex(tmp2); UARTout(0x0A);*/ } } else { /*UARTout('C'); UARTout_hex(tmp); UARTout(','); UARTout_hex(tmp2); UARTout(0x0A);*/ } } //UARTout(0x0A); // do something with received packet...// if (1){ if (newdata ){ // syncronise which channel Receiver is on. set the same as Controller chan_num = data[3]; // top left pad doubles servo movment. if (!(data[7] & 0x01)) { servo_multiplier = 2; } else {servo_multiplier = 1;} // triangle button sets trim. // data_debounce makes sure only one press is recognised. if ((!(data[7] & 0x10)) && (data_debounce[7] & 0x10)){ trimA += - (servo_multiplier*servo_multiplier_2*((2*data[9]) - 255)); trimB += (servo_multiplier*servo_multiplier_1*((2*data[8]) - 255)); eeprom_write_word(&trimA_addr, trimA); eeprom_write_word(&trimB_addr, trimB); } // remember the value of button register on last pass //so we can compare for single reponse to button press. data_debounce[7] = data[7]; // Circle button clears trim if (!(data[7] & 0x20)) { trimA = 0; trimB = 0; eeprom_write_word(&trimA_addr, trimA); eeprom_write_word(&trimB_addr, trimB); } // set servos. aerlon controll: OCR1C = 1900- (4*data[11]); // set servo position OCR1B = 1500+ (servo_multiplier_1*servo_multiplier*((2*data[9]) - 255)) - trimA; OCR1A = 1500+ (servo_multiplier_2*servo_multiplier*((2*data[8]) - 255)) + trimB; OCR3C = 1500+ (servo_multiplier_2*servo_multiplier*((2*data[8]) - 255)) + trimB; } else{ PWM_count_error++; } // cycle between channels every 5 cycles. if (chan_num++ < 5){ //UARTout('a'); SpiByteWrite(0x00,0x45); // CHANNEL } else if ((chan_num >= 5) && (chan_num <= 10)){ //UARTout('b'); SpiByteWrite(0x00,0x48); // CHANNEL } else{ //UARTout('c'); SpiByteWrite(0x00,0x60); // CHANNEL } //UARTout(chan_num); if (chan_num >= 15) { chan_num = 0;} if (count++ == 50){ count = 0; UARTout(TXcount); TXcount=0; } // once per second output transmission statistics. if (PWM_count++ == 49){ // 50 x 20ms devisions have passed. // count time in seconds since last power cycle. time_int++; timeL++; if (timeL > 99){ timeH++; timeL=0; } PWM_count_total+=PWM_count_error; if ((PWM_count_error==50) && (PWM_count_consecutive_error_max==50)){ timeH=0; timeL=0; PWM_count_total=0; PWM_count_error=0; PWM_count_consecutive_error_max=0; time_int=0; } UARTout_dec(timeH); UARTout_dec(timeL); UARTout(' '); UARTout_dec(PWM_count_error); UARTout(','); UARTout_dec(PWM_count_total/time_int); UARTout(0x0A); PWM_count=0; PWM_count_error=0; } while(TCNT0 < 0x97){} TCNT0 = 0; }}// no signal for multiple cycles so reset servo position.void servo_default(uint16_t trimA, uint16_t trimB){ // aerlon control: OCR1B = 1500 - trimA; OCR1A = 1500 + trimB; OCR3C = 1500 + trimB; OCR1C = 1000;/* // R/E controll: OCR1B = 1500 + trimB; OCR1A = 1500 + trimA; OCR1C = 1000;*//* if (OCR1C > 1000){ OCR1C-=0x1; // center servos,stop motor } if (OCR1B > 1503 + trimA){ OCR1B-=0x1; } else if (OCR1B < 1497 + trimA){ OCR1B+=0x1; } if (OCR1A > 1503 + trimB){ OCR1A-=0x1; } else if (OCR1A < 1497 + trimB){ OCR1A+=0x1; } if (OCR3C > 1503 + trimB){ OCR3C-=0x1; } else if (OCR3C < 1497 + trimB){ OCR3C+=0x1; }*/ return;}// set the uart baud ratevoid uartSetUp(unsigned int baudrate){ // calculate division factor for requested baud rate, and set it unsigned int bauddiv = ((F_CPU+(baudrate*8L))/(baudrate*16L)-1); /* Set baud rate */ UBRR1H = (unsigned char)(bauddiv>>8); UBRR1L = (unsigned char)bauddiv; /* Enable receiver and transmitter */ UCSR1B = (1<<RXEN1)|(1<<TXEN1); /* Set frame format: 8data, 2stop bit */ UCSR1C = (1<<USBS1)|(3<<UCSZ10);}// send an 8bit number out of the UART.// *note* this does not use the pesudo manchester encoding // so many RF modules will not transmit numbers with high proportion of "1"s or "0"s correctly.void UARTout(unsigned char data){ while (!(UCSR1A & (1<<UDRE1))) { continue; } UDR1 = data; return;}// send an 8bit number out of the UART. display as decimal number in ASCIIvoid UARTout_dec(unsigned char data){ if(data/100){ UARTout('0' + data/100); } UARTout('0' + ((data%100)/10)); UARTout('0' + data%10); return;}// send an 8bit number out of the UART. display as decimal number in ASCIIvoid UARTout_hex(unsigned char data){ if (((data & 0xF0) >= 0) && ((data & 0xF0) < 0xAA)) { UARTout('0' + ((data >>4) & 0x0F)); } else if (((data & 0xF0) >= 0xA0) && ((data & 0xF0) <= 0xF0)){ UARTout('A' + ((data >>4) & 0x0F) - 0x0A); } if (((data & 0x0F) >= 0) && ((data & 0x0F) < 0x0A)) { UARTout('0' + (data & 0x0F)); } else if (((data & 0x0F) >= 0x0A) && ((data & 0x0F) <= 0x0F)){ UARTout('A' + (data & 0x0F) - 0x0A); } return;}// SPI send byte and receive following byteunsigned char SpiByteRead(unsigned char data){ cbi(PORTB, PB0); // SS low to initiate SPI. SPDR = data; // send byte (Address) while(!(SPSR & (1<<SPIF))); SPDR = 0x00; // not sending anything on the next cycle. while(!(SPSR & (1<<SPIF))); sbi(PORTB, PB0); // SS high to end SPI. return SPDR; // receiving data instead.}// SPI send byte and send following bytevoid SpiByteWrite(unsigned char register_address, unsigned char data){ cbi(PORTB, PB0); // SS low to initiate SPI. SPDR = register_address | 0x80; // send byte (Address) with pit 8 set for write enable while(!(SPSR & (1<<SPIF))); SPDR = data; // send byte (data). while(!(SPSR & (1<<SPIF))); sbi(PORTB, PB0); // SS high to end SPI. return ;}void InitialiseRF(void){ // setup I/O pins connected to RF module. cbi(DDRE, PE7); // set UNIGEN RF module IRQ pin to input sbi(DDRB, PB0); // set UNIGEN RF module SS pin to output sbi(PORTB, PB0); sbi(DDRG, PG3); // set UNIGEN RF module RST pin to output cbi(PORTG, PG3); // set up SPI from: http://www.openavr.org/AVR_SPI_C_Snippets SPCR = _BV(SPE) | _BV(MSTR); // SPI enable bit and the master mode bit DDRB |= _BV(0) | _BV(1) | _BV(2); // SS is at PB0, SCK is at PB1 and MOSI is at PB2. set direction PORTB |= _BV(3); // enable pullups on MISO at PB3. unsigned char tmp; // read registers at startup to clear. tmp = SPSR; tmp = SPDR; //SpiByteWrite(0x26,0x08); // XTAL_CFG (must) //SpiByteWrite(0x32,0x3C); // AUTO_CAL_TIME (must) //SpiByteWrite(0x35,0x14); // AUTO_CAL_OFFSET (must) SpiByteWrite(0x1D,0x01); // MODE_OVERRIDE, RST (Reset module) SpiByteWrite(0x03,0x2F); // TX_CFG, SpiByteWrite(0x05,0x00); // set RX_CTRL_ADR, RX_GO SpiByteWrite(0x06,0x4A); // RX_CFG_ADR, overwrite (RXOW EN)// SpiByteWrite(0x0F,0x83); // XACT_CFG, END_STATE & ACK_EN SpiByteWrite(0x0F,0x93); // XACT_CFG,END_STATE,ACK EN, ACK_TO_15X //SpiByteWrite(0x0F,0x11); // XACT_CFG,END_STATE,ACK EN, ACK_TO_15X// SpiByteWrite(0x10,0xA4); // FRAMING_CFG, LEN EN SpiByteWrite(0x10,0xEE); // FRAMING_CFG, LEN EN //SpiByteWrite(0x11,0x05); // DATA32_THOLD SpiByteWrite(0x11,0x08); // DATA32_THOLD SpiByteWrite(0x12,0x0E); // DATA64_THOLD SpiByteWrite(0x15,0x14); // CRC_SEED_LSB SpiByteWrite(0x16,0x14); // CRC_SEED_MSB SpiByteWrite(0x1B,0x55); // TX_OFFSET_LSB SpiByteWrite(0x1C,0x05); // TX_OFFSET_MSB SpiByteWrite(0x24,0x10); // PREAMBLE SpiByteWrite(0x24,0x33); // PREAMBLE SpiByteWrite(0x24,0x33); // PREAMBLE //SpiByteWrite(0x1E,0x08); // return;}// delay for a minimum of <us> microseconds // the time resolution is dependent on the time the loop takes // e.g. with 4Mhz and 5 cycles per loop, the resolution is 1.25 us void delay_us(unsigned short time_us){ unsigned short delay_loops; register unsigned short i; delay_loops = (time_us+3)/5*CYCLES_PER_US; // +3 for rounding up (dirty) // one loop takes 5 cpu cycles for (i=0; i < delay_loops; i++) {};}void delay_ms(unsigned char time_ms){ unsigned short int i; for (i=0; i < 500; i++) {delay_us(100);} return;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -