Displaying a keypad input onto an LCD

Discussion in 'Embedded Systems and Microcontrollers' started by Jswale, Jul 29, 2015.

  1. Jswale

    Thread Starter Member

    Jun 30, 2015
    121
    6
    Hi everyone,

    I'm using PIC16F1459 and MPLAB v8.92 with the XC8 compiler...

    I am trying to display a variable onto an LCD, the variable is the number pressed on a keypad. I get a few numbers now and again and sometimes it lags or doesn't respond. It is definitely a bug in the code so have a look for yourself and see if you can spot something.


    Code (Text):
    1. //--------------------Keypad Scan------------------------------------
    2. void Scan(void)
    3. {
    4.  
    5. numberpressed = 12;
    6. while (1)                //Starting point, there is no number 12, means its polling
    7.     {
    8.     col1=0;
    9.     col2=1;
    10.     col3=1;                                //B4 is 0, scans for 1,4,7,*
    11.        
    12.     if (row1==0)  
    13.         {
    14.         __delay_ms(10);                    //used for de-bounce purposes
    15.         while (row1==0);                //waits for switch to be released
    16.         __delay_ms(10);                    //used for de-bounce purposes
    17.         numberpressed=1;
    18.         return;                            //'return' leaves current subroutine
    19.         }
    20.    
    21.     if (row2==0)              
    22.         {
    23.         __delay_ms(10);
    24.         while (row2==0);      
    25.         __delay_ms(10);
    26.         numberpressed=4;
    27.         return;
    28.         }
    29.            
    30.     if (row3==0)
    31.         {
    32.         __delay_ms(10);
    33.         while (row3==0);
    34.         __delay_ms(10);
    35.         numberpressed=7;
    36.         return;
    37.         }
    38.        
    39.     if (row4==0)
    40.         {
    41.         __delay_ms(10);
    42.         while (row4==0);
    43.         __delay_ms(10);
    44.         numberpressed=10;
    45.         return;
    46.         }
    47.    
    48.  
    49.     col1=1;                                //B5 is 0, scans for 2,5,8,0
    50.     col2=0;
    51.     col3=1;                  
    52.        
    53.     if (row1==0)
    54.         {
    55.         __delay_ms(10);
    56.         while (row1==0);
    57.         __delay_ms(10);
    58.         numberpressed=2;
    59.         return;
    60.         }
    61.    
    62.     if (row2==0)
    63.         {
    64.         __delay_ms(10);
    65.         while (row2==0);
    66.         __delay_ms(10);
    67.         numberpressed=5;
    68.         return;
    69.         }      
    70.    
    71.     if (row3==0)
    72.         {
    73.         __delay_ms(10);
    74.         while (row3==0);
    75.         __delay_ms(10);
    76.         numberpressed=8;
    77.         return;
    78.         }
    79.        
    80.     if (row4==0)
    81.         {
    82.         __delay_ms(10);
    83.         while (row4==0);
    84.         __delay_ms(10);
    85.         numberpressed=0;
    86.         return;
    87.         }
    88.  
    89.    
    90.     col1=1;                                    //B6 is 0, scans for 3,6,9,#
    91.     col2=1;
    92.     col3=0;              
    93.        
    94.     if (row1==0)
    95.         {
    96.         __delay_ms(10);
    97.         while (row1==0);
    98.         __delay_ms(10);
    99.         numberpressed=3;
    100.         return;
    101.         }
    102.    
    103.     if (row2==0)
    104.         {
    105.         __delay_ms(10);
    106.         while (row2==0);
    107.         __delay_ms(10);
    108.         numberpressed=6;
    109.         return;
    110.         }
    111.            
    112.     if (row3==0)
    113.         {
    114.         __delay_ms(10);
    115.         while (row3==0);
    116.         __delay_ms(10);
    117.         numberpressed=9;
    118.         return;
    119.         }
    120.        
    121.     if (row4==0)
    122.         {
    123.         __delay_ms(10);
    124.         while (row4==0);
    125.         __delay_ms(10);
    126.         numberpressed=11;
    127.         return;
    128.         }
    129.     }
    130. }
    131.  
    132. //======================= MAIN =====================================
    133. void main (void)
    134. {
    135.     initIO();               // init the chip IO
    136.     __delay_ms(300);        // power up delay for LCD - adjust as necessary
    137.     lcd_init();             // init the LCD
    138.     lcd_WriteStr("I am Working");
    139.     lcd_SetCursor(lcdLINE2);
    140.    
    141.     while(1)                                      
    142.     {  
    143.     if (numberpressed==1) break;
    144.  
    145.         while(1)
    146.         {
    147.         Scan();                                //poll for number pressed
    148.         num1=(numberpressed + 0x30);        //add 0x30 for ascii
    149.         __delay_ms(1);                        //1ms delay
    150.         lcd_SetCursor(lcdLINE2);            //set cursor to line1
    151.         lcd_data(num1);                        //display key pressed
    152.         break;                                //break out of while loop
    153.         }    //while
    154.     }    //while
    155.    
    156.     lcd_SetCursor(lcdLINE1);        //sets cursor to line1
    157.     lcd_WriteStr("UNLOCKED     ");
    158.     lcd_SetCursor(lcdLINE2);        //sets cursor to line2
    159.     lcd_WriteStr("UNLOCKED     ");
    160.  
    161.     while(1);    // loop forever
    162. }    //main
    163.  
    All LCD/keypad/Pic config is done earlier in the code but that is all correct, the problem lies somewhere in this code.

    Cheers
    JSwale
     
  2. JohnInTX

    Moderator

    Jun 26, 2012
    2,345
    1,028
    Hi @Jswale ,
    A couple of things:
    You can't add 0x30 to anything >9 and get what you want. You should at least test for >9 and if so, poke in the character translation. A better way to do it is to use the character code (0-12) as an index into an array of printable characters. A bonus is that your scan codes don't have match what's printed on the button, just rearrange the order of the returned codes. For example if your '0' button returns scancode 9, just put '0' in the 10th entry of the table (index 9).

    Like this:
    Code (C):
    1. const char transTable[] = {'0','1','2','3','4','5','6','7','8','9','*','#','?'};
    2. unsigned char ASCIIchar;
    3.  
    4. if(numberpressed>11) numberpressed = 12;  //qualify your index- will print '?' if unknown
    5. ASCIIchar = transTable[numberpressed]; // translate to ASCII numbers and symbols
    6. lcd_data(ASCIIchar); //write it
    7.  
    This looks like a combination lock. If that is the case, you don't have to convert the ASCII keys to numbers - ASCII compares just fine.

    Your debouncing/delay stuff is not doing much for you.

    I would write scan() to scan the array ONCE with no delays and return a key code or noKey. Use scan() like this:
    1) If no switch closure is found, do nothing - keep scanning by calling scan() repeatedly. Do other things in between.
    2) If a switch is closed, save its code and debounce by scanning a few more times with a short delay between scans. Compare the returned code with the first one. If its the same, continue debouncing. If it changes, start over.
    3) Once the key is debounced - process the code while your finger is still on the button.
    4) After processing, scan the keyboard until no keys are reported (finger off button). Again, do other things in between.
    5) When no keys are reported, goto 1)

    A good reason to write the scanner this way is that eventually you'd want to make it called by an interrupt driven timer, do all the debounce and key release detect and just emit keycodes into a FIFO (first in first out) buffer. Then your main routine can just call something .. well like getchar() which fetches characters out of the buffer or returns EMPTY if no chars. A more relevant reason here is that you are hanging in the scanner until someone hits a key - if the code wants to do something else while waiting, you are sunk.

    That's how I'd do it.
    Good luck.
     
    Last edited: Jul 29, 2015
    Jswale likes this.
  3. Jswale

    Thread Starter Member

    Jun 30, 2015
    121
    6
    @JohnInTX Got it working quite nicely, thanks for the help.

    I noticed you helped @nerdegutta out with some ADC stuff a few years back and if you can see why I am only getting 4 vertical lines and not a number between 0-1023 on my ADC?

    code below;

    Code (Text):
    1. TRISC=0b00000001;
    2.     PORTC=0b00000000;
    3.     ANSELC=0b00000001;
    4.     unsigned int ADC_result;
    5.  
    6. void adc_init()
    7. {
    8.     ADCON0= 0b00010001;            //RC0 for ADC use
    9.     ADCON1= 0b10010000;            //Right justified and use of Vsupply + clock conversion 8Fosc = 2us
    10.     ADCON2= 0b00000000;          
    11. }
    12.  
    13.  
    14. while(1)
    15.     {  
    16.        
    17.         ADCON0=0x83;                        //Sets Go_Done bit
    18.         while(ADCON0==0x83);                //Waits for conversion to finish
    19.         __delay_us(10);
    20.         ADC_result=ADRESL+(ADRESH*256);            //gets 10 bit result
    21.         lcd_cmd(0x80);                            //Start of Line 1
    22.         lcd_WriteStr(ADC_result);                //writes the value (0-1023)
    23. }
    24.  
     
  4. nerdegutta

    Moderator

    Dec 15, 2009
    2,515
    785
    Hi.
    Are you still moving your PIC back and forth to program it? I believe RC0 is on pin 16, which is for ICSPDAT. Keep that in mind. It is also the Vref+ pin. Remember to turn off the comparators.

    Try to organize your code like in the other thread. With Include-statements, configurations, definitions and functions separated. It is much easier to read and understand.

    If you at the same time add "=c" in the code tag - that would be awesome.

    Then your code is like this:
    Code (C):
    1.  
    2. TRISC=0b00000001;
    3.     PORTC=0b00000000;
    4.     ANSELC=0b00000001;
    5.     unsigned int ADC_result;
    6. void adc_init()
    7. {
    8.     ADCON0= 0b00010001;            //RC0 for ADC use
    9.     ADCON1= 0b10010000;            //Right justified and use of Vsupply + clock conversion 8Fosc = 2us
    10.     ADCON2= 0b00000000;        
    11. }
    12. while(1)
    13.     {
    14.      
    15.         ADCON0=0x83;                        //Sets Go_Done bit
    16.         while(ADCON0==0x83);                //Waits for conversion to finish
    17.         __delay_us(10);
    18.         ADC_result=ADRESL+(ADRESH*256);            //gets 10 bit result
    19.         lcd_cmd(0x80);                            //Start of Line 1
    20.         lcd_WriteStr(ADC_result);                //writes the value (0-1023)
    21. }
     
  5. Jswale

    Thread Starter Member

    Jun 30, 2015
    121
    6
    Hi,

    Yes I am moving it back and forth so ICSPDAT isn't a problem. I only pasted a small portion of my code. I think I am not breaking down each individual number that is in the result so will be adding;
    Code (C):
    1. char *temp="0000";
    2.  
    3. temp[0] = ADC_result/1000 +48;
    4. temp[1] = (ADC_result/100)%10 +48;
    5. temp[2] = (ADC_result/10)%10 +48;
    6. temp[3] = ADC_value %10 +48;
    7.  
    8. lcd_WriteStr(temp);
    Also it wont let me changer the code tag and C isn't in the language options.
    Code (C):
    1. //Author: Jack Swale
    2. //July 2015
    3. // PIC16F1459 Configuration Bit Settings
    4. // 'C' source line config statements
    5. #include <xc.h>
    6. // #pragma config statements should precede project file includes.
    7. // Use project enums instead of #define for ON and OFF.
    8. // CONFIG1
    9. #pragma config FOSC = INTOSC    // Oscillator Selection Bits (INTOSC oscillator: I/O function on CLKIN pin)
    10. #pragma config WDTE = OFF       // Watchdog Timer Enable (WDT disabled)
    11. #pragma config PWRTE = ON       // Power-up Timer Enable (PWRT enabled)
    12. #pragma config MCLRE = OFF       // MCLR Pin Function Select (MCLR/VPP pin function is Digital Input)
    13. #pragma config CP = OFF         // Flash Program Memory Code Protection (Program memory code protection is disabled)
    14. #pragma config BOREN = OFF      // Brown-out Reset Enable (Brown-out Reset disabled)
    15. #pragma config CLKOUTEN = OFF   // Clock Out Enable (CLKOUT function is disabled. I/O or oscillator function on the CLKOUT pin)
    16. #pragma config IESO = ON        // Internal/External Switchover Mode (Internal/External Switchover Mode is enabled)
    17. #pragma config FCMEN = ON       // Fail-Safe Clock Monitor Enable (Fail-Safe Clock Monitor is enabled)
    18. // CONFIG2
    19. #pragma config WRT = OFF        // Flash Memory Self-Write Protection (Write protection off)
    20. #pragma config CPUDIV = NOCLKDIV// CPU System Clock Selection Bit (NO CPU system divide)
    21. #pragma config USBLSCLK = 48MHz // USB Low SPeed Clock Selection bit (System clock expects 48 MHz, FS/LS USB CLKENs divide-by is set to 8.)
    22. #pragma config PLLMULT = 3x     // PLL Multipler Selection Bit (3x Output Frequency Selected)
    23. #pragma config PLLEN = ENABLED  // PLL Enable Bit (3x or 4x PLL Enabled)
    24. #pragma config STVREN = ON      // Stack Overflow/Underflow Reset Enable (Stack Overflow or Underflow will cause a Reset)
    25. #pragma config BORV = LO        // Brown-out Reset Voltage Selection (Brown-out Reset Voltage (Vbor), low trip point selected.)
    26. #pragma config LPBOR = OFF      // Low-Power Brown Out Reset (Low-Power BOR is disabled)
    27. #pragma config LVP = OFF        // Low-Voltage Programming Enable (High-voltage on MCLR/VPP must be used for programming)
    28. #define _XTAL_FREQ 4000000      // 4MHz for now
    29. //---------------------INIT IO -----------------------------------
    30. void initIO(void)
    31. {
    32.     OSCCON = 0b00110100;  // Internal oscillator = 4MHz (for now)
    33.     TRISC=0b00000001;
    34.     PORTC=0b00000000;
    35.     ANSELC=0b00000001;
    36.     TRISB=0b00000000;
    37.     PORTB=0b00000000;
    38.     ANSELB=0b00000000;
    39.     TRISA=0b11111111;
    40.     PORTA=0b00000000;
    41.     ANSELA=0b00000000;
    42. }
    43.  
    44. //---------------------ADC Definitions---------------------------
    45. void adc_init()
    46. {
    47.     ADCON0= 0b00010001;            //RC0 for ADC use
    48.     ADCON1= 0b10010000;            //Right justified and use of Vsupply + clock conversion 8Fosc = 2us
    49.     ADCON2= 0b00000000;      
    50. }
    51. //---------------------IO DEFINITIONS  --------------------------
    52. #define lcd_port  LATC        // write to LAT, read from PORT
    53. // RC7-4 is the LCD 4 bit databus
    54. #define LCD_RSout LATC2     // moved from ICSP
    55. #define LCD_ENout LATC3
    56.  
    57. #define col1    PORTBbits.RB4
    58. #define col2    PORTBbits.RB5
    59. #define col3    PORTBbits.RB6
    60. #define row1    PORTAbits.RA0
    61. #define row2    PORTAbits.RA1
    62. #define row3    PORTAbits.RA3
    63. #define row4    PORTAbits.RA4
    64.  
    65. int numberpressed;
    66. const char transTable[] = {'0','1','2','3','4','5','6','7','8','9','*','#','?'};
    67. unsigned char ASCIIchar;
    68. unsigned int ADC_result;
    69. //-------------------- DISPLAY SETTINGS  ---------------------
    70. // Define some display settings.
    71. #define lcdLINE1 0x00       // where line 1 begins
    72. #define lcdLINE2 0x40       // where line 2 begins
    73. //--------------------- STROBE LCD ---------------------------
    74. // Pulses E line on LCD to write
    75. int strobeLCD(void)
    76. {
    77. LCD_ENout = 1;
    78. __delay_us(2);     // Added a little here
    79. LCD_ENout = 0;
    80. }
    81. //--------------------- WRITE 8 BIT DATA TO LCD  -----------------
    82. // Assumes LCD is ready and RS is set to correct value
    83. // LCD data bus is RC4-RC7
    84. void writeLCD(unsigned char dat)
    85. {
    86.     lcd_port &= 0x0f;               // get current port, clear upper bits
    87.     lcd_port |= (dat & 0xf0);       // combine w/upper nibble, leave lower same
    88.     strobeLCD();
    89.     lcd_port &= 0x0f;               // get current port, clear upper bits
    90.     lcd_port |= ((dat <<4) & (0xf0)); // combine w/lower nibble, leave lower port same
    91.     strobeLCD();
    92.     __delay_ms(2);                // wait for display to process
    93. }
    94. //-------------------- WRITE LCD COMMAND  -------------------------
    95. // Write cmd to LCD with RS=0
    96. // Assumes E is low and display is NOT busy
    97. void lcd_cmd (unsigned char cmd)
    98. {
    99.     LCD_RSout = 0;       // select command register
    100.     writeLCD(cmd);
    101. }
    102. //---------------------- WRITE LCD DATA  --------------------------
    103. // Write dat to LCD with RS=1
    104. // Assumes E is low and display is NOT busy
    105. void lcd_data (unsigned char dat)
    106. {
    107.     LCD_RSout = 1;       // select data register
    108.     writeLCD(dat);
    109. }
    110. //-------------------- RESET/CONFIGURE LCD  -------------------------
    111. void lcd_init(void)
    112. {
    113.     lcd_port &= 0x0f;   // clear upper bits of LCD port
    114.     lcd_port |= 0x30;   // direct data to LCD DB7-4
    115.     LCD_RSout = 0;
    116.     strobeLCD();        // write 3h, wait 10ms
    117.     __delay_ms(10);
    118.     strobeLCD();        // write 3h, wait..
    119.     __delay_ms(10);
    120.      strobeLCD();       // write 3h
    121.     __delay_ms(10);
    122.    lcd_port &= 0x0f;    // clear upper bits of LCD port
    123.    lcd_port |= 0x20;    // direct data to LCD DB7-4
    124.    strobeLCD();         // write 2h
    125.    __delay_ms(10);
    126.     lcd_cmd(0x28);       // Funciton Set: 4-bit mode - 2 line - 5x7 font.
    127.     lcd_cmd(0x0e);       // DisplayON, cursor ON, blink OFF
    128.     lcd_cmd(0x06);       // Automatic Increment - No Display shift.
    129.     lcd_cmd(0x80);       // Address DDRAM with 0 offset 80h.
    130. }
    131. //----------------------- WRITE STRING TO LCD  ---------------------
    132. // Writes null terminated string to LCD from ROM
    133. void lcd_WriteStr(const unsigned char *c)
    134. {
    135.     while(*c != '\0'){
    136.         lcd_data(*c);
    137.         c++;
    138.     }
    139. }
    140. //--------------------  SETS CURSOR ANYWHERE IN DISPLAY MEMORY  ---------
    141. // Valid locations are 0-79 decimal.  This doesn't check for valid location
    142. void lcd_SetCursor(unsigned char loc)
    143. {
    144.     lcd_cmd(loc | 0x80);        // form and send 'set DDRAM address' cmd
    145. }
    146. //----------------- CANNED LINE COMMANDS  -------------------------
    147. // For a 2 line display
    148. void lcd_LINE1(void)
    149. {
    150.     lcd_SetCursor(lcdLINE1);
    151. }
    152. void lcd_LINE2(void)
    153. {
    154.     lcd_SetCursor(lcdLINE2);
    155. }
    156.  
    157. //--------------------Keypad Scan------------------------------------
    158. void Scan(void)
    159. {
    160.  
    161.  
    162.     col1=0;
    163.     col2=1;
    164.     col3=1;                                //B4 is 0, scans for 1,4,7,*
    165.  
    166.     if (row1==0)
    167.         {
    168.         numberpressed=1;
    169.         return;                            //'return' leaves current subroutine
    170.         }
    171.  
    172.     if (row2==0)          
    173.         {
    174.         numberpressed=4;
    175.         return;
    176.         }
    177.      
    178.     if (row3==0)
    179.         {
    180.         numberpressed=7;
    181.         return;
    182.         }
    183.  
    184.     if (row4==0)
    185.         {
    186.         numberpressed=10;
    187.         return;
    188.         }
    189.  
    190.  
    191.     col1=1;                                //B5 is 0, scans for 2,5,8,0
    192.     col2=0;
    193.     col3=1;              
    194.  
    195.     if (row1==0)
    196.         {
    197.         numberpressed=2;
    198.         return;
    199.         }
    200.  
    201.     if (row2==0)
    202.         {
    203.         numberpressed=5;
    204.         return;
    205.         }  
    206.  
    207.     if (row3==0)
    208.         {
    209.         numberpressed=8;
    210.         return;
    211.         }
    212.  
    213.     if (row4==0)
    214.         {
    215.         numberpressed=0;
    216.         return;
    217.         }
    218.  
    219.  
    220.     col1=1;                                    //B6 is 0, scans for 3,6,9,#
    221.     col2=1;
    222.     col3=0;          
    223.  
    224.     if (row1==0)
    225.         {
    226.         numberpressed=3;
    227.         return;
    228.         }
    229.  
    230.     if (row2==0)
    231.         {
    232.         numberpressed=6;
    233.         return;
    234.         }
    235.      
    236.     if (row3==0)
    237.         {
    238.         numberpressed=9;
    239.         return;
    240.         }
    241.  
    242.     if (row4==0)
    243.         {
    244.         numberpressed=11;
    245.         return;
    246.         }
    247. }
    248.  
    249. //-----------------------verification--------------------------
    250. void Verify (void)
    251. {
    252. numberpressed=50;  
    253. lcd_WriteStr("Press 0 to cont");
    254. while(numberpressed!=0)
    255. {
    256. Scan();
    257. }
    258. lcd_cmd(0x01);
    259. }
    260. //======================= MAIN =====================================
    261. void main (void)
    262. {
    263.     initIO();               // init the chip IO
    264.     __delay_ms(300);        // power up delay for LCD - adjust as necessary
    265.     lcd_init();             // init the LCD
    266.     adc_init();                //ADC init
    267.     Verify();                //Demonstrates LCD powering up
    268.    
    269. while(1)
    270.     {
    271.  
    272.         ADCON0=0x83;                        //Sets Go_Done bit
    273.         while(ADCON0==0x83);                //Waits for conversion to finish
    274.         __delay_us(10);
    275.         ADC_result=ADRESL+(ADRESH*256);            //gets 10 bit result
    276.         lcd_cmd(0x80);                            //Start of Line 1
    277.         lcd_WriteStr(ADC_result);                //writes the value (0-1023)
    278.  
    279.         Scan();
    280.         if(numberpressed>11) numberpressed = 12;  //qualify your index- will print '?' if unknown
    281.         ASCIIchar = transTable[numberpressed]; // translate to ASCII numbers and symbols
    282.         lcd_cmd(0xC0);                            //Starts Line 2
    283.         lcd_WriteStr("The number is ");
    284.         lcd_data(ASCIIchar); //write it
    285.  
    286.     if (numberpressed==1) break;
    287.     }    //while
    288.  
    289.     lcd_SetCursor(lcdLINE1);        //sets cursor to line1
    290.     lcd_WriteStr("UNLOCKED        ");
    291.     lcd_SetCursor(lcdLINE2);           //sets cursor to line2
    292.     lcd_WriteStr("UNLOCKED        ");
    293.  
    294.     while(1);    // loop forever
    295. }    //main
    296.  
    297.  
    The rest of the code is here^^^

    JSwale.
     
    Last edited: Jul 30, 2015
  6. JohnInTX

    Moderator

    Jun 26, 2012
    2,345
    1,028
    Yes, you have to convert the binary ADC result to individual ASCII chars but you have issues with your routine:
    Code (C):
    1. unsigned char temp[5]; // declare characters - you declared an array of pointers to char
    2. temp[0] = ADC_result/1000 + '0';  // a better way to declare that you are converting to ASCII '0' evaluates to 30h
    3. temp[1] = (ADC_result/100)%10 +48;
    4. temp[2] = (ADC_result/10)%10 +48;
    5. temp[3] = ADC_value %10 +48;
    6. temp[4]= '\0';  // NULL terminate the string as lcd_WriteStr requires
    7. lcd_WriteStr(temp); // the name of the char array is a pointer to char so this is OK
    You have to manually edit the code tag once you paste the code - which I see that @nerdegutta already pointed out.
     
  7. Jswale

    Thread Starter Member

    Jun 30, 2015
    121
    6
    I am still a little rusty on Pointers as I have never really used them in my programs.

    I'll try that code now
     
  8. JohnInTX

    Moderator

    Jun 26, 2012
    2,345
    1,028
    The compiler will identify potential problems with warnings about 'illegal pointer conversion' or some such verbiage. That will help you. NEVER ignore such warnings (or any other compiler warning for that matter).
     
  9. Jswale

    Thread Starter Member

    Jun 30, 2015
    121
    6
    What is displayed on the screen is just unrecognisable characters so something must be wrong, i am guessing with the configuration.
     
  10. JohnInTX

    Moderator

    Jun 26, 2012
    2,345
    1,028
    I doubt it. Probably something in your ADC->text routine (I didn't check the arithmetic but it looks OK).
    As a test, load the array with known text in the conversion routine and null terminate that. Call the routine and see if it shows the text. If it does, your arithmetic needs work. If not, fix the text display.

    Note that even 'garbage' on the screen has real numerical values. Pull the display datasheet and look at the character map - match up what you are seeing and it will tell you what codes were written.

    You can simulate the conversion to text in MPSIM. Put a breakpoint before and after calling the routine. Use a watch window with the ADC value int and char array watched. On the first break right click the ADC value and enter something. Run to the next break point and inspect the array of text. That should be the ASCII value of whatever the input number was. Make a dummy loop and try various values. Step through the arithmetic one line at a time, watching the result. Your problem should become apparent.

    Good luck

    EDIT: Is the compiler throwing warnings about lcd_WriteStr? IIRC, its declared to use a const char * (i.e. pointer to a string in ROM). It may not like a string in RAM. XC8 can use both in one routine but you have to declare the parameter qualifier accordingly. I don't know what the syntax is off hand but its in the manual. EDIT Sec 5.5
     
    Last edited: Jul 30, 2015
  11. nerdegutta

    Moderator

    Dec 15, 2009
    2,515
    785
    Not quite what you are looking for, but this little program displays the ADC value and the corresponding voltage. The voltage is approximate. I'm using my version of xlcd.h and xlcd.c along with the standard libraries. I got:
    RS=>RA0
    RW=>RA1
    E=>RA2
    D4=>RC0
    D5=>RC1
    D6=>RC2
    D7=>RC3

    I got a pot connected to RA4, as analog input.
    PIC16F688, 16x02LCD, PICKit3, MPLABX XC8 compiler
    Code (C):
    1.  
    2. // INCLUDES
    3. #include <stdio.h>
    4. #include <stdlib.h>
    5. #include <xc.h>
    6. #include "my_xlcd.h"
    7.  
    8. // CONFIGURATION BITS
    9. #pragma config FOSC = INTOSCIO  // Oscillator Selection bits (INTOSCIO oscillator: I/O function on RA4/OSC2/CLKOUT pin, I/O function on RA5/OSC1/CLKIN)
    10. #pragma config WDTE = OFF       // Watchdog Timer Enable bit (WDT enabled)
    11. #pragma config PWRTE = OFF      // Power-up Timer Enable bit (PWRT disabled)
    12. #pragma config MCLRE = ON       // MCLR Pin Function Select bit (MCLR pin function is MCLR)
    13. #pragma config CP = OFF         // Code Protection bit (Program memory code protection is disabled)
    14. #pragma config CPD = OFF        // Data Code Protection bit (Data memory code protection is disabled)
    15. #pragma config BOREN = ON       // Brown Out Detect (BOR enabled)
    16. #pragma config IESO = ON        // Internal External Switchover bit (Internal External Switchover mode is enabled)
    17. #pragma config FCMEN = ON       // Fail-Safe Clock Monitor Enabled bit (Fail-Safe Clock Monitor is enabled)
    18.  
    19. // DEFINITIONS
    20. #define _XTAL_FREQ 4000000
    21.  
    22. // GLOBAL VARIABLES
    23. unsigned int adc_raw;
    24. unsigned char adc_value[5];
    25. int millivolt;
    26. char message[] = "0.00";
    27.  
    28. // PROTOTYPE FUNCTIONS
    29. void init_XCLD(void);
    30. void DelayFor18TCY(void);
    31. void DelayPORXLCD(void);
    32. void DelayXLCD(void);
    33. void Delay10KTCYx(unsigned char);
    34. void init_OSC(void);
    35. void init_ADC(void);
    36. void read_ADC(void);
    37.  
    38.  
    39. // FUNCTIONS
    40. void init_XLCD(void){
    41.     OpenXLCD(FOUR_BIT & LINES_5X7);
    42.     while (BusyXLCD());
    43.     WriteCmdXLCD(0x06);
    44.     WriteCmdXLCD(0x0C);
    45. }
    46.  
    47. void DelayFor18TCY(void){
    48.     NOP(); NOP(); NOP(); NOP(); NOP(); NOP(); NOP();
    49.     NOP(); NOP(); NOP(); NOP(); NOP(); NOP(); NOP();
    50.     return;
    51. }
    52. void DelayPORXLCD(void){
    53.     __delay_ms(15);
    54. }
    55.  
    56. void DelayXLCD(void){
    57.     __delay_ms(5);
    58. }
    59.  
    60. void Delay10KTCYx(unsigned char){
    61.     __delay_ms(10);
    62. }
    63.  
    64. void init_OSC(void){
    65.     OSCCONbits.IRCF0 = 0b110; // Internal Osc Freq Select bit => 4MHz
    66.     OSCCONbits.HTS = 1;       // Status bit, high freq => Stable
    67.     OSCCONbits.OSTS = 0;      // Osc startup time out => dev run from internal
    68.     OSCCONbits.LTS = 1;       // Low freq bit => stable
    69.     OSCCONbits.SCS = 1;       // Internal osc used for system clock
    70. }
    71.  
    72. void init_ADC(void){
    73.     ADCON0bits.ADFM = 1;        // Right justified
    74.     ADCON0bits.VCFG = 0;        // Voltage ref => Vdd
    75.     ADCON0bits.CHS = 3;         // Analog channel => AN3
    76.     ADCON0bits.ADON = 1;        // ADC enable bit
    77.     ADCON1bits.ADCS = 0b001;    // A/D Conversion clock bit
    78. }
    79.  
    80. void read_ADC(void){
    81.     ADCON0bits.GO = 1;          // A/D conversion is in progress.
    82.     __delay_us(10);
    83.     while(ADCON0bits.nDONE);    // Wait for AD to complete
    84.     __delay_us(10);
    85. }
    86. /*
    87. *   MAIN PROGRAM
    88. */
    89. int main(int argc, char** argv) {
    90.  
    91.     TRISA = 0x00000000;         // All output
    92.     TRISC = 0x00000000;
    93.  
    94.     PORTA = 0b00000000;         // All low
    95.     PORTC = 0b00000000;
    96.     TRISAbits.TRISA4 = 1;       // TRISA4 set to input
    97.  
    98.     ANSEL = 0b00000000;         // Disabling all analog input
    99.     ANSELbits.ANS3 = 1;         // Enabling analog input on ANS3
    100.  
    101.     CMCON0 = 0x07;              // Turn off comparator
    102.  
    103.     init_ADC();                 // Init ADC
    104.     init_XLCD();                // Init XLCD
    105.     putrsXLCD("I'm alive.");    // Alive message
    106.     __delay_ms(1000);
    107.     while(1){
    108.         read_ADC();             // read ADC
    109.         WriteCmdXLCD(0x01);     // Clear LCD home cursor
    110.         adc_raw = (unsigned int) ADRESH;    // Combining ARDRESL & ADRESH
    111.         adc_raw = adc_raw * 256;            // Thanks to JohnInTX
    112.         adc_raw += (unsigned int) ADRESL;   // for this
    113.      
    114.         itoa(adc_value, adc_raw, 10);       // convert int to ascill
    115.      
    116.         putrsXLCD(adc_value);   // Writes ADC value on LCD
    117.  
    118.         SetDDRamAddr(0x40);     // Goto line 2, pos 1
    119.      
    120.         millivolt = (adc_raw * 49) / 10;    // convert ADC to millivolts
    121.    
    122.         message[0] = millivolt / 1000 + 48;        // Sorting out the volt
    123.         message[2] = (millivolt / 100) % 10 + 48;  // the hundreds
    124.         message[3] = (millivolt / 10) % 10 + 48;   // the tenths
    125.      
    126.         putrsXLCD(message);    // Prints the volts ln LCD line 2
    127.      
    128.         __delay_ms(500);        // Waits for 0.5 sec
    129.      
    130.     }
    131.  
    132.     return (EXIT_SUCCESS);
    133. }
    134.  
    I think this program can be made a little smoother, but not now. :)
     
    JohnInTX likes this.
  12. ErnieM

    AAC Fanatic!

    Apr 24, 2011
    7,387
    1,605
    A wonderful thing in the XC8 package is the standard library accessed by including stdlib.h. In there resides a function "itoa" which stands for Integer TO Ascii, which translaterd numbers into text.

    http://mkssoftware.com/docs/man3/itoa.3.asp
     
  13. Jswale

    Thread Starter Member

    Jun 30, 2015
    121
    6
    It looks like it works to some extent but it doesnt stay between the boundaries of 0-1023 that you would expect of a 10 bit result. Also it doesnt change much and the MSB flickers between 9 and 1. I am using a POT to vary vin between 0V and 5V.

    Code used;

    Code (C):
    1.     ADCON0=0x83;                        //Sets Go_Done bit
    2.         while(ADCON0==0x83);                //Waits for conversion to finish
    3.         __delay_us(10);
    4.         ADC_result=ADRESL+(ADRESH*256);            //gets 10 bit result
    5.      
    6.          itoa(temp, ADC_result, 10);
    7.  
    8.     lcd_cmd(0x80);                            //Start of Line 1
    9.         lcd_WriteStr(temp);                //writes the value (0-1023)

    EDIT:
    I also tried the text @JohnInTX by using 'H E L P' but the '? = A C' was displayed
     
    Last edited: Jul 30, 2015
  14. Jswale

    Thread Starter Member

    Jun 30, 2015
    121
    6
    At once extreme it is 907 and at the other extreme it is 107 (with a little flickering). But it is never anything inbetween.


    SOLVED: i was setting the ADCON=0x83 in the while loop instead of the single GO/DONE bit which was causing a problem. All works now!

    @JohnInTX, what i have now got thanks to your help (and @nerdegutta) is a rectified and smoothed waveform that is measured by the Pic16F and is then displayed on the LCD also with a Keypad that displays number pressed . It all works perfectly, which gives me a good base to complicate it even more with interrupts and more features. :)

    Regards JSwale
     
    Last edited: Jul 30, 2015
    nerdegutta and JohnInTX like this.
  15. Jswale

    Thread Starter Member

    Jun 30, 2015
    121
    6
    Just a quick question.

    I have never really used printf() except with Arduino and an LCD library and I see it is quite popular, how would I implement that into displaying it onto an LCD? Would I need an LCD library with it to associate the data bus and enable/RS pins too?
     
  16. ErnieM

    AAC Fanatic!

    Apr 24, 2011
    7,387
    1,605
    A quick answer is to NEVER use printf() on a micro controller. That function (and those similar) while seemingly very useful and powerful are actually too powerful and contain lots and lots of code you will simply never use. I've seen such functions add 3 or 5 K to my build. The only time I used such was when I had a PIC32 with 512K words of memory to play in.

    Keep to lightweight functions such as atoi() and lcd_WriteStr() and you will have room to do other useful things in your processor.
     
    Last edited: Aug 6, 2015
  17. Jswale

    Thread Starter Member

    Jun 30, 2015
    121
    6
    Yeah I agree. Coding my own functions or using the lightweight functions are the way to go!

    Printf() just seems an easy way out.
     
  18. JohnInTX

    Moderator

    Jun 26, 2012
    2,345
    1,028
    @ErnieM makes a good point for most compilers. Microchip addreseses this in XC8 by breaking printf into many small routines that are used only as required. I did a few tests awhile back and found simpler integer ops to take a few hundred instruntions, floats pushed it over 1K.. Still significant but not the big monolithic blocks of some other compilers. I posted the particulars but don't them handy. You can find out for yourself by trying test builds and looking at the dashboard in MPLABX or the compiler output.

    FWIW In MikroC, a simple printf immediately pushed the code to past the free limit for the same code which is in line with ErnieM's remarks.

    YMMV
     
    ErnieM likes this.
  19. ErnieM

    AAC Fanatic!

    Apr 24, 2011
    7,387
    1,605
    Good to know Microchip has been hard at work with the standard libraries.
     
Loading...