crowdy
11.07.2013, 17:38
Hi Leute,
derzeit hänge ich mal wieder an einem nervigen kleinen Problemchen... Ich versuche mir ne Lib für mein LCD-Board (LCD 204B LED) aufzubauen, vermutlich für den Kontroller KS0073 (Das LCD war Teil eines Lern-Experimentier-Boards und ich habe keine gute Dokumentation, bei der ich mir 100% sicher bin, dass sie passt). Eigentlich funktioniert auch alles gut, bis auf das Auslesen des Speichers. Dies brauche ich eigentlich nur um das Busy Flag auszulesen. Wenn ich auf die BF Abfrage verzichte und stattdessen eine kleine Wartezeit einbauen funktioniert auch alles einwandfrei. Aber ich möchte umbedingt den Fehler finden, alles andere befriedigt mich nicht.
Jaaa, betrieben wird das LCD im 4-Bit Modus, die unteren Datenleitungen (DB0-DB3) habe ich Offen gelassen, da das LCD wohl interne Pull-Up's verwendet. Ansonsten ist alles direkt mit möglichst kurzen Leitungen auf meinem Experimentierboard mit einem ATmega 8 angeschlossen.
Also das Problem vermute ich in dieser Funktion
void lcd_busy(void)
{ uint8_t rep;
P_DD_DDR &= (~(0x0F << DD)); //Data-Port as Input
SET_DD(0x00); //No internal Pull-Up's!
RS_0; //Instruction Register
RW_1; //Read-Mode
_delay_us( t_W_RS_RW );
do
{
#ifdef _4_bit_mode_
EN_1;
_delay_us( t_H_EN ); //Wait for LCD: 5us
rep = ( (P_DD_IN >> DD) << 4 ); //Read high nibble
EN_0;
_delay_us( t_L_EN ); //Wait for LCD: 5us
EN_1;
_delay_us( t_H_EN );
rep |= ( (P_DD_IN >> DD) & 0x0F); //Read low nibble
EN_0;
_delay_us( t_L_EN );
#else
EN_1;
_delay_us( t_H_EN);
rep = P_DD_IN;
EN_0;
_delay_us( t_L_EN );
#endif
}while( 0x80 & rep ); //Check Busy Flag
RW_0;
}
Die Konstanten habe ich hier nochmal einzeln
#define F_CPU 8000000L
#include <avr/io.h>
#include <util/delay.h>
#include "uart.h"
/////////////////////////////////////////////////////////////////Mode////////////////////////////////////////////
#define _4_bit_mode_
/////////////////////////////////////////////////////////////////Port Constants//////////////////////////////////
#define RS 7
#define P_RS PORTD
#define P_RS_DDR DDRD
#define RW 0
#define P_RW PORTB
#define P_RW_DDR DDRB
#define EN 6
#define P_EN PORTD
#define P_EN_DDR DDRD
#define DD 2
#define P_DD PORTD
#define P_DD_IN PIND
#define P_DD_DDR DDRD
/////////////////////////////////////////////////////////////////Time delays/////////////////////////////////////////////
///us
#define t_H_EN 5
#define t_L_EN 5
#define t_W_RS_RW 1
///ms
#define t_Init_1 100
#define t_Init_2 5
/////////////////////////////////////////////////////////////////Commands for Bus/////////////////////////////////////////
#define RS_1 P_RS |= _BV(RS)
#define RS_0 P_RS &= ~_BV(RS)
#define RW_1 P_RW |= _BV(RW)
#define RW_0 P_RW &= ~_BV(RW)
#define EN_1 P_EN |= _BV(EN)
#define EN_0 P_EN &= ~_BV(EN)
/////////////////////////////////////////////////////////////////Commands and Addresses///////////////////////////////////
#define CLEAR_SCREEN 0x01
#define RETURN_HOME 0x02
#define ENTRY_MODE 0x04
#define ID 0x02
#define S 0x01
#define DISPLAY_CON 0x08
#define D 0x04
#define C 0x02
#define B 0x01
#define SHIFTING 0x10
#define SC 0x08
#define RL 0x04
#define FUNCTION_SET 0x20
#define DL 0x10
#define N 0x08
#define F 0x04
#define CG_ADD_SET 0x40
#define DD_ADD_SET 0x80
#define Line_1 0x00
#define Line_2 0x40
#define Line_3 0x14
#define Line_4 0x54
#ifdef _4_bit_mode_
#define SET_DD(x) P_DD &= ~(0x0F << DD);\
P_DD |= ((x) << DD)
#else
#define SET_DD(x) P_DD = (x)
#endif
Und Sicherheitshalber hier nochmal die ganze Lib, an der ich jetzt arbeite
/////////////////////////////////////////////////////////////////Display Functions////////////////////////////////////////
void delay_ms(uint16_t ms)
{
for(uint16_t t = 0; t <= ms; t++) _delay_ms(1);
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void Set_P_DD( uint8_t c)
{
EN_1;
#ifdef _4_bit_mode_
SET_DD( c >> 4 ); //Put high Nibble on Pin's
_delay_us( t_H_EN );
EN_0; //LCD reads
_delay_us(t_L_EN);
EN_1;
SET_DD( 0x0F & c ); //Put low nibble on Pin's
#else
P_DD = c;
#endif
_delay_us( t_H_EN );
EN_0;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void lcd_busy(void)
{ uint8_t rep;
P_DD_DDR &= (~(0x0F << DD)); //Data-Port as Input
SET_DD(0x00); //No internal Pull-Up's!
RS_0; //Instruction Register
RW_1; //Read-Mode
_delay_us( t_W_RS_RW );
do
{
#ifdef _4_bit_mode_
EN_1;
_delay_us( t_H_EN ); //Wait for LCD: 5us
rep = ( (P_DD_IN >> DD) << 4 ); //Read high nibble
EN_0;
_delay_us( t_L_EN ); //Wait for LCD: 5us
EN_1;
_delay_us( t_H_EN );
rep |= ( (P_DD_IN >> DD) & 0x0F); //Read low nibble
EN_0;
_delay_us( t_L_EN );
#else
EN_1;
_delay_us( t_H_EN);
rep = P_DD_IN;
EN_0;
_delay_us( t_L_EN );
#endif
}while( 0x80 & rep ); //Check Busy Flag
RW_0;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void lcd_cmd( uint8_t cmd )
{
delay_ms(1); //eigentlich lcd_busy();
RS_0;
RW_0;
_delay_us(t_W_RS_RW);
Set_P_DD( cmd );
RS_1;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void lcd_put( uint8_t dd )
{
delay_ms(1); //eigentlich lcd_busy();
Set_P_DD( dd );
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void lcd_init( void )
{ uint8_t i;
P_RS_DDR |= (1 << RS); //as Output
P_RW_DDR |= (1 << RW);
P_EN_DDR |= (1 << EN);
#ifdef _4_bit_mode_
P_DD_DDR |= (0x0F << DD); //as Output
#else
P_DD_DDR = 0xFF;
#endif
RS_0;
RW_0;
delay_ms(t_Init_1);
#ifdef _4_bit_mode_
SET_DD( (FUNCTION_SET + DL) >> 4 );
#else
SET_DD( FUNCTION_SET + DL );
#endif
for( i=0; i<=2; i++) //3x Function setting
{
EN_1;
_delay_us( t_H_EN );
EN_0;
_delay_us( t_L_EN );
delay_ms(t_Init_2);
}
lcd_cmd( FUNCTION_SET + N ); //2/4 line display
lcd_cmd( DISPLAY_CON + D + C + B ); //Display:ON, Cursor:ON, Blink: ON
lcd_cmd( ENTRY_MODE + ID ); //Increment Cursor
lcd_cmd( CLEAR_SCREEN );
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void lcd_write( const char *dd )
{
while( *dd != '\0' ) lcd_put( *dd++ );
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void lcd_pos( uint8_t x, uint8_t y )
{
uint8_t add;
switch (y)
{ case 1: add = DD_ADD_SET + Line_1 + x;
break;
case 2: add = DD_ADD_SET + Line_2 + x;
break;
case 3: add = DD_ADD_SET + Line_3 + x;
break;
case 4: add = DD_ADD_SET + Line_4 + x;
break;
default: return;
}
lcd_cmd( add );
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void lcd_put_bin( uint8_t c )
{
for(uint8_t j=0x80; j>= 0x01; j>>=1 )
{
if( j == 0x08 ) lcd_put( 0x7C );
if( c & j ) lcd_put( 0xFF );
else lcd_put( 0x20 );
}
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void lcd_CG ( uint8_t add, uint8_t *c)
{
add |= CG_ADD_SET;
lcd_cmd( add );
for (uint8_t i = 0; i<=7; i++) lcd_cmd( c[i] );
}
So ich bin für jeden Tipp und jede Anregung sehr dankbar. Außerdem würde mich es mal interessieren wie Ihr die Lesbarkeit des Codes findet.
Mit freundlichen Grüßen Crowdy
derzeit hänge ich mal wieder an einem nervigen kleinen Problemchen... Ich versuche mir ne Lib für mein LCD-Board (LCD 204B LED) aufzubauen, vermutlich für den Kontroller KS0073 (Das LCD war Teil eines Lern-Experimentier-Boards und ich habe keine gute Dokumentation, bei der ich mir 100% sicher bin, dass sie passt). Eigentlich funktioniert auch alles gut, bis auf das Auslesen des Speichers. Dies brauche ich eigentlich nur um das Busy Flag auszulesen. Wenn ich auf die BF Abfrage verzichte und stattdessen eine kleine Wartezeit einbauen funktioniert auch alles einwandfrei. Aber ich möchte umbedingt den Fehler finden, alles andere befriedigt mich nicht.
Jaaa, betrieben wird das LCD im 4-Bit Modus, die unteren Datenleitungen (DB0-DB3) habe ich Offen gelassen, da das LCD wohl interne Pull-Up's verwendet. Ansonsten ist alles direkt mit möglichst kurzen Leitungen auf meinem Experimentierboard mit einem ATmega 8 angeschlossen.
Also das Problem vermute ich in dieser Funktion
void lcd_busy(void)
{ uint8_t rep;
P_DD_DDR &= (~(0x0F << DD)); //Data-Port as Input
SET_DD(0x00); //No internal Pull-Up's!
RS_0; //Instruction Register
RW_1; //Read-Mode
_delay_us( t_W_RS_RW );
do
{
#ifdef _4_bit_mode_
EN_1;
_delay_us( t_H_EN ); //Wait for LCD: 5us
rep = ( (P_DD_IN >> DD) << 4 ); //Read high nibble
EN_0;
_delay_us( t_L_EN ); //Wait for LCD: 5us
EN_1;
_delay_us( t_H_EN );
rep |= ( (P_DD_IN >> DD) & 0x0F); //Read low nibble
EN_0;
_delay_us( t_L_EN );
#else
EN_1;
_delay_us( t_H_EN);
rep = P_DD_IN;
EN_0;
_delay_us( t_L_EN );
#endif
}while( 0x80 & rep ); //Check Busy Flag
RW_0;
}
Die Konstanten habe ich hier nochmal einzeln
#define F_CPU 8000000L
#include <avr/io.h>
#include <util/delay.h>
#include "uart.h"
/////////////////////////////////////////////////////////////////Mode////////////////////////////////////////////
#define _4_bit_mode_
/////////////////////////////////////////////////////////////////Port Constants//////////////////////////////////
#define RS 7
#define P_RS PORTD
#define P_RS_DDR DDRD
#define RW 0
#define P_RW PORTB
#define P_RW_DDR DDRB
#define EN 6
#define P_EN PORTD
#define P_EN_DDR DDRD
#define DD 2
#define P_DD PORTD
#define P_DD_IN PIND
#define P_DD_DDR DDRD
/////////////////////////////////////////////////////////////////Time delays/////////////////////////////////////////////
///us
#define t_H_EN 5
#define t_L_EN 5
#define t_W_RS_RW 1
///ms
#define t_Init_1 100
#define t_Init_2 5
/////////////////////////////////////////////////////////////////Commands for Bus/////////////////////////////////////////
#define RS_1 P_RS |= _BV(RS)
#define RS_0 P_RS &= ~_BV(RS)
#define RW_1 P_RW |= _BV(RW)
#define RW_0 P_RW &= ~_BV(RW)
#define EN_1 P_EN |= _BV(EN)
#define EN_0 P_EN &= ~_BV(EN)
/////////////////////////////////////////////////////////////////Commands and Addresses///////////////////////////////////
#define CLEAR_SCREEN 0x01
#define RETURN_HOME 0x02
#define ENTRY_MODE 0x04
#define ID 0x02
#define S 0x01
#define DISPLAY_CON 0x08
#define D 0x04
#define C 0x02
#define B 0x01
#define SHIFTING 0x10
#define SC 0x08
#define RL 0x04
#define FUNCTION_SET 0x20
#define DL 0x10
#define N 0x08
#define F 0x04
#define CG_ADD_SET 0x40
#define DD_ADD_SET 0x80
#define Line_1 0x00
#define Line_2 0x40
#define Line_3 0x14
#define Line_4 0x54
#ifdef _4_bit_mode_
#define SET_DD(x) P_DD &= ~(0x0F << DD);\
P_DD |= ((x) << DD)
#else
#define SET_DD(x) P_DD = (x)
#endif
Und Sicherheitshalber hier nochmal die ganze Lib, an der ich jetzt arbeite
/////////////////////////////////////////////////////////////////Display Functions////////////////////////////////////////
void delay_ms(uint16_t ms)
{
for(uint16_t t = 0; t <= ms; t++) _delay_ms(1);
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void Set_P_DD( uint8_t c)
{
EN_1;
#ifdef _4_bit_mode_
SET_DD( c >> 4 ); //Put high Nibble on Pin's
_delay_us( t_H_EN );
EN_0; //LCD reads
_delay_us(t_L_EN);
EN_1;
SET_DD( 0x0F & c ); //Put low nibble on Pin's
#else
P_DD = c;
#endif
_delay_us( t_H_EN );
EN_0;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void lcd_busy(void)
{ uint8_t rep;
P_DD_DDR &= (~(0x0F << DD)); //Data-Port as Input
SET_DD(0x00); //No internal Pull-Up's!
RS_0; //Instruction Register
RW_1; //Read-Mode
_delay_us( t_W_RS_RW );
do
{
#ifdef _4_bit_mode_
EN_1;
_delay_us( t_H_EN ); //Wait for LCD: 5us
rep = ( (P_DD_IN >> DD) << 4 ); //Read high nibble
EN_0;
_delay_us( t_L_EN ); //Wait for LCD: 5us
EN_1;
_delay_us( t_H_EN );
rep |= ( (P_DD_IN >> DD) & 0x0F); //Read low nibble
EN_0;
_delay_us( t_L_EN );
#else
EN_1;
_delay_us( t_H_EN);
rep = P_DD_IN;
EN_0;
_delay_us( t_L_EN );
#endif
}while( 0x80 & rep ); //Check Busy Flag
RW_0;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void lcd_cmd( uint8_t cmd )
{
delay_ms(1); //eigentlich lcd_busy();
RS_0;
RW_0;
_delay_us(t_W_RS_RW);
Set_P_DD( cmd );
RS_1;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void lcd_put( uint8_t dd )
{
delay_ms(1); //eigentlich lcd_busy();
Set_P_DD( dd );
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void lcd_init( void )
{ uint8_t i;
P_RS_DDR |= (1 << RS); //as Output
P_RW_DDR |= (1 << RW);
P_EN_DDR |= (1 << EN);
#ifdef _4_bit_mode_
P_DD_DDR |= (0x0F << DD); //as Output
#else
P_DD_DDR = 0xFF;
#endif
RS_0;
RW_0;
delay_ms(t_Init_1);
#ifdef _4_bit_mode_
SET_DD( (FUNCTION_SET + DL) >> 4 );
#else
SET_DD( FUNCTION_SET + DL );
#endif
for( i=0; i<=2; i++) //3x Function setting
{
EN_1;
_delay_us( t_H_EN );
EN_0;
_delay_us( t_L_EN );
delay_ms(t_Init_2);
}
lcd_cmd( FUNCTION_SET + N ); //2/4 line display
lcd_cmd( DISPLAY_CON + D + C + B ); //Display:ON, Cursor:ON, Blink: ON
lcd_cmd( ENTRY_MODE + ID ); //Increment Cursor
lcd_cmd( CLEAR_SCREEN );
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void lcd_write( const char *dd )
{
while( *dd != '\0' ) lcd_put( *dd++ );
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void lcd_pos( uint8_t x, uint8_t y )
{
uint8_t add;
switch (y)
{ case 1: add = DD_ADD_SET + Line_1 + x;
break;
case 2: add = DD_ADD_SET + Line_2 + x;
break;
case 3: add = DD_ADD_SET + Line_3 + x;
break;
case 4: add = DD_ADD_SET + Line_4 + x;
break;
default: return;
}
lcd_cmd( add );
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void lcd_put_bin( uint8_t c )
{
for(uint8_t j=0x80; j>= 0x01; j>>=1 )
{
if( j == 0x08 ) lcd_put( 0x7C );
if( c & j ) lcd_put( 0xFF );
else lcd_put( 0x20 );
}
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void lcd_CG ( uint8_t add, uint8_t *c)
{
add |= CG_ADD_SET;
lcd_cmd( add );
for (uint8_t i = 0; i<=7; i++) lcd_cmd( c[i] );
}
So ich bin für jeden Tipp und jede Anregung sehr dankbar. Außerdem würde mich es mal interessieren wie Ihr die Lesbarkeit des Codes findet.
Mit freundlichen Grüßen Crowdy