Nerdegutta's logo

nerdegutta.no

PIC16F628A - Move a servo motor 45 degrees

29.12.24

Embedded

These lines of code moves a servomotor 45 degrees and back. We're not using any timers, but make the PWM signal manual with a for-loop.

// INCLUDE LIBRARIES
#include < xc.h >

// CONFIGURATION BITS
#pragma config FOSC     = XT        // Oscillator Selection bits (XT oscillator: Crystal/resonator on RA6/OSC2/CLKOUT and RA7/OSC1/CLKIN)
#pragma config WDTE     = OFF   // Watchdog Timer Enable bit (WDT enabled)
#pragma config PWRTE    = OFF   // Power-up Timer Enable bit (PWRT disabled)
#pragma config MCLRE    = ON    // RA5/MCLR/VPP Pin Function Select bit (RA5/MCLR/VPP pin function is MCLR)
#pragma config BOREN    = OFF   // Brown-out Detect Enable bit (BOD enabled)
#pragma config LVP      = OFF   // Low-Voltage Programming Enable bit (RB4/PGM pin has PGM function, low-voltage programming enabled)
#pragma config CPD      = OFF   // Data EE Memory Code Protection bit (Data memory code protection off)
#pragma config CP       = OFF   // Flash Program Memory Code Protection bit (Code protection off)

// DEFINITIONS
#define _XTAL_FREQ 4000000
#define servo PORTBbits.RB0

// VARIABLES

// PROTOTYPES

// FUNCTIONS
// Servo Initialization function
void Servo_Init(void) {
    servo = 0; // Ensure the pin starts low
}

// Function to create a precise delay in microseconds
void Delay_us(unsigned int us) {
    while (us--) {
        __delay_us(1);
    }
}

// Function to set servo angle
void Set_Servo_Angle(unsigned char angle) {
     unsigned int pulse_width;

    // Calculate pulse width (1ms to 2ms for 0 to 180 degrees)    
    pulse_width = (unsigned int)((angle * 20 / 180) + 5);

    // Generate PWM signal manually
    for (unsigned char i = 0; i < 50; i++) {    // 50 cycles for 20ms period
        servo = 1;                              // Set pin high
        Delay_us(pulse_width * 10);             // Delay for high period
        servo = 0;                              // Set pin low
        Delay_us((20 - pulse_width) * 100);     // Delay for low period
    }
}

void main() {
    TRISBbits.TRISB0 = 0;       // Configure PORTB.RB0 as output
    Servo_Init();               // Initialize Servo control

    while (1) { 
        Set_Servo_Angle(0);     // Set servo to 0 degrees
        __delay_ms(500);        // Wait for 0.5 second

        Set_Servo_Angle(45);    // Set servo to 45 degrees
        __delay_ms(500);        // Wait for 0.5 second
    }
}