Sari la conținut

LCD2x16 si atmega328


dan_e

Postări Recomandate

Salutari tuturor, 

 

E primul meu topic pe anul asta. Am trecut si eu recent de la AVR Studio la MicroCip Studio si am deschis sa fac un program banal in C care sa citeasca valoarea count_adc (0...1023) de pe pinul PA0 la un atmega32 si sa-l afiseze pe ecranul LCD 2x16 si nu-mi iese.

Pentru comanda LCD am descarcat de pe site-ul urmator fisierele:  "lcd_lib.h" si "lcd_lib.c"

https://scienceprog.com/avr-dds-signal-generator-v20/

din arhiva programului DDS prezentat acolo.

Bineinteles ca le-am declarat in header-ul programului sub forma:

#include "lcd_lib.h"
#include "lcd_lib.c"

iar programul, fara partea de initializare adc (sa vad cum fac initializarea adc pe 10bit), arata succint cam asa:

#ifndef F_CPU
#define F_CPU 8000000UL            // Setare quartz MCU la 8 MHz
#endif

#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include "lcd_lib.h"
#include "lcd_lib.c"

double adc;     // Definim variabilele de lucru
unsigned int i;

/* aici urmeaza sa introduc codul de initializare adc pe 10bit, poate are cineva vreo idee */

int main(void)
{
    ADC_Init();        
       
    do 
    {
        adc = 0;
        adc = ADC_Read(0);
        _delay_ms(10);
                
        LCDGotoXY(0, 1);  // de aici m-am blocat
                
    } while (1);
}

 

:scratchchin::scratchchin::scratchchin:

Link spre comentariu
Distribuie pe alte site-uri

In primul rand trebuie sa te asiguri ca ai declarat in fisierul "lcd_lib.h" pinii de conectare LCD cei corecti, inclusiv portul de conectare LCD, pentru ca in fisierul implicit se foloseste portul C a MCU, citez:

//Uncomment this if LCD 4 bit interface is used
//******************************************
#define LCD_4bit
//***********************************************

#define LCD_RS    0     //define MCU pin connected to LCD RS
#define LCD_RW    1     //define MCU pin connected to LCD R/W
#define LCD_E    2    //define MCU pin connected to LCD E
#define LCD_D0    0    //define MCU pin connected to LCD D0
#define LCD_D1    1    //define MCU pin connected to LCD D1
#define LCD_D2    2    //define MCU pin connected to LCD D1
#define LCD_D3    3    //define MCU pin connected to LCD D2
#define LCD_D4    4    //define MCU pin connected to LCD D3
#define LCD_D5    5    //define MCU pin connected to LCD D4
#define LCD_D6    6    //define MCU pin connected to LCD D5
#define LCD_D7    7    //define MCU pin connected to LCD D6
#define LDP PORTC    //define MCU port connected to LCD data pins
#define LCP PORTC    //define MCU port connected to LCD control pins
#define LDDR DDRC    //define MCU direction register for port connected to LCD data pins
#define LCDR DDRC    //define MCU direction register for port connected to LCD control pins

 

Tot in fisierul "lcd_lib.h" sunt mentionate functiile folosite si detaliate in fisierul "lcd_lib.c" citez:

void LCDsendChar(uint8_t);        //forms data ready to send to LCD
void LCDsendCommand(uint8_t);    //forms data ready to send to LCD
void LCDinit(void);            //Initializes LCD
void LCDclr(void);                //Clears LCD
void LCDhome(void);            //LCD cursor home
void LCDstring(uint8_t*, uint8_t);    //Outputs string to LCD
void LCDGotoXY(uint8_t, uint8_t);    //Cursor to X Y position
void CopyStringtoLCD(const uint8_t*, uint8_t, uint8_t);//copies flash string to LCD at x,y
void LCDdefinechar(const uint8_t *,uint8_t);//write char to LCD CGRAM 
void LCDshiftRight(uint8_t);    //shift by n characters Right
void LCDshiftLeft(uint8_t);    //shift by n characters Left
void LCDcursorOn(void);        //Underline cursor ON
void LCDcursorOnBlink(void);    //Underline blinking cursor ON
void LCDcursorOFF(void);        //Cursor OFF
void LCDblank(void);            //LCD blank but not cleared
void LCDvisible(void);            //LCD visible
void LCDcursorLeft(uint8_t);    //Shift cursor left by n
void LCDcursorRight(uint8_t);    //shif cursor right by n
// displays a horizontal progress bar at the current cursor location
// <progress> is the value the bargraph should indicate
// <maxprogress> is the value at the end of the bargraph
// <length> is the number of LCD characters that the bargraph should cover
//adapted from AVRLIB - displays progress only for 8 bit variables
void LCDprogressBar(uint8_t progress, uint8_t maxprogress, uint8_t length);

 

Ca sa afisezi valoarea adc pe ecranul LCD, sunt mai multe metode, una mai simpla as zice este urmatoarea:

unsigned char ch; // definim ch imediat dupa rutinele "include" si apoi dupa citirea adc urmatoarele: 
                     
                         ch = adc /1000u; 
                         LCDGotoXY(0,1);               // extract 10.00 U digit
                         LCDsendChar(48+ch);          // scrie digit ASCII in primul rand, coloana 2
                         
                         ch = (adc / 100u) % 10u;     // extrage 01.00 digit
                         LCDGotoXY(0,2);
                         LCDsendChar(48+ch);               // scrie digit ASCII in dreptul cursorului
                         
                         ch = (adc / 10u) % 10u;      // extrage 00.10 digit
                         LCDGotoXY(0,3);
                         LCDsendChar(48+ch);               // scrie digit ASCII in dreptul cursorului
                         
                         ch = adc % 10u;              // extrage 00.01 digit
                         LCDGotoXY(0,4);
                         LCDsendChar(48+ch);               // scrie digit ASCII in dreptul cursorului

 

In ceea ce priveste configurarea adc in mod 10bit, o solutie ar fi sa aplici metoda sau codul implementat de mine la dezvoltarea soft-ului aferent proiectului DP0514 din noul A350:

void ADC_Init()            // Initializare convertor analog-digital (ADC)
{
    DDRA&=~(1<<PA0);     // Setez ca intrare pinii PA0
    ADCSRA = 0x87;        // Activeaza ADC cu fr/128
    ADMUX = 0x40;        // Vref: Avcc
}

int ADC_Read(char channel)  // configurare ADC Atmega 16 in mod 10 biti
{
    int adcA, adcB;
    
    ADMUX &= 0xE0;                        //Sterge vechiul canal
    ADMUX |= channel;                    //Seteaza noul canal

    ADCSRA |= (1<<ADSC);                // Incepe conversia
    while((ADCSRA&(1<<ADIF))==0);
    
    _delay_us(10);
    adcB = (int)ADCL;                    // Citeste primi 8 biti
    adcA = (int)ADCH*256;                // Citeste si cei 2 biti suplimentari ca sa obtinem 10bit ADC
    
    adcA = adcA + adcB;
    return(adcA);                        // Returneaza valoarea adc pe 10 bit = 0...1023
}

 

Numai bine

  • Thanks 1
Link spre comentariu
Distribuie pe alte site-uri

Mersi.

Am descarcat programul DP0514, am imprumutat de acolo initializarea ADC, am verificarea maparea pinilor LCD si sunt conform fisierului lcd_lib.h dar cred ca partea asta de program nu functioneaza cum trebuie - ma refer la partea de cod de mai jos:

                         ch = adc /1000u;
                         LCDGotoXY(0,1);               // extract 10.00 U digit
                         LCDsendChar(ch);          // scrie digit ASCII in primul rand, coloana 2
                                                  
                         ch = (adc / 100u) % 10u;     // extrage 01.00 digit
                         LCDGotoXY(0,2);
                        LCDsendChar(ch);               // scrie digit ASCII in dreptul cursorului
                                                  
                         ch = (adc / 10u) % 10u;      // extrage 00.10 digit
                         LCDGotoXY(0,3);
                         LCDsendChar(ch);               // scrie digit ASCII in dreptul cursorului
                                                  
                         ch = adc % 10u;              // extrage 00.01 digit
                         LCDGotoXY(0,4);
                        LCDsendChar(ch);               // scrie digit ASCII in dreptul cursorului

Am incercat sa inlocuiesc LCDsendChar(ch); cu LCDdefinechar(txt,ch); unde txt este de tip int char dar nu merge! Sau nu o fi bune fisierele lcd_lib.h si lcd_lib.c pentru ca sunt dezvoltate intr-un AVR GCC destul de vechi si sa nu le inteleaga Microcip Studio ? :scratchchin:                

Link spre comentariu
Distribuie pe alte site-uri

Acum 2 ore, dan_e a spus:

 

Am incercat sa inlocuiesc LCDsendChar(ch); cu LCDdefinechar(txt,ch); unde txt este de tip int char dar nu merge! Sau nu o fi bune fisierele lcd_lib.h si lcd_lib.c pentru ca sunt dezvoltate intr-un AVR GCC destul de vechi si sa nu le inteleaga Microcip Studio ? :scratchchin:         

 

E posibil deoarece am mai intalnit fisiere LCD.h & .c dezvoltate acum 10...15 ani in urma care nu functioneaza pe compilatoarele actuale corect! Incearca totusi sa te "mai joci" cu functiile in cauza. Succes!

Link spre comentariu
Distribuie pe alte site-uri

  • 2 weeks later...

Dan, 

 

pune niste mesaje de eroare ca e greu sa ghicim care e de fapt problema.

recunosc ca n-am citit tot thread-ul dar mi-a sarit in ochi 

 

Citat

unde txt este de tip int char dar nu merge!

In limbajul C nu exista tipul "int char" dar exista "int" si exista "char" daca vrei sa convertesti din int in char si invers poti sa te folosesti de cast.     

de exemplu 

int a = 120;

daca vrei sa sa-l convertest in char

b = (char)a ;     // daca incerci sa tiparesti pe 'b' vei obtine caravterul care corespunde lui ASCII 120 care e litera 'x'

 

daca vrei sa convertesti numere in stringuri (ca sa le afisezi) ai mai multe metode, functii C, dar nu sunt sigur ce vrei sa faci.

 

Cel mai bine e sa faci experimente C fara microcontroller, direct pe PC. 

 

RR

 

  • Thanks 1
Link spre comentariu
Distribuie pe alte site-uri

Dan

 

Eu vad exercitiul tau in 3 pasi.

 

1. Setezi ADC-ul si conversia.

2. Setezi LCD ul si eventual tiparesti ceva de test.

3. Convertesti valoarea de la adc (10 biti) intr-un string de caractere printabil pe LCD. si evident printezi valoarea

 

Daca am inteles eu bine e ca ai probleme cu partea 3.

corect?

 

Am extras din codul tau 

Citat

ch = adc /1000u;                          

LCDGotoXY(0,1);               // extract 10.00 U digit                        LCDsendChar(ch);          // scrie digit ASCII in primul rand, coloana 2

are niste probleme de limbaj C

 

ch = adc / 1000u;

 

Variablila adc e cel mai probabil  uint16_t (adica intreg fara semn pe 16 biti)

Constanta 1000  uint16_t 

rezultatul impartirii celor doua va fi si el un numar pe 16 biti

 

din cauza ca ch e de tip char 

unsigned char ch; // definim ch imediat dupa rutinele "include" si apoi dupa 

 

probabil ca iti va da un warning cum ca incerci sa asignezi un rezultat de 16 biti intr-o variabila de 8 biti, practic in cazul tau pierzi cei mai semnificativi 8 biti din rezultat, in cazul tau nu e o mare problema pentru ca te astepti ca rezultatul sa fie intre 0 si 9 si pierderea nu te doare.

 

daca vrei sa scapi de warning poti sa faci un cast 

ch = (char)(adc / 1000u);

 

practic ii zice compilatorului ca esti ok sa puna rezultatul intr-o variabila char (cu pierderea celor mai semnificativi 8 biti) 

 

Mai departe vrei sa scrii caracterul ascii corespunzator acelui numar obtinut in variabila "ch"

LCDsendChar(ch);

 

problema e ca LcdsendChar nu scrie ASCII-ul ci continutul byte-ului ch (care e de la 0 la 9) si trebuie convertit in ASCII daca vrei sa-l vezi pe LCD

 

Ascii pentru '0' e 48 in zecimal,  pentru '1' e 49  s.a.m.d.

deci inlocuieste 

LCDsendChar(ch);

cu

LCDsendChar(ch+48);

peste tot in programul tau unde vreu sa tiparesti  numere.

 

RR

 

PS - Donpetru a sugerat acelasi lucru intr-un post mai sus din pacate am vazut prea tarziu (dupa ce am scris)

sunt metode mult mai bune decat metoda asta babeasca care o sa-ti tipareasca o gramada de zeoruri in plus (de exemplu 64 o sa apara "0064")

 

Editat de roadrunner
vvv
  • Thanks 1
Link spre comentariu
Distribuie pe alte site-uri

Acum 2 ore, roadrunner a spus:

3. Convertesti valoarea de la adc (10 biti) intr-un string de caractere printabil pe LCD. si evident printezi valoarea

Daca am inteles eu bine e ca ai probleme cu partea 3.

corect?

Salut. Da, ai inteles bine.

Totusi eu am incercat recomandarile tale, spuse si de dl.petru, dar ceva nu merge cu functiile astea, inclusiv LCDsendChar.

Uite mai jos tot programul scris de mine tinand cont si de recomandarile d-lui @donpetru:

#ifndef F_CPU
#define F_CPU 8000000UL            // Setare quartz MCU la 8 MHz
#endif

#include <stdio.h>  // definim bibliotecile C de lucru
#include <stdlib.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include "lcd_lib.h"
#include "lcd_lib.c"

unsigned long adc;     // Definim variabilele de lucru
unsigned int i;
unsigned char ch;
char txt;

void ADC_Init()            // Initializare convertor analog-digital (ADC)
{
    DDRA&=~(1<<PA0);     // Setez ca intrare pinii PA0
    ADCSRA = 0x87;        // Activeaza ADC cu fr/128
    ADMUX = 0x40;        // Vref: Avcc
}

int ADC_Read(char channel)  // configurare ADC Atmega 16 in mod 10 biti
{
    int adcA, adcB;
    
    ADMUX &= 0xE0;                       //Sterge vechiul canal
    ADMUX |= channel;                    //Seteaza noul canal

    ADCSRA |= (1<<ADSC);              // Incepe conversia
    while((ADCSRA&(1<<ADIF))==0);
    
    _delay_us(10);
    adcB = (int)ADCL;                    // Citeste primi 8 biti
    adcA = (int)ADCH*256;            // Citeste si cei 2 biti suplimentari ca sa obtinem 10bit ADC
    
    adcA = adcA + adcB;
    return(adcA);                           // Returneaza valoarea adc pe 10 bit = 0...1023
}

void Main_Init(void){
ADC_Init();     // ADC init   
LCDinit();      // LCD init
LCDclr();
LCDcursorOFF();               
}

int main(void)
{
Main_Init();            
    do 
    {
        adc = 0;
        adc = ADC_Read(0);
        _delay_ms(20);
                
                         ch = adc /1000u;
                         LCDGotoXY(0,5);               // extract 10.00 U digit
                         LCDsendChar(ch);          // scrie digit ASCII in primul rand, coloana 2
                         // LCDdefinechar(txt,ch);
                         
                         ch = (adc / 100u) % 10u;     // extrage 01.00 digit
                         LCDGotoXY(0,6);
                         LCDsendChar(ch);               // scrie digit ASCII in dreptul cursorului
                         // LCDdefinechar(txt,ch);
                         
                         ch = (adc / 10u) % 10u;      // extrage 00.10 digit
                         LCDGotoXY(0,7);
                         LCDsendChar(ch);               // scrie digit ASCII in dreptul cursorului
                         // LCDdefinechar(txt,ch);
                         
                         ch = adc % 10u;              // extrage 00.01 digit
                         LCDGotoXY(0,8);
                         LCDsendChar(ch);               // scrie digit ASCII in dreptul cursorului
                         // LCDdefinechar(txt,ch);     */
    } while (1);
}

Rezultatul pe LCD e ca nu printeaza mai nimic. Ori nu sunt bune fisierele "lcd_lib.h" si "lcd_lib.c" ? :scratchchin:

Editat de dan_e
Link spre comentariu
Distribuie pe alte site-uri

Dan,

 

Testeaza-le independent.

 

 

asigura-te ca LCD-ul e ok.  Cate fire de date ai conectate la lcd 4 sau 8 ?

 

Primul lucru cu alimentarea pusa fara sa rulezi cod (adica fara "Main_Init()") ajusteaza tensiunea de contrast pana vezi niste patrate pe ecran. (poza mai jos)   In timp ce ruleaza Main_Init() ar trebui sa vezi un flicker pe LCD cand se initializeaza.

 

daca totul e ok rulaza 

 

Main_Init();

LCDGotoXY(0,1);                                    

LCDsendChar('X');          // scrie 'X'

while(1);

 

si vezi daca apare X pe LCD.

 

Daca nu apare ai o problema cu conexiunile sau cu functia de initializare. Unele LCD-uri se initalizeaza lent si e bine sa astepti 100ms dupa initializare.

RR

 

image.png.dfa33708e531c51449c37c25822ed465.png

Link spre comentariu
Distribuie pe alte site-uri

Creează un cont sau autentifică-te pentru a adăuga comentariu

Trebuie să fi un membru pentru a putea lăsa un comentariu.

Creează un cont

Înregistrează-te pentru un nou cont în comunitatea nostră. Este simplu!

Înregistrează un nou cont

Autentificare

Ai deja un cont? Autentifică-te aici.

Autentifică-te acum
  • Navigare recentă   0 membri

    • Nici un utilizator înregistrat nu vede această pagină.
×
×
  • Creează nouă...

Informații Importante

Folosim cookie-uri și tehnologii asemănătoare pentru a-ți îmbunătăți experiența pe acest website, pentru a-ți oferi conținut și reclame personalizate și pentru a analiza traficul și audiența website-ului. Înainte de a continua navigarea pe www.tehnium-azi.ro te rugăm să fii de acord cu: Termeni de Utilizare.

ATENTIE !!! Functionarea Tehnium Azi depinde de afisarea de reclame.

Pentru a putea accesa in continuoare site-ul web www.tehnium-azi.ro, va rugam sa dezactivati extensia ad block din browser-ul web al vostru. Dupa ce ati dezactivat extensia ad block din browser dati clic pe butonul de mai jos.

Multumim.

Apasa acest buton dupa dezactivarea extensiei Adblock