Problems with c code for pic (lcd and encoder) - Page 1
Forum section: electronics / beginners

author: little_carlos
author_rank: Regular Contributor
timestamp: April 26, 2016, 12:21:13 pm
content: So, i made this code, to control the pwm output with an encoder and display the duty cycle % on the lcd, I first made a code without the lcd controling the pwm with the encoder and it did perfect, just as i wanted, then i implemented the rest of the code for the lcd, but something weird happens.the response of the encoder is very very slow, on normal situation should increase by 10 decimal, but with the lcd, it takes a lot of turns for the pic to react and increase the duty cycle, what is happening? is this a bottleneck? the pic is 16f887 and the clock is speed is set at 18.432mhzhere is the codeCode:sbit LCD_RS at RB4_bit;sbit LCD_EN at RB5_bit;sbit LCD_D4 at RB0_bit;sbit LCD_D5 at RB1_bit;sbit LCD_D6 at RB2_bit;sbit LCD_D7 at RB3_bit;sbit LCD_RS_Direction at TRISB4_bit;sbit LCD_EN_Direction at TRISB5_bit;sbit LCD_D4_Direction at TRISB0_bit;sbit LCD_D5_Direction at TRISB1_bit;sbit LCD_D6_Direction at TRISB2_bit;sbit LCD_D7_Direction at TRISB3_bit;int i;int flanco; // Variable que almacena lo obtenido en el ADCfloat Tem = 0; // Valor real del ADCchar Text; // Almacena el Tem pero tipo Texto para el LCDchar txt1[] = "duty cycle: "; // Texto mostrado en el LCDvoid main(){PWM1_Init(5000);ANSEL = 0x00; // Configure AN0 pin as analogANSELH = 0x00; // Configure other AN pins as digital I/OTRISA = 1; // AN0 como entradatrisc = 0;portc = 0;porta = 0;C1ON_bit = 0; // Deshabilitar comparadoresC2ON_bit = 0;i = 0;flanco = 1;// Inicializa el Modulo ADC// Retardo para estabilizar el ADCLcd_Init(); // Inicializa el LCDLcd_Cmd(_LCD_CLEAR); // Comando para limpiar el LCDLcd_Cmd(_LCD_CURSOR_OFF); // Comando para quitar el cursorLcd_Out(1,1, txt1); // Mandamos nuestro mensaje al LCDLcd_Chr(2,9,223); // Display symbol "°" (grado)Lcd_Chr(2,10,'%'); // Display "C" for CelsiusDelay_ms(100);while(1){pwm1_start();flanco = 1;if(ra1_bit == 1 && flanco == 1){delay_ms(3);flanco = 0;if(ra0_bit == 1 && flanco == 0){delay_ms(3);i = i+20;flanco = 1;}}else{flanco = 1;if(ra0_bit == 1 ){delay_ms(3);if(ra1_bit == 1 && flanco == 1){delay_ms(3);i = i-20;}}}if(i >= 255){i = 255;}if(i<=0){i = 0;}pwm1_set_duty(i); // Este retardo ayuda a de manera burda a//estabilizar el LCD de las actualizaciones de//la lectura del ADC.Tem = (float)(i/255.00)*100.00; // Obtenemos el valor Real de la Conversion A/D// (ADCread * 0.00488)/0.01)= Vreal// Resumimos que 0.00488 / 0.01 = 0.488//Se convierte el número entero a una cadena de caracteres.FloatToStr(Tem, Text);//Se imprime el resultado.Lcd_Out(2,1, Text);//Retardo de 100m segundos.Delay_ms(50);}}thanks for your time!

author: macboy
author_rank: Super Contributor
timestamp: April 26, 2016, 12:49:03 pm
content: edit your post with the code inside code tags (use the # button)

author: rstofer
author_rank: Super Contributor
timestamp: April 26, 2016, 01:57:09 pm
content: I suspect you are missing the switch transitions while processing floating point arithmetic for the LCD and I don't really understand why you are initializing the PWM on every pass through the while(1) loop.Here's a microchip app note for rotary encoders and it doesn't use interrupts. However, the handler code needs to be called often (multiple times in the while(1) loop, after each significant step) or there will be slippage. So create a function to handle it and just call if from various places.http://www.engr.mun.ca/~dpeters/6806/postings/RotaryEncoder.pdfYou could also use a timer interrupt handler to process the encoder at some rate. Use the ideas from the app note about XORing the current switch values versus the previous.http://www.hobbytronics.co.uk/rotary-encoder-tutorialNone of these will ever work as well as using the pin change interrupts. Once you study the transition sequence, you will see how to use pin change interrupts to increment or decrement the value. All of this will happen in the background and the encoder count just changes whenever the user wants, not when the program eventually gets around to reading the pins.I found an Instructable but it doesn't solve the entire problem:http://www.instructables.com/id/How-to-Program-a-PIC-Microcontroller-Read-an-Encod/?ALLSTEPSYou need to search the Internet for 'PIC encoder interrupt'.At startup, you note the existing condition of the encoder pins and set up the interrupt on change such that you will see an interrupt on the very next transition of either. Once you get the interrupt, you note which pin (A or B) has changed and from your knowledge of the transition sequence, you increment or decrement the counter. Then you set the register to interrupt on the alternate transition of that bit. If you just got a falling edge interrupt, the next interrupt for that pin is a rising edge.In one direction, let's call it increment, the transitions are A=0, B=0 to A=1, B=0 to A=1, B=1 to A=0, B=1 to A=0, B=0. There are four transitions and in my application I added a count at each transition. So my count went up by 4. For knob encoders, the count should probably just go up by one after a complete set of transitions. That gives one count per detent.In the other direction the transitions are A=0, B=0 to A=0, B=1 to A=1, B=1 to A=1, B=0 to A=0, B=0. Again, four transitions.The tricky part is to be able to get, say, two of the forward transitions, one of the reverse transitions followed by three of the forward transitions and still get the right count. You get that odd reverse transition from switch bounce. When you build your state transition table, you need to consider this problem. That's why the quadrature encoder was invented.I did this on an AVR several years ago and it worked great! Unfortunately, I can't get to the code right now and, anyway, it isn't for a PIC.ADD: My code was for a rotary encoder on a shaft and I needed to measure distance so I might have an initial condition that was like A=1, B=0. For a knob encoder, the detent position will either be A=0,B=0 or A=1, B=1. Knowing which will make it easy to set up the pin transition interrupt. On the AVR, I could select whether I wanted rising or falling edges as my next interrupt. I'm not sure the PIC works that way, you may have to fiddle around to determine which transition just occurred.