Hjälp med buggar, XC8 PIC16F690

PIC, AVR, Arduino, Raspberry Pi, Basic Stamp, PLC mm.
Användarvisningsbild
90kar08
Inlägg: 1602
Blev medlem: 3 september 2009, 15:27:45
Ort: Staffanstorp

Hjälp med buggar, XC8 PIC16F690

Inlägg av 90kar08 »

Håller på med ett projekt tillsammans med en kompis. Det ska bli en intervalltimer till systemkamera men för tillfället är det ett menysystem på 16x2 LCD, en rotationsenkoder, en LED och en tryckknapp.



I slutet av videon ser man hur menyn är tänkt att fungera men som synes finns det lite buggar... :roll:

Videon är från några veckor sedan, koden nedan generar samma buggar men inte riktigt lika ofta. Vi har försökt kommentera bort eller ändra på tveksamma kodstycken i tur och ordning men vi får ingen vidare förbättring och börjar få slut på idéer... Är det kanske så att vi gör något man kanske inte bör göra i C? Vi är båda mest vana vid Java och assembler.

Kod: Markera allt

/****************************************************
*													*
*	Filename:	IMSv1.2.c							*
*	Date:		2014-03-20							*
*													*
*	Author:		Kalle Jonsson						*
*													*
*****************************************************
*													*
*	Processor:	PIC16F690							*
*	Compiler:	MPLAB XC8							*
*													*
****************************************************/

#include 	<xc.h>
#include 	<string.h>
#define 	_XTAL_FREQ 	4000000
#define		ENTMOD		0x06
#define 	FNCSET		0x38
#define		DSPOFF		0x08
#define		DSPON		0x0C
#define		LCD_RS		PORTCbits.RC0
#define		LCD_E		PORTCbits.RC1
#define		LCD_BL		PORTCbits.RC5
#define		LED			PORTAbits.RA4
#define		BTN			PORTAbits.RA1
#define		SHT			PORTCbits.RC7


__CONFIG(BOREN_OFF & CPD_OFF & CP_OFF & MCLRE_OFF & WDTE_OFF & PWRTE_OFF & FOSC_INTRCIO);

volatile bit A, B, BTN_pressed, BTN_released;
volatile signed char rotcnt = 0;
volatile unsigned char AB, BA, PORTCs;
volatile signed int cnt = 0;
volatile unsigned int BTN_Time = 0;
volatile unsigned long currentTime = 0, lastChange;

//Initialize IO pins
void IOInit()
{
	BTN_released = 1;
	TRISA = 0b00000111;
	TRISB = 0b00000000;
	TRISC = 0b01001100;
	ANSEL = 0;				//No analog pins
	ANSELH = 0;				//--------------
	//ADCON0 = 0b00011000;
	//		   0------- Left justified
	//		   -0------ VDD voltage ref
	//		   --0110-- AN6
	//         ------0- GO/DONE
	//		   -------1 ADON
	//ADCON1 = 0x10;		//AD Conversion Clock Fosc/8
}

//Initialize all interrupts
void interruptInit()
{
	//ADIF = 0;				//A/D Converter Interrupt Flag bit clear
	//ADIE = 1;				//A/D Converter Interrupt Enable bit set
	IOCA = 0b000101;		//Interrupt-on-change PORTA
	RABIF = 0;				//IOC Flag bit clear
	RABIE = 1;				//IOC Enabled 
	OPTION_REG =0b11010001;	//TIMER 0: internal clock, prescaler 1:4
	T0IF = 0;				//TIMER 0 Interrupt Flag bit clear
	T0IE = 1;				//TIMER 0 Overflow Interrupt Enabled
	//PEIE = 1;				//Peripheral Interrupt Enable bit set
}

//Send an instruction to the LCD display
void LCD_cmd(char B)		
{
	LCD_RS = 0;
	PORTB = B & 0xF0;
	NOP();
	LCD_E = 1;
	__delay_us(50);
	LCD_E = 0;
	__delay_us(50);
	PORTB = ((B & 0xF)<<4);
	NOP();
	LCD_E = 1;
	__delay_us(50);
	LCD_E = 0;
	__delay_us(50);
}

//Clear and home the LCD display
void LCD_clr() 				
{
	LCD_cmd(1);
	__delay_ms(2);
	LCD_cmd(2);
	__delay_ms(2);
}

//Output a character onto the LCD display
void LCD_out(char c)		
{
	LCD_RS = 1;
	PORTB = (c & 0xF0);
	NOP();
	LCD_E = 1;
	__delay_us(50);
	LCD_E = 0;
	__delay_us(50);
	PORTB = ((c & 0x0F)<<4);
	NOP();
	LCD_E = 1;
	__delay_us(50);
	LCD_E = 0;
	__delay_us(50);
}

//Move the cursor on the LCD to the specified adress
void LCD_adr(char adr) 
{
	LCD_cmd(0x80 + adr);
}	

//Output an integer with a specified number of digits
void LCD_int_places(unsigned int nbr, int places)
{
	int i, j, out, temp;

	for(i = places; i > 0; i--) {
		out = nbr;
		temp = 1;
		for(j = i-1; j > 0; j--) {
			out /= 10;
			temp *= 10;
		}
		LCD_out('0' + out);
		nbr = nbr-out*temp;
	}	
}

//Output a string on the LCD at the specified adress
void LCD_String(const char *ch, char adr)
{
	LCD_adr(adr);
	while(*ch!='\0')
	{
		LCD_out(*ch++);
	}
}

//Initialize the LCD display
void LCD_Init()				//Initialize LCD diplay
{
	__delay_ms(100);
	LCD_RS = 0;
	LCD_E = 0;
	PORTB = 0x20;			//4-bit Mode
	LCD_E = 1;
	__delay_us(50);
	LCD_E = 0;
	__delay_ms(2);
	LCD_cmd(0b00101000);	//4-bit, two line, 5x8 font
	__delay_ms(1);
	LCD_cmd(0b00001100);	//Display on, Cursor off, Blink off
	__delay_ms(1);
	LCD_cmd(0x01);			//Clear display
	__delay_ms(2);
	LCD_cmd(0b0110);		//Increment mode, shift off
	
	PORTB = 0;
	__delay_ms(100);
}	

//Return 1 if the button has been pressed, else 0
char getBTN() {
	if (BTN_pressed) {
		BTN_pressed = 0;
		return 1;
	} else {
		return 0;
	}
}

//Return 1 or -1 if the rotary encoder has been moved, else 0
signed char getROT() {
	if (rotcnt < 0) {
		rotcnt++;
		return -1;
	} else if (rotcnt > 0) {
		rotcnt--;
		return 1;
	} else {
		return 0;
	}
}

//Add or remove one from var and return
unsigned int useROT(unsigned int var, unsigned int max) {
	signed char rotTemp = 0;
	if (rotcnt < 0) {
		rotcnt++;
		rotTemp = -1;
	} else if (rotcnt > 0) {
		rotcnt--;
		rotTemp = 1;
	}
	signed long temp = var + rotTemp;
	if (temp <= max && temp >= 0) {
		return temp;
	} else {
		return var;
	}
}

void interrupt ISR()
{
	GIE = 0;
	if (T0IF && T0IE) {						//Timer 0 overflow interrupt, once every ms
		TMR0 += 6;
		currentTime++;						//Elapsed time in ms since reset
		if (!BTN && BTN_released) {
			BTN_pressed = 1;
			BTN_released = 0;
		} else if (BTN) {
			BTN_released = 1;
		}	
		T0IF = 0;
	}

	if (RABIF && RABIE) {					//Interrupt-on-change
		unsigned char PORTAcopy = PORTA;
//		if ((currentTime - lastChange) > 2) {
//			lastChange = currentTime;
			
			A = PORTAcopy & 0b001;
			B = (PORTAcopy & 0b100) >> 2;
	
			AB = ((A << 1) + B);
			char test = (BA ^ AB) & 0b11;
	
			BA = ((B << 1) + A);
	
			if (test == 0x01) {
				cnt++;
				if (cnt%4 == 0 && (rotcnt < 127)) {	
					rotcnt++;
					cnt = 0;
				}
				
			} else if (test == 0x02) {				
				cnt++;
				if (cnt%4 == 0 && rotcnt > -127) {
					rotcnt--;
					cnt = 0;
				}
			}
		//}
		RABIF = 0;
	}
	GIE = 1;
}

void main() 
{
	unsigned char shutterUnit='s', intervalUnit='s', sensorMode=2,
		BLMode=3, trigger=1, battery = 0, BL = 100, sensor = 45, state = 0, btn, 
 		arrowRow = 2, arrowPos = 0x40, nextUnit='s', openUnit='s';
	unsigned int shutter=25, interval=10, next=24, open=19, pictures=389, 
		picturesTaken=145, sensorVal=25;

	IOInit();
	interruptInit();
	LED = 1;
	SHT = 0;
	LCD_BL = 1;					//Turn on LCD backlight

	__delay_ms(500);
	//LED = 0;
	LCD_Init();					//Initialize LCD display

	GIE = 1;					//Turn on interrupts
	LCD_clr();					//Clear display

	char state = 0;

	while (1) {
		LED ^= 1;	
        switch (state) { 		//MAIN MENU print
            case 0: 
                LCD_String(" --SETTINGS--  ", 0x1); 
                LCD_String("Shutter   ", 0x41);
				LCD_adr(0x4B);
				LCD_int_places(shutter, 2); 
				LCD_adr(0x4D);
                LCD_out(shutterUnit); 
                break; 
            case 1:
                LCD_String("Shutter   ", 0x1); 
                LCD_String("Interval  ", 0x41); 
				LCD_adr(0xB);
				LCD_int_places(shutter, 2);
				LCD_adr(0xD);
                LCD_out(shutterUnit); 
				LCD_adr(0x4B);
				LCD_int_places(interval, 2);
				LCD_adr(0x4D); 
                LCD_out(intervalUnit); 
                break; 
            case 2: 
                LCD_String("Interval  ", 0x1); 
                LCD_String("Pictures  ", 0x41); 
				LCD_adr(0xB);
				LCD_int_places(interval, 2);
				LCD_adr(0xD);
                LCD_out(intervalUnit);
				LCD_adr(0x4B);
				LCD_int_places(pictures, 3);
                break; 
            case 3: 
                LCD_String("Pictures  ", 0x1); 
                LCD_String("Sensor    ", 0x41);
				LCD_adr(0xB);
				LCD_int_places(pictures, 3); 
				LCD_adr(0x4B);
				LCD_int_places(sensor, 3);
                break;   
            case 4: 
                LCD_String("Sensor    ", 0x1); 
                LCD_String("Sensor    ", 0x41); 
                LCD_adr(0xB);
				LCD_int_places(sensor, 3); 
                if (sensorMode == 1) 
                    LCD_String("ON ", 0x4B); 
                else
                    LCD_String("OFF", 0x4B); 
                break; 
            case 5: 
                LCD_String("Sensor    ", 0x1); 
                LCD_String("Trigger   ", 0x41); 
                if (sensorMode == 1) 
                    LCD_String("ON ", 0xB); 
                else
                    LCD_String("OFF", 0xB); 
                if (trigger == 1) 
                    LCD_String("ON ", 0x4B); 
                else
                    LCD_String("OFF", 0x4B); 
                break; 
            case 6:
                LCD_String("Trigger   ", 0x1); 
                LCD_String("Backlight ", 0x41); 
                if (trigger == 1) 
                    LCD_String("ON ", 0xB); 
                else
                    LCD_String("OFF", 0xB);
				LCD_adr(0x4B);
				LCD_int_places(BL, 3);
                break; 
            case 7: 
                LCD_String("Backlight ", 0x1); 
                LCD_String("Backlight ", 0x41); 
				LCD_adr(0xB);
				LCD_int_places(BL, 3);
				if (BLMode == 1) 
                    LCD_String("ON ", 0x4B); 
                else if(BLMode == 2) 
                    LCD_String("OFF", 0x4B); 
                else
                    LCD_String("AUT", 0x4B); 
				
                break; 
			default:
				break;
        } 
  		
		if (arrowPos == 0) {				//Arrow printing and removing 
			LCD_adr(0);
        	LCD_out(0x7E); 
			LCD_adr(0x40);
			LCD_out(' ');  
		} else {
			LCD_adr(0);
			LCD_out(' '); 
			LCD_adr(0x40);
			LCD_out(0x7E); 	
		}	
        
		signed char rotTemp = getROT();		//Check if the rotary encoder has been turned
        if (rotTemp > 0 && arrowRow < 9){ 
            if(arrowPos == 0)  
                arrowPos = 0x40; 
            else
                state++; 
            arrowRow++; 
        } else if (rotTemp < 0 && arrowRow > 2) { 
            if(arrowPos == 0x40) 
                arrowPos = 0; 
            else
                state--; 
            arrowRow--; 
        } else if (rotTemp < 0 && arrowRow == 2 && state == 1) { 
            state = 0; 
            arrowPos = 0x40; 
        }	

		if (getBTN()) {					//Enable modifying value with button press
			LCD_adr(0);					//Remove arrows in the first column
			LCD_out(' ');				//-
			LCD_adr(0x40);				//-
			LCD_out(' '); 				//-
			LCD_adr(arrowPos + 0xA);	//Output the arrow to the left of the value
			LCD_out(0x7E);				//-	
			
			while (!getBTN()) {
				LED ^= 1;
				unsigned int varTemp;
				char unitTemp;
				char type = 0;			//Variable print type, 2 digit int, 3 digit int or string
				switch (arrowRow) {
					case 2:
						shutter = useROT(shutter, 60);
						varTemp = shutter;
						unitTemp = shutterUnit;
						type = 1;
						break;
					case 3:
						interval = useROT(interval, 60);
						varTemp = interval;
						unitTemp = intervalUnit;
						type = 1;
						break;
					case 4:
						pictures = useROT(pictures, 999);
						varTemp = pictures;
						unitTemp = 0;
						type = 2;
						break;
					case 5:
						sensor = useROT(sensor, 255);
						varTemp = sensor;
						unitTemp = 0;
						type = 2;
						break;
					case 6:
						sensorMode = useROT(sensorMode, 3);
						varTemp = sensorMode;
						unitTemp = 0;
						type = 3;
						break;
					default:
						type = 0;
						break;						
				}

				LCD_adr(arrowPos + 0xB);
				switch (type) {
					case 0:
						break;
					case 1:
						LCD_int_places(varTemp, 2); 
						LCD_adr(arrowPos + 0xD);
        		        LCD_out(unitTemp);
						break;
					case 2:
						LCD_int_places(varTemp, 3);
						break;
					case 3:
						if (varTemp == 1)
							LCD_String("ON ",arrowPos + 0xB);
						else if (varTemp == 2)
							LCD_String("OFF", arrowPos + 0xB);
						else if (varTemp == 3)
							LCD_String("AUT", arrowPos + 0xB);
						break;
					default: 
						break;
				}
			}
		}
		//while (rotcnt == 0 && BTN_pressed == 0);
	}
}
ElectricNooB
Inlägg: 600
Blev medlem: 26 juli 2011, 20:58:06

Re: Hjälp med buggar, XC8 PIC16F690

Inlägg av ElectricNooB »

Känslan man får är att ni skickar data för fort till displayen för då kan man ju få sånt där. Annars kanske interuptsen ställer till det, dvs, kanske bryts sändningen till displayen av något interupt(tex timern), inte för att borde göra något men det kanske ändrar nått annat tex pin states. Kort sagt, interupts kan leda till lustigheter.
Användarvisningsbild
90kar08
Inlägg: 1602
Blev medlem: 3 september 2009, 15:27:45
Ort: Staffanstorp

Re: Hjälp med buggar, XC8 PIC16F690

Inlägg av 90kar08 »

Tack för svar :)

Att vi pratade för fort med LCD:n var vår tanke också men det hjälper inte att lägga till längre fördröjningar.

Verkar som om det var pin-change-interrupet som ställde till det. Stängde av det och la rotationsenkoder-checken under timer-interruptet istället och nu funkar det bättre :) Än så länge iaf...
sodjan
EF Sponsor
Inlägg: 43251
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Re: Hjälp med buggar, XC8 PIC16F690

Inlägg av sodjan »

Om det är en vanlig/billig mekanisk rot.enkoder så var det väl kontaktstudsar.
Och ja, det bör försvinna om man pollar i ett timer interrupt istället, i alla
fall om timern har tillräckligt lång tid så att studsarna hinner klinga ut.
Om man vill köra IOC så kanske man behöver någon elektronik
mellan som snyggar till signalen.
Användarvisningsbild
90kar08
Inlägg: 1602
Blev medlem: 3 september 2009, 15:27:45
Ort: Staffanstorp

Re: Hjälp med buggar, XC8 PIC16F690

Inlägg av 90kar08 »

Vi satte kondingar på rotationsenkodern just för att slippa kontaktstuds men vi blev väl inte av med dem helt antagligen. Men jag tror inte det kommer bli några problem att kolla enkodern i timerinterruptet istället så vi kör på det :)
Användarvisningsbild
90kar08
Inlägg: 1602
Blev medlem: 3 september 2009, 15:27:45
Ort: Staffanstorp

Re: Hjälp med buggar, XC8 PIC16F690

Inlägg av 90kar08 »

Så till nästa problem; timerinterruptet är tänkt att komma varje ms men det verkar komma varannan istället. Räknar upp en variabel var 1000:e interrupt och skriver ut den på displayen och tycker att vi borde få ut sekunder men sekunderna blir dubbelt så långa som de ska.

Vi har räknat såhär:

Intern oscillator på 4MHz ger 1MHz instructionscykler (1 MIPS, är det samma sak ?).
Prescaler på 1:4 enl.

Kod: Markera allt

OPTION_REG =0b11010001;   //TIMER 0: internal clock, prescaler 1:4
ger 250kHz

Då borde väl timer0 som är 8-bitars slå runt med ~1kHz?
sodjan
EF Sponsor
Inlägg: 43251
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Re: Hjälp med buggar, XC8 PIC16F690

Inlägg av sodjan »

Har du några IOC igång samtidigt?
Jag ser att du i ISR-koden hanterar GIE. GIE "släcks" med
automatik då ett interrupt inträffar och "enablras" igen
automatiskt vid RETFIE (return from intgerrupt).
Du borde nog inte försöka göra samma sak, det kan bli
underligt om du enablar interrupt manuellt innan context
har äterställts korrekt via RETFIE (och den eventuella övríga
kod som kompilatorn lägger till för att hantera context).
Användarvisningsbild
90kar08
Inlägg: 1602
Blev medlem: 3 september 2009, 15:27:45
Ort: Staffanstorp

Re: Hjälp med buggar, XC8 PIC16F690

Inlägg av 90kar08 »

Nope, inga andra interrupt alls igång.

Sant det där med GIE, har tagit bort det nu. Men det verkar inte vara det som ställde till det i det här fallet.

Det känns ju som om det skulle vara något enkelt räknefel någonstans, eller något liknande i och med att interruptet kommer mer eller mindre exakt hälften å ofta som det är tänkt. Men jag kan inte hitta några sådana feltänk...
sodjan
EF Sponsor
Inlägg: 43251
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Re: Hjälp med buggar, XC8 PIC16F690

Inlägg av sodjan »

Du har inget instrument (frekvensräknare eller oscilloskop) så att du kan
verifiera frekvensen?

Även om 4 MHz ska vara default, så kan det vara vettigt (i alla fall
tydligare, eftersom jag letade efter OSCCON i din kod) att sätta
OSCCON specifikt till det man vill ha. Du kan även testa med
andra prescalers för att verifiera att det fungerar.

Vad har du egentligen gjort för felsökning? Lite onödigt att
föreslå sådant som du redan har kollat... :-)
Användarvisningsbild
Glenn
Inlägg: 36726
Blev medlem: 24 februari 2006, 12:01:56
Ort: Norr om Sthlm
Kontakt:

Re: Hjälp med buggar, XC8 PIC16F690

Inlägg av Glenn »

Är du säker på att du har rätt frekvens då ? alltså den du räknar efter, det är ju en klassiker annars, speciellt med intern oscillator.

EN sekund efter sodjan.. :P ;)
Användarvisningsbild
Icecap
Inlägg: 26648
Blev medlem: 10 januari 2005, 14:52:15
Ort: Starup (Haderslev), Danmark

Re: Hjälp med buggar, XC8 PIC16F690

Inlägg av Icecap »

Jag ser ingen initiering av den interna oscillator och jag drar mig till minnes att den startar på halva av max-frekvensen automatisk.
Användarvisningsbild
90kar08
Inlägg: 1602
Blev medlem: 3 september 2009, 15:27:45
Ort: Staffanstorp

Re: Hjälp med buggar, XC8 PIC16F690

Inlägg av 90kar08 »

Sätter jag OSCCON så att frekvensen blir 8MHz så blir sekunderna rätt, men då är ju fortfarande uträkningarna fel... Mao, det är något annat som blivit fel än frekvensen.

Har oscilloskop men det står hemma hos föräldrarna, ska ta mig till skolan strax, passar på att ta en tur in i labbet där och låna oscilloskop. Testar att toggla en pinne varje interrupt för att försäkra mig om att nerdelningen till sekunder som blir fel utan just att timern tickar för långsamt.

Jo, halva max-frekvensen stämmer med det vi räknat. Max är 8MHz.
sodjan
EF Sponsor
Inlägg: 43251
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Re: Hjälp med buggar, XC8 PIC16F690

Inlägg av sodjan »

Toggla en pinne på kritiska punkter under uträkningen och
stäm av med oscilloskop. Det är nog enklast. Jag har inte
kört så mycket i C, men kan man inte köra det i MPSIM?
Användarvisningsbild
90kar08
Inlägg: 1602
Blev medlem: 3 september 2009, 15:27:45
Ort: Staffanstorp

Re: Hjälp med buggar, XC8 PIC16F690

Inlägg av 90kar08 »

Det visade sig vara ett ganska enkelt fel... Var visst inte så smart att göra if(currentTime%1000 == 0) på en long för att få ut sekunder av millisekunderna :oops:

Dels så tog det ca 10 % av programminnet och dels så tog det för lång tid att beräkna så bara vartannat timer-interrupt hanns med. Men nu funkar det fint :D

Tackar för hjälpen igen, det var oscilloskopet som löste det hela.
sodjan
EF Sponsor
Inlägg: 43251
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Re: Hjälp med buggar, XC8 PIC16F690

Inlägg av sodjan »

Aha, där ser man... :-)
De flesta fel är enkla.
Skriv svar