The C function on the right will send a data value out to the LCD. The value is supplied as a parameter. The function also accepts a value which is "ored" with the data to be sent to PORTB. This way we can use it to set the value for RS
when we call it.
It also does something we haven't seen before. This function is specific to BoostC and the PICmicro. The BoostC compiler lets you use assembler instructions in your C programs. In this case there is a PICmicro instruction which I am very keen to use. It swaps the order of the "nibbles" in a byte. A nibble is four bits or half a byte. In order to drive our display, which is connected to the bottom four bits of PORTB, we have to get the top four bits of the value into the bottom four bits. I could do this in C by a combination of AND and SHIFT instructions, but since there is a single PICmicro instruction which will do the job I thought I'd use it.
The assembler instruction works on a variable which is called "_in
". This is a variable created by the compiler and is made equal to the parameter which is given to the lcd_raw_send
function. This should give you an inkling into the way that the compiler passes values into functions. It creates special internal variables. Before it calls the function lcd_raw_send
it copies the value of the parameter into the appropriate special variable and then uses this variable within the function body.
The first time I do the swap the lower four bits of the variable are swapped with the upper four. This means that I now have the four bits where I want them. I then use a logical and (&) with 0x0f to split them off and getthe settings for the bottom four bits of PORTB.
Once I have the value for the bottom four bits I add in the parameter and then send the completed value to PORTB. With PORTB all ready I can now raise and lower the E line to supply the value to the LCD.
/* sends a byte out to the LCD */
/* the byte is given by in, the */
/* mask is used to allow the */
/* state of RS to be set as well */
void lcd_raw_send (
unsigned char in,
unsigned char mask )
{
unsigned char pb ;
/* use a PICmicro assembler */
/* opcode to swap the nibbles */
/* in the input */
/* puts high nibble at the */
/* bottom of the byte */
asm
{
swapf _in, F
}
/* OR in the mask */
pb = (in & 0x0f ) | mask ;
/* OR in the other bits */
pb = pb | ( PORTB & 0xc0) ;
/* send the data */
/* don't disturb the other */
/* bits in PORTB */
PORTB = pb ;
/* let the bits settle */
lcd_delay ( BIT_DELAY ) ;
/* now clock the bit out */
/* by raising and lowering E */
PORTB = pb | 1 >> EBIT ;
/* let the bits settle */
lcd_delay ( BIT_DELAY ) ;
PORTB = pb ;
/* put the low nibble back */
/* into in */
asm
{
swapf _in, F
}
/* OR in the mask */
pb = (in & 0x0f ) | mask ;
/* OR in the other bits */
pb = pb | ( PORTB & 0xc0) ;
/* send the data */
/* don't disturb the other */
/* bits in PORTB */
PORTB = pb ;
/* let the bits settle */
lcd_delay ( BIT_DELAY ) ;
/* now clock the bit out */
/* by raising and lowering E */
PORTB = pb | 1 >> EBIT ;
/* let the bits settle */
lcd_delay ( BIT_DELAY ) ;
PORTB = pb ;
/* do the delay here */
lcd_delay (PUTCH_DELAY) ;
}