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.

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

Status
Not open for further replies.

xpress_embedo

Advanced Member level 4
Joined
Jul 5, 2011
Messages
1,154
Helped
161
Reputation
396
Reaction score
189
Trophy points
1,353
Location
India
Activity points
10,591
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/threads/250386/

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:
Working.PNG

Thanks in advance.
 

Attachments

  • Lcd4Bit.X.zip
    182.6 KB · Views: 71

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.

4-bit transfer.jpg
 
Status
Not open for further replies.

Similar threads

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top