📄 rc_mk1.2.1_tx.c
字号:
// TX/** * \file main.c * \brief Firmware for the CYRF6936 based RC system. * \author Duncan Law * \version main.c V1.2 * * \log. * 01/12/08 v1 firmware complete. * 30/12/08 added check for ACK packet and retransmit if ACK not detected. * 01/10/09 enabled watch dog timer * 01/10/09 added timer0 based timing control. * * * License: See documentation. */ #include "main.h"#include </usr/avr/include/avr/iom2561_dla.h>#include </usr/avr/include/compat/deprecated.h>#include <avr/pgmspace.h>#include <avr/wdt.h> // watchdog timer#define NOP asm("nop");#define F_CPU 8000000 // 8MHz processor#define CYCLES_PER_US ((F_CPU+500000)/1000000) // cpu cycles per microsecond#define PSclock 7 // PB7 clock. blue#define PSdata 6 // PB6 data. brown#define PScommand 5 // PB5 command. orange#define PSattention 5 // PE5 attention. yellowint main(){ // set the baud rate of the UART uartSetUp(19200); UARTout(0x0A); //newline UARTout(0x0D); //newline UARTout('s'); UARTout('t'); UARTout('a'); UARTout('r'); UARTout('t'); UARTout(0x0A); //newline UARTout(0x0D); //newline short int i; // loop short int j; // loop 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); // PSx controller I/O pin setup: sbi(DDRB, PSclock); // clock. output. (blue) cbi(DDRB, PSdata); // data. input. (brown) sbi(PORTB, PSdata); // enable pullup resistor sbi(DDRB, PScommand); // command. output. (orange) sbi(DDRE, PSattention); // attention. output. (yellow) // 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. spi_Init_RF(); // setup SPI with RF module settings initialisePS2(); // setup PS2 controller. unsigned char tmp; // read registers at startup to clear. tmp = SPSR; tmp = SPDR; unsigned char CHANNEL_ADR_A = 0x48; unsigned char CHANNEL_ADR_B = 0x00; unsigned char RSSI; unsigned char data[12]; unsigned char PacketType = 0x01; unsigned char timeL = 0; unsigned char timeH = 0; short int PWM_count_total = 0, time_int = 0; unsigned char chan_num, test_time1; short int PWM_count, PWM_count_error, PWM_count_consecutive_error_max, PWM_count_consecutive_error, PacketTX_result, PacketTX_debounce; // setting up RF module.... SpiByteWrite(0x1D,0x01); // MODE_OVERRIDE, RST (Reset module) //SpiByteWrite(0x26,0x08); // XTAL_CFG (must) //SpiByteWrite(0x32,0x3C); // AUTO_CAL_TIME (must) //SpiByteWrite(0x35,0x14); // AUTO_CAL_OFFSET (must) SpiByteWrite(0x15,0x14); // CRC_SEED_LSB SpiByteWrite(0x16,0x14); // CRC_SEED_MSB SpiByteWrite(0x00,0x48); // CHANNEL. (0x48 is default.) SpiByteWrite(0x03, 0x2F); // TX_CFG, set power level SpiByteWrite(0x06,0x4A); // RX_CFG_ADR SpiByteWrite(0x0F,0x83); // XACT_CFG,END_STATE,ACK EN, ACK_TO_4X SpiByteWrite(0x10,0xEE); // FRAMING_CFG, LEN EN SpiByteWrite(0x11,0x05); // DATA32_THOLD SpiByteWrite(0x12,0x0E); // DATA64_THOLD SpiByteWrite(0x1B,0x55); // TX_OFFSET_LSB //SpiByteWrite(0x1B,0x30); // TX_OFFSET_LSB SpiByteWrite(0x1C,0x05); // TX_OFFSET_MSB SpiByteWrite(0x24,0x10); // PREAMBLE SpiByteWrite(0x24,0x33); // PREAMBLE SpiByteWrite(0x24,0x33); // PREAMBLE //SpiByteWrite(0x39,0x01); // ANALOG_CTRL_ADR, ALL SLOW (for GFSK) // timer0 setup TCCR0A = 0x00; TCCR0B = 0x05; // timer0 prescaler = 1024 TCNT0 = 0x00; // set timer0 to 0x00. // watchdog timer reset and enable wdt_reset(); wdt_enable(0x02); // reset after 60ms. while (1) // Loop forever { wdt_reset(); // watchdog timer reset RSSI = SpiByteRead(0x13); // RSSI read. (initialise) RSSI = SpiByteRead(0x13); // RSSI read. (RX signal strength) readPS2(data); // finishes on 0x1D. data[0] = PacketType; data[1] = RSSI & 0x1F; // Received power level. data[2] = 0x07; // transmit power level. (at both ends) data[3] = chan_num; // counter to keep track of chanel changes data[4] = TCNT0; // timer0 value to syncronise clocks. // RF transmit and log any errors: if(PacketTX_result = PacketTX(data)){ PWM_count_error++; PWM_count_consecutive_error++; } else{ if (PWM_count_consecutive_error > PWM_count_consecutive_error_max){ PWM_count_consecutive_error_max = PWM_count_consecutive_error; } PWM_count_consecutive_error = 0; } // once per second output transmission statistics. if (PWM_count++ == 49){ // 50 x 20ms devisions have passed. if (PWM_count_consecutive_error > PWM_count_consecutive_error_max){ PWM_count_consecutive_error_max = PWM_count_consecutive_error; } // 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_consecutive_error_max); UARTout(','); UARTout_dec(PWM_count_total/time_int); UARTout(' '); UARTout_dec(RSSI & 0x1F); UARTout(0x0A); PWM_count=0; PWM_count_error=0; PWM_count_consecutive_error = 0; PWM_count_consecutive_error_max=0; } // cycle between channels every 5 cycles. if (chan_num++ < 5){ SpiByteWrite(0x00,0x45); // CHANNEL //UARTout('A'); } else if ((chan_num >= 5) && (chan_num <= 10)){ SpiByteWrite(0x00,0x48); // CHANNEL //UARTout('B'); } else{ SpiByteWrite(0x00,0x60); // CHANNEL //UARTout('C'); } if (chan_num >= 15) { chan_num = 0;} // pause untill end of 20ms cycle. while (TCNT0 < 0x97){} TCNT0 = 0x00; //reset system clock. }}// 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 */ UBRR0H = (unsigned char)(bauddiv>>8); UBRR0L = (unsigned char)bauddiv; /* Enable receiver and transmitter */ UCSR0B = (1<<RXEN0)|(1<<TXEN0); /* Set frame format: 8data, 2stop bit */ UCSR0C = (1<<USBS0)|(3<<UCSZ00);}// send an 8bit number out of the UART.void UARTout(unsigned char data){ while (!(UCSR0A & (1<<UDRE0))) { continue; } UDR0 = 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;}// 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 ;}// transmit packet on RF module.unsigned char PacketTX(unsigned char *data){ // unsigned int tmp=0x00; SpiByteWrite(0x01,0x10); // TX_LENGTH SpiByteWrite(0x02,0x40); // TX_CTRL_ADR, TX_CLR while(TCNT0 < 0x90){ // retransmit until out of time. //SpiByteWrite(0x02,0x40); // TX_CTRL_ADR, TX_CLR. (do this!) SpiByteWrite(0x02,0xC0); // TX_CTRL_ADR, TX_CLR & TX_GO SpiByteWrite(0x20,data[0]); // 1st byte of TX buffer. (packet type.) SpiByteWrite(0x20,data[1]); SpiByteWrite(0x20,data[2]); SpiByteWrite(0x20,data[3]); SpiByteWrite(0x20,TCNT0); // timestamp SpiByteWrite(0x20,data[5]); SpiByteWrite(0x20,data[6]); SpiByteWrite(0x20,data[7]); SpiByteWrite(0x20,data[8]); SpiByteWrite(0x20,data[9]); SpiByteWrite(0x20,data[10]); SpiByteWrite(0x20,data[11]); SpiByteWrite(0x20,data[12]); SpiByteWrite(0x20,data[13]); SpiByteWrite(0x20,data[14]); SpiByteWrite(0x20,data[15]); tmp=0x00; //SpiByteWrite(0x02,0x80); // TX_CTRL_ADR, TX_GO. Start transmit while (!(tmp & (1<<1))){ //&& (TCNT0 < 0x90)){ // wait until write complete tmp = SpiByteRead(0x04); // TX_IRQ_STATUS, TXC IRQ } //UARTout(tmp); if (!(tmp & (1<<0))) { // check TXE (checking for ACK) if (!(SpiByteRead(0x04) & (1<<0))){ // check TXE again. //UARTout(1); return 0; // ACK came back. no TX errors. } } //else { // TX error occured. transmit again} // need to put a random length delay in here before repeat // to stop bandwidth hogging. //delay_us(100); } //UARTout(0); return 1;}void spi_Init_RF(){ // these are the SPI settings needed for the RF module. SPCR = _BV(SPE) | _BV(MSTR); // SPI enable bit and the master mode bit return;}// PSx controller communication function.// send a byte on the command line and receive one on the data line.// needs Attention pin to have gone low before called to activate controller.int gameByte(short int command){ short int i ; short int data = 0x00; // clear data variable to save setting low bits later. for(i=0;i<8;i++) { if(command & _BV(i)) {sbi(PORTB, PScommand);} // bit bang "command" out on PScommand wire. else cbi(PORTB, PScommand); cbi(PORTB, PSclock); // CLOCK LOW delay_us(0); // wait for output to stabilise if((PINB & _BV(PSdata))) sbi(data, i); // read PSdata pin and store //else cbi(data, i); sbi(PORTB, PSclock); // CLOCK HIGH } sbi(PORTB, PScommand);// **need to check there are no controller read repeats without this delay**// delay_us(10); // wait for ACK to pass. return(data);}void initialisePS2(void){ // this loop continues to put PSx controller into analouge mode untill the // controller responds with 0x73 in the 2nd byte. // (PS2 controller responds with 0x73 when in analouge mode.) // the status LEDs will continue to count upwards untill a controller is found. // if everything is working correctly this should happen on the first pass of // this loop but occasionally errors occur and a 2nd or 3rd itteration happen. unsigned char chk_ana = 0, cnt = 0; while(chk_ana != 0x73){ // put controller in config mode sbi(PORTB, PScommand); sbi(PORTB, PSclock); cbi(PORTE, PSattention); gameByte(0x01); gameByte(0x43); gameByte(0x00); gameByte(0x01); gameByte(0x00); sbi(PORTB, PScommand); sbi(PORTE, PSattention); delay_us(1); // put controller in analouge mode sbi(PORTB, PScommand); sbi(PORTB, PSclock); cbi(PORTE, PSattention); gameByte(0x01); gameByte(0x44); gameByte(0x00); gameByte(0x01); gameByte(0x03); gameByte(0x00); gameByte(0x00); gameByte(0x00); gameByte(0x00); sbi(PORTB, PScommand); sbi(PORTE, PSattention); delay_us(1); // exit config mode sbi(PORTB, PScommand); sbi(PORTB, PSclock); cbi(PORTE, PSattention); gameByte(0x01); gameByte(0x43); gameByte(0x00); gameByte(0x00); gameByte(0x5A); gameByte(0x5A); gameByte(0x5A); gameByte(0x5A); gameByte(0x5A); sbi(PORTB, PScommand); sbi(PORTE, PSattention); delay_us(1); // poll controller and check in analouge mode. sbi(PORTB, PScommand); sbi(PORTB, PSclock); cbi(PORTE, PSattention); gameByte(0x01); chk_ana = gameByte(0x42); // the 2nd byte to be returned from the controller should = 0x73 for "red" analouge controller. gameByte(0x00); gameByte(0x00); gameByte(0x00); gameByte(0x00); gameByte(0x00); gameByte(0x00); gameByte(0x00); sbi(PORTB, PScommand); sbi(PORTE, PSattention); delay_us(1); }}void readPS2(unsigned char *data){ unsigned char verify = 0; unsigned char chk = 0; while ((verify !=0x73)){ // repeat this section untill it works sbi(PORTB, PScommand); sbi(PORTB, PSclock); cbi(PORTE, PSattention); gameByte(0x01); verify = gameByte(0x42); gameByte(0x00); data[6] = gameByte(0x00); data[7] = gameByte(0x00); data[8] = gameByte(0x00); data[9] = gameByte(0x00); data[10] = gameByte(0x00); data[11] = gameByte(0x00); data[12] = chk++; // keep count of number of repeats sbi(PORTB, PScommand); sbi(PORTE, PSattention); } 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 < 10; i++) {delay_us(100);} return;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -