0% found this document useful (0 votes)
3 views

Solar Tracker Code

The document contains C code for a solar tracker application using a PIC16F877A microcontroller. It utilizes four LDR sensors for horizontal and vertical tracking, two servomotors controlled via PWM, and an LCD display for output. The code initializes ports, ADC, PWM, and continuously reads sensor data to adjust the servomotors accordingly while displaying the sensor readings on the LCD.

Uploaded by

Dores Tamdem
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
3 views

Solar Tracker Code

The document contains C code for a solar tracker application using a PIC16F877A microcontroller. It utilizes four LDR sensors for horizontal and vertical tracking, two servomotors controlled via PWM, and an LCD display for output. The code initializes ports, ADC, PWM, and continuously reads sensor data to adjust the servomotors accordingly while displaying the sensor readings on the LCD.

Uploaded by

Dores Tamdem
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 3

/*

* solar_tracker.c
* MPLAB X / XC8 code pour PIC16F877A
* Application: Solar Tracker à 2 axes (horizontal + vertical)
* Capteurs: 4 LDR en pont diviseur (canaux AN0..AN3)
* Actionneurs: 2 servomoteurs via PWM (CCP1, CCP2)
* Afficheur: LCD HD44780 16x2 (mode 4 bits)
*/

#include <xc.h>

// Configuration bits
#pragma config FOSC = HS // Oscillateur externe haute vitesse
#pragma config WDTE = OFF // Watchdog Timer désactivé
#pragma config PWRTE = ON // Power-up Timer activé
#pragma config BOREN = ON // Brown-out Reset activé
#pragma config LVP = OFF // Low-Voltage Programming désactivé
#pragma config CPD = OFF // Data EEPROM protection off
#pragma config WRT = OFF // Flash write protection off
#pragma config CP = OFF // Code protection off

#define _XTAL_FREQ 20000000UL // Fréquence du quartz 20 MHz

// LCD 4 bits -> RB0..RB3 = D4..D7, RB4=RS, RB5=E


#define LCD_PORT LATB
#define LCD_TRIS TRISB
#define RS LATBbits.LATB4
#define E LATBbits.LATB5

// Prototypes
void init_ports(void);
void init_adc(void);
unsigned int read_adc(uint8_t channel);
void init_pwm(void);
void set_servo1(uint16_t duty);
void set_servo2(uint16_t duty);
void lcd_cmd(uint8_t cmd);
void lcd_data(uint8_t data);
void lcd_init(void);
void lcd_goto(uint8_t line, uint8_t pos);
void lcd_puts(const char *s);

void main(void) {
unsigned int ad0, ad1, ad2, ad3;
int16_t diff_h, diff_v;
uint16_t duty1, duty2;

init_ports();
init_adc();
init_pwm();
lcd_init();

lcd_goto(1,1);
lcd_puts("Solar Tracker");

while (1) {
// Lecture des 4 LDR
ad0 = read_adc(0); // canal AN0
ad1 = read_adc(1); // AN1
ad2 = read_adc(2); // AN2
ad3 = read_adc(3); // AN3

// Calcul des écarts


diff_h = (int16_t)ad0 - (int16_t)ad1; // horizontal
diff_v = (int16_t)ad2 - (int16_t)ad3; // vertical
// Convertir diff en largeur d'impulsion servo (1ms..2ms)
duty1 = 300 + diff_h / 8; // ajustez gain
duty2 = 300 + diff_v / 8;
if (duty1 < 150) duty1 = 150;
if (duty1 > 600) duty1 = 600;
if (duty2 < 150) duty2 = 150;
if (duty2 > 600) duty2 = 600;

set_servo1(duty1);
set_servo2(duty2);

// Affichage LCD (ligne 2)


lcd_goto(2,1);
char buf[17];
sprintf(buf, "H:%4u V:%4u", (unsigned int)ad0+ad1, (unsigned int)ad2+ad3);
lcd_puts(buf);

__delay_ms(200);
}
}

void init_ports(void) {
ADCON1 = 0x0E; // AN0..AN3 analogique, reste numérique
TRISA = 0x0F; // RA0..RA3 en entrée (LDR)
TRISB = 0x00; // PORTB sorties pour LCD et PWM
TRISCbits.TRISC2 = 0; // CCP1
TRISCbits.TRISC1 = 0; // CCP2
PORTB = 0;
}

void init_adc(void) {
ADCON2 = 0b10101010; // ADFM=1 (droite), ACQT=101, ADCS=010
ADCON0 = 0; // ADC off
__delay_ms(2);
}

unsigned int read_adc(uint8_t channel) {


ADCON0 = (channel << 3) | 0x01; // sélection canal + ADON=1
__delay_us(20);
GO_nDONE = 1;
while (GO_nDONE);
return ((ADRESH<<8) | ADRESL);
}

void init_pwm(void) {
// Timer2: prescaler 16 -> PWM_Freq ~50Hz
T2CON = 0b00000110;
PR2 = 249;
CCP1CON = 0b00001100; // PWM mode
CCP2CON = 0b00001100;
TMR2 = 0;
T2CONbits.TMR2ON = 1;
}

void set_servo1(uint16_t duty) {


CCPR1L = duty >> 2;
CCP1CONbits.DC1B = duty & 0x03;
}

void set_servo2(uint16_t duty) {


CCPR2L = duty >> 2;
CCP2CONbits.DC2B1 = (duty >> 1) & 0x01;
CCP2CONbits.DC2B0 = duty & 0x01;
}
// ===== Fonctions LCD =====
void lcd_pulse(void) {
E = 1;
__delay_us(1);
E = 0;
__delay_us(100);
}

void lcd_cmd(uint8_t cmd) {


RS = 0;
LCD_PORT = (LCD_PORT & 0x0F) | (cmd & 0xF0);
lcd_pulse();
LCD_PORT = (LCD_PORT & 0x0F) | ((cmd<<4) & 0xF0);
lcd_pulse();
}

void lcd_data(uint8_t data) {


RS = 1;
LCD_PORT = (LCD_PORT & 0x0F) | (data & 0xF0);
lcd_pulse();
LCD_PORT = (LCD_PORT & 0x0F) | ((data<<4) & 0xF0);
lcd_pulse();
}

void lcd_init(void) {
__delay_ms(20);
lcd_cmd(0x33);
lcd_cmd(0x32);
lcd_cmd(0x28);
lcd_cmd(0x0C);
lcd_cmd(0x06);
lcd_cmd(0x01);
__delay_ms(2);
}

void lcd_goto(uint8_t line, uint8_t pos) {


uint8_t addr = (line==1) ? 0x80 : 0xC0;
lcd_cmd(addr + pos - 1);
}

void lcd_puts(const char *s) {


while (*s) {
lcd_data(*s++);
}
}

You might also like