<?php echo _title;?> www.prochazka.zde.cz
www.ccsinfo.com/CEH
Server si právě čte 30 lidí, dnes je čtvrtek, 18. Duben 2024   
Kategorie: Knihovnička, Programy, HW

LCD display s radičem HD44780 a mikrořadič ATMEL16...

icons pic Ovládaní dvou řádkový LCD display kompatibilní s HD44780 po 7mi drátech. Pomocí ATMELu. Konkrétně ATMEGA16- 16AU - SMD. Kde display je připojen na portu C. Kód je napsán v Céčku.

Po nějakém čase sem se opět na chvilku dostal k programování...

Potřeboval jsem ovládat dvou řádkový LCD display kompatibilní s HD44780 po 7mi drátech. Je použita platforma ATMEL. Konkrétně ATMEGA16- 16AU - SMD. Kde display je připojen na portu C. V tomto pořadí:

Text code

PORTC.0 -> LCD_RS
PORTC.1 -> LCD_RW
PORTC.2 -> LCD_E
PORTC.3 -> NC

PORTC.4 -> D4
PORTC.5 -> D5
PORTC.6 -> D6
PORTC.7 -> D7

 

PINy D0 až D3 na LCD nutno uzemnit.

Program je napsán v céčku, ve vývojovém prostředí Atmel Studio 7.0. pod WIN10. Jako programátor je použit: USB programátor atmel

Tento programátor se mě nepodařil rozjet ve vývojovém prostředí Atmel Studio 7.0., tak jsem nainstaloval Atmel Studio 4. V Atmel Studio 7.0. v nástrojové záložce TOOLS položka EXTERNAL TOOLS... nakonfigurujte spouštění AS4 (Atmel Studio 4). Potom samotné programování je otázkou jen třech kliknuti (Spustit AT4, CONNECT TO THE SELECTED AVR PROGRAMMER, PROGRAM) a za cca 7 sekund je naprogramováno.

Jen jedna malá poznámka ke kódu. Jak určitě víte, tak na PORTU C mikrořadiče ATMEGA16 sídlí JTAG interface. Který sice lze vypnout v průběhu programování pojistek a konfigurace, ale jako odkojený PIC mikrořadiči, nelogický postup něco někde nastavovat programátorem, to vše má bejt už v obslužném kódu. Jak jsem záhy zjistil, téměř nikdo nepoužívá SW vypnutí JTAG interface. Nedalo mě to, musel jsem na to přijít. Výsledek snažení je zde:

PIC16 code

        //MCUCSR |= (1 << JTD); // <-- toto se nesmí použít. Kompilér to zoptimalizuje do nepoužitelné podoby!!!
        //MCUCSR |= (1 << JTD);
        MCUCSR = 0x80; //vypne JTAG interface. Nutno dodržet že za 4clk postat tento příkaz dvakrát!!!
        MCUCSR = 0x80; // druhé potvrzující vypnutí JTAG interface. Nepoužívat bitoví maskovaní. Natvrdo poslat hodnotu celého registru!!!
        /*Bits 7 - JTD: JTAG Interface Disable
        When this bit is zero /, the JTAG interface is enabled if the JTAGEN Fuse is programmed.
        If this bit is one, the JTAG interface is disabled. In order to avoid unintentional disabling
        or enabling of the JTAG interface, a timed sequence must be followed when changing
        this bit: The application software must write this bit to the desired value twice within FOUR
        cycles to change its value.
       
       
        Z céckového zápisu po kompilaci vypadne toto:

        278:    80 e8           ldi     r24, 0x80       ; 128
        27a:    84 bf           out     0x34, r24       ; 52
        27c:    84 bf           out     0x34, r24       ; 52

        Což splňuje požadavek 4clk.
       
        Zapnout optimalizaci -Os! -->  This is optimalizace for size
        */
 

Další drobný problém byl, že mikrokontrolér je taktován na 16MHz a pulzy byli strašně krátké, tak se muselo použít před každou instrukcí:

PIC16 code
LCDport SetLcdEn;

 

Čekání 1us. To samé platí i pro nastavení PINu EN do LOG. 0. Také je potřeba čekat 1us. Před provedením jakékoliv operace s LCD (kromě prvních dvou při inicializaci -> tam se vždy čeká 100ms) je proveden test na BF FLAG, zda je předchozí příkaz už proveden. Když jednotlivé kódy porovnáte, zjistíte že je témeř identicky jak pro PIC procesor: čtyřbitová komunikace LCD display s radičem HD44780 a mikrořadiče PIC16Fxx

Main.c

PIC16 code

void Main_Init(void)
{
# warning "    >>>   LCD HD44780   <<<       www.prochazka.zde.cz                                                                               "
#if DEBUG
        #define F_CPU 1000UL    // 1Khz clk
        # warning "F_CPU Definuji kmitocet oscilatoru 1 Khz pro --> MODE DEBUG --> <util/delay.h>                                 "
#else
        #define F_CPU 16000000UL // 16MHz clk
        # warning "F_CPU Definuji kmitocet oscilatoru 16 MHz pro --> MODE RELEASE --> <util/delay.h>                          "
#endif
#include <stdio.h>
#include <stdlib.h>
#include <avr/io.h>
#include <util/delay.h>
#include "lcd_lib.h"


lcd_init();

lcd_goto(0,0);
lcd_string("  LCD HD44780");   
_delay_ms(1000);
lcd_goto(0,1);
lcd_string("prochazka.zde.cz");        
_delay_ms(2000);
ScrollMessage(0,1,"     Pokus rotace...                      ");
}

 

lcd_lib.c

PIC16 code

#include "lcd_lib.h"
#include <inttypes.h>
#include <avr/io.h>
#include <avr/pgmspace.h>
#include <avr/sfr_defs.h>


#if DEBUG
        #define F_CPU 1000UL    // 1Khz clk
#else
        #define F_CPU 16000000UL // 16 MHz clk
#endif
#include <util/delay.h>

void lcd_busy (void){
        LCDtris &= ~(1<<DB7);   //shození bitů do 0 (a zbytek ponechán stávající stav) --> SET BITs INPUT
        LCDport ClearLcdRs;
        LCDport SetLcdRw;
        _delay_us(1);
        LCDport SetLcdEn;
        _delay_us(1);
        while (bit_is_set(PINC, 7)) { //Nektere displaye neposilaji informaci o dokonceni. Test na BF příznak.
                LCDport ClearLcdEn;
                _delay_us(1);
                LCDport SetLcdEn;
                _delay_us(1);
                LCDport ClearLcdEn;
                _delay_us(1);
                LCDport SetLcdEn;
        }
        _delay_us(1);
        LCDport ClearLcdRw;
        LCDtris |= (1<<DB7);    //nahození bitů do 1 (a zbytek ponechán stávající stav) --> SET BITs OUTPUT
}
//----------------------------------------------------------------
void send_prikaz (unsigned int bCommand){
        lcd_busy();
        LCDport ClearLcdRw;
        _delay_us(1);
        LCDport SetLcdEn;
        zapis_w(bCommand);
        LCDport ClearLcdEn;
}
//----------------------------------------------------------------
void WriteChangeNimble(unsigned int bCommand){
        //zkopirovat 0 az 3 bity z promenne bCommand na porty LCDport do BITu 4 az 7.
        //samozrejme ze tento cely slozity zapis se da nahradid jednou ASM instrukci na prohozeni nimble a nasledne zavolat funkci zapis_w(), bohuzel jak to napsat v Cecku je me zahadou...
        //coment is ASM for PIC
       
        _delay_us(1);
        if (bCommand &(1 << 0)){                        //btfsc bCommand,0
                LCDport |= (1<<DB4);                    //bsf LCDport,4
        } else{ LCDport &= ~(1<<DB4);}                  //bcf _PORTB,4
               
        if (bCommand &(1 << 1)){                        //btfsc bCommand,1
                LCDport |= (1<<DB5);                    //bsf LCDport,5
        } else{ LCDport &= ~(1<<DB5);}                  //bcf _PORTB,5
                       
        if (bCommand &(1 << 2)){                        //btfsc bCommand,2
                LCDport |= (1<<DB6);                    //bsf LCDport,6
        } else{ LCDport &= ~(1<<DB6);}                  //bcf _PORTB,6
                               
        if (bCommand &(1 << 3)){                        //btfsc bCommand,3
                LCDport |= (1<<DB7);                    //bsf LCDport,7
        } else{ LCDport &= ~(1<<DB7);}                  //bcf _PORTB,7
}
//----------------------------------------------------------------
void zapis_w(unsigned int bCommand){
        //zkopirovat 4 az 7 bity z promenne bCommand na porty LCDport.
        //coment is ASM for PIC

        _delay_ms(1);
        if (bCommand &(1 << DB4)){                      //btfsc bCommand,4
                LCDport |= (1<<DB4);                    //bsf LCDport,4
        } else{ LCDport &= ~(1<<DB4);}                  //bcf _PORTB,4
       
        if (bCommand &(1 << DB5)){                      //btfsc bCommand,5
                LCDport |= (1<<DB5);                    //bsf LCDport,5
        } else{ LCDport &= ~(1<<DB5);}                  //bcf _PORTB,5
               
        if (bCommand &(1 << DB6)){                      //btfsc bCommand,6
                LCDport |= (1<<DB6);                    //bsf LCDport,6
        } else{ LCDport &= ~(1<<DB6);}                  //bcf _PORTB,6
                       
        if (bCommand &(1 << DB7)){                      //btfsc bCommand,7
                LCDport |= (1<<DB7);                    //bsf LCDport,7
        } else{ LCDport &= ~(1<<DB7);}                  //bcf _PORTB,7
}
//----------------------------------------------------------------
void lcd_put_cmd (unsigned int bCommand){
        //Posle prikaz na Display.
        //asm ("movwf _lcd_data");
        send_prikaz (bCommand);
        LCDport SetLcdEn;
        WriteChangeNimble(bCommand);                            //asm ("swapf _lcd_data , f");
        LCDport ClearLcdEn;
}
//----------------------------------------------------------------
void lcd_put_char (unsigned char sString){
        //Pošle znak na Display.
        lcd_busy();
        LCDport ClearLcdRw;     //LCD_RW = 0;
        LCDport SetLcdRs;       //LCD_RS = 1;
        _delay_us(1);
        LCDport SetLcdEn;
        zapis_w (sString);
        LCDport ClearLcdEn;
        _delay_us(1);
        LCDport SetLcdEn;
        WriteChangeNimble(sString);                             //asm ("swapf _lcd_data , f");
        _delay_us(1);
        LCDport ClearLcdEn;
}
//----------------------------------------------------------------
void lcd_string(const char * s){
        while(*s)
        lcd_put_char(*s++);
}
//----------------------------------------------------------------
void ScrollMessage(unsigned char pozice, unsigned char radek,const char Message[])
//Pohybuje textem na zvoleném řádku od zadané pozice.
{
        char TempS[20];
        unsigned int MHead=0,Done=0,count;
        while(Done==0)
        {
                for(count=0;count<20;count++)
                {
                        TempS[count]=Message[MHead+count];
                        if(Message[MHead+count+1]==0) Done=1;
                }
                MHead++;
                lcd_goto(pozice, radek);
                lcd_string(TempS);
                _delay_ms(250);
        }
}
//----------------------------------------------------------------
void lcd_scroll(char Direction)
//Pohybuje celým displayem. Toto je funkce LCD (HW)
{
        if(Direction==SCROLL_LEFT)
        {
                lcd_put_cmd(0b00011000); //Scroll LEFT
        }
        else
        {
                lcd_put_cmd(0b00011100); //Scroll RIGHT
        }
}
//----------------------------------------------------------------
void lcd_goto(unsigned char pozice, unsigned char radek)
{
        if(radek >1) radek=1;
        lcd_put_cmd(((radek * 40) + 0x80)+ pozice);
}
//----------------------------------------------------------------
void lcd_init1(void){
 _delay_ms(100);
//***************** Nastaveni 8-bitové komunikace ***************************
 send_prikaz(0x30);             //8-bit-interface
 _delay_ms(100);
//*************** Nastaveni 4-bitové komunikace *****************************
 send_prikaz(0x20);             //4-bit-interface
 _delay_ms(100);
//***************************************************************************
 lcd_put_cmd (0x28);    //4-bit-interface, 2-lines
 //lcd_put_cmd (0b00100000);

 lcd_put_cmd (0x08);    //disp.off, curs.off, no-blink
 lcd_put_cmd (0x01);    //lcd smazat
 lcd_put_cmd (0x0c);    //disp.on, curs.off
//lcd_put_cmd (0x0F);   //Display ON, Cursor On, Cursor Blinking
 lcd_put_cmd (0x06);    //Inkrementace, normalni mod.
}
//----------------------------------------------------------------
void lcd_init(void){    //Pro jistotu se provede několikrát inicializace

        //MCUCSR |= (1 << JTD); // <-- toto se nesmi pouzit, kompiler to zoptimalizuje do nepouzitelne podoby!!!
        //MCUCSR |= (1 << JTD);
        MCUCSR = 0x80; //vypne JTAG interface, nutno dodrzet ze za 4clk postat tento prikaz dvakrat!!!
        MCUCSR = 0x80; // drude potvrzujici vypnuti JTAG interface, nepouzivet bitove maskovani, natvrdo poslat hodnotu celeho registru!!!
        /*Bits 7 – JTD: JTAG Interface Disable
        When this bit is zero, the JTAG interface is enabled if the JTAGEN Fuse is programmed.
        If this bit is one, the JTAG interface is disabled. In order to avoid unintentional disabling
        or enabling of the JTAG interface, a timed sequence must be followed when changing
        this bit: The application software must write this bit to the desired value twice within FOUR
        cycles to change its value.
       
        278:    80 e8           ldi     r24, 0x80       ; 128
        27a:    84 bf           out     0x34, r24       ; 52
        27c:    84 bf           out     0x34, r24       ; 52
       
        Zapnout optimalizaci  -Os! -->  This is optimalizace for size
        */
                       
        LCDtris |= ((1<<DB4) | (1<<DB5) | (1<<DB6) | (1<<DB7) | (1<<LcdEn) | (1<<LcdRw) | (1<<LcdRs));  //nahození bitů do 1 (a zbytek ponechán stávající stav) --> SET PORT OUTPUT
        lcd_init1();
}

 

lcd_lib.h

PIC16 code

#ifndef LCD_LIB
#define LCD_LIB

#include <inttypes.h>


#define DB4 4
#define DB5 5
#define DB6 6
#define DB7 7
#define LcdEn 2
#define LcdRw 1
#define LcdRs 0
#define SET &=
#define CLEAR |=
#define INVERT ^=
#define NULLh 0
#define TRUE 1
#define FALSE 0

#define ClearLcdEn &= ~((1<<LcdEn))
#define ClearLcdRw &= ~((1<<LcdRw))
#define ClearLcdRs &= ~((1<<LcdRs))

#define setb(port,pin) port |= 1<<pin           // definuje nastavení bitu
#define clrb(port,pin) port &= ~(1<<pin)        // definuje vynulování bitu
#define negb(port,pin) port ^= 1<<pin           // definuje negování bitu


#define SetLcdEn |= ((1<<LcdEn))
#define SetLcdRw |= ((1<<LcdRw))
#define SetLcdRs |= ((1<<LcdRs))

#define LCDport PORTC
#define LCDtris DDRC
#define BF_FLAG (PINC & (1<<5))
#define Led (1<<0)
#define LedSet |= Led
#define LedClear &= ~Led
#define LedPort PORTA
#define LedTris DDRA
#define SCROLL_LEFT 0xAA
#define SCROLL_RIGHT 0xCC

 

print Formát pro tisk

Komentáře rss

Nemáte oprávnění přidávat příspěvky.

Uživatelské jméno
Heslo
     

Registrace >
Ztracené heslo >


Nebyly přidány žádné komentáře.

Všechny informace jsou zahrnuty pod GPL licenci, pokud není explicitně uveden jiný typ licence.
Používání těchto stránek ke komerčním účelům lze jen se souhlasem autora.
Všechna práva vyhrazena (c) 1997 - 2024 hacesoft.
Jste návštevník číslo: 370727
Celkem zobrazeno stránek: 12325425
Přihlásit do administrace