Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Микроконтроллеры (MCU) и микропроцессоры (MPU) > Atmega32a+ds1338


Автор: Yarmak 15.7.2013, 16:45
Доброго времени суток. Прошерстил темки, но решения своей проблемы не нашел. А суть вот в чем: пытаюсь разобраться с аппаратным twi, использую atmega32a, wh1601a и ds1338, как видно из темы. С дисплеем разобрался, а вот с часами не смог. Пытаюсь вытащить секунды из rtc и вывести их на дисплей. Скурил море даташитов и прочитал кучу статей, но данных из rtc добиться не смог. Привожу код ниже, помогите найти ошибку пожалуйста. В МК совсем плох, но активно осваиваю.
Код

/*
 * display.c
 *
 * Created: 09.07.2013 11:28:44
 *  Author: George Yarmak
 */ 

#define F_CPU 1600000
#define F_SCL 10000

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

// ds1338 defines
#define ds_address            11010000
#define TWI_START            0
#define TWI_RESTART         1
#define TWI_STOP            2
#define TWI_TRANSMIT        3
#define TWI_RECEIVE_ACK     4
#define TWI_RECEIVE_NACK    5

//LCD Port defines
#define LCD_DDR        DDRA
#define LCD_OUT        PORTA
#define LCD_IN        PINA
#define    E            2
#define    RW            1
#define    RS            0
#define    D7            7
#define    D6            6
#define    D5            5
#define    D4            4

#define   SetBit(reg, bit)   reg |= (1<<bit)
#define   ClearBit(reg, bit) reg &= (~(1<<bit))
#define   InvBit(reg, bit)   reg ^= (1<<bit)
#define   BitIsSet(reg, bit)   ((reg & (1<<bit)) != 0)
#define   BitIsClear(reg, bit)   ((reg & (1<<bit)) == 0)

void LCD4Char(uint8_t ch)
{
    LCD_OUT=(ch&0b11110000);
    LCD_OUT|=1<<RS;
    LCD_OUT|=1<<E;
    _delay_ms(2);
    LCD_OUT&=~(1<<E);
    LCD_OUT&=~(1<<RS);
    _delay_ms(2);
    LCD_OUT=((ch&0b00001111)<<4);
    LCD_OUT|=1<<RS;
    LCD_OUT|=1<<E;
    _delay_ms(2);
    LCD_OUT&=~(1<<E);
    LCD_OUT&=~(1<<RS);
    _delay_ms(2);
}

void LCD4_cmd(uint8_t cmd)
{
    LCD_OUT=(cmd&0b11110000);
    LCD_OUT|=1<<E;
    _delay_ms(2);
    LCD_OUT&=~(1<<E);
    _delay_ms(2);
    LCD_OUT=((cmd&0b00001111)<<4);
    LCD_OUT|=1<<E;
    _delay_ms(2);
    LCD_OUT&=~(1<<E);
    _delay_ms(2);
}

void LCD_cmd(uint8_t cmd)
{
    LCD_OUT=cmd;
    SetBit(LCD_OUT,E);
    _delay_ms(2);
    ClearBit(LCD_OUT,E);
    _delay_ms(2);
}

void LCD4_init(void)
{
    LCD_DDR=(1<<E)|(1<<RS)|(1<<RW)|(1<<D7)|(1<<D6)|(1<<D5)|(1<<D4);
    _delay_ms(40);
    //function set 0 //8-bit
    LCD_cmd(0b000110000);
    //function set 1 //8-bit
    LCD_cmd(0b000110000);
    //function set 2 //set 4-bit mode
    LCD4_cmd(0b00100000);
    //function set 3 //4-bit mode
    LCD4_cmd(0b00100000);
    //display on //set blink cursor
    LCD4_cmd(0b00001100);
    //display clear
    LCD4_cmd(0b00000001);
    //entry mode set
    LCD4_cmd(0b00000010);
}

void twi_init(void)
{
    TWBR=(F_CPU/F_SCL-16)/2;
    TWSR=0x00;
    TWDR = 0xFF;    // Default content = SDA released.
    TWCR = 0;
    TWCR = (1<<TWEN)|(0<<TWIE)|(0<<TWINT)|(0<<TWEA)|(0<<TWSTA)|(0<<TWSTO)|(0<<TWWC);  
}

uint8_t TWI(uint8_t action){
    switch(action){
        case TWI_START:
        case TWI_RESTART:
        TWCR = _BV(TWSTA) | _BV(TWEN) | _BV(TWINT);// | _BV(TWIE);
        break;
        case TWI_STOP:
        TWCR = _BV(TWSTO) | _BV(TWEN) | _BV(TWINT);// | _BV(TWIE);
        break;
        case TWI_TRANSMIT:
        TWCR = _BV(TWEN) | _BV(TWINT);// | _BV(TWIE);
        break;
        case TWI_RECEIVE_ACK:
        TWCR = _BV(TWEN) | _BV(TWINT) | _BV(TWEA);//| _BV(TWIE);
        break;
        case TWI_RECEIVE_NACK:
        TWCR = _BV(TWEN) | _BV(TWINT);// | _BV(TWIE);
        break;
    }
    if(action != TWI_STOP)while (!(TWCR & _BV(TWINT)));
    return (TWSR & 0xF8);
}

unsigned char TWI_Transceiver_Busy( void )
{
    while (!(TWCR & (1<<TWINT)));            //Wait for TWINT Flag set. This indicates that the START condition has been transmitted
}

int main(void)
{
    twi_init();
    LCD4_init();
    uint8_t sec;

    while(1)
    {
        //TWI_Transceiver_Busy();    // Wait until TWI is ready for next transmission.
        TWI(TWI_START);                        //start
        TWDR=ds_address;                    //target device address (ds1338) 
        TWI(TWI_TRANSMIT);                    //transmit
        TWI(TWI_RECEIVE_ACK);                
        TWI_Transceiver_Busy();    // Wait until TWI is ready for next transmission.
        TWDR=0x00;                            //seconds address in table
        TWI(TWI_TRANSMIT);                    //transmit
        TWI(TWI_RECEIVE_ACK);
        TWI_Transceiver_Busy();    // Wait until TWI is ready for next transmission.
        TWI(TWI_RESTART);                    //restart
        TWDR=ds_address & 1;                //target device address (ds1338)
        TWI(TWI_TRANSMIT);                    //transmit
        TWI_Transceiver_Busy();    // Wait until TWI is ready for next transmission.
        //twi(TWI_RECEIVE_ACK);                //form ACK
        //sec=TWDR;                            //take byte of seconds ds1338
        TWI(TWI_RECEIVE_NACK);                //form NACK (don't need more data)
        sec = TWDR;                            //take last byte of seconds ds1338
        TWI(TWI_STOP);                        //stop
        LCD4_cmd(0b00000010);
        LCD4Char(0b00110000 | (sec & 00001111));
        LCD4Char(0b00110000 | (sec>>4));
        _delay_ms(10000);
    }
}

Автор: LeonidPr 16.7.2013, 10:54
Хорошо бы для начала посмотреть осциллографом идет-ли передача (хотя-бы есть ли попытки)?
Если нет такой возможности, проверьте код инициализации модуля I2C.

Автор: Mazzi 16.7.2013, 15:29
В программе нет инициализации выводов портов TWI. Думаю что проблема в этом.

Автор: Yarmak 17.7.2013, 11:43
Цитата(Mazzi @ 16.7.2013,  15:29)
В программе нет инициализации выводов портов TWI. Думаю что проблема в этом.

Не подскажите как? У меня прямо сейчас перед глазами раздел TWI даташита атмеги и там ничего про открытие портов не написано. Я добавил следующие строки, как я понимаю инициализацию порта TWI:
Код

    PORTC |= (1<<0)|(1<<1);
    DDRC &=~(1<<0)|(1<<1);

Но от этого работать не стало.:(

Автор: Yarmak 31.7.2013, 13:01
Ни у кого идеи не появились? Очень надо. Скажите что выложить и я это выложу.

Автор: Romikgy 31.7.2013, 14:56
сделай свой проект в протеусе и закинь его и исходники в архив , там и посмотрим

Автор: Yarmak 31.7.2013, 16:27
Цитата(Romikgy @ 31.7.2013,  14:56)
сделай свой проект в протеусе и закинь его и исходники в архив , там и посмотрим

Ок, подождите, надо скачать и освоить оный. 

UPD: Подождите недельку так. :/ Это сложнее, чем я думал.

Автор: Yarmak 1.8.2013, 15:48
Ок, готово. И даже в Протеусе мне выводит два ноля. На что-то намекает...

Автор: Yarmak 5.8.2013, 16:33
Сам нашел ошибку:
Цитата

Код

TWDR=ds_address & 1;                //target device address (ds1338)


Это же надо было так обсраться: неделю вкуривал, а ошибка такая тривиальная.

Автор: Romikgy 13.8.2013, 09:44
зато протеус освоил ))

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)