Share Pastebin
Guest
Public paste!

RabidCicada

By: a guest | Apr 16th, 2009 | Syntax: None | Size: 8.10 KB | Hits: 162 | Expires: Never
Copy text to clipboard
  1. // Servo.c
  2. // RabidCicada
  3. // RabidCicada@gmail.com
  4.  
  5.  
  6. #define F_CPU 14745600
  7.  
  8. #include <stdio.h>
  9. #include <math.h>
  10.  
  11. #include <avr/io.h>
  12. #include <avr/interrupt.h>
  13. #include <avr/pgmspace.h>
  14. #include <inttypes.h>
  15.  
  16. #include "../libnerdkits/delay.h"
  17. #include "../libnerdkits/lcd.h"
  18.  
  19. uint8_t timer0_clkslct;
  20. uint8_t timer1_clkslct;
  21.  
  22. uint16_t step;
  23. uint16_t servo_pos_time_period;
  24. uint16_t ADC_val;
  25.  
  26.  //INitialize the Analog to Digital Converter
  27.  void adc_init(){
  28.  
  29.         //DIDR0=0;
  30.        
  31.         //Configure ADC to use external reference voltage (5v) and to use ADC0
  32.         ADMUX = 0;
  33.        
  34.         //ADCSRA |= (1<<ADEN);
  35.        
  36.         //Enable ADC and configure the prescale to be 1/128
  37.         //--witha clock of 14745600 this means it will be 115.2khz
  38.         ADCSRB = 0;
  39.         ADCSRA =(1<<ADEN) | (1<<ADPS2) | (1<<ADPS1) | (1<<ADPS0) | (1<<ADATE);
  40.  
  41.        
  42.         //Kick off the ADC Initializing conversion
  43.         //This causes the hardware logic initialization
  44.         //which takes longer then normal conversions.
  45.         ADCSRA |= (1<<ADSC);
  46.  
  47.  }
  48.  
  49.  //Perform a read of the Analog to Digital Converter
  50.  //Assuming a conversion has already been initiated
  51.  //Reads 10 bits worth of unique values(1024)
  52.  uint16_t adc_read(){
  53.  
  54.         //Spin in circles waiting for a conversion to finish (ADCSC=0)
  55.         //while( ADCSRA & (1<<ADSC) ){
  56.        
  57.         //}
  58.  
  59.         //This actually reads from the result registers of the ADC
  60.         uint16_t result = ADCL;
  61.         uint16_t temp = ADCH;
  62.         result = result + (temp<<8);
  63.        
  64.         //Kickoff the next conversion
  65.         //ADCSRA |= (1<<ADSC);
  66.        
  67.         return result;
  68.        
  69.  }
  70.  
  71.  //Timer initialization of Timer 1
  72.  //Used to control length of control pulse for servo
  73.  //Need the smallest timeslice possible(resolution)
  74.  //for the most accuracy
  75.  //Configure Timer/Counter1 to run at prescale(8)(14745600/8) 1843200Hz
  76.  //Did this because we want smallest resolution possible that fits
  77.  //in 2bytes(16bits)
  78.  void timer1_init(){
  79.  
  80.         //Timer Counter Control Register 1 (B)
  81.         TCCR1B = (1<<WGM12);
  82.                 //Parially set mode to Clear Timer on Counter match (WGM13,12)
  83.                 //and incidentally stop timer (0->bits CS1, CS2, and CS3)
  84.        
  85.         //Timer Counter Control Register 1 (A)
  86.         TCCR1A = 0;     //Finish setting mode to Clear Timer on Counter match (0-> bits WGM11, WGM10)
  87.                                 //Sets compare output match mode for both channels(a,b) to not use normal ports
  88.                                 //as counter outputs.(disconnected)
  89.                                 //In total, what this means is that the timer will count up to it's
  90.                                 //limit(OCR1A and OCR1B) then reset to 0.      
  91.        
  92.        
  93.         timer1_clkslct = ((0<<CS12) | (1<<CS11) | (0<<CS10));
  94.                                 //Will be used in timer1_start to set prescaler to 8
  95.        
  96.  }
  97.  
  98.   //Timer Initialization of Timer 0
  99.   //Sets up the timer used for maintaining the pulse window that the
  100.   //hobby servo likes (10-20 ms window) We have chosen 15ms
  101.   void timer0_init(){
  102.  
  103.         //Configure Timer/Counter0 to run at prescale(1024)(14745600/256) 14400Hz
  104.         //Arbitrarily chose a prescale that had a large timeslice (large resolution)
  105.         //So that the number of counter cycles in our window would fit
  106.         //in 8 bits of resolution
  107.        
  108.         //Due to the way the timer operates the timer prescale will be set
  109.         //in start_timer0 where the clock select is set to the 1024 prescale
  110.        
  111.         //Timer Counter Control Register 0 (B)
  112.         TCCR0B = 0;
  113.                 //Parially set mode to Clear Timer on Counter match (WGM01,00)
  114.                 //and incidentally stop timer (0->bits CS1, CS2, and CS3)
  115.                 //This allows us to make updates without worrying about the timer.
  116.                
  117.         timer0_clkslct = ((1<<CS02) | (0<<CS01) | (1<<CS00));
  118.                 //Will be used in timer0_start to set prescaler to 1024
  119.        
  120.         //Timer Counter Control Register 0 (A)
  121.         TCCR0A = (1<<WGM01);    //Finish setting mode to Clear Timer on Counter match (0-> bits WGM11, WGM10)
  122.                                 //Sets compare output match mode for both channels(a,b) to not use normal ports
  123.                                 //as counter outputs.(disconnected)
  124.                                 //In total, what this means is that the timer will count up to it's
  125.                                 //limit(OCR1A and OCR1B) then reset to 0.      
  126.        
  127.         //Set the compare register A to the timer fire limit
  128.         //OCR0A = 216; // - number of cycles in 15ms at 1024 prescale
  129.         OCR0A = 250;
  130.         //OCR0A = 288; // - number of cycles in 20ms at 1024 prescale
  131.  
  132.         //Set the Interrupt enable flag for the compare reg A (OCR0A)
  133.         TIMSK0 = (1<<OCIE0A);  
  134.        
  135.  }
  136.  
  137.  void timer0_start(){
  138.         //Timer Counter Control Register 0 (B)
  139.         TCCR0B |= timer0_clkslct;
  140.                                 //Sets prescaler to 1024
  141.  }
  142.  
  143.   void timer1_start(){
  144.         //Timer Counter Control Register 1 (B)
  145.         TCCR1B |= timer1_clkslct;
  146.                                 //Sets prescaler to 8
  147.  }
  148.  
  149.  void timer0_stop(){
  150.         TCCR0B &= ~((1<<CS12) | (1<<CS11) | (1<<CS10));
  151.  }
  152.  
  153.  void timer1_stop(){
  154.         TCCR1B &= ~((1<<CS12) | (1<<CS11) | (1<<CS10));
  155.  }
  156.  
  157.  
  158.  void portio_init(){
  159.         //Enable output on pin 4 of port C
  160.         //Inputs on all others
  161.         DDRC = (1<<DDC4);
  162.        
  163.         //PORTC = (0<<PORTC0);
  164.  
  165.  }
  166.  
  167.  
  168.  //It is critical that this entire routine finish in under the servo
  169.  //actuator window so that it can does not get clipped.
  170.  void poll_adc_and_actuate(){
  171.         uint16_t pot_value = adc_read();
  172.         //ADC_val += 1;//pot_value;
  173.         ADC_val = pot_value;
  174.         //servo_pos +=1;//
  175.         servo_pos_time_period = 2037 + (uint16_t) (pot_value * 1.45);
  176.        
  177.         //Set Timer upper bound for length of pulse to actuate servo
  178.         //The potentiometer only measures 10 bits worth of distinct
  179.         //values(1024 exactly).  Because of this we must scale the potentiometer value
  180.         //by 1.45 to cover the full range of the number of cycles needed to span
  181.         //.8ms below(1482)
  182.        
  183.         //Precalculated values based on number of cycles in a given timeframe...
  184.         //Base number of cycles 2037 (1.1 ms) + difference(0-1482 cycles)3519(range of .8ms)
  185.         //This gives actuation signal of 1.1-1.9ms
  186.         OCR1A = servo_pos_time_period;
  187.         TCNT1 = 0;//Clear timer to 0--will count up to limit (OCR1A)   
  188.        
  189.         PORTC|=(1<<PORTC4);     //Set control pulse for servo high     
  190.         timer1_start();
  191.        
  192.         //Wait for timer to be over
  193.         //Check the timer output compare pin to see if a match has occured.
  194.         //OCF1A is set when a compare match occured(timer hit our limit)
  195.         //Spin in circles while timer hasn't hit limit.(1.1ms-1.9ms)
  196.         while(!(TIFR1 & (1<<OCF1A))){
  197.         }
  198.        
  199.         timer1_stop(); 
  200.         TIFR1|=(1<<OCF1A);//clear compare match flag.
  201.        
  202.         //Clear output bit
  203.         PORTC&= ~(1<<PORTC4); //Set control pulse for servo low
  204.        
  205.        
  206.  
  207.  }
  208.  
  209.  //Interrupts are automatically disabled in this  
  210.  ISR(TIMER0_COMPA_vect){
  211.         poll_adc_and_actuate();
  212.  }
  213.  
  214.  
  215. //The plan is to use timer based calls for controlling the servo
  216. //The servo expects a pulse every 15-20 milliseconds
  217. //Every time poll_adc_and_actuate is called it will
  218. //kick off the timer for a new poll_adc_and_actuate call,
  219. //do a read of the adc, actuate the servo, then spin in an
  220. //infinite loop waiting for the timer to fire again
  221.  
  222.  int main(){
  223.         int cnt=0;
  224.         step=0;
  225.         ADC_val=0;
  226.         servo_pos_time_period=0;
  227.  
  228.         // fire up the LCD
  229.         lcd_init();
  230.         FILE lcd_stream = FDEV_SETUP_STREAM(lcd_putchar, 0, _FDEV_SETUP_WRITE);
  231.         lcd_home();
  232.        
  233.         // print message to screen
  234.         lcd_write_string(PSTR("  Initializing System    "));
  235.         lcd_line_two();
  236.         lcd_write_string(PSTR("                         "));
  237.        
  238.         //Initialize ADC
  239.         adc_init();
  240.        
  241.         //Initialize ports for use
  242.         portio_init();
  243.        
  244.         //Initialize the timer that repeatedly executes the
  245.         //poll_adc_and_actuate() function
  246.         //This one is our "window" timer for the servo pulses
  247.         timer0_init();
  248.        
  249.         //Initialize the timer that controls the length of the pulse
  250.         //for each servo actuation
  251.         timer1_init();
  252.        
  253.         //Enable Interrupts
  254.         sei();
  255.        
  256.         //Delay for visual confirmation
  257.         delay_ms(3000);
  258.         // print message to screen
  259.         lcd_clear_and_home();
  260.         lcd_write_string(PSTR(" Entering Actuator Loop  "));
  261.         lcd_line_two();
  262.         lcd_write_string(PSTR("                         "));
  263.         delay_ms(3000);
  264.        
  265.         //Start timer0...This starts our 15ms window loop
  266.         timer0_start();
  267.        
  268.         //Spin in infinite loop letting interrupt for poll_adc_and_actuate trigger
  269.         while(1){
  270.                 //ADC_val = adc_read();
  271.                 lcd_home();
  272.                 lcd_write_int16(cnt);
  273.                 lcd_write_string( PSTR(" ADC Value:   "));
  274.                 lcd_write_int16(ADC_val);
  275.                 lcd_write_string(PSTR(" of 1024"));
  276.                 lcd_line_two();
  277.                 lcd_write_string( PSTR(" Servo position: "));
  278.                 lcd_write_int16(servo_pos_time_period);
  279.                 cnt=!cnt;
  280.                 //delay_ms(1000);
  281.         }
  282.        
  283.         //poll_adc_and_actuate();
  284.        
  285.  
  286.  return 0;
  287.  }