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í:
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:
//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í:
Č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
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
#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
#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
Komentáře
Nebyly přidány žádné komentáře.