+ Post New Thread
Results 1 to 2 of 2
  1. #1
    Advanced Member level 4
    Points: 7,319, Level: 20
    Achievements:
    Created Blog entry 7 years registered
    xpress_embedo's Avatar
    Join Date
    Jul 2011
    Location
    India
    Posts
    1,162
    Helped
    199 / 199
    Points
    7,319
    Level
    20
    Blog Entries
    4

    Can anyone help me in fixing PIC code for Lcd 4bit with Busy Flag

    Hello! Everyone
    Checking busy flag with 4 bit of 16x2 lcd is discussed in various post of this forum and i have taken reference of these post and wrote the code for lcd 4 bit mode and checking the busy flag.
    Reference Taken from this post.
    https://www.edaboard.com/thread250386.html

    If i use delay, lcd is working in 4-bit mode properly but when i use the busy flag it doesn't work and i am getting the following error in proteus.
    [HD44780] Attempted to read after writing a single nibble [LCD1]

    Can someone please look at my code and point at the mistake which i have done.

    I am using PIC18F45k50 micro-controller with XC8 compiler and MPLABX IDE (The program is tested on real hardware as well and even on that it is not working with busy flag check, but working with delay)

    Busy Flag code is:
    Code C - [expand]
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    
    void lcd_busy( void )
    {
      uint32_t timeout = 0u;
      uint8_t value;
      lcd_initialized = TRUE;               // Become False if, initialization fails
      LCD_BUSY_PIN_DIR = 1;                 // Make Busy Pin as Input.
      
      LCD_RS = 0;
      LCD_RW = 1;
      value = LCD_BUSY_PIN;
      while( value )
      {
        LCD_EN = 1;
        Nop();
        Nop();
        value = LCD_BUSY_PIN;
        Nop();
        LCD_EN = 0;
        Nop();
        Nop();
        Nop();
        Nop();
        LCD_EN = 1;
        Nop();
        Nop();
        // value = LCD_BUSY_PIN;
        Nop();
        LCD_EN = 0;
        timeout++;
        if( timeout > 2500u)
        {
          lcd_initialized = FALSE;
          break;
        }
      }
      LCD_BUSY_PIN_DIR = 0;                 // Make Busy Pin as Output.
      LCD_RS = 0;
    }


    The Complete code is as follow:
    Code C - [expand]
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
    226
    227
    228
    229
    230
    231
    232
    233
    234
    235
    236
    237
    238
    239
    240
    241
    242
    243
    244
    245
    246
    247
    248
    249
    250
    251
    252
    253
    254
    255
    256
    257
    258
    259
    260
    261
    262
    263
    264
    265
    266
    267
    268
    269
    270
    271
    272
    273
    274
    275
    276
    277
    278
    279
    280
    281
    282
    283
    284
    285
    286
    287
    288
    289
    290
    291
    292
    293
    294
    295
    296
    297
    298
    299
    300
    301
    302
    303
    304
    305
    306
    307
    308
    309
    310
    311
    312
    313
    314
    315
    316
    317
    318
    319
    320
    321
    322
    323
    324
    325
    
    #pragma config PLLSEL = PLL4X   // PLL Selection (4x clock multiplier)
    #pragma config CFGPLLEN = OFF   // PLL Enable Configuration bit (PLL Disabled (firmware controlled))
    #pragma config CPUDIV = NOCLKDIV// CPU System Clock Postscaler (CPU uses system clock (no divide))
    #pragma config LS48MHZ = SYS24X4// Low Speed USB mode with 48 MHz system clock (System clock at 24 MHz, USB clock divider is set to 4)
     
    // CONFIG1H
    // #pragma config FOSC = INTOSCIO  // Oscillator Selection (Internal oscillator)
    #pragma config FOSC = INTOSCCLKO   // Oscillator Selection (Internal oscillator)
    #pragma config PCLKEN = ON      // Primary Oscillator Shutdown (Primary oscillator enabled)
    #pragma config FCMEN = OFF      // Fail-Safe Clock Monitor (Fail-Safe Clock Monitor disabled)
    #pragma config IESO = OFF       // Internal/External Oscillator Switchover (Oscillator Switchover mode disabled)
     
    // CONFIG2L
    #pragma config nPWRTEN = OFF    // Power-up Timer Enable (Power up timer disabled)
    #pragma config BOREN = SBORDIS  // Brown-out Reset Enable (BOR enabled in hardware (SBOREN is ignored))
    #pragma config BORV = 190       // Brown-out Reset Voltage (BOR set to 1.9V nominal)
    #pragma config nLPBOR = OFF     // Low-Power Brown-out Reset (Low-Power Brown-out Reset disabled)
     
    // CONFIG2H
    #pragma config WDTEN = OFF      // Watchdog Timer Enable bits (WDT disabled in hardware (SWDTEN ignored))
    #pragma config WDTPS = 32768    // Watchdog Timer Postscaler (1:32768)
     
    // CONFIG3H
    #pragma config CCP2MX = RC1     // CCP2 MUX bit (CCP2 input/output is multiplexed with RC1)
    #pragma config PBADEN = OFF     // PORTB A/D Enable bit (PORTB<5:0> pins are configured as digital I/O on Reset)
    #pragma config T3CMX = RC0      // Timer3 Clock Input MUX bit (T3CKI function is on RC0)
    #pragma config SDOMX = RB3      // SDO Output MUX bit (SDO function is on RB3)
    #pragma config MCLRE = ON       // Master Clear Reset Pin Enable (MCLR pin enabled; RE3 input disabled)
     
    // CONFIG4L
    #pragma config STVREN = ON      // Stack Full/Underflow Reset (Stack full/underflow will cause Reset)
    #pragma config LVP = OFF        // Single-Supply ICSP Enable bit (Single-Supply ICSP disabled)
    #pragma config ICPRT = OFF      // Dedicated In-Circuit Debug/Programming Port Enable (ICPORT disabled)
    #pragma config XINST = OFF      // Extended Instruction Set Enable bit (Instruction set extension and Indexed Addressing mode disabled)
     
    // CONFIG5L
    #pragma config CP0 = OFF        // Block 0 Code Protect (Block 0 is not code-protected)
    #pragma config CP1 = OFF        // Block 1 Code Protect (Block 1 is not code-protected)
    #pragma config CP2 = OFF        // Block 2 Code Protect (Block 2 is not code-protected)
    #pragma config CP3 = OFF        // Block 3 Code Protect (Block 3 is not code-protected)
     
    // CONFIG5H
    #pragma config CPB = OFF        // Boot Block Code Protect (Boot block is not code-protected)
    #pragma config CPD = OFF        // Data EEPROM Code Protect (Data EEPROM is not code-protected)
     
    // CONFIG6L
    #pragma config WRT0 = OFF       // Block 0 Write Protect (Block 0 (0800-1FFFh) is not write-protected)
    #pragma config WRT1 = OFF       // Block 1 Write Protect (Block 1 (2000-3FFFh) is not write-protected)
    #pragma config WRT2 = OFF       // Block 2 Write Protect (Block 2 (04000-5FFFh) is not write-protected)
    #pragma config WRT3 = OFF       // Block 3 Write Protect (Block 3 (06000-7FFFh) is not write-protected)
     
    // CONFIG6H
    #pragma config WRTC = OFF       // Configuration Registers Write Protect (Configuration registers (300000-3000FFh) are not write-protected)
    #pragma config WRTB = OFF       // Boot Block Write Protect (Boot block (0000-7FFh) is not write-protected)
    #pragma config WRTD = OFF       // Data EEPROM Write Protect (Data EEPROM is not write-protected)
     
    // CONFIG7L
    #pragma config EBTR0 = OFF      // Block 0 Table Read Protect (Block 0 is not protected from table reads executed in other blocks)
    #pragma config EBTR1 = OFF      // Block 1 Table Read Protect (Block 1 is not protected from table reads executed in other blocks)
    #pragma config EBTR2 = OFF      // Block 2 Table Read Protect (Block 2 is not protected from table reads executed in other blocks)
    #pragma config EBTR3 = OFF      // Block 3 Table Read Protect (Block 3 is not protected from table reads executed in other blocks)
     
    // CONFIG7H
    #pragma config EBTRB = OFF      // Boot Block Table Read Protect (Boot block is not protected from table reads executed in other blocks)
     
    #include <xc.h>
    #include <stdint.h>
     
    #define _XTAL_FREQ  16000000UL
     
    #define USE_LCD_BUSY_FLAG             /**< Use Busy Bit instead of Delay.*/
     
    #define LCD_DATA              LATD    /**< LCD Data Port.*/
    #define LCD_DATA_DIR          TRISD   /**< LCD Data Direction Register.*/
     
    #define LCD_BUSY_PIN          PORTDbits.RD7 /**< LCD Busy Pin.*/
    #define LCD_BUSY_PIN_DIR      TRISD7  /**< LCD Busy Pin Direction.*/
      
    #define LCD_RS                LATB2   /**< LCD RS Pin.*/
    #define LCD_RS_DIR            TRISB2  /**< LCD RS Direction.*/
    #define LCD_RW                LATB4   /**< LCD RW Pin.*/
    #define LCD_RW_DIR            TRISB4  /**< LCD RW Direction.*/
    #define LCD_EN                LATB5   /**< LCD EN Pin.*/
    #define LCD_EN_DIR            TRISB5  /**< LCD EN Direction.*/
     
    /* LCD Commands */
    #define LCD_16x2_INIT         0x38    /**< Initialize 16x2 Lcd in 8-bit Mode.*/
    #define LCD_16x1_INIT         0x03    /**< Initialize 16x1 Lcd in 8-bit Mode.*/
    #define LCD_16x1_INIT_4BIT    0x02    /**< Initialize 16x1 Lcd in 4-bit Mode.*/
    #define LCD_16x2_INIT_4BIT    0x28    /**< Initialize 16x2 Lcd in 4-bit Mode.*/
    #define LCD_DISP_ON_CUR_ON    0x0E    /**< LCD Display On Cursor On.*/
    #define LCD_DISP_ON_CUR_OFF   0x0C    /**< LCD Display On Cursor Off.*/
    #define LCD_DISP_ON_CUR_BLNK  0x0F    /**< LCD Display On Cursor Blink.*/
    #define LCD_ENTRY_MODE        0x06    /**< LCD Entry Mode. */
    #define LCD_FIRST_ROW         0x80    /**< Move Pointer to First Row.*/
    #define LCD_SECOND_ROW        0xC0    /**< Move Pointer to Second Row.*/
    #define LCD_CLEAR             0x01    /**< Clear LCD Display.*/
     
    #define TRUE  0xFF
    #define FALSE 0x00
     
    static uint8_t lcd_initialized = FALSE;   /**< LCD Initializatin Status.*/
     
    #ifdef USE_LCD_BUSY_FLAG
    void lcd_busy(void);
    #endif
     
    /* LCD Function Prototypes */
    void LCD_Init(void);
    void LCD_Cmd(uint8_t command);
    void LCD_Write(uint8_t Data);
    void LCD_Write_Text(char *msg);
     
    void main( void )
    {
      // Select 16MHz Internal Oscillator
      OSCCONbits.IRCF = 0x07;             // From 1MHz to 16MHz
      __delay_ms(2);
      LCD_Init();
      __delay_ms(2);
      LCD_Write ('A');
      LCD_Cmd (LCD_SECOND_ROW);
      LCD_Write_Text ((char*)"EDA Board");
      while(1);
    }
     
    /**
     * @brief Initialize 16x2 LCD Module.
     *
     * Initialize 16x2 LCD Module in 4-bit mode.
     * 
     */
    #define LCD_MODE_4BIT
    void LCD_Init(void)
    {
    #ifndef USE_LCD_BUSY_FLAG
      lcd_initialized = TRUE;     // Set to True if using delay mode
    #endif
      // Set the LCD Pins as Output Pins
      LCD_DATA_DIR &= 0x0F;
      // Set LCD Control Pins as Output Pins
      LCD_RS_DIR = 0;             // RS
      LCD_RW_DIR = 0;             // RW
      LCD_EN_DIR = 0;             // EN
      
      // Set Back-Lit Pin as Output (If Present)
      
      // Clear Values
      ANSELD &= ~(0x80);
      LCD_DATA &= 0x0F;
      LCD_RS = 0;
      LCD_RW = 0;
      LCD_EN = 0;
      
      // Clear Back-Lit 
      
    #ifdef USE_LCD_BUSY_FLAG
      lcd_busy();
    #else
      __delay_ms(2);
    #endif
      __delay_ms(10);
      __delay_ms(10);
      LCD_Cmd(LCD_16x1_INIT);
      __delay_ms(10);
      LCD_Cmd(LCD_16x1_INIT);
      __delay_ms(10);
      LCD_Cmd(LCD_16x1_INIT);
      __delay_ms(10);
      LCD_Cmd(LCD_16x1_INIT_4BIT);
      __delay_ms(10);
      
      LCD_Cmd(LCD_16x2_INIT_4BIT);
      LCD_Cmd(LCD_DISP_ON_CUR_ON);
      LCD_Cmd(LCD_DISP_ON_CUR_OFF);
      LCD_Cmd(LCD_CLEAR);
      LCD_Cmd(LCD_ENTRY_MODE);
      LCD_Cmd(LCD_FIRST_ROW);
      
    }
     
    /**
     * @brief Send Command to LCD.
     *
     * Send Command to LCD, use the following commands.
     * <b>LCD_16x2_INIT,LCD_DISP_ON_CUR_ON,LCD_DISP_ON_CUR_OFF,LCD_DISP_ON_CUR_BLNK,
     * LCD_FIRST_ROW,LCD_SECOND_ROW,LCD_CLEAR</b>.
     * @param command Command to Send to the LCD.
     */
    void LCD_Cmd(uint8_t command)
    {
      LCD_DATA &= 0x0F; // Clear Data
      LCD_DATA |= (command & 0xF0);
      LCD_RS = 0;
      LCD_RW = 0;
      LCD_EN = 1;
      Nop();
      Nop();
      LCD_EN = 0;
    #ifdef USE_LCD_BUSY_FLAG
      lcd_busy();
    #else
      __delay_ms(2);
    #endif
      LCD_DATA &= 0x0F; // Clear Data
      LCD_DATA |= ((command<<4) & 0xF0);
      LCD_EN = 1;
      Nop();
      Nop();
      LCD_EN = 0;
    #ifdef USE_LCD_BUSY_FLAG
      lcd_busy();
    #else
      __delay_ms(2);
    #endif
    }
     
    /**
     * @brief Write Data on LCD.
     *
     * Write Data on LCD, specified as arguments.
     * @param Data Data to Write on LCD.
     */
    void LCD_Write(uint8_t Data)
    { 
      if( !lcd_initialized )
      {
        LCD_Init();   // Re-Initialize LCD
      }
      
      if( lcd_initialized )
      {
        LCD_DATA &= 0x0F; // Clear Data
        LCD_DATA |= (Data & 0xF0);
        LCD_RS = 1;
        LCD_RW = 0;
        LCD_EN = 1;
        Nop();
        Nop();
        LCD_EN = 0;
    #ifdef USE_LCD_BUSY_FLAG
        lcd_busy();
    #else
        __delay_ms(2);
    #endif
        LCD_DATA &= 0x0F; // Clear Data
        LCD_DATA |= ((Data<<4) & 0xF0);
        LCD_EN = 1;
        Nop();
        Nop();
        LCD_EN = 0;
    #ifdef USE_LCD_BUSY_FLAG
        lcd_busy();
    #else
        __delay_ms(2);
    #endif
      }
    }
     
    /**
     * @brief Write String on LCD.
     *
     * Write String on LCD, specified as arguments.
     * @param *msg First Character Address of the String.
     * @note String Must be terminated by NULL Character.
     */
    void LCD_Write_Text(char *msg)
    {
      while(*msg)
      {
        LCD_Write(*msg);
        msg++;
      }
    }
     
    #ifdef USE_LCD_BUSY_FLAG
    /**
     * @brief Lcd Busy.
     *
     * Wait for LCD Controller to get Ready.
     * @note Timeout Counter is added to protect the system from hanging state. In 
     * most of the cases timeout counter value is < 50 but as clear command takes 
     * time, and at that point counter value is around < 1800. Things will change 
     * with operating frequency of micro. Please re-evaluate the optimum value for
     * your setup.
     */
    void lcd_busy( void )
    {
      uint32_t timeout = 0u;
      uint8_t value;
      lcd_initialized = TRUE;               // Become False if, initialization fails
      LCD_BUSY_PIN_DIR = 1;                 // Make Busy Pin as Input.
      
      LCD_RS = 0;
      LCD_RW = 1;
      value = LCD_BUSY_PIN;
      while( value )
      {
        LCD_EN = 1;
        Nop();
        Nop();
        value = LCD_BUSY_PIN;
        Nop();
        LCD_EN = 0;
        Nop();
        Nop();
        Nop();
        Nop();
        LCD_EN = 1;
        Nop();
        Nop();
        // value = LCD_BUSY_PIN;
        Nop();
        LCD_EN = 0;
        timeout++;
        if( timeout > 2500u)
        {
          lcd_initialized = FALSE;
          break;
        }
      }
      LCD_BUSY_PIN_DIR = 0;                 // Make Busy Pin as Output.
      LCD_RS = 0;
    }
    #endif

    In my project, i can't use lcd in 4-bit mode with delay as it is taking too much time and delaying other things.
    I am also attaching my project and proteus simulation in a zip folder.

    LCD Working in 4-bit mode with delay, image shown below:
    Click image for larger version. 

Name:	Working.PNG 
Views:	3 
Size:	44.6 KB 
ID:	136536

    Thanks in advance.

    •   AltAdvertisment

        
       

  2. #2
    Super Moderator
    Points: 251,556, Level: 100
    Awards:
    1st Helpful Member

    Join Date
    Jan 2008
    Location
    Bochum, Germany
    Posts
    43,806
    Helped
    13321 / 13321
    Points
    251,556
    Level
    100

    Re: Can anyone help me in fixing PIC code for Lcd 4bit with Busy Flag

    Proteus is correctly complaining about your code. Why don't you follow the 4-bit transfer sequence specification in the 44780 datasheet strictly? It requires read and write accesses to be performed always with two EN cycles. You are however querying busy state in the middle of a write access, e.g. in lines 201 and 242.

    Click image for larger version. 

Name:	4-bit transfer.jpg 
Views:	4 
Size:	73.0 KB 
ID:	136537


    1 members found this post helpful.

--[[ ]]--