Advertisement
phillip_bourdon234

Servo_Driver.c

Feb 28th, 2021
723
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 4.40 KB | None | 0 0
  1. #include "stm32f10x.h"
  2. #include "system_stm32f10x.h"
  3. #include "GPIO_Driver.h"
  4. #include "Servo_Driver.h"
  5.  
  6. void servo_init(uint8_t timer, uint8_t channel)
  7. {
  8.     GPIO_TYPE PWM_Output_Servo;
  9.     TIM_TypeDef *timerPort = TIM2;
  10.     uint8_t channelOffset = 0;
  11.    
  12.     PWM_Output_Servo.mode = OUTPUT;
  13.     PWM_Output_Servo.mode_type = OUTPUT_ALT_FUNCTION;
  14.     PWM_Output_Servo.speed = SPEED_50MHZ;
  15.    
  16.     switch(timer)
  17.     {
  18.         case 2:
  19.             timerPort = TIM2;
  20.             RCC->APB1ENR |= RCC_APB1ENR_TIM2EN;
  21.            
  22.             if(channel == 1)
  23.             {
  24.                     PWM_Output_Servo.port = PORTA;
  25.                     PWM_Output_Servo.pin = 15;
  26.             }
  27.             else if(channel == 2)
  28.             {
  29.                     PWM_Output_Servo.port = PORTA;
  30.                     PWM_Output_Servo.pin = 1;
  31.             }
  32.             else if(channel == 3)
  33.             {
  34.                 PWM_Output_Servo.port = PORTA;
  35.                 PWM_Output_Servo.pin = 2;
  36.             }
  37.             else
  38.             {
  39.                 PWM_Output_Servo.port = PORTA;
  40.                 PWM_Output_Servo.pin = 3;
  41.             }
  42.            
  43.         break;
  44.        
  45.         case 3:
  46.             timerPort = TIM3;
  47.             RCC->APB1ENR |= RCC_APB1ENR_TIM3EN;
  48.            
  49.             if(channel == 1)
  50.             {
  51.                     PWM_Output_Servo.port = PORTA;
  52.                     PWM_Output_Servo.pin = 6;
  53.             }
  54.             else if(channel == 2)
  55.             {
  56.                     PWM_Output_Servo.port = PORTA;
  57.                     PWM_Output_Servo.pin = 7;
  58.             }
  59.             else if(channel == 3)
  60.             {
  61.                 PWM_Output_Servo.port = PORTB;
  62.                 PWM_Output_Servo.pin = 0;
  63.             }
  64.             else
  65.             {
  66.                 PWM_Output_Servo.port = PORTB;
  67.                 PWM_Output_Servo.pin = 1;
  68.             }
  69.            
  70.         break;
  71.  
  72.         case 4:
  73.             timerPort = TIM4;
  74.             RCC->APB1ENR |= RCC_APB1ENR_TIM4EN;
  75.            
  76.             if(channel == 1)
  77.             {
  78.                     PWM_Output_Servo.port = PORTB;
  79.                     PWM_Output_Servo.pin = 6;
  80.             }
  81.             else if(channel == 2)
  82.             {
  83.                     PWM_Output_Servo.port = PORTB;
  84.                     PWM_Output_Servo.pin = 7;
  85.             }
  86.             else if(channel == 3)
  87.             {
  88.                 PWM_Output_Servo.port = PORTB;
  89.                 PWM_Output_Servo.pin = 8;
  90.             }
  91.             else
  92.             {
  93.                 PWM_Output_Servo.port = PORTB;
  94.                 PWM_Output_Servo.pin = 9;
  95.             }
  96.         break;
  97.     }
  98.    
  99.     switch(channel)
  100.     {
  101.         case 1:
  102.             channelOffset = 0;
  103.             //enable PWM mode 1 and the preloader for channel 4
  104.             timerPort->CCMR1 |= TIM_CCMR1_OC1M_1 | TIM_CCMR1_OC1M_2 | TIM_CCMR1_OC1PE;
  105.         break;
  106.        
  107.         case 2:
  108.             channelOffset = 4;
  109.             //enable PWM mode 1 and the preloader for channel 4
  110.             timerPort->CCMR1 |= TIM_CCMR1_OC2M_1 | TIM_CCMR1_OC2M_2 | TIM_CCMR1_OC2PE;
  111.         break;
  112.    
  113.         case 3:
  114.             channelOffset = 8;
  115.             //enable PWM mode 1 and the preloader for channel 4
  116.             timerPort->CCMR2 |= TIM_CCMR2_OC3M_1 | TIM_CCMR2_OC3M_2 | TIM_CCMR2_OC3PE;
  117.         break;
  118.  
  119.         case 4:
  120.             channelOffset = 12;
  121.             //enable PWM mode 1 and the preloader for channel 4
  122.             timerPort->CCMR2 |= TIM_CCMR2_OC4M_1 | TIM_CCMR2_OC4M_2 | TIM_CCMR2_OC4PE;
  123.         break; 
  124.     }
  125.        
  126.     init_gpio(PWM_Output_Servo);
  127.    
  128.     //init AFIO clock
  129.     RCC->APB2ENR |= RCC_APB2ENR_AFIOEN;
  130.    
  131.     //enable capture/compare for specified channel
  132.     timerPort->CCER |= (1<<channelOffset);
  133.    
  134.     //init the ARR
  135.     timerPort->CR1 |= TIM_CR1_ARPE;
  136.  
  137.    
  138.     //enable duty cycle
  139.     timerPort->PSC = 1440;
  140.     timerPort->ARR = 1000; // 50Hz for servo control
  141.    
  142.     //enable the update generation and turn timer on
  143.     timerPort->EGR |= TIM_EGR_UG;
  144.     timerPort->CR1 |= TIM_CR1_CEN;
  145. }
  146.  
  147. void servo_writeMicroseconds(int microseconds, uint8_t timer, uint8_t channel)
  148. {
  149.     uint16_t dutyCycle = 0;
  150.     TIM_TypeDef *timerPort = TIM3;
  151.    
  152.     switch(timer)
  153.     {
  154.         case 2:
  155.             timerPort = TIM2;
  156.         break;
  157.         case 3:
  158.             timerPort = TIM3;
  159.         break;
  160.         case 4:
  161.             timerPort = TIM4;
  162.         break;
  163.     }
  164.    
  165.     //servos have a range of 180 degrees, and the duty cycle in ms from 0-180 degrees equals
  166.     //1ms to 2ms. Because of this, I wanted the input to be of longer range, so I have the user
  167.     //input the time they want in microseconds from 1000-2000. The equation below sets
  168.     //the dutyCycle variable to a proportional value from microseconds to a value that can be
  169.     //given to the timers CCRx register. for example, if the user wants to move the servo to 0
  170.     //degrees, the user passes in 1000, this will be divided by 20000.0 to equal 0.05. 0.05 will
  171.     //be multiplied by timerPort->ARR (which is 1000) to equal 50. 50 is now a number that can
  172.     //be set to the timers CCRx register to give a duty cycle of 5% (1ms pulse over a period of 20ms(50hz))
  173.     dutyCycle = (uint16_t)((microseconds/20000.0)*(timerPort->ARR));
  174.    
  175.     switch(channel)
  176.     {
  177.         case 1:
  178.             timerPort->CCR1 = dutyCycle;
  179.             break;
  180.         case 2:
  181.             timerPort->CCR2 = dutyCycle;
  182.             break;
  183.         case 3:
  184.             timerPort->CCR3 = dutyCycle;
  185.             break;
  186.         case 4:
  187.             timerPort->CCR4 = dutyCycle;
  188.             break;
  189.     }      
  190. }
  191.  
  192.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement