?? lab3.c
字號:
/************************************************************************ *********
* Proiectarea cu Microprocesoare
* Laborator 3
* Programarea in C sub AVR, Interfatare LCD alfanumeric, Comunicatie seriala RS232
*********************************************************************************/
#include <stdio.h>
#include <avr\io.h>
#include <avr\interrupt.h>
/************************************************************************
* DEFINE-uri pentru parametrizarea modulului LCD
************************************************************************/
#define LcdDATA_DDR DDRA // Portul pe care conectam firele de date la LCD-ul
#define LcdDATA_PORT PORTA
#define LcdDATA_PIN PINA
#define LcdCMD_DDR DDRA // Portul pe care conectam firele de comenzi la LCD
#define LcdCMD_PORT PORTA
#define LcdCMD_PIN PINA
#define LcdD4 PA0 // Pin-ul pentru firul de date D4 de pe LCD
#define LcdD5 PA1 // Pin-ul pentru firul de date D5 de pe LCD
#define LcdD6 PA2 // Pin-ul pentru firul de date D6 de pe LCD
#define LcdD7 PA3 // Pin-ul pentru firul de date D7 de pe LCD
#define LcdRS PA4 // Pinul pentru selectare operatie (LCD)
#define LcdRW PA5 // Pinul pentru Read/ Write (LCD)
#define LcdE PA6 // Pinul de Enable (LCD)
#define LCD_INSTR_4wire 0x28 // 4 fire date, font 5x8
#define LCD_INSTR_display 0x0C // Display On, Cursor On, Blinking On ( 1 Display Cursor Blink )
#define LCD_INSTR_clearDisplay 0x01 // Clear Display
#define LCD_INSTR_returnHome 0x02 // Return Cursor and LCD to Home Position
#define LCD_INSTR_nextLine 0xC0 // Return Cursor and LCD to Home Position
/************************************************************************
* REDIRECTARE stdin, stdout pentru receptie, transmisie seriala
************************************************************************/
int uart_putchar(char c, FILE *unused);
int uart_getchar(FILE* f);
FILE mystdout = FDEV_SETUP_STREAM(uart_putchar, NULL, _FDEV_SETUP_WRITE);
FILE mystdin = FDEV_SETUP_STREAM(NULL, uart_getchar, _FDEV_SETUP_READ);
/************************************************************************
* API LCD.. implementare este in partea de jos a fisierului
************************************************************************/
void LCD_init(); // Initializare modul LCD.. trebuie apelata inainte de a se face orice operatie cu LCD-ul
void LCD_writeInstruction(unsigned char _instruction); // Trimite o instructiune catre lcd (vezi datasheet)
void LCD_writeData(unsigned char _data); // Trimite date catre LCD pentru afisare
void LCD_write(unsigned char _byte); // trimite un bute catre LCD la modul general (nu conteaza daca e instructiune sau date)
void LCD_waitNotBusy(); // Asteptam pana cand lcd-ul devine disponibil pt o noua comanda
void LCD_print(char* _msg); // Afiseaza imformatia pe LCD (doar 1 linie, primele 16 caractere)
void LCD_print2(char* _msg1, char* _msg2); // Afisare pe 2 lini pe LCD
void LCD_printDecimal2u(unsigned int _n); // Afisare numar in baza 10 pe LCD
void LCD_printHexa(unsigned int _n); // Afisare numar in baza 16 pe LCD
void LCD_waitInstructions(unsigned char _instructions); // Asteapta un numar de cicli de tact.. loop
/************************************************************************
* Vectorul de intreruperi... exemplu pt labroatorul 2, intreruperi
************************************************************************/
// Exemplu de functie ce se apeleaza la interval de 1 secunda, intrerupere generata de timerul 1 (vezi laboratorul 2)
SIGNAL(SIG_OUTPUT_COMPARE1A)
{
// Cod ce se apeleaza 1 data pe secunda
// Exemplu de implemenare in C pentru laboratorul nr 2 (ASM)
}
void initUsart();
void initTimer1();
/************************************************************************
* PROGRAMUL PRINCIPAL
************************************************************************/
int main(void)
{
// Mesajul ce este citit pe seriala si afisat pe LCD
char message[33];
// Initializare
initUsart();
initTimer1();
stdin = &mystdin;
stdout = &mystdout;
// Activare sistem de intreruperi
sei();
// Functie pentru initializarea LCD-ului si afisarea mesajului WELCOME
LCD_init();
LCD_writeInstruction(LCD_INSTR_clearDisplay);
LCD_print("WELCOME");
// Asteptam dupa un mesaj si apoi il afisam pe LCD, dupa care reluam ciclul
for(;;)
{
printf("\nEnter message: ");
scanf("%s",message);
LCD_writeInstruction(LCD_INSTR_clearDisplay);
LCD_print(message);
}
return 0;
}
void initUsart() // Initializare modul USART pt comunicatie la 9600bps, 8 biti de date, la 16MHz
{
//TODO
}
void initTimer1() // Initializare timer 1 compare match A pentru a avea un timer la nivel de 1 secunda, 16MHz
{
OCR1A = 15624;
TCCR1A = 0;
TCCR1B = (1<<WGM12)|(1<<CS12)|(1<<CS10);
TIMSK |= _BV(OCIE1A);
}
/************************************************************************
* IMPLEMENTARE FUNCTII TRANSMISIE/RECEPTIE SERIALA, pentru mapare stdin, stdout
************************************************************************/
// Functie ce trateaza trimiterea unui caracter pe seriala
int uart_putchar(char c, FILE *unused)
{
//TODO
}
// Functie ce trateaza primirea unui caracter pe seriala
int uart_getchar(FILE* f)
{
//TODO
}
/************************************************************************
* IMPLEMENTARE API LCD.. implementare este in partea de jos a fisierului
************************************************************************/
void LCD_init()
{
LcdDATA_DDR |= (1<<LcdD4)|(1<<LcdD5)|(1<<LcdD6)|(1<<LcdD7); // setam pinii de date ca pini de iesire
LcdCMD_DDR |= (1<<LcdRS)|(1<<LcdRW)|(1<<LcdE); // setam pinii de comenzi ca pini de iesire
LCD_waitNotBusy();
LcdCMD_PORT &= ~(1<<LcdRS); // Setam linia RS pe low
LcdCMD_PORT &= ~(1<<LcdRW); // Setam linia RW pe low (acum suntem in modul de trimis instructiuni)
LcdDATA_PORT &= ~(1<<LcdD4)&~(1<<LcdD6)&~(1<<LcdD7); // Specificam ca vrem 4 fire de date, prima comanda (LcdD5 activ, restul nu)
LcdDATA_PORT |= (1<<LcdD5); // setam pinii de comenzi ca pini de iesire
LcdCMD_PORT |= (1<<LcdE); // Setam linia E(nable) pe high; aceasta ii specifica LCD-ului sa preia datele
LCD_waitInstructions(6); // Asteptam o perioada de timp T
LcdCMD_PORT &= ~(1<<LcdE ); // Setam linia E(nable) pe low; transferul s-a terminat
LCD_writeInstruction(LCD_INSTR_4wire); // Incarcam comanda: 4 bit data, 2 lines, 5x8 font
LCD_writeInstruction(LCD_INSTR_display); // Display On, Cursor On, Blinking On
LCD_writeInstruction(0x06); // Increment, no shift
LCD_writeInstruction(0x01); // Clear Display
}
void LCD_writeInstruction(unsigned char _instruction)
{
//TODO
// asteptam ca LCD-ul sa fie liber sa primeasca comenzile
// setam pinul RS pe low.. low=instructiuni, high=date
// setam pinul RW pe low (suntem in modul de comenzi acum)
// apelam procedura ce trimite byte-ul pe firele de date
}
void LCD_writeData(unsigned char _data)
{
//TODO
// asteptam ca LCD-ul sa fie liber sa primeasca comenzile
// setam pinul RS pe high
// setam pinu RW pe low (suntem in modul de date acum)
// apelam procedura ce trimite byte-ul pe firele de date
}
void LCD_write(unsigned char _byte)
{
unsigned char _byte2;
_byte2 = _byte>>4;
LcdDATA_PORT &= ~(1<<LcdD4);
if ( bit_is_set( _byte2, 0 ) )
LcdDATA_PORT |= (1<<LcdD4);
LcdDATA_PORT &= ~(1<<LcdD5);
if ( bit_is_set( _byte2, 1 ) )
LcdDATA_PORT |= (1<<LcdD5);
LcdDATA_PORT &= ~(1<<LcdD6);
if ( bit_is_set( _byte2, 2 ) )
LcdDATA_PORT |= (1<<LcdD6);
LcdDATA_PORT &= ~(1<<LcdD7);
if ( bit_is_set( _byte2, 3 ) )
LcdDATA_PORT |= (1<<LcdD7);
LcdCMD_PORT |= (1<<LcdE); // Setam Pinul E pe high
LCD_waitInstructions(6); // Asteptam o perioada de timp T
LcdCMD_PORT &= ~(1<<LcdE); // Setam Pinul E pe low
LCD_waitInstructions(6); // Asteptam o perioada de timp T
LcdDATA_PORT &= ~(1<<LcdD4);
if ( bit_is_set( _byte, 0 ) )
LcdDATA_PORT |= (1<<LcdD4);
LcdDATA_PORT &= ~(1<<LcdD5);
if ( bit_is_set( _byte, 1 ) )
LcdDATA_PORT |= (1<<LcdD5);
LcdDATA_PORT &= ~(1<<LcdD6);
if ( bit_is_set( _byte, 2 ) )
LcdDATA_PORT |= (1<<LcdD6);
LcdDATA_PORT &= ~(1<<LcdD7);
if ( bit_is_set( _byte, 3 ) )
LcdDATA_PORT |= (1<<LcdD7);
LcdCMD_PORT |= (1<<LcdE); // Setam Pinul E pe high
LCD_waitInstructions(6); // Asteptam o perioada de timp T
LcdCMD_PORT &= ~(1<<LcdE); // Setam Pinul E pe low
}
void LCD_waitNotBusy()
{
unsigned char _loop = 1;
while (_loop)
{
LcdDATA_DDR &= ~(1<<LcdD4 | 1<<LcdD5 | 1<<LcdD6 | 1<<LcdD7); // Setam pinii de date de la LCD pe in pt a citi busy flag
LcdDATA_PORT &= ~(1<<LcdD4 | 1<<LcdD5 | 1<<LcdD6 | 1<<LcdD7); // Dezactivam pullup resistor pentru pinii de in
LcdCMD_PORT &= ~(1<<LcdE); // Setam pin-ul e pe low; ar trebui sa fie deja low, doar ne asiguram
LcdCMD_PORT &= ~(1<<LcdRS); // Setam pinul RS pe low
LcdCMD_PORT |= (1<<LcdRW); // Setam pinul RW pe high (acum suntem in modul de interogare busy/adr)
LcdCMD_PORT |= (1<<LcdE); // Setam Pinul E pe high
LCD_waitInstructions(6); // Asteptam o perioada de timp T
_loop = LcdDATA_PIN & (1<<LcdD7); // Citim busy flag-ul
LcdCMD_PORT &= ~(1<<LcdE); // Setam Pinul E pe low
LCD_waitInstructions(6); // Asteptam o perioada de timp T
LcdCMD_PORT |= (1<<LcdE); // Setam Pinul E pe high
LCD_waitInstructions(6); // Asteptam o perioada de timp T
LcdCMD_PORT &= ~(1<<LcdE); // Setam Pinul E pe low
LcdDATA_DDR |= (1<<LcdD4 | 1<<LcdD5 | 1<<LcdD6 | 1<<LcdD7); // Setam Portul de LCD ca port de iesire la loc
}
}
void LCD_printDecimal2u(unsigned int _n)
{
unsigned char tmp=0;
// Extragem sutele
while(_n>=100)
_n-=100;
while(_n>=10){
tmp++;
_n-=10;
}
LCD_writeData(tmp+'0');
LCD_writeData(_n+'0');
}
void LCD_printHexa(unsigned int _n)
{
unsigned char _tmp = _n>>4;
if (_tmp>9)
_tmp += 'A'-10;
else
_tmp += '0';
LCD_writeData( _tmp );
_tmp = _n & 0x0F;
if (_tmp>9)
_tmp += 'A'-10;
else
_tmp += '0';
LCD_writeData( _tmp );
}
void LCD_print(char* _msg)
{
unsigned char i=0;
for( ; _msg[i]!=0 && i<16; i++)
LCD_writeData( _msg[i] );
}
void LCD_print2(char* _msg1, char* _msg2)
{
LCD_writeInstruction(LCD_INSTR_clearDisplay);
LCD_print(_msg1);
LCD_writeInstruction(LCD_INSTR_nextLine);
LCD_print(_msg2);
}
void LCD_waitInstructions(unsigned char _instructions)
{
while (_instructions--)
;
}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -