pastebin - collaborative debugging

pastebin is a collaborative debugging tool allowing you to share and modify code snippets while chatting on IRC, IM or a message board.

This site is developed to XHTML and CSS2 W3C standards. If you see this paragraph, your browser does not support those standards and you need to upgrade. Visit WaSP for a variety of options.

pastebin - collaborative debugging tool View Help


Posted by RabidCicada on Thu 16 Apr 12:05
report abuse | download | new post

  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.  }

Submit a correction or amendment below (click here to make a fresh posting)
After submitting an amendment, you'll be able to view the differences between the old and new posts easily.

Syntax highlighting:

To highlight particular lines, prefix each line with @@


Remember me so that I can delete my post