Elektroda.pl
Elektroda.pl
X
Proszę, dodaj wyjątek dla www.elektroda.pl do Adblock.
Dzięki temu, że oglądasz reklamy, wspierasz portal i użytkowników.

Atmega16 + LCD. LCD robi tylko standardowe kwadraty.

02 Lut 2009 22:13 2174 5
  • Poziom 13  
    Witam
    Aż wstyd mi zacząć bo temat niby taki banalny

    Otóż Zbudowałem sobie urządzonko na Atmedze16 z LCD 16x4

    Wszystko ładnie ruszyło oprócz LCD on oprócz standardowych kwadratów nic nie robi
    R/W oczywiście jest do masy wszystkie połączenia są na 100%ok
    LCD po podłączeniu do PC przez LPT rusza bez zająknięcia
    a z Atmegą nie chce

    Program jest napisany w bascomie
    oto listing
    Code:
    $regfile = "m16def.dat"
    
    $crystal = 8000000
    Config Lcdmode = Port                                       'Wybieram typ podlaczenia lcd
    Config Lcdbus = 4                                           'LCD podpiety na 4 zyly
    Config Lcd = 16 * 4                                         'Typ LCD
    Config Lcdpin = Pin , Db4 = Pc.5 , Db5 = Pc.4 , Db6 = Pc.3 , Db7 = Pc.2 , E = Pc.6 , Rs = Pc.7       'Jak podpiety LCD
    Cursor Off                                                  'Wylaczam kursor na LCD
    Display On                                                  'Wlaczam LCD
    Cursor Noblink   
    Cls
    Do
    Lcd "ABC"
    Loop   

    Jest mnie ktoś w stanie nakierować co może być nie tak ?
    Proszę o pomoc i Pozdrawiam
  • Poziom 32  
    Wyłącz JTAGA bo jest on standardowo uruchomiony i blokuje niektóre końcówki portu C.
  • Poziom 13  
    Niestety po wyłączeniu JTAGA w Fusebitach LCD nie ruszył ale dzięki za pomoc
  • Pomocny post
    Poziom 32  
    Na pewno masz te 8MHz? Po za tym spróbuj wyrzucić to:
    Code:
    Config Lcdmode = Port
    i to
    Code:
    Display On   
    oraz zamiast pisać tak:
    Code:
    Db4 = Pc.5
    napisz tak:
    Code:
    Portc.5
    . Śmiem twierdzić że połączenia sprawdzałeś kilka razy oraz sprawdziłeś czy na wszystkich końcówkach portu C pojawia się określony stan(specjalnie wykonany test).
  • Poziom 13  
    Dzięki za pomoc
    Już działa
    Po zmianie programu
    Troche przyznam mnie to zdziwilo bo jak robiłem zawsze coś na tych LCDkach w bascomie to na tamtym kodzie zawsze działało
    Ale jak by nie było to dzięki za pomoc :p
    Pozdrawiam
  • Poziom 10  
    Mój problem trochę zazębia sie z tym wątkiem, dlatego tutaj go opiszę.
    Atmega16 z wyświetlaczem podpiętym do portu C (JTAG wyłączony). Po kompilacji programu, wgraniu programu do procesora i ustawieniu fuse bitów 0xff i 0xc9 na wyświetlaczu LCD w pierwszej linii świecą się tylko prostokąty. Reset procesora niczego nie zmienia.
    LCD podłączony poprawnie, wyświetlacz sprawny, układ montażowy też poprawny (po wgraniu innego programu w tym układzie docelowym program jest wykonywany i wyświetlacz działa poprawnie). Wniosek - źle napisany program (chyba :cry:).
    Program sprawdzany wiele razy, komplilacja wykonywana bez błędów, a mimo to coś nie działa.
    Może ktoś pomoże znaleźć błędy w programie? Załączam listing programu:
    Code:

    #define debug

    //MCU ATMega16, 14.7456MHz

    /*PIN assignment

    LCD display (standard text controller):
       PC0-3=DB4-7
       PC4=E
       PC5=RW
       PC6=RS
       PC7= reserved (for light via NPN transistor - 150mA)

    Rotational coder (capacitors 100nF at contacts necessary to prevent spurious edges):
       PD2 (left)
       PD3 (right)
       PB2 (press)

    FETs:
       PD4 charge
       PD5 weld_power
       PD6 discharge

    ADCs:
       PA0,1,2 .. potenciometr 0,1,2
       PA3 ... Vext R divisor 33k+220k
       PA4 ... Vcap R divisor 33k+220k

    LED:    PB0 via 470R

    Triger pedal switch (normally open):   PB1 (using internal pullup, 100nF cap. parallel)
       

    */
    #define XTAL 14745600
    #define BAUD 19200

    #include "backward.h"
    #include <avr/io.h>
    #include <avr/pgmspace.h>
    #include <avr/eeprom.h>
    #include <avr/interrupt.h>
    #include <setjmp.h>
    #include <avr/sleep.h>
    #include <avr/wdt.h>
    #include <stdlib.h>
    #include <string.h>




    #if defined(at90s2313) || defined(at90s8535)
    #else
    #define ATmega
    #endif

    #ifdef ATmega
    #define USR UCSRA
    #endif


    #ifndef MCU
    #define emulate
    #else
    #define AVR_assembler
    #endif

    #define itoa10(N,S) itoa(N,S,10)
    #define itoa16(N,S) itoa(N,S,16)


    void printP (PGM_P string){
            char c;
            c=pgm_read_byte(string);
                       while (c) {
                       loop_until_bit_is_set(USR, UDRE);
                       UDR = c;
                       c=pgm_read_byte(++string);
                       }
                       return;
                     }



    void print (char *string){                                     
                       while (*string) {                                           
                       loop_until_bit_is_set(USR, UDRE);                           
                       UDR = *string++;
                       }                                                           
                       return;                                                     
                     }                                                             




    //UART initialize
    #ifdef ATmega
    #define UCR UCSRB
    #define UART_INIT(baud) { \
    UBRRH=0; \
    UBRRL= (XTAL/baud+15)/16-1; \
    UCSRB=(1<<TXEN)|(1<<RXEN)|(1<<RXCIE); \
    UCSRC=(1<<URSEL)|(1<<UCSZ0)|(1<<UCSZ1)|(1<<USBS); }
    #else
    #define UART_INIT(baud) { \
    UBRR = (XTAL/baud+15)/16-1; \
    sbi(UCR, TXEN); \
    sbi(UCR, RXEN); \
    }
    #endif

    //UART routines
    volatile uint8_t inuartlen=0;
    volatile uint8_t uartline=0;
    #define MAXUART 64
    volatile char inuart[MAXUART];
    INTERRUPT(SIG_UART_RECV)
    {
    char c=UDR;
    if(uartline) return; //ignore until line is processed
    UDR = c; //echo
    if(c=='\n' || c== '\r' || inuartlen == MAXUART-1) {uartline=1; inuart[inuartlen]=0; inuartlen=0;}
    else inuart[inuartlen++]=c;
    }

    uint16_t Vset = 120;


    watchdog(uint8_t onoff)
    {
    if(onoff) {wdt_enable(WDTO_2S); wdt_reset();}
    else {wdt_reset();wdt_disable();}
    }


    //rotational coder routines
    volatile static uint8_t menustate=0;
    volatile static int8_t menuselect=0;


    #define N_MENULABEL 1
    typedef char MENULABEL[9];
    static const MENULABEL  menulabel[N_MENULABEL] = {"WELDER"};


    void process_rotation(uint8_t sense)
    {
    switch (menustate) {
            case 1:
          if(sense) ++menuselect; else --menuselect;
          if(menuselect<0) menuselect+=N_MENULABEL;
          menuselect = menuselect%N_MENULABEL;
                    break;
            case 0:
          if(sense) ++Vset; else --Vset;
          if(Vset<10) Vset=10;
          if(Vset>350) Vset=350;
            default:
          break;
    }
    }


    //right:
    //I0:01
    //I1:00
    //I0:10
    //I1:11
    //
    //left:
    //I1:10
    //I0:00
    //I1:01
    //I0:11
    //

    volatile static int8_t rotcount=0;
    void rotcoder(uint8_t interrupt, uint8_t pins)
    {
    if(interrupt)
       {
       if(pins==0 || pins==3) ++rotcount;
       else --rotcount;
       }
    else
       {
       if(pins==0 || pins==3) --rotcount;
       else ++rotcount;
       }
    if(rotcount==4) {process_rotation(1); rotcount=0;}
    if(rotcount== -4) {process_rotation(0); rotcount=0;}
    }

    volatile static uint8_t light=0;

    void process_press(uint8_t length)
    {
    switch (menustate) {
       default:
          if(length)  //long press
             {
             }
          else      //short press
             {
             }
    }
    }

    INTERRUPT(SIG_INTERRUPT0)
    {
    rotcoder(0,(PIND>>2)&3);
    }

    INTERRUPT(SIG_INTERRUPT1)
    {
    rotcoder(1,(PIND>>2)&3);
    }

    volatile static uint8_t timer0x=0;

    INTERRUPT(SIG_INTERRUPT2)
    {
    uint16_t tim;
    uint8_t x;
    cbi(GIMSK,INT2);
    cbi(GICR,INT2);
    //toggle the active edge
    if(x=bit_is_set(PINB,PB2))
       {
       cbi(MCUCSR,ISC2);
       tim=timer0x;
       tim = (tim<<8)|TCNT0;
       }
    else
       {
       sbi(MCUCSR,ISC2);
       TCNT0=0;
       timer0x=0;
       }
    cbi(GIFR,INTF2);
    sbi(GICR,INT2);
    sbi(GIMSK,INT2);
    if(!x) return;
    process_press(tim>3000);
    }

    INTERRUPT(SIG_OVERFLOW0)
    {
    ++timer0x;
    }


    init_rotcoder(void)
    {
    //start timer0
    TCNT0=0;
    TCCR0=CK1024;
    OCR0=0;
    sbi(TIMSK,TOIE0);

    //pull-up pins
    cbi(DDRD,PD2); sbi(PORTD,PD2);
    cbi(DDRD,PD3); sbi(PORTD,PD3);
    cbi(DDRB,PB2); sbi(PORTB,PB2);

    //and allow edge interrupts on INT0,1,2
    sbi(MCUCR,ISC00); cbi(MCUCR,ISC01);
    sbi(GIMSK,INT0);
    sbi(MCUCR,ISC10); cbi(MCUCR,ISC11);
    sbi(GIMSK,INT1);
    cbi(MCUCSR,ISC2);
    sbi(GIMSK,INT2);
    }


    //delay routines

    void delay_xs(uint16_t xs) //xs takes 4 clocks time
    {
            asm volatile (
            "\n"
            "L_dl1%=:" "\n\t"
            "sbiw %0, 1" "\n\t"
            "brne L_dl1%=" "\n\t"
            : "=&w" (xs)
            );
            return;
    }

    void delay_ms(uint16_t ms) //ms takes 1/1000 s
    {
    while(ms--) delay_xs(XTAL/4/1000);
    }

    void delay_ms10(uint8_t ms) //ms takes 1/10000 s
    {
    while(ms--) delay_xs(XTAL/4/10000);
    }

    void delay_ms100(uint8_t ms) //ms takes 1/100000 s
    {
    while(ms--) delay_xs(XTAL/4/100000);
    }



    //display routines

    #define lcd_delay 50

    void lcd_w4bit(uint8_t rs, uint8_t x)
    {
    PORTC= 1<<PC4|light
    #if (MCU == atmega8 )
       ; if(rs) sbi(PORTD,PD4); else cbi(PORTD,PD4);
    #else
        | rs <<PC6;
    #endif
    delay_xs(lcd_delay);
    PORTC |= x&0x0f;
    delay_xs(lcd_delay);
    cbi(PORTC,PC4);
    delay_xs(lcd_delay);
    sbi(PORTC,PC4);
    delay_xs(lcd_delay);
    }

    uint8_t lcd_r4bit(uint8_t rs)
    {
    uint8_t r;
    PORTC= 1<<PC4 | 1<<PC5|light
    #if (MCU == atmega8 )
            ; if(rs) sbi(PORTD,PD4); else cbi(PORTD,PD4);
    #else
             | rs <<PC6;
    #endif
    delay_xs(lcd_delay);
    cbi(PORTC,PC4);
    delay_xs(lcd_delay);
    r=PINC&0x0f;
    cbi(PORTC,PC5);
    delay_xs(lcd_delay);
    return r;
    }

    uint8_t lcd_rbyte(uint8_t rs)
    {
    #if (MCU == atmega8 )
    sbi(DDRD,PD4);
    DDRC=0x30;
    #else
    DDRC=0xf0;
    #endif
    delay_xs(lcd_delay);
    return (lcd_r4bit(rs)<<4)|lcd_r4bit(rs);
    #if (MCU == atmega8 )
    sbi(DDRD,PD4);
    DDRC=0x3f;
    #else
    DDRC=0xff;
    #endif
    delay_xs(lcd_delay);
    }

    void lcd_init4bit(void)
    {
    #if (MCU == atmega8 )
    sbi(DDRD,PD4);
    DDRC=0x3f;
    #else
    DDRC=0xff;
    #endif
    delay_xs(20000);
    lcd_w4bit(0,3);
    delay_xs(10000);
    lcd_w4bit(0,3);
    delay_xs(500);
    lcd_w4bit(0,3);
    lcd_w4bit(0,2);
    }

    void lcd_wbyte(uint8_t rs, uint8_t x)
    {
    lcd_w4bit(rs,x>>4);
    lcd_w4bit(rs,x);
    }

    void lcd_clear(void)
    {
    lcd_wbyte(0,0x01);
    delay_xs(30000);
    }

    void lcd_init(void)
    {
    lcd_init4bit();
    lcd_wbyte(0,0x28);
    lcd_wbyte(0,0x08);
    lcd_clear();
    lcd_wbyte(0,0x06);
    lcd_wbyte(0,0x0c);
    }

    void lcd_print(char *t)
    {
    while(*t) if(*t=='\n') {++t; lcd_wbyte(0,0xc0);} else lcd_wbyte(1,*t++);
    }


    void lcd_print8(char *t)
    {
    uint8_t l=0;
    while(*t) {lcd_wbyte(1,*t++); ++l;}
    while(l<8) {lcd_wbyte(1,' '); ++l;}
    }

    void lcd_cursor(uint8_t r, uint8_t c)
    {
    lcd_wbyte(0,0x80+c+(r<<6));
    }


    void printx(uint16_t x, char z, char *t)
    {
    strcpy(t,"  .  ");
    t[4]= z;
    t[3]= '0'+x%10; x/=10;
    t[1]= '0'+x%10; x/=10;
    t[0]= '0'+x%10;
    }

    void printy(uint16_t x, char z, char *t)
    {
    strcpy(t," .   ");
    t[4]= z;
    t[3]= '0'+x%10; x/=10;
    t[2]= '0'+x%10; x/=10;
    t[0]= '0'+x%10;
    }

    uint16_t adcread(uint8_t i)
    {
    ADMUX= i;
    ADCSRA= (1<<ADEN)|(1<<ADIF)|(1<<ADSC)|7;
    loop_until_bit_is_set(ADCSRA,ADIF);
    uint16_t v=ADCL;
    v|= (ADCH<<8);
    return v;
    }

    uint16_t voltage(uint8_t i)
    {
    uint32_t tmp= 1176; //calibrated for a given voltage divider resistor tolerance and the fact that the reference voltage is not exactly 5V but depends on the particular stabilizer. High accuracy is not needed anyway
    tmp *= adcread(i);
    tmp /= 3;
    return tmp>>10;
    }


    int main(void)
    {
    uint16_t pass;
    UART_INIT(BAUD);

    //global interrupt activate
    sbi(SREG,7);

    //setup inputs and outputs
    sbi(DDRB,PB0); cbi(PORTB,PB0); //led
    cbi(DDRB,PB1); sbi(PORTB,PB1); //trigger
    sbi(DDRD,PD4); cbi(PORTD,PD4); //charge
    sbi(DDRD,PD5); cbi(PORTD,PD5); //weld
    sbi(DDRD,PD6); cbi(PORTD,PD6); //discharge

    //write initial message to the display and blink leds
    lcd_init();
    lcd_print("Spot Welder");
    printP(PSTR("Spot Welder Reset!\n"));

    delay_ms(500);
    lcd_clear();

    //enable rotcoder
    init_rotcoder();

    uint16_t Vext, Vcap;
    uint8_t times[3];
    const  uint8_t timemax[3]={200,150,150};

    //MAIN LOOP
    while(1)
    {
    ++pass;
    uint8_t i;

    //read potentiometers
    for(i=0; i<=2; ++i)
       {
       uint32_t tmp= timemax[i];
       tmp *= (adcread(i)+1);
       times[i]= tmp>>10;
       }

    //read Vext and Vcap
    Vext = voltage(3);
    Vcap = voltage(4);

    //charge/discharge for a while if needed
    cbi(PORTD,PD5);
    cbi(PORTD,PD4);
    cbi(PORTD,PD6);
    if(Vcap<Vset) sbi(PORTD,PD4); //charge
    if(Vcap>Vset+1) sbi(PORTD,PD6); //discharge

    //
    //control display according state set by asynchronous events
    switch (menustate) {
       case 1: //in menu
          break;
       case 0:
       default:
          {
          char text[17];
          printx(Vext,' ',text);
          printx(Vset,' ',text+5);
          printx(Vcap,' ',text+10);
          lcd_cursor(0,0);
          lcd_print(text);
          printy(times[0],' ',text);
                    printx(times[1],' ',text+5);
                    printx(times[2],' ',text+10);
          lcd_cursor(1,0);
          lcd_print(text);
          }
       break;
    }

    //if ready, light the LED and check trigger
    if(abs(Vset-Vcap)<2)
       {
       sbi(PORTB,PB0);
       if(bit_is_clear(PINB,PB1))
          {
          uint16_t Vcap0 = Vcap;
          printP(PSTR("FIRE!\n"));
          if(times[0]) {sbi(PORTD,PD5); delay_ms100(times[0]);}
          cbi(PORTD,PD5); delay_ms10(times[1]);
          uint16_t Vcap1 = voltage(4);
          if(times[2]) {sbi(PORTD,PD5); delay_ms10(times[2]);}
          cbi(PORTD,PD5);
          delay_ms(1);
          Vcap = voltage(4);
          char text[6];
          printx(Vcap,' ',text);
          lcd_clear();
          lcd_cursor(0,0);
          lcd_print("Vcap left ");
          lcd_cursor(0,10);
          lcd_print(text);
          printP(PSTR("Vcap remaining: ")); print(text); print("\n");
          printP(PSTR("Pulse energies: "));
          lcd_cursor(1,0); lcd_print("Puls E ");
          uint32_t energy = Vcap0*Vcap0 - Vcap1*Vcap1;
          energy *=94; energy /= 10000; //for 0.94Farad capacitance
          itoa10((uint16_t)(energy&0xffff),text); print(text);
          print(" ");
          lcd_cursor(1,7); lcd_print(text);
          energy = Vcap1*Vcap1 - Vcap*Vcap;
                    energy *=94; energy /= 10000; //for 0.94Farad capacitance
                    itoa10((uint16_t)(energy&0xffff),text); print(text);
          print("\n");
          lcd_cursor(1,11); lcd_print(text);
          do{} while(bit_is_clear(PINB,PB1)); //wait for release of trigger
          lcd_clear();
          }
       }
    else
       {
       cbi(PORTB,PB0);
       cbi(PORTD,PD5);
       }

    delay_ms(5);
    }//while
    }


    Do poprawnej kompilacji potrzebne jeszcze pliki:

    Liczę na pomoc bardziej doświadczonych w programowaniu AVR