#include #include #include // CONFIGURATION #pragma config FOSC = INTRCCLK // Internal oscillator #pragma config WDTE = OFF // Watchdog timer off #pragma config PWRTE = ON // Power-up timer enabled #pragma config MCLRE = OFF #define _XTAL_FREQ 4000000 volatile uint8_t current_button_status = 1; volatile uint8_t current_mode = 0; volatile uint8_t servo_pos = 127; // 0=1ms, 255=2ms volatile uint8_t pulse_state = 0; // 0=start pulse, 1=end pulse volatile uint8_t isincreasing = 0; void __interrupt() ISR(void) { INTCONbits.GIE = 0; if (PIR1bits.TMR1IF) { PIR1bits.TMR1IF = 0; // Clear interrupt flag T1CONbits.TMR1ON = 0; // Calculate pulse parameters // 3000 ticks = 20ms uint8_t postoms= (uint16_t)(servo_pos*126) / 255; uint16_t on_ticks = 16 + postoms * 2; uint16_t off_ticks = 3000 - on_ticks; if (pulse_state == 0) { RC5 = 1; // Start pulse TMR1L = (0xFFFF - on_ticks)& 0xFF;//on_ticks; TMR1H = (0xFFFF - on_ticks) >> 8; pulse_state = 1; } else { RC5 = 0; // End pulse TMR1L = (0xFFFF - off_ticks) & 0xFF; TMR1H = (0xFFFF - off_ticks) >> 8; pulse_state = 0; } T1CONbits.TMR1ON = 1; } INTCONbits.GIE = 1; } void setup() { // Set RA1 as digital input ANSEL = 0; CMCON = 0x07; TRISC = 0x00; TRISAbits.TRISA1 = 1; WPUAbits.WPUA1 = 1; OPTION_REGbits.nRAPU = 0; // Configure Timer1 T1CON = 0b00110000; // Timer1: prescaler 1:8, internal clock, OFF TMR1H = (65535 - 188) >> 8; // Initial 1.5ms pulse (high byte) TMR1L = (65535 - 188) & 0xFF; // Initial 1.5ms pulse (low byte) PIR1bits.TMR1IF = 0; // Clear interrupt flag PIE1bits.TMR1IE = 1; // Enable Timer1 interrupt INTCONbits.PEIE = 1; // Enable peripheral interrupts INTCONbits.GIE = 1; // Enable global interrupts T1CONbits.TMR1ON = 1; // Configure ADC TRISAbits.TRISA2 = 1; ANSELbits.ANS2 = 1; ADCON0 = 0b00001001; ADCON1 = 0; } #define bool uint8_t #define false 0 #define true 1 void UpdateLeds() { RC0 = current_mode == 0; RC1 = current_mode == 1; RC2 = current_mode == 2; } void check_button() { if (!RA1 && current_button_status) { __delay_ms(20); if(!RA1) { current_mode = (current_mode + 1) % 3; // Cycle through modes UpdateLeds(); } } current_button_status = RA1; } void smooth_servo(uint8_t target_pos) { // Move servo_pos towards target_pos gradually if (servo_pos < target_pos) { servo_pos++; } else if (servo_pos > target_pos) { servo_pos--; } } inline uint8_t read_adc() { ADCON0bits.GO = 1; while(ADCON0bits.GO_DONE); return ADRESH; } void main() { setup(); // Initialize peripherals UpdateLeds(); while(1) { check_button(); // Check for button presses switch(current_mode) { case 0: smooth_servo(read_adc()); __delay_us(100); break; case 1: smooth_servo(94); __delay_us(100); break; case 2: if(isincreasing) { smooth_servo(servo_pos + 1); __delay_ms(5); if(servo_pos + 1 >= 254) isincreasing = 0; } else { smooth_servo(servo_pos - 1); __delay_ms(5); if(servo_pos - 1 <= 0) isincreasing = 1; } break; } } }