complete
This commit is contained in:
parent
17f4d96a72
commit
b74b63cd3b
183
main.c
183
main.c
|
|
@ -6,123 +6,132 @@
|
|||
#pragma config FOSC = INTRCIO // 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
|
||||
static uint16_t off_ticks; // Retains value between interrupts
|
||||
static uint16_t timer;
|
||||
if (pulse_state == 0) {
|
||||
// Calculate pulse parameters
|
||||
uint16_t on_ticks = 75 + ((uint16_t)servo_pos * 237) / 255; // Map to 0.5ms-2.5ms
|
||||
off_ticks = 2500 - on_ticks; // 2500 ticks = 20ms
|
||||
RC5 = 1; // Start pulse
|
||||
timer = 65535 - on_ticks;
|
||||
TMR1L = (unsigned char)(timer & 0xFF);
|
||||
TMR1H = (unsigned char)(timer >> 8);
|
||||
pulse_state = 1;
|
||||
} else {
|
||||
RC5 = 0; // End pulse
|
||||
timer = 65535 - off_ticks;
|
||||
TMR1L = (unsigned char)(timer & 0xFF);
|
||||
TMR1H = (unsigned char)(timer >> 8);
|
||||
pulse_state = 0;
|
||||
}
|
||||
}
|
||||
INTCONbits.GIE = 1;
|
||||
}
|
||||
|
||||
void setup() {
|
||||
// Set RA0 as analog input, rest of PORTA as outputs
|
||||
TRISA = 0x01;
|
||||
|
||||
// Set PORTC as outputs except RC5 which will toggle PWM
|
||||
TRISC = 0x00;
|
||||
// Set RA1 as digital input
|
||||
ANSEL = 0;
|
||||
CMCON = 0x07;
|
||||
TRISC = 0x00;
|
||||
TRISAbits.TRISA1 = 1;
|
||||
WPUAbits.WPUA1 = 1;
|
||||
OPTION_REGbits.nRAPU = 0;
|
||||
|
||||
// Enable analog input on RA0
|
||||
ANSEL = 0x01;
|
||||
// Configure Timer1
|
||||
T1CON = 0b00110000; // Timer1: prescaler 1:8, internal clock, OFF
|
||||
TMR1H = (65536 - 188) >> 8; // Initial 1.5ms pulse (high byte)
|
||||
TMR1L = (65536 - 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
|
||||
ADCON0 = 0b00000101; // Channel 0, ADC enabled
|
||||
ADCON1 = 0b10001110; // Right justified, Vdd/Vss reference
|
||||
|
||||
// Timer0 initialization
|
||||
OPTION_REG = 0b11110111; // Prescale = 256, Internal clock source
|
||||
TMR0 = 0; // Clear timer register
|
||||
}
|
||||
|
||||
#define SERVO_MIN_PULSE_US 750 // Minimum pulse width (approximately 0°)
|
||||
#define SERVO_MAX_PULSE_US 2250 // Maximum pulse width (approximately 180°)
|
||||
void delay_us(uint16_t us) {
|
||||
uint16_t i;
|
||||
for(i = 0; i < us; i++) {
|
||||
_nop(); // Insert assembly-level no-operation instruction
|
||||
}
|
||||
}
|
||||
|
||||
void generate_pwm(uint16_t pulse_width_us) {
|
||||
RC5 = 1; // Start high
|
||||
delay_us(pulse_width_us); // Keep high for desired pulse width
|
||||
RC5 = 0; // Go low until next pulse
|
||||
delay_us(20 - (pulse_width_us / 1000)); // Wait remaining 20ms period
|
||||
TRISAbits.TRISA2 = 0;
|
||||
ANSELbits.ANS2 = 1;
|
||||
ADCON0 = 0b00001001;
|
||||
ADCON1 = 0;
|
||||
}
|
||||
|
||||
#define bool uint8_t
|
||||
#define false 0
|
||||
#define true 1
|
||||
volatile bool button_pressed = false;
|
||||
uint8_t current_mode = 0;
|
||||
|
||||
void UpdateLeds()
|
||||
{
|
||||
RC0 = current_mode == 0;
|
||||
RC1 = current_mode == 1;
|
||||
RC2 = current_mode == 2;
|
||||
}
|
||||
|
||||
void check_button() {
|
||||
if (!RA1 && !button_pressed) { // Detect falling edge of button press
|
||||
button_pressed = true;
|
||||
__delay_ms(50); // Basic debounce delay
|
||||
current_mode++;
|
||||
if (current_mode > 2) current_mode = 0; // Cycle through modes
|
||||
|
||||
// Update LEDs based on mode
|
||||
switch(current_mode) {
|
||||
case 0:
|
||||
RC0 = 1; RC1 = 0; RC2 = 0; break; // Manual mode LED
|
||||
case 1:
|
||||
RC0 = 0; RC1 = 1; RC2 = 0; break; // Center mode LED
|
||||
case 2:
|
||||
RC0 = 0; RC1 = 0; RC2 = 1; break; // Oscillator mode LED
|
||||
if (!RA1 && current_button_status) {
|
||||
__delay_ms(20);
|
||||
if(!RA1) {
|
||||
current_mode = (current_mode + 1) % 3; // Cycle through modes
|
||||
UpdateLeds();
|
||||
}
|
||||
}
|
||||
if (RA1) {
|
||||
button_pressed = false; // Release button
|
||||
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--;
|
||||
}
|
||||
}
|
||||
|
||||
void manual_mode() {
|
||||
uint16_t adc_value = (ADRESH << 8) | ADRESL; // Get ADC value
|
||||
uint16_t pulse_width = (SERVO_MIN_PULSE_US + (adc_value * (SERVO_MAX_PULSE_US - SERVO_MIN_PULSE_US) / 1023));
|
||||
generate_pwm(pulse_width);
|
||||
}
|
||||
|
||||
void center_mode() {
|
||||
generate_pwm((SERVO_MIN_PULSE_US + SERVO_MAX_PULSE_US) / 2);
|
||||
}
|
||||
|
||||
int8_t direction = 1; // Direction of movement
|
||||
uint8_t osc_duty = 75; // Start at min duty cycle
|
||||
|
||||
uint16_t osc_pulse_width = SERVO_MIN_PULSE_US;
|
||||
bool increasing = true;
|
||||
|
||||
void oscillator_mode() {
|
||||
generate_pwm(osc_pulse_width);
|
||||
|
||||
if (increasing) {
|
||||
osc_pulse_width += 10; // Gradual increment
|
||||
if (osc_pulse_width >= SERVO_MAX_PULSE_US) {
|
||||
increasing = false;
|
||||
}
|
||||
} else {
|
||||
osc_pulse_width -= 10; // Gradual decrement
|
||||
if (osc_pulse_width <= SERVO_MIN_PULSE_US) {
|
||||
increasing = true;
|
||||
}
|
||||
}
|
||||
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
|
||||
|
||||
check_button(); // Check for button presses
|
||||
switch(current_mode) {
|
||||
case 0:
|
||||
manual_mode();
|
||||
case 0:
|
||||
smooth_servo(read_adc());
|
||||
__delay_us(100);
|
||||
break;
|
||||
case 1:
|
||||
center_mode();
|
||||
//target_pos = 511;
|
||||
smooth_servo(127);
|
||||
__delay_us(100);
|
||||
break;
|
||||
case 2:
|
||||
oscillator_mode();
|
||||
if(isincreasing) {
|
||||
smooth_servo(servo_pos + 1);
|
||||
__delay_ms(10);
|
||||
if(servo_pos + 1 >= 254) isincreasing = 0;
|
||||
} else
|
||||
{
|
||||
smooth_servo(servo_pos - 1);
|
||||
__delay_ms(10);
|
||||
if(servo_pos - 1 <= 0) isincreasing = 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// Perform ADC conversion
|
||||
GO_nDONE = 1; // Start ADC conversion
|
||||
while(GO_nDONE); // Wait for completion
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user