CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to CCS Technical Support

Unable to write character '0' (zero) on LCD using flex_LCD

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
Shaheers



Joined: 23 Sep 2013
Posts: 14

View user's profile Send private message

Unable to write character '0' (zero) on LCD using flex_LCD
PostPosted: Mon Sep 23, 2013 1:50 pm     Reply with quote

I am using ccs compiler PCM 4.114 and using a PIC 16F887 uC.

I am unable to write zero on lcd as i am using flex_lcd.c

I found ccs's keypad and lcd routines useless for me so i use flex_lcd for LCD and write my own code for 4x3 keypad.

All keys are working fine but i am unable to write zero.
I am testing it on Proteus.
All the code i use are as follows:

Main program file:
Code:

void main()
{
char key;

lcd_init();
lcd_putc("Starting ...\n");

while(TRUE)
  {
   key=get_key();
   if(key!='H'){
   
         lcd_putc(key);
         delay_ms(50);
     }
  }
}

Config file:
Code:

#include <16F887.h>

#FUSES NOWDT                    //No Watch Dog Timer
#FUSES INTRC_IO                 //Internal RC Osc, no CLKOUT
#FUSES NOPUT                    //No Power Up Timer
#FUSES MCLR                     //Master Clear pin enabled
#FUSES NOPROTECT                //Code not protected from reading
#FUSES NOCPD                    //No EE protection
#FUSES BROWNOUT                 //Reset when brownout detected
#FUSES IESO                     //Internal External Switch Over mode enabled
#FUSES FCMEN                    //Fail-safe clock monitor enabled
#FUSES NOLVP                    //No low voltage prgming, B3(PIC16) or B5(PIC18) used for I/O
#FUSES NODEBUG                  //No Debug mode for ICD
#FUSES BORV40                   //Brownout reset at 4.0V
#FUSES NOWRT                    //Program memory not write protected

#use delay(int=8000000)

LCD file:
Code:

// flex_lcd.c

// These pins are for the Microchip PicDem2-Plus board,
// which is what I used to test the driver.  Change these
// pins to fit your own board.

#define LCD_DB4   PIN_D4
#define LCD_DB5   PIN_D5
#define LCD_DB6   PIN_D6
#define LCD_DB7   PIN_D7

#define LCD_E     PIN_D1
#define LCD_RS    PIN_D0
#define LCD_RW    PIN_D2

// If you only want a 6-pin interface to your LCD, then
// connect the R/W pin on the LCD to ground, and comment
// out the following line.

//#define USE_LCD_RW   1     

//========================================

#define lcd_type 2        // 0=5x7, 1=5x10, 2=2 lines
#define lcd_line_two 0x40 // LCD RAM address for the 2nd line


BYTE const LCD_INIT_STRING[4] =
{
 0x20 | (lcd_type << 2), // Func set: 4-bit, 2 lines, 5x8 dots
 0xc,                    // Display on
 1,                      // Clear display
 6                       // Increment cursor
 };
                             

//-------------------------------------
void lcd_send_nibble(BYTE nibble)
{
// Note:  !! converts an integer expression
// to a boolean (1 or 0).
 output_bit(LCD_DB4, !!(nibble & 1));
 output_bit(LCD_DB5, !!(nibble & 2));
 output_bit(LCD_DB6, !!(nibble & 4));   
 output_bit(LCD_DB7, !!(nibble & 8));   

 delay_cycles(1);
 output_high(LCD_E);
 delay_us(2);
 output_low(LCD_E);
}

//-----------------------------------
// This sub-routine is only called by lcd_read_byte().
// It's not a stand-alone routine.  For example, the
// R/W signal is set high by lcd_read_byte() before
// this routine is called.     

#ifdef USE_LCD_RW
BYTE lcd_read_nibble(void)
{
BYTE retval;
// Create bit variables so that we can easily set
// individual bits in the retval variable.
#bit retval_0 = retval.0
#bit retval_1 = retval.1
#bit retval_2 = retval.2
#bit retval_3 = retval.3

retval = 0;
   
output_high(LCD_E);
delay_cycles(1);

retval_0 = input(LCD_DB4);
retval_1 = input(LCD_DB5);
retval_2 = input(LCD_DB6);
retval_3 = input(LCD_DB7);
 
output_low(LCD_E);
   
return(retval);   
}   
#endif

//---------------------------------------
// Read a byte from the LCD and return it.

#ifdef USE_LCD_RW
BYTE lcd_read_byte(void)
{
BYTE low;
BYTE high;

//output_high(LCD_RW);
delay_cycles(1);

high = lcd_read_nibble();

low = lcd_read_nibble();

return( (high<<4) | low);
}
#endif

//----------------------------------------
// Send a byte to the LCD.
void lcd_send_byte(BYTE address, BYTE n)
{
output_low(LCD_RS);

#ifdef USE_LCD_RW
while(bit_test(lcd_read_byte(),7)) ;
#else
delay_us(60);
#endif

if(address)
   output_high(LCD_RS);
else
   output_low(LCD_RS);
     
 delay_cycles(1);

#ifdef USE_LCD_RW
output_low(LCD_RW);
delay_cycles(1);
#endif

output_low(LCD_E);

lcd_send_nibble(n >> 4);
lcd_send_nibble(n & 0xf);
}

//----------------------------
void lcd_init(void)
{
BYTE i;

output_low(LCD_RS);

#ifdef USE_LCD_RW
output_low(LCD_RW);
#endif

output_low(LCD_E);

delay_ms(15);

for(i=0 ;i < 3; i++)
   {
    lcd_send_nibble(0x03);
    delay_ms(5);
   }

lcd_send_nibble(0x02);

for(i=0; i < sizeof(LCD_INIT_STRING); i++)
   {
    lcd_send_byte(0, LCD_INIT_STRING[i]);
   
    // If the R/W signal is not used, then
    // the busy bit can't be polled.  One of
    // the init commands takes longer than
    // the hard-coded delay of 60 us, so in
    // that case, lets just do a 5 ms delay
    // after all four of them.
    #ifndef USE_LCD_RW
    delay_ms(5);
    #endif
   }

}

//----------------------------

void lcd_gotoxy(BYTE x, BYTE y)
{
BYTE address;

if(y != 1)
   address = lcd_line_two;
else
   address=0;

address += x-1;
lcd_send_byte(0, 0x80 | address);
}

//-----------------------------
void lcd_putc(char c)
{
 switch(c)
   {
    case '\f':
      lcd_send_byte(0,1);
      delay_ms(2);
      break;
   
    case '\n':
       lcd_gotoxy(1,2);
       break;
   
    case '\b':
       lcd_send_byte(0,0x10);
       break;
   
    default:
       lcd_send_byte(1,c);
       break;
   }
}

//------------------------------
#ifdef USE_LCD_RW
char lcd_getc(BYTE x, BYTE y)
{
char value;

lcd_gotoxy(x,y);

// Wait until busy flag is low.
while(bit_test(lcd_read_byte(),7));

output_high(LCD_RS);
value = lcd_read_byte();
output_low(lcd_RS);

return(value);
}
#endif


and keypad code:
Code:

#define col0 PIN_B4 // columns are output
#define col1 PIN_B5
#define col2 PIN_B6
#define row0 PIN_B0  // rows are as input
#define row1 PIN_B1
#define row2 PIN_B2
#define row3 PIN_B3

// Keypad layout:

char get_key() {
char k;
delay_ms(50);
k='H';   // a dummy value ,if no key is pressed
output_high(col0);
output_high(col1);
output_high(col2);
delay_ms(50);
output_low(col0);
delay_ms(10);
port_b_pullups(true);
if(input(row0)==0)
{delay_ms(50);if(input(row0)==0) {k= '1'; return (k);}}

else if(input(row1)==0)
{delay_ms(50);if(input(row1)==0) {k= '4';return (k);}}

else if(input(row2)==0)
{delay_ms(50);if(input(row2)==0) {k= '7';return (k);}}

else if(input(row3)==0)
{delay_ms(50);if(input(row3)==0) {k= '*';return (k);}}

output_high(col0);
output_low(col1);
delay_ms(10);
if(input(row0)==0)
{delay_ms(50);if(input(row0)==0) {k= '2';return (k);}}

else if(input(row1)==0)
{delay_ms(50);if(input(row1)==0) {k= '5';return (k);}}

else if(input(row2)==0)
{delay_ms(50);if(input(row2)==0) {k= '8';return (k);}}

else if(input(row3)==0)
{delay_ms(50);if(input(row3)==0) {k= '0';return (k);}}

output_high(col1);
output_low(col2);
delay_ms(10);

if(input(row0)==0)
{delay_ms(50);if(input(row0)==0) {k= '3';return (k);}}

else if(input(row1)==0)
{delay_ms(50);if(input(row1)==0) {k= '6';return (k);}}

else if(input(row2)==0)
{delay_ms(50);if(input(row2)==0) {k= '9';return (k);}}

else if(input(row3)==0)
{delay_ms(50);if(input(row3)==0) {k= '#';return (k);}}
else {delay_ms(10); return('H');}}
temtronic



Joined: 01 Jul 2010
Posts: 9243
Location: Greensville,Ontario

View user's profile Send private message

PostPosted: Mon Sep 23, 2013 6:34 pm     Reply with quote

Easy answer..

there's a 'bug' in Proteus !

Really, if all 11 of the other keypad presses are OK, and only the '0' is bad, then it MUST be another Proteus bug.Simple basic logic.

Since you're not dealing with a real PIC, LCD module,and keypad and the ONLY hardware is really software( Proteus), the conclusion is that Proteus is once again at fault.Please read PIC101 sticky.

Also...
both the keypad and LCD driver's that CCS supply work 100% with real PIC,keypad and LCD modules.They have for years.That they 'don't work' using Proteus again shows several flaws in Proteus.


hth
Jay
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Mon Sep 23, 2013 6:47 pm     Reply with quote

Quote:
I am using ccs compiler PCM 4.114 and using a PIC 16F887 uC.

char get_key() {
char k;
delay_ms(50);
k='H'; // a dummy value ,if no key is pressed
output_high(col0);
output_high(col1);
output_high(col2);
delay_ms(50);
output_low(col0);
delay_ms(10);
port_b_pullups(true);
if(input(row0)==0)

I can't help you with Proteus but using 'true' for port_b_pullups() is wrong.
The 16F887 data sheet says:
Quote:

3.4.2 WEAK PULL-UPS

Each of the PORTB pins has an individually configurable
internal weak pull-up. Control bits WPUB<7:0> enable or
disable each pull-up (see Register 3-7).

This means you don't use 'True' or 'False' as a parameter for
port_b_pullups() with this PIC.

The CCS manuals says:
Quote:
port_x_pullups ( )

Syntax:
port_b_pullups (value)

Parameters: value is TRUE or FALSE on most parts, some parts that allow
pullups to be specified on individual pins permit an 8 bit int here,
one bit for each port pin.

This means if you want to turn on all pullups on PortB, you need to use
a parameter of 0xFF instead of 'True'.

Also, the PortB pullups are weak and do not pull up instantly. It takes
a little time, depending on the amount of pin capacitance and any other
capacitance in the trace or the device that it's connected to. Therefore,
add a small delay after enabling the pull-ups. 10 usec should be enough.
Quote:

port_b_pullups(0xFF); // Turn on all pull-ups
delay_us(10); // Allow time for them to pull up
if(input(row0)==0)
Shaheers



Joined: 23 Sep 2013
Posts: 14

View user's profile Send private message

PostPosted: Tue Sep 24, 2013 7:56 pm     Reply with quote

Thanks for the reply, there is a minor confusion that can we call functions in a functions freely or is there any limit eg.
Code:

main()
{

function1();
}

function1(){

instructions;

function2();

}


function3(){
instructions;

function1();
}
Ttelmah



Joined: 11 Mar 2010
Posts: 19538

View user's profile Send private message

PostPosted: Wed Sep 25, 2013 2:03 am     Reply with quote

Start with this:

Code:

void main(void)
{
    //One huge unbroken lump of code
}


This immediately has 'limits', since the chip ROM is 'paged', and even if you have lots of spare space in the chip, the 'unbroken lump', can't be split up to go onto separate pages...

Then:
Code:

void one_function(void)
{
}

void another_function(void)
{
}

void yetanother_function(void)
{
}

void main(void)
{
    one_function();
    another_function();
    yetanother_function();
    ....
    //yet more functions
}

This allows the code to be broken up, and is effectively unlimited, since no function calls another, and the compiler is 'smart enough' to actually combine multiple functions to be a single code block. It puts the bits together to try to minimise the overheads involved.

Then:
Code:

void one_function(void)
{
    //Possibly more functions
}

void another_function(void)
{
    one_function();
}

void yetanother_function(void)
{
    another_function();
}

void main(void)
{
    yetanother_function();
    ....
    //yet more functions
}

Now here each function is called inside another. Potentially this uses 'stack' space, to hold the return address. The PIC has a limited amount of stack storage (depends on the chip you are using). Again though the compiler is 'smart', and if single functions call functions in only one place, will actually build them to be compiled 'inline' to save stack levels. Generally unless you have lots of functions called from lots of locations, each calling lots more functions inside themselves, this is unlikely to cause problems, _but it can_. At the top of the .lst file generated when you compile a program, there is a little line, telling you the 'worst case' stack usage, and the maximum size, so you can check this is not a problem.

Then:
Code:

void one_function(void)
{
    yetanother_function();
}

void another_function(void)
{
}

void yetanother_function(void)
{
    one_function();
}

void main(void)
{
    yetanother_function();
    ....
    //yet more functions
}

This is not allowed.

Here when you call 'yetanother_function', it calls 'one_function', which then calls 'yetanother_function'. So it is tryiing to run 'yetanother_function', inside itself. This is called 'recursion'. Now, more complex processors, have 'data stacks', (as well as the simple 'call stack' on the PIC). With these you can save multiple copies of the variables used inside a function on this stack, and recursion can be supported. On the PIC (except on the larger DsPIC's), there is no hardware support for this, so 'recursion' is not permitted. Even on these other processors, there are problems though, since recursion can result in the stack required growing exponentially.....

So, there are limits everywhere. Generally 'logic' is your friend. Since the compiler will attempt to put small bits of code, even if declared as a separate function 'inline' (put them where they are called), being logical by having small functions to make it easy to understand a simple operation as an 'entity', helps code clarity, and costs nothing.

There is another limitation. Any function called inside an interrupt routine, can (effectively) be called anywhere from the main code. If you use the same function in the external code, this could potentially cause recursion. Hence the compiler, will automatically _disable interrupts_ inside the function, if it is called in the main code.

Best Wishes
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group