Continue to Site

Welcome to EDAboard.com

Welcome to our site! EDAboard.com is an international Electronics Discussion Forum focused on EDA software, circuits, schematics, books, theory, papers, asic, pld, 8051, DSP, Network, RF, Analog Design, PCB, Service Manuals... and a whole lot more! To participate you need to register. Registration is free. Click here to register now.

[SOLVED] 16F887 > MikroC > minus « - » never display on lcd for negative values ...

Status
Not open for further replies.

Eric_O

Advanced Member level 4
Joined
May 31, 2020
Messages
104
Helped
0
Reputation
0
Reaction score
0
Trophy points
16
Activity points
995
Here under a former code obtained here. I insert a new routine for conversion of long to char ... but minus never display on LCD while counting negatives values ...
Some body have an idea ? 🤔
Merci !

Here under my code ...

C:
// LCD module connections :

                                        // VSS (pin  1) -> GND
                                        // VDD (pin  2) -> VCC
                                        // VEE (pin  3) -> middle pin contrast potentiometer
sbit LCD_RS at RB4_bit;                 // RS  (pin  4) -> portB.b4 (pin 37)
// RW not used.                         // RW  (pin  5) -> GND
sbit LCD_EN at RB5_bit;                 // EN  (pin  6) -> portB.b5 (pin 38)
                                        // D0  (pin  7) -> GND
                                        // D1  (pin  8) -> GND
                                        // D2  (pin  9) -> GND
                                        // D3  (pin 10) -> GND
sbit LCD_D4 at RB0_bit;                 // D4  (pin 11) -> portB.b0 (pin 33)
sbit LCD_D5 at RB1_bit;                 // D5  (pin 12) -> portB.b1 (pin 34)
sbit LCD_D6 at RB2_bit;                 // D6  (pin 13) -> portB.b2 (pin 35)
sbit LCD_D7 at RB3_bit;                 // D7  (pin 14) -> portB.b3 (pin 36)
                                        //     (pin 15) -> GND
                                        //     (pin 16) -> GND
sbit LCD_RS_Direction at TRISB4_bit;
sbit LCD_EN_Direction at TRISB5_bit;
sbit LCD_D4_Direction at TRISB0_bit;
sbit LCD_D5_Direction at TRISB1_bit;
sbit LCD_D6_Direction at TRISB2_bit;
sbit LCD_D7_Direction at TRISB3_bit;
/******************************************************************************/
// Declaration of variables :
float sec;                              // - 1.5 x 10 puissance 45 to + 3.4 x 10 puissance 38
//double sec;                           // - 1.5 x 10 puissance 45 to + 3.4 x 10 puissance 38
//long sec;
char texte[64];                         // 0 to 255
                                        // Pour Essais 16.3, 16.4 :
                                        // Variables ci-dessous sorties du main() pour les déclarer en global.
                                        // Le PIC 16F a moins de mémoire RAM et ROM que le PIC 18F.
unsigned char *pointeur_de_char;        // Déclaration d'un pointeur (*) de char "pointeur_de_char".
//char texte[] = "Counting ...";        // Déclaration d'un tableau "texte" de type char et initialisé avec la chaine de caractères "Counting ..." :
                                        // En n'indiquant aucun chiffre entre les cochets [], le compilateur ajustera automatiquement la taille du
                                        // tableau, et allouera en mémoire RAM, le bon nombre d'éléménts, soit 13 ...
char txt[13];
// Routines :
void LCD_E_pulse(void)
{
LCD_EN = 1;
Delay_us(5);
LCD_EN = 0;
}
void LCD_Write_Cmd(unsigned char octet)                        
LCD_RS = 0;                                                      // Select Command Register.
                                                                  // Send upper nibble.
LCD_D4 = ((octet & 0x10) == 0x10) ? 1 : 0;                       // Si ((octet & 0x10) == 0x10) alors LCD_D4 = 1 sinon = 0.
LCD_D5 = ((octet & 0x20) == 0x20) ? 1 : 0;                       // Si ((octet & 0x20) == 0x20) alors LCD_D5 = 1 sinon = 0.
LCD_D6 = ((octet & 0x40) == 0x40) ? 1 : 0;                       // Si ((octet & 0x40) == 0x40) alors LCD_D6 = 1 sinon = 0.
LCD_D7 = ((octet & 0x80) == 0x80) ? 1 : 0;                       // Si ((octet & 0x80) == 0x80) alors LCD_D7 = 1 sinon = 0.
LCD_E_Pulse();
                                                                  // Send lower nibble.
LCD_D4 = ((octet & 0x01) == 0x01) ? 1 : 0;                       // Si ((octet & 0x01) == 0x01) alors LCD_D4 = 1 sinon = 0.
LCD_D5 = ((octet & 0x02) == 0x02) ? 1 : 0;                       // Si ((octet & 0x02) == 0x02) alors LCD_D5 = 1 sinon = 0.
LCD_D6 = ((octet & 0x04) == 0x04) ? 1 : 0;                       // Si ((octet & 0x04) == 0x04) alors LCD_D6 = 1 sinon = 0.
LCD_D7 = ((octet & 0x08) == 0x08) ? 1 : 0;                       // Si ((octet & 0x08) == 0x08) alors LCD_D7 = 1 sinon = 0.
void LCD_Write_Data(char octet)                                
LCD_RS = 1;                                                      // Select Data Register.
void strConstRamCpy(unsigned char *dest, const code char *source)
while (*source)*dest ++ = *source ++;
*dest = 0;                                                       // Terminateur "0" fin de chaine de caractère.
void LCD_Write_CString_v2(char *msg)
int k;
k = 0;
//while(*(msg) > 0)                                              // FAIL.
while(*(msg + k) > 0)
  LCD_Write_Data(*(msg + k));                                     // Data pointée par (msg + k).
  k++;
  if (k > 15) break;                                              // Si k > 15 sortie de la boucle while ...
void LCD_CString_Position_v2(char row, char col, char *msg)
if (row == 1)
    {
     LCD_Write_Cmd((col & 0x0F)|0x80);                            // Print message on 1st row and desired location.
    }
else if (row == 2)
     LCD_Write_Cmd((col & 0x0F)|0xC0);                            // Print message on 2nd row and desired location.
LCD_Write_CString_v2(msg);                                       // OK.
void print_float_v7(char *flt, long number, char digits)
if (number < 0)
     number = - number;
     *(flt) = 45;                                                 // 45 = '-'
     *(flt + 1) = 32;                                             // 32 = space
if (number >= 0)
     *(flt) = 32;                                                 // 32 = space
  
if (digits == 2)
     *(flt + 2) = number / 1000000 + 48;
     //if (*(flt + 2) == 48) *(flt + 2) = 32;                     // 32 = space
     *(flt + 3) = ((number % 1000000) / 100000) + 48;
     *(flt + 4) = ((number % 100000) / 10000) + 48;
     *(flt + 5) = ((number % 10000) / 1000) + 48;
     *(flt + 6) = ((number % 1000) / 100) + 48;
     *(flt + 7) = ((number % 100) / 10) + 48;
     *(flt + 8) = ((number % 10) / 1) + 48;
     *(flt + 9) = 44;                                             // 44 = ','
     *(flt + 10) = ((number % 100) / 10) + 48;
     *(flt + 11) = (number % 10) + 48;
     *(flt + 12) = 0;
    else
       {
        *(flt + 2) = number / 100000 + 48;
        //if (*(flt + 2) == 48) *(flt + 2) = 32;                  // 32 = space
        *(flt + 3) = ((number % 100000) / 10000) + 48;
        *(flt + 4) = ((number % 10000) / 1000) + 48;
        *(flt + 5) = ((number % 1000) / 100) + 48;
        *(flt + 6) = ((number % 100) / 10) + 48;
        *(flt + 7) = 44;                                          // 44 = ','
        *(flt + 8) = (number % 10) + 48;
        *(flt + 9) = 0;
       }
void LCD_Init_v4 (void)                                        
Delay_ms(15);                                                    // LCD power ON initialization time >= 15 mS.
LCD_Write_Cmd(0x30);                                             // 4 datas bits > Initialization of LCD with nibble method (4 datas bits).
LCD_Write_Cmd(0x02);                                             // 4 datas bits > Initialization of LCD with nibble method (4 datas bits).
LCD_Write_Cmd(0x28);                                             // 4 datas bits > 2 lines display, 5 × 8 dot character font.
LCD_Write_Cmd(0x0C);                                             // 4 datas bits > Display ON. Cursor OFF.
LCD_Write_Cmd(0x06);                                             // 4 datas bits > Auto increment cursor.
LCD_Write_Cmd(0x01);                                             // 4 datas bits > Clear display.
Delay_ms(1);                                                     // Ajustable ... (indispensable, sinon affichage erratique à la mise sous tension)
// Main program :
void main()
ANSEL = 0;                                                // Configure AN pins as digital I/O.
ANSELH = 0;
C1ON_bit = 0;                                             // Disable Comparator 1.
C2ON_bit = 0;                                             // Disable Comparator 2.
PORTB = 0;
TRISB = 0;
PORTC = 0;
TRISC = 0;
// Essai 18.1 : OK
Lcd_Init_v4();                                            // Initialize LCD.
while(1)                                                  // Endless loop.
  unsigned char *pointeur_de_char;                         // Déclaration d'un pointeur (*) de char "pointeur_de_char".
  //char texte[] = "Counting ...";                         // Déclaration d'un tableau "texte" de type char et initialisé avec la chaine de caractères "Counting ..." :
                                                           // En n'indiquant aucun chiffre entre les cochets [], le compilateur ajustera automatiquement la taille du
                                                           // tableau, et allouera en mémoire RAM, le bon nombre d'éléménts, soit 13 ...
  char txt[13];
  pointeur_de_char = &texte[0];                            // pointeur_de_char pointe sur le premier élément du tableau "texte", soit texte[0].
                                                           // Autrement dit, pointeur_de_char contient l'adresse (&) de texte[0].
  //for(sec = -1000000; sec <= 1000000; sec = sec + 0.5)   // sec déclarée en float. OK.
  //for(sec = -8000000; sec <= 8000000; sec = sec + 0.5)   // sec déclarée en float. OK.
  for(sec = -8388607; sec <= 8388607; sec = sec + 0.5)     // sec déclarée en float. OK. Plage maximale : 8388607 = (2 puissance 23) - 1.
  //for(sec = -8388608; sec <= 8388608; sec = sec + 0.5)   // sec déclarée en float. FAIL. 8388608 = 2 puissance 23.
  //for(sec = -9000000; sec <= 9000000; sec = sec + 0.5)   // sec déclarée en float. FAIL.
     {
      portc.b2 = 1;                                        // LED yellow ON.
      strConstRamCpy(pointeur_de_char, "Counting ...");    // OK.
      LCD_CString_Position_v2(1, 0, pointeur_de_char);     // OK. Voir dans void LCD_Write_CString_v2(char *msg), le while(*(msg + k) > 0).
      //LCD_CString_Position_v2(1, 0, "Counting ...");
      //print_float(sec, txt, 8);                          // On LCD : Line 1 : Decounting ... Line 2 : nothing
      //print_float_v2(sec, txt, 8);                       // On LCD : Line 1 : Decounting ... Line 2 : nothing
      //print_float_v3(sec, txt, 8);                       // On LCD : Line 1 : Decounting ... Line 2 : unreadable 16 characters
      //print_float_v4(sec, txt, 8);                       // On LCD : Line 1 : Decounting ... Line 2 : unreadable 16 characters
      //print_float_v5(&txt[0], sec, 2);                   // On LCD : Line 1 : Decounting ... Line 2 : Count from 00.00 to 99.99.
      //print_float_v6(&txt[0], sec, 2);                   //
      print_float_v7(&txt[0], sec, 2);
    
      //LCD_CString_Position_v2(2, 0, txt);                // Write txt in 2nd row, starting at 1st digit.
      LCD_CString_Position_v2(2, 0, &txt[0]);
      LCD_CString_Position_v2(2, 13, "uS");                // Write "uS" in 2nd row, starting at 14th digit
      Delay_us(1);
     }
  portc.b2 = 0;                                            // LED yellow OFF.
  portc.b3 = 1;                                            // LED green ON.
  portc.b4 = 1;                                            // BUZZER ON.
  Delay_ms(5000);
  portc.b3 = 0;                                            // LED green OFF.
  portc.b4 = 0;                                            // BUZZER OFF.

}
 
Last edited by a moderator:

Solution
Hello!

Could you explain what you are trying to do here?

C:
void LCD_Write_Data(char octet)
{
    LCD_RS = 1;                                                                 // Select Data Register.
    // Send upper nibble.
    LCD_D4 = ((octet & 0x10) == 0x10) ? 1 : 0;                                  // Si ((octet & 0x10) == 0x10) alors LCD_D4 = 1 sinon = 0.
    LCD_D5 = ((octet & 0x20) == 0x20) ? 1 : 0;                                  // Si ((octet & 0x20) == 0x20) alors LCD_D5 = 1 sinon = 0.
    LCD_D6 = ((octet & 0x40) == 0x40) ? 1 : 0;                                  // Si ((octet & 0x40) == 0x40) alors LCD_D6 = 1 sinon = 0.
    LCD_D7 = ((octet & 0x80) == 0x80) ? 1 : 0;                                  // Si ((octet &...
Which PIC16 are you using?

Doh... answer is in the title .. I feel stupid now :(

I will load your code and see if I can find solution...
 

Which PIC16 are you using?

Doh... answer is in the title .. I feel stupid now :(

I will load your code and see if I can find solution...
Bonjour HexReader,
Thanks to reply me.
Hope you will enlighten me.
Merci !
 

hello,

if long number is unsigned by default , so becoms never negative
or test the MSB bit off the long number
if egal 1 =>considere it as negative number
 

hello,

if long number is unsigned by default , so becoms never negative
or test the MSB bit off the long number
if egal 1 =>considere it as negative number

long number with MikroC compiler is implicitly signed as mentioned here :

But I will test your suggestion. Have to reread basics of signed binary numbers ...
 

I do not understand your code, but I tried my best to improve it. MikroC project is attached.

See my commenting at the top of the forum.c file.
 

Attachments

  • forum.zip
    75.2 KB · Views: 134

I do not understand your code, but I tried my best to improve it. MikroC project is attached.

See my commenting at the top of the forum.c file.
Sorry,
I missed to tell you that I’am a beginner in programming PIC. In this code I just want to know / understand how to manage LCD without just using subroutines of MikroE library without understanding what inside. The aim of the code was to write my own opensource subroutines with helps on this forum.
The counting is of course not logical, but I wanted to learn how to send a string on first row and fast as possible and wider as possible changing values of a variable on second row.
Microseconds was the best unit to earn time and just following the counting on maximum digits.
I will implement the test of MSB as Paul explained me in the previous message. If you have an idea how to insert this test in the subroutine you will help me to gain time.
Merci !
 

I just want to know / understand how to manage LCD without just using subroutines of MikroE library
Yes, I apologise.
I tend to only see problems that need fixing. I often forget the educational need.
I make a poor teacher.
Will try to improve :)
 

Yes, I apologise.
I tend to only see problems that need fixing. I often forget the educational need.
I make a poor teacher.
Will try to improve :)
No worries HexReader.
I m confident. You are a good one. 👍
You will find the bug in my code.
Merci beaucoup.
 

I think I see the problem at the start of the print_float_v7() function:

If number is negative - you change it to positive, so the next test for positive will pass.
This results on the '-' character being overwritten with a space.

Either do the positive test before the negative test...
... or use "if" - "else" test
 

    Eric_O

    Points: 2
    Helpful Answer Positive Rating
Hello!

Could you explain what you are trying to do here?

C:
void LCD_Write_Data(char octet)
{
    LCD_RS = 1;                                                                 // Select Data Register.
    // Send upper nibble.
    LCD_D4 = ((octet & 0x10) == 0x10) ? 1 : 0;                                  // Si ((octet & 0x10) == 0x10) alors LCD_D4 = 1 sinon = 0.
    LCD_D5 = ((octet & 0x20) == 0x20) ? 1 : 0;                                  // Si ((octet & 0x20) == 0x20) alors LCD_D5 = 1 sinon = 0.
    LCD_D6 = ((octet & 0x40) == 0x40) ? 1 : 0;                                  // Si ((octet & 0x40) == 0x40) alors LCD_D6 = 1 sinon = 0.
    LCD_D7 = ((octet & 0x80) == 0x80) ? 1 : 0;                                  // Si ((octet & 0x80) == 0x80) alors LCD_D7 = 1 sinon = 0.
    LCD_E_Pulse();


    // Send lower nibble.
    LCD_D4 = ((octet & 0x01) == 0x01) ? 1 : 0;                                  // Si ((octet & 0x01) == 0x01) alors LCD_D4 = 1 sinon = 0.
    LCD_D5 = ((octet & 0x02) == 0x02) ? 1 : 0;                                  // Si ((octet & 0x02) == 0x02) alors LCD_D5 = 1 sinon = 0.
    LCD_D6 = ((octet & 0x04) == 0x04) ? 1 : 0;                                  // Si ((octet & 0x04) == 0x04) alors LCD_D6 = 1 sinon = 0.
    LCD_D7 = ((octet & 0x08) == 0x08) ? 1 : 0;                                  // Si ((octet & 0x08) == 0x08) alors LCD_D7 = 1 sinon = 0.
    LCD_E_Pulse();
}

I mean: why do you write bits one by one? You can write 4 bits in parallel,
that's what ports are made for.

An alternative solution:

C:
void LCD_Write_Data(uint8 data) {
    uint8 low, high;
    low = (data << 4) & 0xF0;  // Put the low bits on bits 4~7
    high = data & 0xF0;           // Leave the high bits on bits 4 ~ 7
     LCD_RS = 1;
     LCD_PORT = low;   // Put half of your byte at the input of the LCD
    LCD_E_Pulse();  // Strobe
     LCD_PORT = high; // Same as above.
    LCD_E_Pulse();
}

Beside this, your LCD_Write_Data is the same as LCD_Write_Cmd. You could consider:

C:
#define DATA 1
#define CMD 0

void LCD_Write(cmd_dat, uint8 val) {
    uint8 low, high;
    low = (data << 4) & 0xF0;  // Put the low bits on bits 4~7
    high = data & 0xF0;           // Leave the high bits on bits 4 ~ 7
     LCD_RS = cmd_dat;
     LCD_PORT = low;
    LCD_E_Pulse();
     LCD_PORT = high;
    LCD_E_Pulse();
}

So when you want to call this function for command, you call LCD_Write(CMD, cmd);
and if you want to write data, LCD_Write(DATA, data);

And you reduce your code size without impeding the speed too much or at all.

Dora.
 

hello,


nota : missing parenthessis below !
Code:
if (number < 0)
     number = - number;
     *(flt) = 45;                                                 // 45 = '-'
     *(flt + 1) = 32;                                             // 32 = space
if (number >= 0)
     *(flt) = 32;

if number is negative
you first, transform it as positive
and store the sign '-' at the first position of flt pointer
but then
you test if number is positive
it is now the case, because you tranformed negative number to positive number just before !
and you put a space instead of sign '-'
sign dispears !

Code:
     if (number < 0)
     {
       number = - number;
       *(flt) = '-';
     }   
     else
     {
        *(flt) = 32; // *(flt)='+'
      }
     // are you sure you wnat a space betwee sign and value
     *(flt + 1) = 32;        // 32 = space
 

    Eric_O

    Points: 2
    Helpful Answer Positive Rating
Hi,

why do you write
*(flt) = 45;
insted of
*(flt) = '-';
45 is more cryptic to read and understand.

the same is with 32 and ' '


Klaus
 

I think I see the problem at the start of the print_float_v7() function:

If number is negative - you change it to positive, so the next test for positive will pass.
This results on the '-' character being overwritten with a space.

Either do the positive test before the negative test...
... or use "if" - "else" test

Code modified and compiled. Just starting to decount with minus displayed.
Wait for passing thru 0.
After your advice it is so obvious now. 👍
Merci beaucoup !
--- Updated ---

Hi,

why do you write
*(flt) = 45;
insted of
*(flt) = '-';
45 is more cryptic to read and understand.

the same is with 32 and ' '


Klaus
Bonsoir,

Completely agree with you. I just wanted to test the decimal values, after hex.

Yes cryptic is more pleasant for understanding code.
--- Updated ---

hello,


nota : missing parenthessis below !
Code:
if (number < 0)
     number = - number;
     *(flt) = 45;                                                 // 45 = '-'
     *(flt + 1) = 32;                                             // 32 = space
if (number >= 0)
     *(flt) = 32;

if number is negative
you first, transform it as positive
and store the sign '-' at the first position of flt pointer
but then
you test if number is positive
it is now the case, because you tranformed negative number to positive number just before !
and you put a space instead of sign '-'
sign dispears !

Code:
     if (number < 0)
     {
       number = - number;
       *(flt) = '-';
     }   
     else
     {
        *(flt) = 32; // *(flt)='+'
      }
     // are you sure you wnat a space betwee sign and value
     *(flt + 1) = 32;        // 32 = space
It works. After have been enlighted it is always more obvious
Merci !
 
Last edited:

Hello!

Could you explain what you are trying to do here?

C:
void LCD_Write_Data(char octet)
{
    LCD_RS = 1;                                                                 // Select Data Register.
    // Send upper nibble.
    LCD_D4 = ((octet & 0x10) == 0x10) ? 1 : 0;                                  // Si ((octet & 0x10) == 0x10) alors LCD_D4 = 1 sinon = 0.
    LCD_D5 = ((octet & 0x20) == 0x20) ? 1 : 0;                                  // Si ((octet & 0x20) == 0x20) alors LCD_D5 = 1 sinon = 0.
    LCD_D6 = ((octet & 0x40) == 0x40) ? 1 : 0;                                  // Si ((octet & 0x40) == 0x40) alors LCD_D6 = 1 sinon = 0.
    LCD_D7 = ((octet & 0x80) == 0x80) ? 1 : 0;                                  // Si ((octet & 0x80) == 0x80) alors LCD_D7 = 1 sinon = 0.
    LCD_E_Pulse();


    // Send lower nibble.
    LCD_D4 = ((octet & 0x01) == 0x01) ? 1 : 0;                                  // Si ((octet & 0x01) == 0x01) alors LCD_D4 = 1 sinon = 0.
    LCD_D5 = ((octet & 0x02) == 0x02) ? 1 : 0;                                  // Si ((octet & 0x02) == 0x02) alors LCD_D5 = 1 sinon = 0.
    LCD_D6 = ((octet & 0x04) == 0x04) ? 1 : 0;                                  // Si ((octet & 0x04) == 0x04) alors LCD_D6 = 1 sinon = 0.
    LCD_D7 = ((octet & 0x08) == 0x08) ? 1 : 0;                                  // Si ((octet & 0x08) == 0x08) alors LCD_D7 = 1 sinon = 0.
    LCD_E_Pulse();
}

I mean: why do you write bits one by one? You can write 4 bits in parallel,
that's what ports are made for.

An alternative solution:

C:
void LCD_Write_Data(uint8 data) {
    uint8 low, high;
    low = (data << 4) & 0xF0;  // Put the low bits on bits 4~7
    high = data & 0xF0;           // Leave the high bits on bits 4 ~ 7
     LCD_RS = 1;
     LCD_PORT = low;   // Put half of your byte at the input of the LCD
    LCD_E_Pulse();  // Strobe
     LCD_PORT = high; // Same as above.
    LCD_E_Pulse();
}

Beside this, your LCD_Write_Data is the same as LCD_Write_Cmd. You could consider:

C:
#define DATA 1
#define CMD 0

void LCD_Write(cmd_dat, uint8 val) {
    uint8 low, high;
    low = (data << 4) & 0xF0;  // Put the low bits on bits 4~7
    high = data & 0xF0;           // Leave the high bits on bits 4 ~ 7
     LCD_RS = cmd_dat;
     LCD_PORT = low;
    LCD_E_Pulse();
     LCD_PORT = high;
    LCD_E_Pulse();
}

So when you want to call this function for command, you call LCD_Write(CMD, cmd);
and if you want to write data, LCD_Write(DATA, data);

And you reduce your code size without impeding the speed too much or at all.

Dora.
Dear Dora San
Very smart suggestions.
I fitted your routines in my code. Compilation with 0 errors. But nothing happend on LCD. Just LED yellow ON ...
Will troubleshoot deeper ...
Arigatou.
Eric
 

Solution
Dear Dora San
Very smart suggestions.
I fitted your routines in my code. Compilation with 0 errors. But nothing happend on LCD. Just LED yellow ON ...
Will troubleshoot deeper ...
Arigatou.
Eric
Dear Dora San
Very smart suggestions.
I fitted your routines in my code. Compilation with 0 errors. But nothing happend on LCD. Just LED yellow ON ...
Will troubleshoot deeper ...
Arigatou.
Eric

Here under the code :

Code:
// LCD module connections :

                                        // VSS (pin  1) -> GND

                                        // VDD (pin  2) -> VCC

                                        // VEE (pin  3) -> middle pin contrast potentiometer

sbit LCD_RS at RB4_bit;                 // RS  (pin  4) -> portB.b4 (pin 37)

// RW not used.                         // RW  (pin  5) -> GND

sbit LCD_EN at RB5_bit;                 // EN  (pin  6) -> portB.b5 (pin 38)

                                        // D0  (pin  7) -> GND

                                        // D1  (pin  8) -> GND

                                        // D2  (pin  9) -> GND

                                        // D3  (pin 10) -> GND

sbit LCD_D4 at RB0_bit;                 // D4  (pin 11) -> portB.b0 (pin 33)

sbit LCD_D5 at RB1_bit;                 // D5  (pin 12) -> portB.b1 (pin 34)

sbit LCD_D6 at RB2_bit;                 // D6  (pin 13) -> portB.b2 (pin 35)

sbit LCD_D7 at RB3_bit;                 // D7  (pin 14) -> portB.b3 (pin 36)

                                        //     (pin 15) -> GND

                                        //     (pin 16) -> GND



sbit LCD_RS_Direction at TRISB4_bit;

sbit LCD_EN_Direction at TRISB5_bit;

sbit LCD_D4_Direction at TRISB0_bit;

sbit LCD_D5_Direction at TRISB1_bit;

sbit LCD_D6_Direction at TRISB2_bit;

sbit LCD_D7_Direction at TRISB3_bit;



/******************************************************************************/



#define LCD_PORT      PORTB

#define LCD_PORT      TRISB



/******************************************************************************/



// Declaration of variables :



float sec;                              // - 1.5 x 10 puissance 45 to + 3.4 x 10 puissance 38

//double sec;                           // - 1.5 x 10 puissance 45 to + 3.4 x 10 puissance 38

//long sec;                             // - 2147483648 to 2147483647

char texte[64];                         // 0 to 255

                                        // Variables ci-dessous sorties du main() pour les déclarer en global.

                                        // Le PIC 16F a moins de mémoire RAM et ROM que le PIC 18F.

unsigned char *pointeur_de_char;        // Déclaration d'un pointeur (*) de char "pointeur_de_char".

//char texte[] = "Counting ...";        // Déclaration d'un tableau "texte" de type char et initialisé avec la chaine de caractères "Counting ..." :

                                        // En n'indiquant aucun chiffre entre les cochets [], le compilateur ajustera automatiquement la taille du

                                        // tableau, et allouera en mémoire RAM, le bon nombre d'éléménts, soit 13 ...

char txt[13];



/******************************************************************************/



// Routines :



void LCD_E_Pulse(void)

{

LCD_EN = 1;

Delay_us(5);

LCD_EN = 0;

Delay_us(5);

}



void LCD_Write_Cmd(unsigned char command_byte)

{

char low, high;

low = (command_byte << 4) & 0xF0;                                // Put the 4 lowest bits (low nibble) on bits 4 to 7.

high = command_byte & 0xF0;                                      // Put the 4 highest bits (high nibble) on bits 4 to 7.

LCD_RS = 0;

LCD_PORT = low;                                                  // Put half of the byte, low nibble, on inputs of the LCD.

LCD_E_Pulse();

LCD_PORT = high;                                                 // Put half of the byte, high nibble, on inputs of the LCD.

LCD_E_Pulse();

}



void LCD_Write_Data(unsigned char data_byte)

{

char low, high;

low = (data_byte << 4) & 0xF0;                                   // Put the 4 lowest bits (low nibble) on bits 4 to 7..

high = data_byte & 0xF0;                                         // Put the 4 highest bits (high nibble) on bits 4 to 7.

LCD_RS = 1;

LCD_PORT = low;                                                  // Put half of the byte, low nibble, on inputs of the LCD.

LCD_E_Pulse();

LCD_PORT = high;                                                 // Put half of the byte, high nibble, on inputs of the LCD.

LCD_E_Pulse();

}



void strConstRamCpy(unsigned char *dest, const code char *source)

{

while (*source)*dest ++ = *source ++;

*dest = 0;                                                       // Terminateur "0" fin de chaine de caractère.

}



void LCD_Write_CString_v2(char *msg)

{

int k;

k = 0;

//while(*(msg) > 0)                                              // FAIL.

while(*(msg + k) > 0)

{

  LCD_Write_Data(*(msg + k));                                     // Data pointée par (msg + k).

  k++;

  if (k > 15) break;                                              // Si k > 15 sortie de la boucle while ...

}

}



void LCD_CString_Position_v2(char row, char col, char *msg)

{

if (row == 1)

    {

     LCD_Write_Cmd((col & 0x0F)|0x80);                            // Print message on 1st row and desired location.

    }

else if (row == 2)

    {

     LCD_Write_Cmd((col & 0x0F)|0xC0);                            // Print message on 2nd row and desired location.

    }

LCD_Write_CString_v2(msg);                                       // OK.

}



      

void print_float_v4(char *flt, long number, char digits)

{

if (number < 0)

    {

     number = - number;

     *(flt) = '-';

    }

    else

       {

        *(flt) = ' ';

       }



*(flt + 1) = ' ';



if (digits == 2)

    {

     *(flt + 2) = number / 1000000 + 48;

     *(flt + 3) = ((number % 1000000) / 100000) + 48;

     *(flt + 4) = ((number % 100000) / 10000) + 48;

     *(flt + 5) = ((number % 10000) / 1000) + 48;

     *(flt + 6) = ((number % 1000) / 100) + 48;

     *(flt + 7) = ((number % 100) / 10) + 48;

     *(flt + 8) = ((number % 10) / 1) + 48;

     *(flt + 9) = ',';

     *(flt + 10) = ((number % 100) / 10) + 48;

     *(flt + 11) = (number % 10) + 48;

     *(flt + 12) = 0;

    }

    else

       {

        *(flt + 2) = number / 100000 + 48;

        *(flt + 3) = ((number % 100000) / 10000) + 48;

        *(flt + 4) = ((number % 10000) / 1000) + 48;

        *(flt + 5) = ((number % 1000) / 100) + 48;

        *(flt + 6) = ((number % 100) / 10) + 48;

        *(flt + 7) = ',';

        *(flt + 8) = (number % 10) + 48;

        *(flt + 9) = 0;

       }



if (*(flt + 2) == '0')                                           // Suppression des zéros inutiles.

    {

     *(flt + 2) = ' ';

     if (*(flt + 3) == '0')

        {

         *(flt + 3) = ' ';

         if (*(flt + 4) == '0')

            {

             *(flt + 4) = ' ';

             if (*(flt + 5) == '0')

                {

                 *(flt + 5) = ' ';

                 if (*(flt + 6) == '0')

                    {

                     *(flt + 6) = ' ';

                     if (*(flt + 7) == '0')

                        {

                         *(flt + 7) = ' ';

                        }

                    }

                }

            }

        }

    }

}



void LCD_Init_v4 (void)

{

Delay_ms(15);                                                    // LCD power ON initialization time >= 15 mS.

LCD_Write_Cmd(0x30);                                             // 4 datas bits > Initialization of LCD with nibble method (4 datas bits).

LCD_Write_Cmd(0x02);                                             // 4 datas bits > Initialization of LCD with nibble method (4 datas bits).

LCD_Write_Cmd(0x28);                                             // 4 datas bits > 2 lines display, 5 × 8 dot character font.

LCD_Write_Cmd(0x0C);                                             // 4 datas bits > Display ON. Cursor OFF.

LCD_Write_Cmd(0x06);                                             // 4 datas bits > Auto increment cursor.

LCD_Write_Cmd(0x01);                                             // 4 datas bits > Clear display.

Delay_ms(1);                                                     // Ajustable ... (indispensable, sinon affichage erratique à la mise sous tension)

}



/******************************************************************************/



// Main program :



void main()

{

ANSEL = 0;                                                // Configure AN pins as digital I/O.

ANSELH = 0;

C1ON_bit = 0;                                             // Disable Comparator 1.

C2ON_bit = 0;                                             // Disable Comparator 2.



PORTB = 0;

TRISB = 0;

PORTC = 0;

TRISC = 0;



// Essai 19.1 : DEBUGGING ...



Lcd_Init_v4();                                            // Initialize LCD.



while(1)                                                  // Endless loop.

{

  unsigned char *pointeur_de_char;                         // Déclaration d'un pointeur (*) de char "pointeur_de_char".

  //char texte[] = "Counting ...";                         // Déclaration d'un tableau "texte" de type char et initialisé avec la chaine de caractères "Counting ..." :

                                                           // En n'indiquant aucun chiffre entre les cochets [], le compilateur ajustera automatiquement la taille du

                                                           // tableau, et allouera en mémoire RAM, le bon nombre d'éléménts, soit 13 ...

  char txt[13];

  pointeur_de_char = &texte[0];                            // pointeur_de_char pointe sur le premier élément du tableau "texte", soit texte[0].

                                                           // Autrement dit, pointeur_de_char contient l'adresse (&) de texte[0].



  //for(sec = -1000000; sec <= 1000000; sec = sec + 0.5)   // sec déclarée en float. OK.

  //for(sec = -8000000; sec <= 8000000; sec = sec + 0.5)   // sec déclarée en float. OK.

  for(sec = -8388607; sec <= 8388607; sec = sec + 0.5)     // sec déclarée en float. OK. Plage maximale : 8388607 = (2 puissance 23) - 1.

  //for(sec = -8388608; sec <= 8388608; sec = sec + 0.5)   // sec déclarée en float. FAIL. 8388608 = 2 puissance 23.

  //for(sec = -9000000; sec <= 9000000; sec = sec + 0.5)   // sec déclarée en float. FAIL.

     {

      portc.b2 = 1;                                        // LED yellow ON.



      strConstRamCpy(pointeur_de_char, "Counting ...");    // OK.

      LCD_CString_Position_v2(1, 0, pointeur_de_char);     // OK. Voir dans void LCD_Write_CString_v2(char *msg), le while(*(msg + k) > 0).

      //LCD_CString_Position_v2(1, 0, "Counting ...");



      //print_float_v1(&txt[0], sec, 2);                   // While counting, minus values never displayed with '-".

      //print_float_v2(&txt[0], sec, 2);                   // OK.

      //print_float_v3(&txt[0], sec, 2);                   // OK.

      print_float_v4(&txt[0], sec, 2);                     // OK.



      //LCD_CString_Position_v2(2, 0, txt);                // Write txt in 2nd row, starting at 1st digit.

      LCD_CString_Position_v2(2, 0, &txt[0]);

      LCD_CString_Position_v2(2, 13, "uS");                // Write "uS" in 2nd row, starting at 14th digit



      Delay_us(1);

     }



  portc.b2 = 0;                                            // LED yellow OFF.

  portc.b3 = 1;                                            // LED green ON.

  portc.b4 = 1;                                            // BUZZER ON.

  Delay_ms(5000);

  portc.b3 = 0;                                            // LED green OFF.

  portc.b4 = 0;                                            // BUZZER OFF.

}

}
 
Last edited by a moderator:

Hello!

I had a look at your code, and there are many things to be improved.

1. LCD row.
You may consider defining this:
char ROW[] = {0x80, 0xC0};
So if you start numbering your rows at 0, you can do:

Code:
void LCD_CString_Position_v2(char row, char col, char *msg) {
    LCD_Write_Cmd((col & 0x0F)| ROW[row]);    // Print message on 1st row and desired location.
    LCD_Write_CString_v2(msg);                // OK.
}

Advantages:
- You don't need to test if else for rows.
- If you ever use a 4 lines display, you just modify the line:
char row[] = {a, b, c, f}; // a, b, c, d are the codes fro the 4 lines.
And you can use the exact same function.

2. In your print float function.
You have better options:
Use <stdio.h> (but that can be string.h in some environments)
and you end up with
sprintf(flt, "%f", your_float_number) in which case you can even
specify the number of decimals, the length, etc.
Example: sprintf(flt, "%8.3f", your_float_number);

Advantages:
This code has been tested for decades, it will always work.
Drawbacks:
It will use quite some code memory, so your "manual" method might be good depending on
how much memory you want to spend.

BUT: if you really want to make your own brew of printing a float number,
you have to try a bit smarter. For instance, removing the heading zeroes
can be done better with a loop.

Beside this: you have used '0' when suppressing the useless 0s. You should also
do this when calculating the number instead of 48 or 0x30.

Next: you shouldn't have 2 cases, if (digits == 2), you should do it on a more
generic way. Beside this, why calling digit something that should be named "decimals",
i.e. number of digits after the point.

Next: don't use hardcoded values. If k>15 is good for your LCD. If you change it to
a 4x20 LCD, your code will still work, but it will not use the 4 extra chars of every line.
Use a #define LCD_COLS 16, #define LCD_ROWS 2 and replace in your code.

About the naming:
Why calling a function LCD_CString_Position_v2? What is v2? Is it the second version
of this function? That should not appear in the code (1).
Apparently the only role of this one is to write a string at a given position.
Why not calling it WriteStringAt(x, y, string)? Everybody would understand at once
what it does. Why CString? String already says everything, and since the program
is in C...

(1). I would also recommend a versioning system, for example tortoise git if you are
using windows. It probably already happened to you a few times: you have a working
program, you modify something and nothing works anymore and you don't know what caused
it to fail. Then you spend hours looking at what you made wrong. A versioning system
helps you to point out everything you have modified and you can come back instantly to
an earlier version.

Regards,

Dora.
 

Hello!

I had a look at your code, and there are many things to be improved.

1. LCD row.
You may consider defining this:
char ROW[] = {0x80, 0xC0};
So if you start numbering your rows at 0, you can do:

Code:
void LCD_CString_Position_v2(char row, char col, char *msg) {
    LCD_Write_Cmd((col & 0x0F)| ROW[row]);    // Print message on 1st row and desired location.
    LCD_Write_CString_v2(msg);                // OK.
}

Advantages:
- You don't need to test if else for rows.
- If you ever use a 4 lines display, you just modify the line:
char row[] = {a, b, c, f}; // a, b, c, d are the codes fro the 4 lines.
And you can use the exact same function.

2. In your print float function.
You have better options:
Use <stdio.h> (but that can be string.h in some environments)
and you end up with
sprintf(flt, "%f", your_float_number) in which case you can even
specify the number of decimals, the length, etc.
Example: sprintf(flt, "%8.3f", your_float_number);

Advantages:
This code has been tested for decades, it will always work.
Drawbacks:
It will use quite some code memory, so your "manual" method might be good depending on
how much memory you want to spend.

BUT: if you really want to make your own brew of printing a float number,
you have to try a bit smarter. For instance, removing the heading zeroes
can be done better with a loop.

Beside this: you have used '0' when suppressing the useless 0s. You should also
do this when calculating the number instead of 48 or 0x30.

Next: you shouldn't have 2 cases, if (digits == 2), you should do it on a more
generic way. Beside this, why calling digit something that should be named "decimals",
i.e. number of digits after the point.

Next: don't use hardcoded values. If k>15 is good for your LCD. If you change it to
a 4x20 LCD, your code will still work, but it will not use the 4 extra chars of every line.
Use a #define LCD_COLS 16, #define LCD_ROWS 2 and replace in your code.

About the naming:
Why calling a function LCD_CString_Position_v2? What is v2? Is it the second version
of this function? That should not appear in the code (1).
Apparently the only role of this one is to write a string at a given position.
Why not calling it WriteStringAt(x, y, string)? Everybody would understand at once
what it does. Why CString? String already says everything, and since the program
is in C...

(1). I would also recommend a versioning system, for example tortoise git if you are
using windows. It probably already happened to you a few times: you have a working
program, you modify something and nothing works anymore and you don't know what caused
it to fail. Then you spend hours looking at what you made wrong. A versioning system
helps you to point out everything you have modified and you can come back instantly to
an earlier version.

Regards,

Dora.
Bonjour Dora,
Thanks for your help and all your advices. I will try them soon.
But, in order to run my code, after your previous advice of saturday 4:27 pm, which point in your last answer should I modify ?
Merci.
Eric
 

Hi
your previous advice of saturday 4:27 pm
It´s no good idea to refer to the date/time, because it´s a worldwide forum thus the time is displayed in "local time", means it is different for every user.

Please refer to the post number instead.

Klaus
 

Hi

It´s no good idea to refer to the date/time, because it´s a worldwide forum thus the time is displayed in "local time", means it is different for every user.

Please refer to the post number instead.

Klaus
Hi

It´s no good idea to refer to the date/time, because it´s a worldwide forum thus the time is displayed in "local time", means it is different for every user.

Please refer to the post number instead.

Klaus
Sorry about that Klaus.
Can I modify the post or should I send a new one ?
Please, can you remind me again how to copy/paste codes in a post ? I think I made wrong again.
Merci.
Eric
 

Status
Not open for further replies.

Similar threads

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top