Continue to Site

Welcome to our site!

Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

  • Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

How to use Interrupt in PIC16F877A in C..??

Status
Not open for further replies.
I have been playing.... I have created a 8x32 LED array with row scanning... I have still used interrupts but I am scanning exactly the same way as the T6963C controller scans the LCD. I can change pixel by pixel and draw animations

https://www.youtube.com/watch?v=6UmvOTKGY7Q&feature=youtu.be

It looks laggy but that isn't how it is I can't produce decent video's.

This way you can draw to the screen just as we do for the larger screen..

Here is the code..

Code:
#include<pic.h>
#define _XTAL_FREQ 20000000L			// 20 meg crsytal
__CONFIG(0x3F52);						// HS on,  WDT off, BOR on, PWRTon..

char displayPointer=0;					// for interrupt use...
extern const char  fnt[];				// Font in external C file
extern const char  anim[];
unsigned char buffer[32]; 				// buffer for screen 
unsigned char backbuffer[32];			// Spare screen for drawing on
char pow[8]={128,64,32,16,8,4,2,1};

void interrupt ISR()					// This just swaps the buffer to the display
	{
	if(TMR2IF)							// Make sure its the timer interrupt.
		{
		PORTB = 0;						// Clear old data first
		if(displayPointer == 0 )  		// 1st frame..
			RC4 = 1;					// Data = 1 on the first clock only
		RC3 = 1;
		__delay_us(20);					// Clock the shift registers
		RC3 = 0;
		RC4 = 0;						// Make sure data stays low for the rest of the cycles
		PORTB = buffer[displayPointer];	// Move buffer row by row( 4 row sections per row )		
		if(++displayPointer==32) 		// 32 LED row sections in total
			displayPointer = 0;			// Back to first row..
		}
	TMR2IF = 0;							// Clear timer 2 interrupt flag
	}

void pixel(signed char x,signed char y,int cond)
	{
	int tmp;
	char pix,msk;
	if(x<0 || y<0) return;			// outside drawing limits negative
	if(x>31 || y>7) return;			// outside drawing limits positive
	tmp = (y << 2) + (x>>3);		// Linear position
	pix = x%8;						// pixel required
	pix = pow[ pix];
	msk = backbuffer[tmp];			// get exsisting data
	if(cond == 2)
		pix ^= msk;					// XOR data to screen
	if (cond == 1)
		{
		pix = ~pix;
		pix &= msk;					// AND data to screen
		}
	if(cond == 0)
		pix |= msk;					// OR data to screen
	backbuffer[tmp] = pix;			// apply changes
	}

void charput(char ch, signed char x,signed char y)
	{
	signed char x1, y1;				
	const char* addr2;				// pointer to character
	char disp;
	ch -= 0x20;						// characters starts a 0 not 0x20
	addr2 = &fnt[0];				// start of font array
	addr2 = addr2 + ((int)ch * 8);	// start place in font array
	for( y1=0;y1<8;y1++)			// eight rows
		{
		disp = *addr2;
		for (x1 = 0; x1<8; x1++)	// eight pixels
			{			
			if(disp & pow[x1])
				pixel(x+x1,y+y1,0); // OR the pixel to the display buffer
			}
		addr2++;
		}	
	}

void strput(const char* ch, signed char x,signed char y)
	{
	int addr;
	
	while (*ch )
		{
		charput(*ch++,x,y);			// write a string to the display buffer
		x+=7;
		}		
	}

void clr()
	{
	int addr;
	for(addr=0;addr<32;addr++)				// Empty display buffer
		backbuffer[addr]= 0;
	}

void Blit()
	{
	int addr=0;
	GIE = 0;
	for(addr=0;addr < 32;addr ++)
		{
		buffer[addr] = backbuffer[addr];	// put all data from display buffer
		}									// to screen buffer
 	GIE = 1;
	}

void animation(void)
	{
	char x,y;
	const char* frame;						// pointer to frames
	for(x=0;x<14;x++)						// 14 frames in animation
		{
		clr();								// clears the display buffer
		frame = &anim[0];					// start of frames
		frame += x*32; 						// each frame is 32 bytes long
		for(y=0;y<32;y++)
			backbuffer[y] = *frame++;		// Cycle through the animation
		Blit();								// pass to screen buffer
		__delay_ms(200);					// time to view
		}
	}

void displaystring(void)				// this routine prints through the screen buffer
	{									// moving one pixel at a time
	signed char x=32,y=0;				// I made these signed so I could print 
	for(y = 0;y  < 96 ;y++)				// to nowhere so I could produce the scrolling effect
		{
		clr();							// Clear the display buffer
		strput("HELLO WORLD!!",x--,0);	// adjust the scrolling string
		Blit();							// pass to screen buffer
		__delay_ms(100);				// time to view
		}
	}

void main(void)
	{
	int s;
	ADCON1 = 0x6;						// ALL digital
	T2CON = 0x1e;						// T2 on, 16:1 pre scale
	PR2 = 109;							// timer preload value ( equates to 1.4mS with 20mhz crystal)
	TMR2IE = 1;							// enable timer 2 interrupt
	PEIE = 1;							// enable peripheral interrupt
	GIE = 1;							// enableglobal interrupt
	TRISB = 0;							// Port B as output...
	TRISC = 0;							// Port C as ouput...
	animation();
	displaystring();
	while(1)
		{
		clr();
		if(s==0) strput("LOL",0,0);   			// Here's the message
		if(s==1) strput(" LOL",0,0);
		if(++s == 2) s=0;
		__delay_ms(500);
		Blit();
		}
	}	// End main

Thre are two external files ... The animation and the font... The font is slightly different as the screen writes are for row orientation..
 
Last edited:
Thanks for the help...
are using using another external animation file where is it??
and why are you using different font? pls give it...
 
Ok the animation file.... I have remarked so you can see how it works

The ball in the bouncing ball is the "°" symbol but its easier to define "]" as that character as the "°" symbol isn't on the keyboard..
 

Attachments

  • anim.c
    5.4 KB · Views: 163
  • LED tutorial2.c
    4.3 KB · Views: 220
The code on display is doing nothing why???
I have programed the chip but the led is showing random/damage effect not taht what u have send, why??
i have connected the Rc4 and 3 and RSt to Vcc
 
Each matrix must be the right way round.... I haven't got the circuit to hand but A,B,C etc are at the bottom and 123 etc at the top

YOU MUST change the properties of each matrix in ISIS to "NOT INVERT"

Are you using the same shift registers that I'm using?
 
One other thing.... I didn't mention the order of the shift registers...

The scan is row by row... When I say row I mean complete row all four matrices..


scan.PNG

This way I can use the memory as linear... Perfect for drawing..
 
Are you using the same shift registers that I'm using?

Hi,

I am using my old display that i was using before i have tied RST to Vcc. 74hc164
if you are using row scanning then why are using scanning column by ISR ....and how are you feeding serial data??
I have more question first i want to clear this!!
 
if you are using row scanning then why are using scanning column by ISR ....and how are you feeding serial data??
I'm not!! I'm using row scanning.. The ISR doesn't need to change as there are as many rows as columns...

If you are using your old display you would need to change the way you write your data to the buffer..

I scan a full row... You scan a full matrix..

and how are you feeding serial data??
There is no serial data... I feed all 8 led's in a single row from portb

All I do is ground the leds row by row...

I have been following your progress on AAC.. If you want to use animation... This is definitely the best option...

Remember your title of this thread How to use interrupt in pic16f877a in c??

I am trying to get you to use interrupts...
 
I'm not!! I'm using row scanning.. The ISR doesn't need to change as there are as many rows as columns...

If you are using your old display you would need to change the way you write your data to the buffer..

I scan a full row... You scan a full matrix..

I am still confused a image can help...what are you trying to do?
 
Its a union. This is a data structure in which all the elements are contained within the same data space.

you also said this, are you using unions please explain little bit more about your code..
 
Hitech HAS a really good interrupt example..
Code:
#include	<htc.h>

/*
 *	Interrupt test for PIC 
 *
 *	Copyright (C)1997 HI-TECH Software.
 *	Freely distributable.
 */

static volatile long	count;
static volatile bit	bad_intr;

void
main(void)
{
	/* setup stuff */

	T0CS = 0;		// Timer increments on instruction clock
	TRISB = 0xFE;		// Port B bit 0 is output 
	T0IE = 1;		// Enable interrupt on TMR0 overflow
	GIE = 1;		// Global interrupt enable
	for(;;)
		CLRWDT();	// Idly kick the dog
}

static void interrupt
isr(void)			// Here be interrupt function - the name is
				// unimportant.
{
	if(!T0IF)		// Was this a timer overflow?
		bad_intr = 1;	// NO! Shock horror!
	count++;		// Add 1 to count - insert idle comment
	T0IF = 0;		// Clear interrupt flag, ready for next
	PORTB ^= 1;		// toggle bit 0 of Port B, to show we're alive
}

I must admit that the stimulus in MPLAB is a bit of a grind.... I'll make a stimulas file and some code for the RB0 int, so you can see how it works!!

what use of interrupt exactly? i think i read someone post that interrupt we cant detect as it occur very fast...
 
you also said this, are you using unions please explain little bit more about your code..

I WAS going to use a union... But I though if we did a basic scanning system (Row scanning was your idea ) You could animate the screen FAR FAR easier than you have been doing..

Let me explain.


Once you are scanning the complete display, just the same as your computer scans its monitor, From left to right from top to bottom... Most imaging software creates their images this way..... All you need to do is paste the image into a buffer... You need this for speed as virtually no image processing is needed..

I have implemented a technique called "clipping"... Any pixel outside the drawing surface isn't drawn... This way you could have a larger picture than the display and scroll up, down, left or right just by changing the initial x,y value.... You can create frames in "Paint" and use that "FastLCD" program to create your binary images... Then you can blit your backbuffer to the displaybuffer in milliseconds... creating any animation you want.... If you create a string ie... "Hello world!!!"... This has 14 characters 14x8 pixels or 114 pixels long.. If you print the string to the buffer... ( clear the buffer first )
Code:
for(i=32;i> -96;i--)
   {
   clr();
   strput(str,i,0);
   blit();
   __delay_ms(100);
   }
The first character STARTS at 32,0... "Off screen" so none of the rest of the string is printed..

When "i" becomes negative, all the pixels negative are "Off screen" so they are not printed, all the pixels positive will..
That routine above will print the string, in full, across the display but only the pixels that fall in between 0 and 31 will be seen!!!
 
what use of interrupt exactly? i think i read someone post that interrupt we cant detect as it occur very fast...

You should really start your own thread if you need to ask something....

The idea of interrupts is mainly for convenience... Lets say you have a keypad connected to PORTB... You can poll the keypad all day long if you need to, but if you need to be getting on with some process and polling the keypad is taking some valuable ticks... You need to use the interrupt to read in PORTB and assign the key input to a variable that you can use in you main program...

Or if you have data coming in on the serial port to fast for you to handle... For example your main super loop takes 200mS to complete and your data is coming in at a rate of 199mS between packets... You know if you poll the serial port your going to miss one or two packets... Then you need to read the uart "on the fly" so you DON'T miss anything.

As I sad before... Once you get your head around using interrupts, you'll wonder why you didn't use them all the time...
 
Code:
for(i=32;i> -96;i--)
   {
   clr();
   strput(str,i,0);
   blit();
   __delay_ms(100);
   }

The first character STARTS at 32,0...?? "Off screen" so none of the rest of the string is printed..

When "i" becomes negative, all the pixels negative are "Off screen" so they are not printed, all the pixels positive will..
That routine above will print the string, in full, across the display but only the pixels that fall in between 0 and 31 will be seen!!!

Still not so clear especially your deep logic behind this??
why -ve I loop and
Code:
strput(str,i,0);
   blit();

logic you are using is going over my head......
 
Take a look at my scroll logic... This is a snapshot of x at 32 then at 8 and lastly at -16

The four matrices are highlighted...

scroll logic.png


The string "HELLO!" is first printed at 32,0 so nothing appears as every pixel is outside the display area ( clipped).

The string is then printed at 31,30,29.... and you will only see the partial string...

As you can see at position "8" the letters "HEL" are visible.... And eventually at -16 you can see "LLO!" ... Quite simple really.
 
OK, x indicate the number where the display is starting.....
anyway i was searching strput is this C command?? but i can't find this in Google also the use of it?
and you full code is also using :

Code:
void pixel(signed char x,signed char y,int cond)
	{
	int tmp;
	char pix,msk;
	if(x<0 || y<0) return;			// outside drawing limits negative
	if(x>31 || y>7) return;			// outside drawing limits positive
	tmp = (y << 2) + (x>>3);		// Linear position
	pix = x%8;						// pixel required
	pix = pow[ pix];
	msk = backbuffer[tmp];			// get exsisting data
	if(cond == 2)
		pix ^= msk;					// XOR data to screen
	if (cond == 1)
		{
		pix = ~pix;
		pix &= msk;					// AND data to screen
		}
	if(cond == 0)
		pix |= msk;					// OR data to screen
	backbuffer[tmp] = pix;			// apply changes
	}

what is linear here?? and cond =0/1/2 mean??
I am confused with full code that why going through it one by one!!
 
anyway i was searching strput is this C command?? but i can't find this in Google also the use of it?

Its MY routine... two functions under the pixel routine....

The pixel routine lights an individual LED

The LED matrices make up a small screen of 32x8 pixels ( think of pixels as small dots... Each LED is a dot..)

The pixel routine determines the position of the LED you wish to light ... READ THE REMARKS...

pix (LED we want to change) ^= msk( LED status now);

This takes the status of LED's in a single row and XOR's the new LED value.. ( if its not the same invert it)

pix (LED we want to change) = ~msk( LED status now);
pix (LED we want to change) &= msk( LED status now);

This takes the status of the LED's.. Complemets them and AND's the new value ( turns it off)

pix (LED we want to change) |= msk( LED status now);

This just turns the new LED on...
 
Code:
void interrupt ISR()					// This just swaps the buffer to the display
	{
	if(TMR2IF)							// Make sure its the timer interrupt.
		{
		PORTB = 0;						// Clear old data first
		if(displayPointer == 0 )  		// 1st frame..
			RC4 = 1;					// Data = 1 on the first clock only
		RC3 = 1;
		__delay_us(20);					// Clock the shift registers
		RC3 = 0;
		RC4 = 0;						// Make sure data stays low for the rest of the cycles
		PORTB = buffer[displayPointer];	// [B]Move buffer row by row( 4 row sections per row )[/B]		
		if(++displayPointer==32) 		// 32 LED row sections in total
			displayPointer = 0;			// Back to first row..
		}
	TMR2IF = 0;							// Clear timer 2 interrupt flag
	}
Move buffer row by row( 4 row sections per row )
what do you mean by this????
the code is same as you have done this before in column scanning scrolling....
 
what do you mean by this????
the code is same as you have done this before in column scanning scrolling....


Aha!! You are very observant!!... Look at the shift register outputs.... Each one accesses the rows in turn.

The first output ( Q0 ) is connected to matrix row 1
The second ( Q1 ) is connected to matrix 2 row 1
The third ( Q2 ) .... third matrix row 1
Then ( Q3 ) ... forth matrix row 1

BUT THEN!!

(Q4 ) is connected to the first matrix row 2
...
.. so on....

The changes needed were in the hardware...
 
Status
Not open for further replies.

New Articles From Microcontroller Tips

Back
Top