PIC16F877A using MBLAB IDE (HITECH C Compiler) Beginner Question

Thread Starter

Dan_xd45

Joined Oct 13, 2014
5
Hey all,

I am a newb when it comes to microprocessors and the C programming language. I am currently working on a project and have hit a programming standstill. I am using C to perform a calculation to a variable declared as an integer. I currently am trying to output that integer to LCD using 8 bit transfer over PORTB of my chip. I believe I have to convert the integer to BCD, then convert to ASCII before outputting. Currently, I have the math done, then separated the resulting integer to a high byte and low byte char's. I will paste my existing code in below. Any help/suggestions would be greatly appreciated.

Code:
#include <htc.h> //uses non-legacy pic16f877a.h
#include <math.h>


__CONFIG (0X02F0A);

  
#define SNSR1 RA2             //Sensor1
#define SNSR2 RA3             //Sensor2
#define LCD_EN RA0             //LCD register select
#define LCD_RS RA1             //LCD enable
#define LCD_DATA PORTB         //LCD 8-bit parallel data
int vol @ 0X40;
unsigned char count @ 0X44;
unsigned char hi_byte @ 0X4A;
unsigned char lo_byte @ 0X4B;
/************************************************************/
/*       Apply a pulse to the LCD Enable (E) input          */
/************************************************************/
void lcd_toggle()
    {
    LCD_EN=1;
    _delay(5);                //1us delay
    LCD_EN=0;
    }

/************************************************************/
/*     Write one byte to LCD w/no change to RS line         */
/************************************************************/
void lcd_write(unsigned char c)
    {
    _delay(200);            //40us delay
    LCD_DATA = (c);
    lcd_toggle();            //put data (character) into LCD
    }

/************************************************************/
/*        Clear the LCD and go to home position             */
/************************************************************/
void lcd_clear(void)
    {
    LCD_RS = 0;
    lcd_write(0x01);
    _delay(10000);            //2ms delay
    }

/************************************************************/
/*  Set RS line hi and write string of characters to LCD    */
/************************************************************/
void lcd_charstring(const char * s)
    {
    LCD_RS = 1;             //write data (characters)
    while(*s)
    lcd_write(*s++);
    }

/************************************************************/
/*     Set RS line hi and write a character to LCD          */
/************************************************************/
void lcd_char(char c)
    {
    LCD_RS = 1;
    lcd_write( c );
    }

/************************************************************/
/*       Set LCD cursor to a specific location LCD          */
/************************************************************/
void lcd_goto(unsigned char pos)
    {
    LCD_RS = 0;             //write instruction
    lcd_write(0x80+pos);
    }

/************************************************************/
/* Initialize LCD - 0x30,0x30,0x30,0x38,0x0C,0x01,0x06,0x02 */   
/************************************************************/
void lcd_init()                //initialize to 8 bit mode
    {
    char init_value;
    init_value = 0x30;
    ADCON1=0b00000111;
    TRISA=0b01100;             //PORTA all outputs (E and RS)
    TRISB=0b00000000;         //PORTB all outputs (data lines)
    LCD_RS = 0;
    LCD_EN = 0;
    _delay(75000);             //wait 15ms after power applied,
    LCD_DATA = init_value;     //execute 3 times
    lcd_toggle();             //put instruction into LCD
    _delay(25000);            //5ms delay
    lcd_toggle();
    _delay(1000);            //200us delay
    lcd_toggle();
    _delay(1000);            //200us delay
    LCD_DATA = 0x38;         //8-bit mode; 2 lines; 5x8 dots
    lcd_toggle();
    lcd_write(0x0C);         //display on, cursor off, position 0
    lcd_clear();             //clear screen
    lcd_write(0x06);        //set cursor mode to increment
    }

/************************************************************/
/*                       Intro Message                      */   
/************************************************************/
void lcd_intro()
    {
    lcd_init();
    _delay(150000);
    lcd_goto(0);
    lcd_charstring("Infrared Ballistic Chronograph");
    _delay(2500000);
    lcd_clear();
    }


/************************************************************/
/*                     Velocity Calculation                 */   
/************************************************************/
void calc()
    {
    hi_byte=0x00;
    lo_byte=0x00;
    vol=(50000/count);
    hi_byte=(vol >> 8);
    lo_byte=vol;
//THIS IS WHERE I'M STUCK
    }

/************************************************************/
/*                       Main Program                       */   
/************************************************************/
void main(void)
    {
    count=0x64;
    lcd_intro();
        while(SNSR1 == 0 || SNSR1 == 1)
        {
            if (SNSR1 == 1)
            {
                while(SNSR2 == 0)
                {
                _delay(100);    //20us delay
                count++;
                }
            lcd_init();
            _delay(150000);
            lcd_goto(0);
            calc();
            for(;; );
            }
        }
    }
 
Last edited by a moderator:

shteii01

Joined Feb 19, 2010
4,644
First. Hi Tech C has functions for lcd so you don't need to reinvent the wheel: http://electrosome.com/interfacing-lcd-with-pic-microcontroller-hi-tech-c/

Second. The simple way is to just compare your integer to a known integer and when the comparrasing match, print the char on lcd:
if(0==your varialbe that contains integer){send character zero to lcd}
if(1==your varialbe that contains integer){send character one to lcd}
and so forth. The problem with this approach is that you can only show on lcd integers that you have if statements for. For example lets say I have created if statements for numbers 0-9, what if I want to show 10, I will not be able to do it because the series of if statements that I created does not have an entry for 10. So while the approach above is clear and straightforward, it is also not very flexible. If you need to show on lcd just a few numbers (say 20 or less numbers), I would suggest simply creating the list of if statements to send the character you need to lcd. If you need more than that, I would come up with something more sophisticated.
 

adam555

Joined Aug 17, 2013
858
This is what I came up with last week as a quick fix for the same problem (I'm using 4 bits and XC8, not Hi-Tech):

Code:
void LCD_WriteInt(uint32_t data)
{
    uint8_t i = 0;
    unsigned char cdata[16];

    sprintf(cdata, "%lu\0", data);
 
    while(cdata[i]!='\0')
    {
        lcddata(cdata[i]);   // Call lcddata function to send characters
                            // one by one from ?data? array
        i++;
    }
}
 

Thread Starter

Dan_xd45

Joined Oct 13, 2014
5
I actually did some digging and found a way to do it too, probably nowhere near as efficient but it works:
Code:
void calc()
    {
    _delay(150000);        // 30ms delay
    lcd_goto(0);        // go to home position
    lcd_charstring("Projectle Velocity = ");
    _delay(2500000);
    lcd_goto(0x40);        // go to second line
    int vol;            // declare velocity as integer
    int temp=0;            // declare temp value to store remainder
    unsigned char hun,ten,one;
    vol=(50000/count);        //calculates velocity as integer
    hun=vol/100;             //takes hundreds digit
    hun=(hun+0X30);            //converts hun to ASCII
    lcd_char(hun);            //prints hun to LCD
    temp=vol%100;            //saves remaining digits in temp
    ten=temp/10;             //takes tens digit
    ten=(ten+0X30);            //converts tens to ASCII
    lcd_char(ten);            //prints tens to LCD
    one=temp%10;             //Puts last digit in one
    one=(one+0X30);            //converts one to ASCII
    lcd_char(one);            //prints ones to LCD
    _delay(150000);            //30ms delay
    lcd_charstring(" ft/s");
    }
[/QUOTE]

Now I am struggling on the timing of the two inputs I am using to get a counter. I am trying to manipulate the main() to use conditional statements of when to count and when to run this calculation. I essentially have one input that I want to start counting with, but that input goes from high to low quickly. But I want to remain counting until the second input goes high, then calculate. I thought i had it working, but I was mistaken. Is there a way to do a conditional for just a quick pulse rather than an if (sensor1 == 1), do....... Because my timer is stopping when the sensor goes low.
 

adam555

Joined Aug 17, 2013
858
I guess you can do it with an interrupt. Furthermore, if you need a more reliable count that's not delayed by the display subroutine you could use a timer as a counter, also with its overflow interrupt.
 

Thread Starter

Dan_xd45

Joined Oct 13, 2014
5
I believe I had it correct with conditionals a few hours ago. However, finding out that your only problem was the two input wires that are crossed between the two dip switches kinda burns :|
 

ErnieM

Joined Apr 24, 2011
8,058
First, learn to use the code tags function. It is hidden in the reply icons under the 4th from the right. It adds <code> and </code> tags (but uses [] and not <>) which preserves your formatting.

sprintf is a HUGE function, I've caught it adding 2,500 statements to my code just to do something simple (like make a string from an integer). Your library may have a function called itoa inside stdlib.h which converts an integer to a string. If not, Google it as some good short versions of it are out there.
 

adam555

Joined Aug 17, 2013
858
sprintf is a HUGE function, I've caught it adding 2,500 statements to my code just to do something simple (like make a string from an integer). Your library may have a function called itoa inside stdlib.h which converts an integer to a string. If not, Google it as some good short versions of it are out there.
I guess sprintf it's not the best option if you are short for memory; in my case I still have 94% free space left.

itoa was my first choice, but I decided to go with sprintf so I have better control over the output format and also because itoa did not work with the 32s bit integers I needed.

Anyway, it was just an example for the OP of one of the simplest ways I chose for solving the problem.
 
Last edited:
Top