Jeroen Boere
IF you can't convince them, then confuse them!
Onderstaande code heb ik gebakken.
op het moment dat er iets binnenkomt, word er inderdaad de vergelijking gemaakt, geeft inderdaad de melding terug als de vergelijking klopt, maar dan gaat de controller niet terug naar main() en loopt de ISR ook niet als er nieuwe data binnen komt.
Hoe kan dit?
compiler: MikroC PRO 2009
char match1[] = "help";
char OUTPUT[20];
enum LED {INT_LED = 3};
void interrupt();
void main() {
PORTA = 0;
TRISA = 0;
PORTB = 0;
TRISB = 0;
INTCON.GIE = 1; // ENABLE GLOBAL INTERRUPTS
INTCON.PEIE = 1; // peripheral interrupt enable bit
UART1_INIT(19200);
delay_ms(100); // delay to start up uart
PIE1.RCIE = 1; // ENABLE RECEIVE INTERRUPT
while(1) {
PORTB.INT_LED = 1;
delay_ms(1000);
PORTB.INT_LED = 0;
delay_ms(1000);
}
}
void interrupt() {
if (UART1_Data_Ready() == 1) { // if data is received
UART1_Read_Text(OUTPUT, "!", 17);
}
if(strcmp(match1,OUTPUT)==0){
UART1_WRITE_TEXT("Help requested!");
}
PIE1.RCIE = 1; // ENABLE RECEIVE INTERRUPT
return;
}
Misschien een stackoverflow ?
Ik zou in een interruptroutine ook geen grote andere routines aanroepen die gebruik maken van andere hardware.
Het is wellicht handiger om in de interrupt routine een flag te zetten en die in het hoofprogramma uitwaarderen en de desbetreffende actie ondernemen.
Het is ook een beetje afhankelijk van de compiler of die reentrant interrupt routines maakt waardoor de stack kan vollopen als je iets gaat doen wat veel tijd kost zoars een string verdturen met de uart.
Of misschien wordt de interrupt wel weer vrijgegeven in de uart routines en zorgt dat voor problemen.
Ik weet niet op welke hardware dit moet werken maar de AVR's hebben een heel mooie JTAG poort waarmee je goed kunt debuggen vermits de compiler dit ondersteund.
Jeroen Boere
IF you can't convince them, then confuse them!
Uiteraard ben ik wat verder gegaan:
char match1[] = "help";
char OUTPUT[20];
enum LED {INT_LED = 20};
char flag = 0;
void interrupt(){
if (UART1_Data_Ready() == 1) { // if data is received
UART1_Read_Text(OUTPUT, "!", 4);
flag = 1;
}
}
void main() {
PORTA = 0;
TRISA = 0;
PORTB = 0;
TRISB = 0;
INTCON.GIE = 1; // ENABLE GLOBAL INTERRUPTS
INTCON.PEIE = 1; // peripheral interrupt enable bit
UART1_INIT(19200);
delay_ms(100); // delay to start up uart
PIE1.RCIE = 1; // ENABLE RECEIVE INTERRUPT
while(1) {
if(flag == 1){
if(strcmp(OUTPUT,match1)==0){
UART1_WRITE_TEXT("Help requested!");
}
flag = 0;
}
PORTB.INT_LED = 1;
delay_ms(1000);
PORTB.INT_LED = 0;
delay_ms(1000);
}
}
helaas werkt dit ook niet.
de ISR word aangeroepen en vanaf daar blijft het programma hangen.
Ik kan ook niet echt goede referenties vinden waarin UART icm INTERRUPTS moet werken in MikroC voor een PIC (specifiek de 16F628)
timmie
niet met me uitspraken(of opmerkingen) eens mail me.K8048 guide
welke compiler versie gebruik je jeroen? MikroC Pro? ik heb nog een oude versie ik wil het wel compileren voor je als ik de fusesettings weet
Jeroen Boere
IF you can't convince them, then confuse them!
MikroC PRO for PIC 2009 (version 3.2)
Controller: PIC16F628
Fuses:
CONFIG :$2007 : 0x3D2A
osc: HS (20 MHz crystal)
Master clear: Enabled
de rest is OFF of Disabled
[Bericht gewijzigd door Jeroen Boere op (11%)]
Ik weet niet wat de routine UART1_Read_Text doet.
Het kan heel goed zijn dat deze routine blijft wachten op een bepaalde invoer. Er staat in de aanroep een adres waar de data heen moet en daarna waarschijnlijk een karakter waarop gewacht moet worden (om te beginnen of om mee af te sluiten)en een maximale lengte.
Let wel: de laatse twee parameters zijn wat ik er van verwacht maar misschien is het wel helemaal anders.
Arco
Special Member
Arco - "Simplicity is a prerequisite for reliability" - hard-, firm-, en software ontwikkeling: www.arcovox.com
Het is zeer af te raden om trage operaties zoals seriele I/O of delays in een interrrupt uit te voeren.
Ook kan de USART read zoals al gezegd een 'blocking' function zijn...
timmie
niet met me uitspraken(of opmerkingen) eens mail me.K8048 guide
ik heb een hex klaar liggen zal die straks even mailen moet hier eerts nog wat dingen doenis gemaild.
Het probleem is dat je interrupt flag moet resetten, manueel in software.
Als je dat niet doet blijft ie constant naar zen interrupt vector branchen.
/edit:
void interrupt(){
if (UART1_Data_Ready() == 1) { // if data is received
UART1_Read_Text(OUTPUT, "!", 4);
flag = 1;
PIR1.RCIF = 0;}
}
zo dus
[Bericht gewijzigd door ScuD op (41%)]
Jeroen Boere
IF you can't convince them, then confuse them!
@scud: Helaas, helpt ook niet.
@Arco: dat hoor je vaak, agree, maar hoe dan wel? constant je uart pollen is ook geen goede werkwijze. hoe dan wel, geef eens een voorbeeld. je hoort veel mensen dit zeggen, maar een oplossing is er nooit meegegeven 
@driessen: eerste deel is de pointer waar hij de binnengekomen data opslaat. tweede deel (!) dus geeft het break character aan, wat ik dus zelf gekozen heb. en het derde deel geeft zijn maximale pogingen aan om data binnen te lepelen.
[Bericht gewijzigd door Jeroen Boere op (13%)]
Ik moet toegeven dat ik ook geen al te geweldige ervaringen heb met de MikroC uart routines.
Mss kan je best de uart afhandeling zelf schrijven, waarin je in de interrupt gewoon even de data vanuit de uart in een fifo steekt.
Lijkt me de snelst mogelijke oplossing, gezien de interrupt pas wordt aangeroepen als de data effectief binnen is, kan dus praktisch niet sneller..
Zal morgen het streepje code eens simuleren, maar ik zie ook niet direct een probleem.
Ben absoluut niet bekend met PIC's (hou meer vanm AVR's
) maar probeer het volgende eens:
void interrupt(){
char dummy;
if (UART1_Data_Ready() == 1) { // if data is received
dummy = RCSTA; // read status register
dummy = RCREG; // read received data
}
}
Hiermee handel je zelf je UART data af. Je doet er welliswaar nu nog niets mee maar zo kan je zien of het programma in iedergeval blijft lopen na een UART interrupt.
Normaal gesproken moet een leesactie op het UART data register de receive interrupt resetten.
Weet je zeker dat er toevallig ook niet nog andere interrupts aan staan bijv de TX interrupt. Want als dat zo is dat raakt hij ook nooit meer uit die intterrupt omdat die niet gereset wordt.
RobHoi
42
Hoi,
van de PIC heb ik geen verstand, maar in het voorbeeld programma die een vlag zet in de interrupt functie zit misschien een fout. de variabele flag is gedeclareerd als
char flag = 0;
Volgens mij moet dat zijn:
volatile char flag = 0;
"volatile" geeft voor de compiler aan dat de waarde tijdens de executie van het programma kan veranderen (bijvoorbeeld in een interrupt functie). Een goede compiler zal zien dat flag initieel 0 is en niet verandert in het hoofdprogramma en zal het stuk tussen de 'if (flag == 1)' helemaal niet coderen.
Ik weet niet of deze compiler zonder de qualifier volatile goed omgaat met de variabele 'flag', maar toevoegen kan zeker geen kwaad.
Arco
Special Member
Arco - "Simplicity is a prerequisite for reliability" - hard-, firm-, en software ontwikkeling: www.arcovox.com
Heb net even gekeken, en UART1_Read_Text is inderdaad een 'blocking' function, dus die kun je niet in een interrupt gebruiken. Als je toch in een interrupt e.e.a. wilt afhandelen, gebruik dan UART1_Read als er data is. Dat geeft iedere keer als er data is een byte terug, waar je zelf een string van kunt maken.
Is het misschien ook verstandig om de delay eruit te laten en er een teller in te zetten. Op dit moment is de delay ook een blocking iets lijkt mij. Je weet niet wat MikroC doet om die delay te maken.
Je zit toch in een while loop, dus dan kan je daar ook maar beter gebruik van maken 
Arco
Special Member
Arco - "Simplicity is a prerequisite for reliability" - hard-, firm-, en software ontwikkeling: www.arcovox.com
In main() maakt dat niets uit of het blocking is of niet. (Je kunt toch maar 1 ding tegelijk doen zonder RTOS... )
Interrupt wordt altijd uitgevoerd, ongeacht wat er in main gebeurt...
(Nou ja, interrupts moeten natuurlijk wel zijn ge-enabled...)
Jeroen Boere
IF you can't convince them, then confuse them!
heb nu dit, maar werkt nog niet.
waar ga ik verkeerd?
char match1[] = "help";
char *OUTPUT[20];
enum LED {INT_LED = 3};
char flag = 0;
int counter = 0 ;
void Do_Uart(){
PIE1.RCIE = 0; // disable UART Interrupt
counter = 0;
do { // if data is received
OUTPUT[counter] = RCREG;
counter++;
} while (RCIF == 1 );
PIR1.RCIF = 0;
PIE1.RCIE = 1; // ENABLE RECEIVE INTERRUPT
flag = 1; // Set new data flag
}
void interrupt(void){
if (PIR1.RCIF == 1) { // If we have an UART interrupt
Do_Uart(); // call interupt handler for UART
}
}
void main() {
PORTA = 0;
TRISA = 0;
PORTB = 0;
TRISB = 0;
INTCON.GIE = 1; // ENABLE GLOBAL INTERRUPTS
INTCON.PEIE = 1; // peripheral interrupt enable bit
UART1_INIT(19200);
delay_ms(100); // delay to start up uart
PIE1.RCIE = 1; // ENABLE RECEIVE INTERRUPT
while(1) {
if(flag == 1){
UART1_WRITE_TEXT("Data: ");
UART1_WRITE_TEXT(OUTPUT);
//UART1_WRITE_TEXT(counter);
if(strcmp(OUTPUT,match1)==0){
UART1_WRITE_TEXT("Help requested!");
}
flag = 0;
}
PORTB.INT_LED = 1;
delay_ms(100);
PORTB.INT_LED = 0;
delay_ms(100);
}
}
Jeroen Boere
IF you can't convince them, then confuse them!
Heb het over een andere boeg gegooit:
Dit werkt perfect.
Als je er meer dan 40 chars in wilt stoppen dan crasht ie niet.
Hij negeert ze gewoon.
char match1[] = "help";
enum LED {INT_LED = 3};
char flag = 0;
char RxData[40];
int i;
void interrupt(void){ // ISR
if (PIR1.RCIF == 1) { // If we have an UART interrupt
RxData[i] = UART1_Read(); // Read usart RX reg
if ( RxData[i] == 0x0A) { // check if the last byte is CR
RxData[i-1]='\0' ; // Null terminate the string array
i=0; // clear the InBuffer byte counter
flag = 1; // Setup indata flag for MAIN
}
else{
if(i <= 39){ // But, check if not more data then 40 bytes is comming
i++; // 40 not yet reached: increase Byte counter
}
}
}
}
void main() {
PORTA = 0;
TRISA = 0;
PORTB = 0;
TRISB = 0;
INTCON.GIE = 1; // Enable global interrupts
INTCON.PEIE = 1; // peripheral interrupt enable bit
UART1_INIT(19200); // Init the UART with 19200 Baud
delay_ms(100); // small delay to start up the UART
PIE1.RCIE = 1; // Enable receiver interrupt
while(1) { // Start of endless loop for main program
if(flag == 1){ // Oh yes, we did receive UART data, let handle!
UART1_WRITE_TEXT("Data: "); // Write Data:
UART1_WRITE_TEXT(RxData); // Write the received data
if(strcmp(RxData,match1)==0){ // compare the data with the given value
UART1_WRITE_TEXT("Help requested!");// Write the right reply.
}
flag = 0; // RxData processing completed, clear the flag.
}
PORTB.INT_LED = 1; // do something the let the controller looks alive....
delay_ms(100); // ..
PORTB.INT_LED = 0; // ..
delay_ms(100); // ..
}
}