Maker Pro
Maker Pro

16f877a DC encoder motor control help!!!!!!!

wildarms

May 28, 2021
1
Joined
May 28, 2021
Messages
1
Hello everyone. I was trying to control the encoder dc motor using pic 16f877a. I couldn't use the #INT_RB interrupt. can you help me with my code. Angle value due to INT_RB interrupt is always zero, I need to increase it somehow, please help.

Code:
#include <16F877A.h>
#device adc=10 //set the bit value of adc
#FUSES XT, NOWDT, NOPROTECT, NOBROWNOUT, NOLVP, NOPUT, NODEBUG, NOCPD
#use delay(crystal=4000000)
#include <lcd.c>

unsigned int16 last_read,quad;

#INT_RB // RB port interrupt on change
void RB_IOC_ISR(void)
{
int8 encoderRead;
encoderRead = input_b() & 0x30;
if(encoderRead == last_read)
return;

if(bit_test(encoderRead, 4) == bit_test(last_read, 5))
quad -= 1;
else
quad += 1;
last_read = encoderRead;
}

signed long EncoderGet(void)
{
signed long value = 1;

while(quad >= 4)
{
value += 1;
quad -= 4;
}
while(quad <= -4)
{
value -= 1;
quad += 4;
}
return value;
}

signed long PWM,error = 0,change = 0,realPosition = 0,angle = 0.0f;

void main()
{
unsigned int8 temp;
unsigned int16 rev,kp;
unsigned long int16 referance; //variable for ADC reading value from AN0

lcd_init();
delay_ms(10);

set_tris_c(0x00); //set all portb pins as output
set_tris_b(0x00);
port_b_pullups(TRUE);
delay_ms(10);
temp = input_b(); // Add these 4 lines
enable_interrupts(INT_RB);
clear_interrupt(INT_RB);
enable_interrupts(GLOBAL);
setup_ccp1(CCP_PWM); //4kHz PWM signal output at CCP1 pin 17
setup_timer_2(T2_DIV_BY_16, 255, 1);
setup_adc_ports(ALL_ANALOG); //A0A1 A2 A3 A5 E0 E1 E2 analog pins
setup_adc(ADC_CLOCK_DIV_32); //enable ADC and set clock FOR ADC

WHILE(1)
{
set_adc_channel(0); // next analog reading will be from channel 0
delay_us(10); //allow time after channel selection and reading
referance =read_adc(); //start and read A/D
referance=referance*250;
referance=referance/1023;
referance=referance+20;
set_adc_channel(1); // next analog reading will be from channel 1
delay_us(10); //allow time after channel selection and reading
kp = 50+(read_adc()*10/1023); //start and read A/D
delay_ms(200);


change = EncoderGet();
if(change)
{
realPosition += change;
}
rev = realPosition/360.0f; // Here 360 represents the encoder pulses per revolution
angle = ((int16)(rev*360))%360; // Real time angle is determined in this line


error=referance-angle;
PWM=error*kp;
if (PWM>=1023)
PWM=1023;
else if (PWM<=0)
PWM=0;
set_pwm1_duty(PWM);


printf(LCD_PUTC,"\fref=%lu",referance);
printf(LCD_PUTC," kp=%lu",kp);
printf(LCD_PUTC,"\npos=%lu",rev);
lcd_gotoxy(8,2);
printf(LCD_PUTC,"PWM=%lu",PWM);
delay_ms(700);
}
}

Moderators note : used code tags for pieces of code
 
Last edited by a moderator:

Harald Kapp

Moderator
Moderator
Nov 17, 2011
13,722
Joined
Nov 17, 2011
Messages
13,722
The interrupt routine saves the encoder value in the global variable last_read. But this variable is used nowhere else. How do you suppose to get an angle value if you don't use last_read?
Same for the variable quad. Used in EncoderGet() only.
 
Top